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

View file

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

View file

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

View file

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