WIP: Expand the developer documentation #27

Draft
gremond wants to merge 62 commits from develop into developer_docs
4 changed files with 91 additions and 73 deletions
Showing only changes of commit 086667d7a4 - Show all commits

View file

@ -137,16 +137,16 @@ class VariableParam(Param):
optional: bool = False optional: bool = False
class SuffixParam(Param): class IdentifierParam(Param):
type: str type: str
suffix: Optional[int] = None identifier: Optional[int] = None
def __init__( def __init__(
self, self,
**kwargs, **kwargs,
) -> None: ) -> None:
if not kwargs["family_is_dynamic"]: if not kwargs["family_is_dynamic"]:
msg = f'suffix parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family' msg = f'identifier parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family'
raise DictConsistencyError(msg, 10, kwargs["xmlfiles"]) raise DictConsistencyError(msg, 10, kwargs["xmlfiles"])
super().__init__(**kwargs) super().__init__(**kwargs)
@ -174,7 +174,7 @@ class IndexParam(Param):
PARAM_TYPES = { PARAM_TYPES = {
"any": AnyParam, "any": AnyParam,
"variable": VariableParam, "variable": VariableParam,
"suffix": SuffixParam, "identifier": IdentifierParam,
"information": InformationParam, "information": InformationParam,
"index": IndexParam, "index": IndexParam,
} }
@ -209,7 +209,7 @@ class Calculation(BaseModel):
path = self.path path = self.path
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
param["variable"], param["variable"],
self.path_prefix, self.path_prefix,
path, path,
@ -225,15 +225,15 @@ class Calculation(BaseModel):
if not isinstance(variable, objectspace.variable): if not isinstance(variable, objectspace.variable):
raise Exception("pfff it's a family") raise Exception("pfff it's a family")
param["variable"] = variable param["variable"] = variable
if suffix: if identifier:
param["suffix"] = suffix param["identifier"] = identifier
if param.get("type") == "information": if param.get("type") == "information":
if param["variable"]: if param["variable"]:
if self.ori_path is None: if self.ori_path is None:
path = self.path path = self.path
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
param["variable"], param["variable"],
self.path_prefix, self.path_prefix,
path, path,
@ -245,7 +245,7 @@ class Calculation(BaseModel):
msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"' msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"'
raise DictConsistencyError(msg, 14, self.xmlfiles) raise DictConsistencyError(msg, 14, self.xmlfiles)
param["variable"] = variable param["variable"] = variable
if suffix: if identifier:
msg = f'variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}" is a dynamic variable' msg = f'variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}" is a dynamic variable'
raise DictConsistencyError(msg, 15, self.xmlfiles) raise DictConsistencyError(msg, 15, self.xmlfiles)
else: else:
@ -311,7 +311,7 @@ class JinjaCalculation(Calculation):
path = self.path path = self.path
else: else:
path = self.ori_path path = self.ori_path
for sub_variable, suffix, true_path in get_jinja_variable_to_param( for sub_variable, identifier, true_path in get_jinja_variable_to_param(
path, path,
self.jinja, self.jinja,
objectspace, objectspace,
@ -333,8 +333,8 @@ class JinjaCalculation(Calculation):
"type": "variable", "type": "variable",
"variable": sub_variable, "variable": sub_variable,
} }
if suffix: if identifier:
default["params"][true_path]["suffix"] = suffix default["params"][true_path]["identifier"] = identifier
return default return default
def to_function( def to_function(
@ -410,7 +410,7 @@ class _VariableCalculation(Calculation):
path = self.path path = self.path
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
self.variable, self.variable,
self.path_prefix, self.path_prefix,
path, path,
@ -421,13 +421,13 @@ class _VariableCalculation(Calculation):
if variable and not isinstance(variable, objectspace.variable): if variable and not isinstance(variable, objectspace.variable):
# FIXME remove the pfff # FIXME remove the pfff
raise Exception("pfff it's a family") raise Exception("pfff it's a family")
return variable, suffix return variable, identifier
def get_params( def get_params(
self, self,
objectspace, objectspace,
variable: "Variable", variable: "Variable",
suffix: Optional[str], identifier: Optional[str],
*, *,
needs_multi: Optional[bool] = None, needs_multi: Optional[bool] = None,
): ):
@ -439,8 +439,8 @@ class _VariableCalculation(Calculation):
"variable": variable, "variable": variable,
"propertyerror": self.propertyerror, "propertyerror": self.propertyerror,
} }
if suffix: if identifier:
param["suffix"] = suffix param["identifier"] = identifier
params = {None: [param]} params = {None: [param]}
if self.default_values: if self.default_values:
params["__default_value"] = self.default_values params["__default_value"] = self.default_values
@ -454,7 +454,7 @@ class _VariableCalculation(Calculation):
calc_variable_is_multi = variable.path in objectspace.multis calc_variable_is_multi = variable.path in objectspace.multis
if not calc_variable_is_multi: if not calc_variable_is_multi:
if variable.path in objectspace.paths._dynamics and ( if variable.path in objectspace.paths._dynamics and (
suffix is None or suffix[-1] is None identifier is None or identifier[-1] is None
): ):
self_dyn_path = objectspace.paths._dynamics.get(self.path) self_dyn_path = objectspace.paths._dynamics.get(self.path)
if self_dyn_path is not None: if self_dyn_path is not None:
@ -465,7 +465,7 @@ class _VariableCalculation(Calculation):
calc_variable_is_multi = True calc_variable_is_multi = True
else: else:
calc_variable_is_multi = True calc_variable_is_multi = True
elif suffix and '{{ suffix }}' in suffix: elif identifier and '{{ identifier }}' in identifier:
calc_variable_is_multi = True calc_variable_is_multi = True
if needs_multi: if needs_multi:
if calc_variable_is_multi: if calc_variable_is_multi:
@ -499,12 +499,12 @@ class VariableCalculation(_VariableCalculation):
if self.attribute_name != "default" and self.optional: if self.attribute_name != "default" and self.optional:
msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"' msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"'
raise DictConsistencyError(msg, 33, self.xmlfiles) raise DictConsistencyError(msg, 33, self.xmlfiles)
variable, suffix = self.get_variable(objectspace) variable, identifier = self.get_variable(objectspace)
if not variable and self.optional: if not variable and self.optional:
raise VariableCalculationDependencyError() raise VariableCalculationDependencyError()
params = self.get_params(objectspace, params = self.get_params(objectspace,
variable, variable,
suffix, identifier,
) )
return { return {
"function": "calc_value", "function": "calc_value",
@ -521,10 +521,10 @@ class VariablePropertyCalculation(_VariableCalculation):
self, self,
objectspace, objectspace,
) -> dict: ) -> dict:
variable, suffix = self.get_variable(objectspace) variable, identifier = self.get_variable(objectspace)
params = self.get_params(objectspace, params = self.get_params(objectspace,
variable, variable,
suffix, identifier,
needs_multi=False,) needs_multi=False,)
variable = params[None][0]["variable"] variable = params[None][0]["variable"]
if self.when is not undefined: if self.when is not undefined:
@ -579,7 +579,7 @@ class InformationCalculation(Calculation):
path = self.path path = self.path
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
self.variable, self.variable,
self.path_prefix, self.path_prefix,
path, path,
@ -587,7 +587,7 @@ class InformationCalculation(Calculation):
self.namespace, self.namespace,
self.xmlfiles, self.xmlfiles,
) )
if variable is None or suffix is not None: if variable is None or identifier is not None:
raise Exception("pfff") raise Exception("pfff")
params[None][0]["variable"] = variable params[None][0]["variable"] = variable
if self.default_values: if self.default_values:
@ -598,33 +598,33 @@ class InformationCalculation(Calculation):
} }
class _SuffixCalculation(Calculation): class _IdentifierCalculation(Calculation):
suffix: Optional[int] = None identifier: Optional[int] = None
def get_suffix(self) -> dict: def get_identifier(self) -> dict:
suffix = {"type": "suffix"} identifier = {"type": "identifier"}
if self.suffix is not None: if self.identifier is not None:
suffix["suffix"] = self.suffix identifier["identifier"] = self.identifier
return suffix return identifier
class SuffixCalculation(_SuffixCalculation): class IdentifierCalculation(_IdentifierCalculation):
attribute_name: Literal["default", "choice", "dynamic"] attribute_name: Literal["default", "choice", "dynamic"]
def to_function( def to_function(
self, self,
objectspace, objectspace,
) -> dict: ) -> dict:
suffix = {"type": "suffix"} identifier = {"type": "identifier"}
if self.suffix is not None: if self.identifier is not None:
suffix["suffix"] = self.suffix identifier["identifier"] = self.identifier
return { return {
"function": "calc_value", "function": "calc_value",
"params": {None: [self.get_suffix()]}, "params": {None: [self.get_identifier()]},
} }
class SuffixPropertyCalculation(_SuffixCalculation): class IdentifierPropertyCalculation(_IdentifierCalculation):
attribute_name: Literal[*PROPERTY_ATTRIBUTE] attribute_name: Literal[*PROPERTY_ATTRIBUTE]
when: Any = undefined when: Any = undefined
when_not: Any = undefined when_not: Any = undefined
@ -638,7 +638,7 @@ class SuffixPropertyCalculation(_SuffixCalculation):
raise DictConsistencyError(msg, 105, variable.xmlfiles) raise DictConsistencyError(msg, 105, variable.xmlfiles)
if self.when is not undefined: if self.when is not undefined:
if self.when_not is not undefined: if self.when_not is not undefined:
msg = f'the suffix has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
raise DictConsistencyError(msg, 35, variable.xmlfiles) raise DictConsistencyError(msg, 35, variable.xmlfiles)
when = self.when when = self.when
inverse = False inverse = False
@ -646,9 +646,9 @@ class SuffixPropertyCalculation(_SuffixCalculation):
when = self.when_not when = self.when_not
inverse = True inverse = True
else: else:
msg = f'the suffix has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
raise DictConsistencyError raise DictConsistencyError
params = {None: [self.attribute_name, self.get_suffix()], params = {None: [self.attribute_name, self.get_identifier()],
"when": when, "when": when,
"inverse": inverse, "inverse": inverse,
} }
@ -679,14 +679,14 @@ CALCULATION_TYPES = {
"jinja": JinjaCalculation, "jinja": JinjaCalculation,
"variable": VariableCalculation, "variable": VariableCalculation,
"information": InformationCalculation, "information": InformationCalculation,
"suffix": SuffixCalculation, "identifier": IdentifierCalculation,
"index": IndexCalculation, "index": IndexCalculation,
} }
CALCULATION_PROPERTY_TYPES = { CALCULATION_PROPERTY_TYPES = {
"jinja": JinjaCalculation, "jinja": JinjaCalculation,
"variable": VariablePropertyCalculation, "variable": VariablePropertyCalculation,
"information": InformationCalculation, "information": InformationCalculation,
"suffix": SuffixPropertyCalculation, "identifier": IdentifierPropertyCalculation,
"index": IndexCalculation, "index": IndexCalculation,
} }
BASETYPE_CALC = Union[StrictBool, StrictInt, StrictFloat, StrictStr, Calculation, None] BASETYPE_CALC = Union[StrictBool, StrictInt, StrictFloat, StrictStr, Calculation, None]
@ -729,7 +729,7 @@ class Variable(BaseModel):
help: Optional[str] = None help: Optional[str] = None
hidden: Union[bool, Calculation] = False hidden: Union[bool, Calculation] = False
disabled: Union[bool, Calculation] = False disabled: Union[bool, Calculation] = False
mandatory: Union[None, bool, Calculation] = True mandatory: Union[None, bool, Calculation] = None
empty: Union[None, bool, Calculation] = True empty: Union[None, bool, Calculation] = True
auto_save: bool = False auto_save: bool = False
mode: Optional[str] = None mode: Optional[str] = None

View file

@ -138,35 +138,36 @@ func['valid_with_jinja'] = valid_with_jinja
class ConvertDynOptionDescription(DynOptionDescription): class ConvertDynOptionDescription(DynOptionDescription):
"""Suffix could be an integer, we should convert it in str """Identifier could be an integer, we should convert it in str
Suffix could also contain invalid character, so we should "normalize" it Identifier could also contain invalid character, so we should "normalize" it
""" """
def convert_suffix_to_path(self, suffix): def convert_identifier_to_path(self, identifier):
if suffix is None: if identifier is None:
return suffix return identifier
if not isinstance(suffix, str): if not isinstance(identifier, str):
suffix = str(suffix) identifier = str(identifier)
return normalize_family(suffix) return normalize_family(identifier)
def impl_getname( def impl_getname(
self, self,
suffix=None, identifier=None,
) -> str: ) -> str:
"""get name""" """get name"""
name = super().impl_getname(None) name = super().impl_getname(None)
if suffix is None: if identifier is None:
return name return name
path_suffix = self.convert_suffix_to_path(suffix) path_identifier = self.convert_identifier_to_path(identifier)
if "{{ suffix }}" in name: if "{{ identifier }}" in name:
return name.replace("{{ suffix }}", path_suffix) return name.replace("{{ identifier }}", path_identifier)
return name + path_suffix return name + path_identifier
def impl_get_display_name( def impl_get_display_name(
self, self,
subconfig, subconfig,
with_quote: bool=False,
) -> str: ) -> str:
display = super().impl_get_display_name(subconfig) display = super().impl_get_display_name(subconfig, with_quote=with_quote)
if "{{ suffix }}" in display: if "{{ identifier }}" in display:
return display.replace("{{ suffix }}", self.convert_suffix_to_path(self.get_suffixes(subconfig)[-1])) return display.replace("{{ identifier }}", self.convert_identifier_to_path(self.get_identifiers(subconfig)[-1]))
return display return display

View file

@ -89,6 +89,12 @@ class TiramisuReflector:
continue continue
self.text["header"].append(f"load_functions('{funcs_path}')") self.text["header"].append(f"load_functions('{funcs_path}')")
if self.objectspace.export_with_import: if self.objectspace.export_with_import:
if objectspace.main_namespace:
self.text["header"].extend(["try:",
" groups.namespace",
"except:",
" groups.addgroup('namespace')",
])
for mode in self.objectspace.modes_level: for mode in self.objectspace.modes_level:
self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")') self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
self.make_tiramisu_objects() self.make_tiramisu_objects()
@ -322,17 +328,17 @@ class Common:
information_variable.informations.append(information_name) information_variable.informations.append(information_name)
return information_name return information_name
return f'ParamInformation("{param["information"]}", {default})' return f'ParamInformation("{param["information"]}", {default})'
if param["type"] == "suffix": if param["type"] == "identifier":
if "suffix" in param and param["suffix"] != None: if "identifier" in param and param["identifier"] != None:
return f"ParamSuffix(suffix_index={param['suffix']})" return f"ParamIdentifier(identifier_index={param['identifier']})"
return "ParamSuffix()" return "ParamIdentifier()"
if param["type"] == "index": if param["type"] == "index":
return "ParamIndex()" return "ParamIndex()"
if param["type"] == "variable": if param["type"] == "variable":
return self.build_option_param( return self.build_option_param(
param["variable"], param["variable"],
param.get("propertyerror", True), param.get("propertyerror", True),
param.get("suffix"), param.get("identifier"),
param.get("dynamic"), param.get("dynamic"),
param.get('whole', False), param.get('whole', False),
) )
@ -348,7 +354,7 @@ class Common:
self, self,
variable, variable,
propertyerror, propertyerror,
suffix: Optional[str], identifier: Optional[str],
dynamic, dynamic,
whole: bool, whole: bool,
) -> str: ) -> str:
@ -362,9 +368,14 @@ class Common:
self.calls, self.elt.path self.calls, self.elt.path
) )
params = [f"{option_name}"] params = [f"{option_name}"]
if suffix is not None: if identifier is not None:
param_type = "ParamDynOption" param_type = "ParamDynOption"
params.append(self.convert_str(suffix)) identifiers = []
for ident in identifier:
if isinstance(ident, str):
ident = self.convert_str(ident)
identifiers.append(str(ident))
params.append('[' + ', '.join(identifiers) + ']')
else: else:
param_type = "ParamOption" param_type = "ParamOption"
if not propertyerror: if not propertyerror:
@ -518,6 +529,10 @@ class Family(Common):
self.object_type = "Leadership" self.object_type = "Leadership"
else: else:
self.object_type = "OptionDescription" self.object_type = "OptionDescription"
if hasattr(self.elt, 'name') and self.elt.name == self.elt.namespace:
self.group_type = 'groups.namespace'
else:
self.group_type = None
self.children = [] self.children = []
def add(self, child): def add(self, child):
@ -528,8 +543,10 @@ class Family(Common):
self, self,
keys: list, keys: list,
) -> None: ) -> None:
if self.group_type:
keys["group_type"] = self.group_type
if self.elt.type == "dynamic": if self.elt.type == "dynamic":
keys["suffixes"] = self.populate_calculation(self.elt.dynamic) keys["identifiers"] = self.populate_calculation(self.elt.dynamic)
children = [] children = []
for path in self.objectspace.parents[self.elt.path]: for path in self.objectspace.parents[self.elt.path]:
children.append(self.objectspace.paths[path]) children.append(self.objectspace.paths[path])

View file

@ -124,7 +124,7 @@ def get_jinja_variable_to_param(
founded_variables = {} founded_variables = {}
unknown_variables = [] unknown_variables = []
for variable_path in variables: for variable_path in variables:
variable, suffix = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
variable_path, variable_path,
path_prefix, path_prefix,
current_path, current_path,
@ -133,7 +133,7 @@ def get_jinja_variable_to_param(
xmlfiles, xmlfiles,
) )
if variable and variable.path in objectspace.variables: if variable and variable.path in objectspace.variables:
founded_variables[variable_path] = (suffix, variable) founded_variables[variable_path] = (identifier, variable)
else: else:
sub_family = variable_path + '.' sub_family = variable_path + '.'
for founded_variable in chain(founded_variables, unknown_variables): for founded_variable in chain(founded_variables, unknown_variables):
@ -151,7 +151,7 @@ def get_jinja_variable_to_param(
vpath = variable_path vpath = variable_path
while '.' in vpath: while '.' in vpath:
vpath = vpath.rsplit('.', 1)[0] vpath = vpath.rsplit('.', 1)[0]
variable, suffix = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
vpath, vpath,
path_prefix, path_prefix,
current_path, current_path,