feat: leadership => sequence
This commit is contained in:
parent
2f9f263ae0
commit
41caf6967e
9 changed files with 87 additions and 75 deletions
|
|
@ -64,7 +64,7 @@ class Annotator(Walk):
|
|||
self.objectspace = objectspace
|
||||
self.mode_auto = []
|
||||
self.remove_empty_families()
|
||||
self.check_leadership()
|
||||
self.check_sequence()
|
||||
self.families_description()
|
||||
self.set_modes()
|
||||
self.convert_help()
|
||||
|
|
@ -76,15 +76,17 @@ class Annotator(Walk):
|
|||
if not self.objectspace.parents[path]:
|
||||
self.objectspace.del_family(path)
|
||||
|
||||
def check_leadership(self) -> None:
|
||||
"""No subfamily in a leadership"""
|
||||
def check_sequence(self) -> None:
|
||||
"""No subfamily in a sequence"""
|
||||
for family in self.get_families():
|
||||
if family.type != "leadership":
|
||||
if family.type == 'leadership':
|
||||
family.type = "sequence"
|
||||
if family.type != "sequence":
|
||||
continue
|
||||
for variable_path in self.objectspace.parents[family.path]:
|
||||
if variable_path in self.objectspace.families:
|
||||
variable = self.objectspace.paths[variable_path]
|
||||
msg = f'the leadership "{family.path}" cannot have the "{variable.type}" "{variable.path}"'
|
||||
msg = f'the sequence "{family.path}" cannot have the "{variable.type}" "{variable.path}"'
|
||||
raise DictConsistencyError(msg, 24, variable.xmlfiles)
|
||||
|
||||
def families_description(self) -> None:
|
||||
|
|
@ -191,14 +193,14 @@ class Annotator(Walk):
|
|||
family_mode = family.mode
|
||||
else:
|
||||
family_mode = None
|
||||
is_leadership = family.type == "leadership"
|
||||
if is_leadership:
|
||||
is_sequence = family.type == "sequence"
|
||||
if is_sequence:
|
||||
leader = None
|
||||
for child_path in self.objectspace.parents[family.path]:
|
||||
child = self.objectspace.paths[child_path]
|
||||
if child.type == "symlink":
|
||||
continue
|
||||
if is_leadership and leader is None:
|
||||
if is_sequence and leader is None:
|
||||
leader = child
|
||||
leader_mode = leader.mode
|
||||
if child_path in self.objectspace.families:
|
||||
|
|
@ -208,11 +210,11 @@ class Annotator(Walk):
|
|||
else:
|
||||
# set default mode to a variable
|
||||
self.valid_mode(child)
|
||||
if is_leadership and leader:
|
||||
if is_sequence and leader:
|
||||
self.set_default_mode_leader(leader, child)
|
||||
self.set_default_mode_variable(child, family_mode)
|
||||
if is_leadership and leader_mode is not None:
|
||||
# here because follower can change leadership mode
|
||||
if is_sequence and leader_mode is not None:
|
||||
# here because follower can change sequence mode
|
||||
self.set_auto_mode(family, leader_mode)
|
||||
|
||||
def has_mode(self, obj) -> bool:
|
||||
|
|
@ -296,7 +298,7 @@ class Annotator(Walk):
|
|||
else:
|
||||
family_mode = self.default_family_mode
|
||||
min_variable_mode = self.higher_mode
|
||||
is_leadership = family.type == "leadership"
|
||||
is_sequence = family.type == "sequence"
|
||||
for child_path in self.objectspace.parents[family.path]:
|
||||
child = self.objectspace.paths[child_path]
|
||||
if child.type == "symlink":
|
||||
|
|
@ -305,7 +307,7 @@ class Annotator(Walk):
|
|||
if not child.mode:
|
||||
child.mode = self.default_family_mode
|
||||
else:
|
||||
self.change_variable_mode(child, family_mode, is_leadership)
|
||||
self.change_variable_mode(child, family_mode, is_sequence)
|
||||
if self.modes[min_variable_mode] > self.modes[child.mode]:
|
||||
min_variable_mode = child.mode
|
||||
if not family.mode:
|
||||
|
|
|
|||
|
|
@ -56,11 +56,11 @@ class Annotator(Walk):
|
|||
return
|
||||
self.frozen = {}
|
||||
self.variables_default_transitive = []
|
||||
self.convert_leadership()
|
||||
self.convert_sequence()
|
||||
self.convert_family()
|
||||
self.convert_variable()
|
||||
|
||||
def convert_leadership(self) -> None:
|
||||
def convert_sequence(self) -> None:
|
||||
for variable_path in self.objectspace.leaders:
|
||||
variable = self.objectspace.paths[variable_path]
|
||||
if variable.hidden:
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ class _RougailConfig:
|
|||
return getattr(self, key)
|
||||
option = self.config.option(key)
|
||||
if option.isoptiondescription() and option.isleadership():
|
||||
return self.get_leadership(option)
|
||||
return self.get_sequence(option)
|
||||
ret = self.config.option(key).value.get()
|
||||
return ret
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ class _RougailConfig:
|
|||
return False
|
||||
return True
|
||||
|
||||
def get_leadership(self, option) -> dict:
|
||||
def get_sequence(self, option) -> dict:
|
||||
leader = None
|
||||
followers = []
|
||||
for opt, value in option.value.get().items():
|
||||
|
|
|
|||
|
|
@ -53,17 +53,17 @@ class CollectFamily:
|
|||
elif "variable" in self.parameters:
|
||||
self.name += "{{ identifier }}"
|
||||
self.path += "{{ identifier }}"
|
||||
else:
|
||||
elif self.raises:
|
||||
msg = f'dynamic family name must have "{{{{ identifier }}}}" in his name for "{self.path}"'
|
||||
raise DictConsistencyError(msg, 13, self.sources)
|
||||
if self.version == "1.0":
|
||||
if "variable" not in self.parameters:
|
||||
if self.raises and "variable" not in self.parameters:
|
||||
raise DictConsistencyError(
|
||||
f'dynamic family must have "variable" attribute for "{self.path}"',
|
||||
101,
|
||||
self.sources,
|
||||
)
|
||||
if "dynamic" in self.parameters:
|
||||
if self.raises and "dynamic" in self.parameters:
|
||||
raise DictConsistencyError(
|
||||
'variable and dynamic cannot be set together in the dynamic family "{self.path}"',
|
||||
100,
|
||||
|
|
@ -107,7 +107,7 @@ class CollectFamily:
|
|||
# when an attribute starts with "_", the variable name without this "_" is a variable
|
||||
sub_variables = [key[1:] for key in self.parameters if key.startswith('_') and key[1:] in self.parameters]
|
||||
# and known variables
|
||||
if self.path in self.objectspace.paths:
|
||||
if self.test_exists and self.path in self.objectspace.paths:
|
||||
sub_variables.extend([p.rsplit('.', 1)[-1] for p in self.objectspace.parents[self.path]])
|
||||
attributes = self.object["attrs"]
|
||||
attributes_types = self.object["attributes_types"]
|
||||
|
|
@ -116,7 +116,7 @@ class CollectFamily:
|
|||
else:
|
||||
types_children = []
|
||||
for key, value in list(children.items()):
|
||||
if not isinstance(key, str):
|
||||
if self.raises and not isinstance(key, str):
|
||||
raise DictConsistencyError(
|
||||
f'the key "{key}" is not in string format for family {self.path}',
|
||||
103,
|
||||
|
|
@ -152,7 +152,7 @@ class CollectVariable:
|
|||
self.parameters = obj
|
||||
self.parse_type_params()
|
||||
self.parse_secret_manager()
|
||||
if not self.check_no_extra_keys:
|
||||
if self.raises and not self.check_no_extra_keys:
|
||||
extra_attrs = set(obj) - self.object["attrs"]
|
||||
if extra_attrs:
|
||||
raise DictConsistencyError(
|
||||
|
|
@ -174,14 +174,14 @@ class CollectVariable:
|
|||
if isinstance(params, list):
|
||||
# the conversion has already be done (in types purpose)
|
||||
for param in params:
|
||||
if not isinstance(param, AnyParam):
|
||||
if self.raises and not isinstance(param, AnyParam):
|
||||
raise DictConsistencyError(
|
||||
_("params must be a dict for {0}").format(self.path),
|
||||
55,
|
||||
self.sources,
|
||||
)
|
||||
return
|
||||
elif not isinstance(params, dict):
|
||||
elif self.raises and not isinstance(params, dict):
|
||||
raise DictConsistencyError(
|
||||
_("params must be a dict for {0}").format(self.path),
|
||||
55,
|
||||
|
|
@ -204,13 +204,14 @@ class CollectVariable:
|
|||
)
|
||||
)
|
||||
except ValidationError as err:
|
||||
raise DictConsistencyError(
|
||||
_('"{0}" has an invalid "params" for {1}: {2}').format(
|
||||
key, self.path, err
|
||||
),
|
||||
54,
|
||||
self.sources,
|
||||
) from err
|
||||
if self.raises:
|
||||
raise DictConsistencyError(
|
||||
_('"{0}" has an invalid "params" for {1}: {2}').format(
|
||||
key, self.path, err
|
||||
),
|
||||
54,
|
||||
self.sources,
|
||||
) from err
|
||||
self.parameters["params"] = new_params
|
||||
|
||||
def parse_secret_manager(self):
|
||||
|
|
@ -232,7 +233,7 @@ class CollectType:
|
|||
1/ self.option_type must be "variable" or "family" option type
|
||||
needs to determinate if the option is a variable or a family
|
||||
an option is a family if:
|
||||
- user specified a know family type: family, leadership (user must set it explicitly) or dynamic)
|
||||
- user specified a know family type: family, sequence (user must set it explicitly) or dynamic)
|
||||
- has a family custom type
|
||||
- has "dynamic" attribute (a variable could not has dynamic attribut)
|
||||
- it's already a family (so we are certainly in redefine purpose
|
||||
|
|
@ -247,7 +248,7 @@ class CollectType:
|
|||
else:
|
||||
self.short_hand_variable()
|
||||
self.set_user_redefined()
|
||||
self.variable_in_leadership()
|
||||
self.variable_in_sequence()
|
||||
self.family_or_variable()
|
||||
if self.user_type:
|
||||
logging.info("family_or_variable: %s is a %s (%s)", self.path, self.option_type, self.user_type)
|
||||
|
|
@ -280,13 +281,13 @@ class CollectType:
|
|||
self.set_object_user_type_family()
|
||||
if not self.object:
|
||||
self.set_object_user_type_variable()
|
||||
if not self.object:
|
||||
if self.raises and not self.object:
|
||||
msg = _('cannot determine the type of the {0} "{1}"').format(self.user_type, self.path)
|
||||
raise DictConsistencyError(msg, 43, self.sources)
|
||||
break
|
||||
|
||||
def set_custom_type(self, custom: dict) -> None:
|
||||
if self.path in self.objectspace.paths:
|
||||
if self.raises and self.test_exists and self.path in self.objectspace.paths:
|
||||
msg = f'cannot redefine "{self.path}" object to a custom type'
|
||||
raise DictConsistencyError(msg, 64, self.sources)
|
||||
self.types = custom
|
||||
|
|
@ -324,12 +325,12 @@ class CollectType:
|
|||
break
|
||||
|
||||
def set_user_redefined(self) -> None:
|
||||
if self.path not in self.objectspace.paths:
|
||||
if not self.test_exists or self.path not in self.objectspace.paths:
|
||||
return
|
||||
# it's already a variable or a family
|
||||
old_option_type = self.option_type if self.user_type else None
|
||||
self.option_type = "family" if self.path in self.objectspace.families else "variable"
|
||||
if old_option_type and self.option_type != old_option_type:
|
||||
if self.raises and old_option_type and self.option_type != old_option_type:
|
||||
msg = f'the {old_option_type} "{self.path}" is redefine as a {self.option_type}, which is not allowed'
|
||||
raise DictConsistencyError(msg, 11, self.sources)
|
||||
if self.user_type:
|
||||
|
|
@ -357,11 +358,11 @@ class CollectType:
|
|||
self.option_type = "variable"
|
||||
self.object = self.objectspace.variable_objects[0]
|
||||
|
||||
def variable_in_leadership(self):
|
||||
# in a leadership there have only variables
|
||||
if not self.option_type and self.family_is_leadership:
|
||||
def variable_in_sequence(self):
|
||||
# in a sequence there have only variables
|
||||
if not self.option_type and self.family_is_sequence:
|
||||
self.option_type = "variable"
|
||||
if not self.find_variable_object():
|
||||
if self.raises and not self.find_variable_object():
|
||||
msg = f'"{self.path}" seems to be a family, which is not allowed in a family'
|
||||
raise DictConsistencyError(msg, 17, self.sources)
|
||||
|
||||
|
|
@ -434,6 +435,9 @@ class Collect(CollectType, CollectFamily, CollectVariable):
|
|||
parameters: dict,
|
||||
comment: Optional[str],
|
||||
parent_option: Optional[Collect],
|
||||
*,
|
||||
raises: bool=True,
|
||||
test_exists: bool=True,
|
||||
) -> None:
|
||||
self.sources_types = None
|
||||
self.types = None
|
||||
|
|
@ -442,7 +446,9 @@ class Collect(CollectType, CollectFamily, CollectVariable):
|
|||
path = name
|
||||
else:
|
||||
path = f"{subpath}.{name}"
|
||||
if name.startswith("_"):
|
||||
self.raises = raises
|
||||
self.test_exists = test_exists
|
||||
if self.raises and name.startswith("_"):
|
||||
msg = f'the variable or family "{self.path}" is incorrect, it must not starts with "_" character'
|
||||
raise DictConsistencyError(msg, 16, obj["sources"])
|
||||
self.path = path
|
||||
|
|
@ -457,15 +463,15 @@ class Collect(CollectType, CollectFamily, CollectVariable):
|
|||
if parent_option is not None and parent_option.types is not None and self.name in parent_option.types.children:
|
||||
self.set_custom_type(parent_option.types.children[self.name])
|
||||
self.check_no_extra_keys = False
|
||||
if path in objectspace.paths:
|
||||
if self.test_exists and path in objectspace.paths:
|
||||
for source in reversed(self.objectspace.paths[path].xmlfiles):
|
||||
self.sources.insert(0, source)
|
||||
if parent_option:
|
||||
self.family_is_leadership = parent_option.user_type == "leadership"
|
||||
self.family_is_sequence = parent_option.user_type in ["leadership", "sequence"]
|
||||
self.family_is_dynamic = parent_option.family_is_dynamic
|
||||
self.parent_dynamic = parent_option.parent_dynamic
|
||||
else:
|
||||
self.family_is_leadership = False
|
||||
self.family_is_sequence = False
|
||||
self.family_is_dynamic = False
|
||||
self.parent_dynamic = None
|
||||
self.version = self.objectspace.version
|
||||
|
|
@ -497,11 +503,12 @@ class Collect(CollectType, CollectFamily, CollectVariable):
|
|||
value,
|
||||
)
|
||||
except ValidationError as err:
|
||||
raise DictConsistencyError(
|
||||
_('the {0} "{1}" has an invalid "{2}": {3}').format(self.option_type, self.path, key, err),
|
||||
84,
|
||||
self.sources,
|
||||
) from err
|
||||
if self.raises:
|
||||
raise DictConsistencyError(
|
||||
_('the {0} "{1}" has an invalid "{2}": {3}').format(self.option_type, self.path, key, err),
|
||||
84,
|
||||
self.sources,
|
||||
) from err
|
||||
continue
|
||||
if not isinstance(value, list):
|
||||
continue
|
||||
|
|
@ -601,7 +608,7 @@ class Collect(CollectType, CollectFamily, CollectVariable):
|
|||
f'unknown "return_type" in {attribute} of variable "{self.path}"'
|
||||
)
|
||||
#
|
||||
if typ == "identifier" and not self.family_is_dynamic:
|
||||
if self.raises and typ == "identifier" and not self.family_is_dynamic:
|
||||
msg = f'identifier calculation for "{attribute}" in "{self.path}" cannot be set variable is not in dynamic family'
|
||||
raise DictConsistencyError(msg, 53, self.sources)
|
||||
if attribute in PROPERTY_ATTRIBUTE:
|
||||
|
|
@ -648,7 +655,7 @@ class Collect(CollectType, CollectFamily, CollectVariable):
|
|||
value["attribute"] = attribute
|
||||
value["namespace"] = self.objectspace.namespace
|
||||
value["xmlfiles"] = self.sources
|
||||
if param_typ not in PARAM_TYPES:
|
||||
if self.raises and param_typ not in PARAM_TYPES:
|
||||
raise DictConsistencyError(
|
||||
f'unknown type "{param_typ}" for "{self.path}"',
|
||||
52,
|
||||
|
|
@ -657,11 +664,12 @@ class Collect(CollectType, CollectFamily, CollectVariable):
|
|||
try:
|
||||
params.append(PARAM_TYPES[param_typ](**value))
|
||||
except ValidationError as err:
|
||||
raise DictConsistencyError(
|
||||
f'"{attribute}" has an invalid "{key}" for "{self.path}": {err}',
|
||||
29,
|
||||
self.sources,
|
||||
) from err
|
||||
if self.raises:
|
||||
raise DictConsistencyError(
|
||||
f'"{attribute}" has an invalid "{key}" for "{self.path}": {err}',
|
||||
29,
|
||||
self.sources,
|
||||
) from err
|
||||
calculation_object["params"] = params
|
||||
|
||||
def set_param_type(self, val):
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ class ParserVariable:
|
|||
return
|
||||
root = Path(__file__).parent.parent
|
||||
self.walker = None
|
||||
variable = Variable
|
||||
family = Family
|
||||
self.variable = Variable
|
||||
self.family = Family
|
||||
for structural_name in self.structurals:
|
||||
structural = f"structural_{structural_name}"
|
||||
module_path = root / structural / "__init__.py"
|
||||
|
|
@ -212,26 +212,26 @@ class ParserVariable:
|
|||
continue
|
||||
module = load_modules(f"rougail.{structural}", str(module_path))
|
||||
if "Variable" in module.__all__:
|
||||
variable = type(
|
||||
variable.__name__ + "_" + structural,
|
||||
(variable, module.Variable),
|
||||
self.variable = type(
|
||||
self.variable.__name__ + "_" + structural,
|
||||
(self.variable, module.Variable),
|
||||
{},
|
||||
)
|
||||
if "Family" in module.__all__:
|
||||
family = type(
|
||||
family.__name__ + "_" + structural, (family, module.Family), {}
|
||||
self.family = type(
|
||||
self.family.__name__ + "_" + structural, (self.family, module.Family), {}
|
||||
)
|
||||
if not self.walker and "Walker" in module.__all__:
|
||||
self.walker = module.Walker
|
||||
dynamic = type(Dynamic.__name__, (Dynamic, family), {})
|
||||
choices = type(Choices.__name__, (Choices, variable), {})
|
||||
regexp = type(Regexp.__name__, (Regexp, variable), {})
|
||||
self.dynamic = type(Dynamic.__name__, (Dynamic, self.family), {})
|
||||
self.choices = type(Choices.__name__, (Choices, self.variable), {})
|
||||
self.regexp = type(Regexp.__name__, (Regexp, self.variable), {})
|
||||
variable_types = self.convert_options.copy()
|
||||
variable_types.remove("choice")
|
||||
variable_types.remove("regexp")
|
||||
variable_types.remove("symlink")
|
||||
self.variable_objects = [self.get_variable_object(obj, is_variable=True) for obj in [(variable, variable_types), SymLink, choices, regexp]]
|
||||
self.family_objects = [self.get_variable_object(obj, is_variable=False) for obj in [dynamic, family]]
|
||||
self.variable_objects = [self.get_variable_object(obj, is_variable=True) for obj in [(self.variable, variable_types), SymLink, self.choices, self.regexp]]
|
||||
self.family_objects = [self.get_variable_object(obj, is_variable=False) for obj in [self.dynamic, self.family]]
|
||||
self.is_init = True
|
||||
|
||||
def get_variable_object(self, obj, *, is_variable: bool) -> dict:
|
||||
|
|
@ -520,7 +520,7 @@ class ParserVariable:
|
|||
variable_obj,
|
||||
"option_",
|
||||
)
|
||||
if option.family_is_leadership:
|
||||
if option.family_is_sequence:
|
||||
if first_variable:
|
||||
self.leaders.append(path)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1059,7 +1059,7 @@ class Family(BaseModel):
|
|||
help: Optional[StrictStr] = None
|
||||
mode: Optional[StrictStr] = None
|
||||
# validation
|
||||
type: Literal["family", "leadership"] = "family"
|
||||
type: Literal["family", "leadership", "sequence"] = "family"
|
||||
# properties
|
||||
hidden: Union[bool, Calculation] = False
|
||||
disabled: Union[bool, Calculation] = False
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ class Family(Common):
|
|||
if self.elt.type == "dynamic":
|
||||
self.tiramisu.objectspace.has_dyn_option = True
|
||||
self.object_type = "ConvertDynOptionDescription"
|
||||
elif self.elt.type == "leadership":
|
||||
elif self.elt.type == "sequence":
|
||||
self.object_type = "Leadership"
|
||||
else:
|
||||
self.object_type = "OptionDescription"
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ isolated_namespace:
|
|||
|
||||
extra_namespaces:
|
||||
description: {_("Extra namespaces")}
|
||||
type: leadership
|
||||
type: sequence
|
||||
disabled:
|
||||
jinja: >-
|
||||
{{{{ ('directory' not in _.step.structural and 'string' not in _.step.structural) or not _.main_namespace }}}}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,9 @@ CONVERT_OPTION = {
|
|||
"symlink": dict(opttype="SymLinkOption"),
|
||||
}
|
||||
# only version 1.1
|
||||
RENAME_TYPE = {"number": "integer"}
|
||||
RENAME_TYPE = {"number": "integer",
|
||||
"leadership": "sequence",
|
||||
}
|
||||
|
||||
|
||||
def get_identifier_from_dynamic_family(true_name, name) -> str:
|
||||
|
|
|
|||
Loading…
Reference in a new issue