fix: better support for identifier calculation

This commit is contained in:
egarette@silique.fr 2026-03-04 08:38:39 +01:00
parent 130bb4d8da
commit f7aad40ee7
11 changed files with 163 additions and 10 deletions

View file

@ -248,10 +248,14 @@ class Annotator(Walk): # pylint: disable=R0903
).format(variable.path)
raise DictConsistencyError(msg, 75, variable.xmlfiles)
self._convert_variable_multi(calculated_variable)
identifier_is_a_calculation = False
if isinstance(variable.default, Calculation):
identifier_is_a_calculation = isinstance(variable.default.identifier, Calculation)
variable.multi = calc_multi_for_type_variable(
variable,
calculated_variable_path,
calculated_variable,
identifier_is_a_calculation,
self.objectspace,
)[1]
if (

View file

@ -248,7 +248,7 @@ class ParserVariable:
set(hint) - {"name", "path", "xmlfiles"} | {"redefine", "exists"}
)
self.variable_calculations = self.search_calculation( # pylint: disable=W0201
hint
hint, variable=True,
)
self.is_init = True
@ -969,6 +969,9 @@ class ParserVariable:
return value["type"] in CALCULATION_TYPES
# auto set type
typ = set(CALCULATION_TYPES) & set(value)
# XXX variable could have identifier
if typ == {"variable", "identifier"}:
typ = {"variable"}
# XXX variable is also set to information
if typ == {"variable", "information"}:
typ = {"information"}
@ -1002,7 +1005,12 @@ class ParserVariable:
#
if attribute == "default" and "identifier" in calculation_object:
identifier = calculation_object["identifier"]
if isinstance(identifier, dict):
if isinstance(identifier, dict) and self.is_calculation(
"identifier",
identifier,
self.variable_calculations,
inside_list,
):
self.set_calculation(calculation_object, "identifier", identifier, path, family_is_dynamic, xmlfiles, inside_list=inside_list, index=index)
if "params" in calculation_object:
if not isinstance(calculation_object["params"], dict):
@ -1091,10 +1099,15 @@ class RougailConvert(ParserVariable):
def search_calculation(
self,
hint: dict,
variable: bool=False,
) -> Tuple[List[Any], List[Any]]:
"""attribute is calculated if typing is like: Union[Calculation, xxx]"""
inside_list = []
outside_list = []
if variable:
inside_list = ["identifier"]
outside_list = ["identifier"]
else:
inside_list = []
outside_list = []
for key, value in hint.items():
if "Union" in value.__class__.__name__ and (
Calculation in value.__args__ or VariableCalculation in value.__args__

View file

@ -575,10 +575,9 @@ class _VariableCalculation(Calculation):
params["__default_value"] = self.default_values
if self.allow_none:
params["allow_none"] = True
if not identifier_is_a_calculation:
self.check_multi(
objectspace, path, variable_in_calculation_path, variable_in_calculation,
)
self.check_multi(
objectspace, path, variable_in_calculation_path, variable_in_calculation, identifier_is_a_calculation,
)
if path in objectspace.followers:
multi = objectspace.multis[path] == "submulti"
else:
@ -588,7 +587,7 @@ class _VariableCalculation(Calculation):
return params
def check_multi(
self, objectspace, path, variable_in_calculation_path, variable_in_calculation
self, objectspace, path, variable_in_calculation_path, variable_in_calculation, identifier_is_a_calculation,
):
local_variable = objectspace.paths[path]
local_variable_multi, variable_in_calculation_multi = (
@ -596,6 +595,7 @@ class _VariableCalculation(Calculation):
local_variable,
variable_in_calculation_path,
variable_in_calculation,
identifier_is_a_calculation,
objectspace,
)
)

View file

@ -157,6 +157,7 @@ def calc_multi_for_type_variable(
local_variable: "Variable",
variable_in_calculation_path: str,
variable_in_calculation: "Variable",
identifier_is_a_calculation: bool,
objectspace: "RougailConvert",
) -> Union[bool, str]:
variable_in_calculation_multi = variable_in_calculation.multi
@ -192,7 +193,10 @@ def calc_multi_for_type_variable(
common_variable_path = variable_in_calculation_path
if common_path:
common_variable_path = common_variable_path[len(common_path) + 1 :]
count_identifiers = common_variable_path.count("{{ identifier }}")
if identifier_is_a_calculation:
count_identifiers = 0
else:
count_identifiers = common_variable_path.count("{{ identifier }}")
if count_identifiers == 1:
if variable_in_calculation_multi is False:
variable_in_calculation_multi = True

View file

@ -0,0 +1,31 @@
{
"rougail.var1": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.var2": {
"owner": "default",
"value": "val1"
},
"rougail.dynval1.var": {
"owner": "default",
"value": [
"val1"
]
},
"rougail.dynval2.var": {
"owner": "default",
"value": [
"val2"
]
},
"rougail.var3": {
"owner": "default",
"value": [
"val1"
]
}
}

View file

@ -0,0 +1,16 @@
{
"rougail.var1": [
"val1",
"val2"
],
"rougail.var2": "val1",
"rougail.dynval1.var": [
"val1"
],
"rougail.dynval2.var": [
"val2"
],
"rougail.var3": [
"val1"
]
}

View file

@ -0,0 +1,31 @@
{
"rougail.var1": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.var2": {
"owner": "default",
"value": "val1"
},
"rougail.dynval1.var": {
"owner": "default",
"value": [
"val1"
]
},
"rougail.dynval2.var": {
"owner": "default",
"value": [
"val2"
]
},
"rougail.var3": {
"owner": "default",
"value": [
"val1"
]
}
}

View file

@ -0,0 +1,16 @@
{
"rougail.var1": [
"val1",
"val2"
],
"rougail.var2": "val1",
"rougail.dynval1.var": [
"val1"
],
"rougail.dynval2.var": [
"val2"
],
"rougail.var3": [
"val1"
]
}

View file

@ -0,0 +1,19 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="var1", doc="A suffix variable", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
option_3 = StrOption(name="var2", doc="A suffix variable2", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
option_5 = StrOption(name="var", doc="A dynamic variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamIdentifier())))], default_multi=Calculation(func['calc_value'], Params((ParamIdentifier()))), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
optiondescription_4 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="dyn{{ identifier }}", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_2)))), children=[option_5], properties=frozenset({"standard"}), informations={'dynamic_variable': 'rougail.var1', 'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml']})
option_6 = StrOption(name="var3", doc="A variable calculated", multi=True, default=Calculation(func['calc_value'], Params((ParamDynOption(option_5, Calculation(func['calc_value'], Params((ParamOption(option_3)), kwargs={'__internal_multi': ParamValue(True)})))), kwargs={'__internal_multi': ParamValue(True)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3, optiondescription_4, option_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,18 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="var1", doc="A suffix variable", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
option_2 = StrOption(name="var2", doc="A suffix variable2", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
option_4 = StrOption(name="var", doc="A dynamic variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamIdentifier())))], default_multi=Calculation(func['calc_value'], Params((ParamIdentifier()))), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
optiondescription_3 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="dyn{{ identifier }}", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_1)))), children=[option_4], properties=frozenset({"standard"}), informations={'dynamic_variable': 'var1', 'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml']})
option_5 = StrOption(name="var3", doc="A variable calculated", multi=True, default=Calculation(func['calc_value'], Params((ParamDynOption(option_4, Calculation(func['calc_value'], Params((ParamOption(option_2)), kwargs={'__internal_multi': ParamValue(True)})))), kwargs={'__internal_multi': ParamValue(True)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/60_5family_dynamic_calc_identifier_multi/rougail/00-base.yml'], 'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2, optiondescription_3, option_5])