diff --git a/src/rougail/annotator/family.py b/src/rougail/annotator/family.py index bd29ee433..0bd0b3e32 100644 --- a/src/rougail/annotator/family.py +++ b/src/rougail/annotator/family.py @@ -79,7 +79,7 @@ class Annotator(Walk): 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 @@ -113,7 +113,9 @@ class Annotator(Walk): ) self.objectspace.informations.add(family.path, "dynamic_variable", path) if family.xmlfiles: - self.objectspace.informations.add(family.path, "ymlfiles", family.xmlfiles) + self.objectspace.informations.add( + family.path, "ymlfiles", family.xmlfiles + ) def set_modes(self): if self.objectspace.modes_level: @@ -130,8 +132,12 @@ class Annotator(Walk): modes = self.modes = { name: Mode(idx) for idx, name in enumerate(self.objectspace.modes_level) } - default_variable_mode = self.default_variable_mode = self.objectspace.default_variable_mode - default_family_mode = self.default_family_mode = self.objectspace.default_family_mode + default_variable_mode = self.default_variable_mode = ( + self.objectspace.default_variable_mode + ) + default_family_mode = self.default_family_mode = ( + self.objectspace.default_family_mode + ) list_modes = list(modes) if default_variable_mode not in list_modes: msg = _( @@ -177,7 +183,9 @@ class Annotator(Walk): if self.has_mode(obj): msg = _( 'mode "{0}" for "{1}" is not a valid mode, valid modes are {2}' - ).format(obj.mode, obj.name, display_list(list(self.modes), add_quote=True)) + ).format( + obj.mode, obj.name, display_list(list(self.modes), add_quote=True) + ) raise DictConsistencyError(msg, 71, obj.xmlfiles) elif self.has_mode(obj) and obj.mode not in self.modes: msg = _( diff --git a/src/rougail/annotator/property.py b/src/rougail/annotator/property.py index c72d1c19c..e3f1d46b5 100644 --- a/src/rougail/annotator/property.py +++ b/src/rougail/annotator/property.py @@ -173,9 +173,7 @@ class Annotator(Walk): for tag in variable.tags: self.check_tag(tag, variable.xmlfiles) self.objectspace.properties.add(variable.path, tag, True) - self.objectspace.informations.add( - variable.path, "tags", tuple(variable.tags) - ) + self.objectspace.informations.add(variable.path, "tags", tuple(variable.tags)) def check_tag( self, diff --git a/src/rougail/annotator/variable.py b/src/rougail/annotator/variable.py index 04a49060b..6e3a7b8c7 100644 --- a/src/rougail/annotator/variable.py +++ b/src/rougail/annotator/variable.py @@ -106,9 +106,7 @@ class Annotator(Walk): # pylint: disable=R0903 'the variable "{0}" has attribute "secret_manager" so must not have default value' ) raise DictConsistencyError(msg.format(path), 59, variable.xmlfiles) - self.objectspace.informations.add( - path, "secret_manager", True - ) + self.objectspace.informations.add(path, "secret_manager", True) def convert_variable(self): """convert variable""" @@ -214,9 +212,9 @@ class Annotator(Walk): # pylint: disable=R0903 if variable.type is not None: return ## choice type inference from the `choices` attribute - #if variable.choices is not None: + # if variable.choices is not None: # variable.type = "choice" - #elif variable.regexp is not None: + # elif variable.regexp is not None: # variable.type = "regexp" if variable.default not in [None, []]: if isinstance(variable.default, list): @@ -253,7 +251,9 @@ class Annotator(Walk): # pylint: disable=R0903 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) + identifier_is_a_calculation = isinstance( + variable.default.identifier, Calculation + ) variable.multi = calc_multi_for_type_variable( variable, calculated_variable_path, @@ -317,11 +317,11 @@ class Annotator(Walk): # pylint: disable=R0903 self.objectspace.multis[variable.path] = "submulti" elif variable.multi: self.objectspace.multis[variable.path] = True -# if variable.regexp is not None and variable.type != "regexp": -# msg = _( -# 'the variable "{0}" has regexp attribut but has not the "regexp" type' -# ).format(variable.path) -# raise DictConsistencyError(msg, 37, variable.xmlfiles) + # if variable.regexp is not None and variable.type != "regexp": + # msg = _( + # 'the variable "{0}" has regexp attribut but has not the "regexp" type' + # ).format(variable.path) + # raise DictConsistencyError(msg, 37, variable.xmlfiles) if variable.mandatory is None: variable.mandatory = True @@ -358,9 +358,9 @@ class Annotator(Walk): # pylint: disable=R0903 def verify_choices(self): for variable in self.get_variables(): # FIXME -# if variable.type is None and variable.choices: -# # choice type inference from the `choices` attribute -# variable.type = "choice" + # if variable.type is None and variable.choices: + # # choice type inference from the `choices` attribute + # variable.type = "choice" if variable.type != "choice": continue if variable.default is None: diff --git a/src/rougail/config/__init__.py b/src/rougail/config/__init__.py index d0105cbd6..dcc775a93 100644 --- a/src/rougail/config/__init__.py +++ b/src/rougail/config/__init__.py @@ -82,9 +82,7 @@ class _RougailConfig: self.generate_config() config = self.config.config.copy() config.value.importation(self.config.value.exportation()) - config.property.importation( - self.config.property.exportation() - ) + config.property.importation(self.config.property.exportation()) config.property.read_only() if backward_compatibility is None: backward_compatibility = self.backward_compatibility @@ -250,7 +248,7 @@ class StaticRougailConvert(RougailConvert): def __init__( self, add_extra_options: bool, - rougailconfig: dict={}, + rougailconfig: dict = {}, ) -> None: self.add_extra_options = add_extra_options super().__init__(rougailconfig) @@ -434,10 +432,11 @@ secret_manager: # {_("The secret manager")} "user data": [], "output": [], } - processes_tr = {"structural": _("structural"), - "user data": _("user data"), - "output": _("output"), - } + processes_tr = { + "structural": _("structural"), + "user data": _("user data"), + "output": _("output"), + } processes_empty = [] for module in get_sub_modules().values(): data = module.get_rougail_config(backward_compatibility=backward_compatibility) @@ -495,7 +494,9 @@ secret_manager: # {_("The secret manager")} "NAME", hidden_output ) rougail_process += f""" description: {_('outputs {0} did not allow user data')} -""".format(display_list(hidden_outputs, add_quote=True, separator="or")) +""".format( + display_list(hidden_outputs, add_quote=True, separator="or") + ) elif objects: rougail_process += " default: {DEFAULT}".format( DEFAULT=objects[0]["name"] @@ -557,7 +558,9 @@ def _rougail_config( backward_compatibility: bool = True, add_extra_options: bool = True, ) -> "OptionDescription": - processes, processes_empty, rougail_options = get_common_rougail_config(backward_compatibility=backward_compatibility) + processes, processes_empty, rougail_options = get_common_rougail_config( + backward_compatibility=backward_compatibility + ) convert = StaticRougailConvert(add_extra_options) convert.init() convert.namespace = None diff --git a/src/rougail/convert/__init__.py b/src/rougail/convert/__init__.py index edbe10dec..23b988498 100644 --- a/src/rougail/convert/__init__.py +++ b/src/rougail/convert/__init__.py @@ -32,13 +32,16 @@ class Rougail(UserData): def __init__( self, - rougailconfig: Optional[RougailConfig]=None, - load_from_tiramisu_cache: bool=False, + rougailconfig: Optional[RougailConfig] = None, + load_from_tiramisu_cache: bool = False, ) -> None: if rougailconfig is None: rougailconfig = RougailConfig self.rougailconfig = rougailconfig - self.load_from_tiramisu_cache = load_from_tiramisu_cache and Path(self.rougailconfig["tiramisu_cache"]).is_file() + self.load_from_tiramisu_cache = ( + load_from_tiramisu_cache + and Path(self.rougailconfig["tiramisu_cache"]).is_file() + ) types = rougail_type(self.rougailconfig) if not self.load_from_tiramisu_cache: self.converted = RougailConvert(self.rougailconfig, **types) diff --git a/src/rougail/convert/collect.py b/src/rougail/convert/collect.py index c4980477d..ed481dacb 100644 --- a/src/rougail/convert/collect.py +++ b/src/rougail/convert/collect.py @@ -17,6 +17,7 @@ details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . """ + import logging from warnings import warn from pydantic import ValidationError @@ -104,10 +105,16 @@ class CollectFamily: new_parameters = {} children = self.parameters # 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] + sub_variables = [ + key[1:] + for key in self.parameters + if key.startswith("_") and key[1:] in self.parameters + ] # and known variables 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]]) + 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"] if self.types: @@ -127,10 +134,12 @@ class CollectFamily: children.pop(key) else: new_parameters[key[1:]] = children.pop(key) - elif key in types_children or \ - key not in attributes or \ - key in sub_variables or \ - not self.parameter_is_an_attributes(key, value, attributes_types): + elif ( + key in types_children + or key not in attributes + or key in sub_variables + or not self.parameter_is_an_attributes(key, value, attributes_types) + ): if key == "type" and self.types and key not in types_children: children.pop(key) else: @@ -227,6 +236,7 @@ class CollectVariable: secret_manager, ) + class CollectType: """Determine the option type 1/ self.option_type must be "variable" or "family" option type @@ -250,7 +260,12 @@ class CollectType: 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) + logging.info( + "family_or_variable: %s is a %s (%s)", + self.path, + self.option_type, + self.user_type, + ) else: logging.info("family_or_variable: %s is a %s", self.path, self.option_type) @@ -259,18 +274,24 @@ class CollectType: ) -> None: """Check 'type' attributes and determine the option type""" for type_name in ["_type", "type"]: - if type_name not in self.parameters or not isinstance(self.parameters[type_name], str): + if type_name not in self.parameters or not isinstance( + self.parameters[type_name], str + ): continue self.user_type = self.parameters[type_name] if self.user_type in self.objectspace.custom_family_types: - self.set_custom_type(self.objectspace.custom_family_types[self.user_type]) + self.set_custom_type( + self.objectspace.custom_family_types[self.user_type] + ) if self.user_type is None: self.object = self.objectspace.family_objects[-1] else: self.set_object_user_type_family() break elif self.user_type in self.objectspace.custom_variable_types: - self.set_custom_type(self.objectspace.custom_variable_types[self.user_type]) + self.set_custom_type( + self.objectspace.custom_variable_types[self.user_type] + ) if self.user_type is None: self.object = self.objectspace.variable_objects[0] else: @@ -281,11 +302,13 @@ class CollectType: if not self.object: self.set_object_user_type_variable() if self.raises and not self.object: - msg = _('cannot determine the type of the {0} "{1}"').format(self.user_type, self.path) + 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, from_parent: bool=False) -> None: + def set_custom_type(self, custom: dict, from_parent: bool = False) -> None: 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) @@ -302,7 +325,11 @@ class CollectType: self.user_type = self.types.user_type self.sources = self.types.sources + self.sources self.object = self.types.object - if not from_parent and self.option_type == "variable" and "type" in self.parameters: + if ( + not from_parent + and self.option_type == "variable" + and "type" in self.parameters + ): self.parameters.pop("type") def set_object_user_type_family(self): @@ -323,7 +350,9 @@ class CollectType: if self.user_type: return for type_name in ["_dynamic", "dynamic"]: - if type_name in self.parameters and isinstance(self.parameters[type_name], (list, dict)): + if type_name in self.parameters and isinstance( + self.parameters[type_name], (list, dict) + ): self.user_type = "dynamic" self.option_type = "family" break @@ -333,7 +362,9 @@ class CollectType: 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" + self.option_type = ( + "family" if self.path in self.objectspace.families else "variable" + ) 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) @@ -382,7 +413,9 @@ class CollectType: def find_variable_object(self) -> bool: attrs = set(self.parameters) for variable in self.objectspace.variable_objects: - if not attrs - variable["attrs"] and self.check_variable_parameters(variable): + if not attrs - variable["attrs"] and self.check_variable_parameters( + variable + ): self.option_type = "variable" self.check_no_extra_keys = True self.object = variable @@ -399,22 +432,39 @@ class CollectType: return False return True - def parameter_is_an_attributes(self, key: str, value: Any, attributes_types: dict) -> bool: + def parameter_is_an_attributes( + self, key: str, value: Any, attributes_types: dict + ) -> bool: if value is None: return True - if key in attributes_types["literals"] and value in attributes_types["literals"][key]: + if ( + key in attributes_types["literals"] + and value in attributes_types["literals"][key] + ): return True - for k, typ in [("strings", str), ("booleans", bool), ("integers", int), ("floats", float)]: + for k, typ in [ + ("strings", str), + ("booleans", bool), + ("integers", int), + ("floats", float), + ]: if key in attributes_types[k] and isinstance(value, typ): return True if isinstance(value, dict): if key in attributes_types["calculation"]: - return self.is_calculation(key, value, attributes_types=attributes_types) + return self.is_calculation( + key, value, attributes_types=attributes_types + ) if key in attributes_types["params"]: return True if isinstance(value, list): current_value = value.copy() - for k, typ in [("strings", str), ("booleans", bool), ("integers", int), ("floats", float)]: + for k, typ in [ + ("strings", str), + ("booleans", bool), + ("integers", int), + ("floats", float), + ]: if key in attributes_types["lists"][k]: for idx, val in reversed(list(enumerate(current_value))): if val is not None and not isinstance(val, typ): @@ -424,7 +474,9 @@ class CollectType: return True if key in attributes_types["lists"]["calculation"]: for val in current_value: - if isinstance(val, dict) and not self.is_calculation(key, val, inside_list=True, attributes_types=attributes_types): + if isinstance(val, dict) and not self.is_calculation( + key, val, inside_list=True, attributes_types=attributes_types + ): return False return True return False @@ -440,8 +492,8 @@ class Collect(CollectType, CollectFamily, CollectVariable): comment: Optional[str], parent_option: Optional["Collect"], *, - raises: bool=True, - test_exists: bool=True, + raises: bool = True, + test_exists: bool = True, ) -> None: self.sources_types = None self.types = None @@ -464,14 +516,23 @@ class Collect(CollectType, CollectFamily, CollectVariable): self.sources = objectspace.sources.copy() self.user_type = None self.option_type = None - 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], from_parent=True) + 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], from_parent=True + ) self.check_no_extra_keys = False 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_sequence = parent_option.user_type in ["leadership", "sequence"] + 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: @@ -509,7 +570,9 @@ class Collect(CollectType, CollectFamily, CollectVariable): except ValidationError as err: if self.raises: raise DictConsistencyError( - _('the {0} "{1}" has an invalid "{2}": {3}').format(self.option_type, self.path, key, err), + _('the {0} "{1}" has an invalid "{2}": {3}').format( + self.option_type, self.path, key, err + ), 84, self.sources, ) from err @@ -536,17 +599,21 @@ class Collect(CollectType, CollectFamily, CollectVariable): f"at index {idx}: {err}" ) from err - def is_dict(self, key: str, value: Any, *, attributes_types: Optional[dict]=None) -> bool: + def is_dict( + self, key: str, value: Any, *, attributes_types: Optional[dict] = None + ) -> bool: """it's a dict, so it's a new variables!""" - return isinstance(value, dict) and not self.is_calculation(key, value, attributes_types=attributes_types) + return isinstance(value, dict) and not self.is_calculation( + key, value, attributes_types=attributes_types + ) def is_calculation( self, attribute: str, value: dict, *, - attributes_types: Optional[dict]=None, - inside_list: bool=False, + attributes_types: Optional[dict] = None, + inside_list: bool = False, ): """Check if it's a calculation""" if not isinstance(value, dict): @@ -603,11 +670,16 @@ class Collect(CollectType, CollectFamily, CollectVariable): calculation_object["namespace"] = namespace calculation_object["xmlfiles"] = self.sources # - self.set_identifier_calculation_in_default_attribut(attribute, calculation_object, inside_list, index) + self.set_identifier_calculation_in_default_attribut( + attribute, calculation_object, inside_list, index + ) self.set_params_calculation(calculation_object, attribute) # return_type = calculation_object.get("return_type") - if return_type and return_type not in self.objectspace.variable_objects[0]["types"]: + if ( + return_type + and return_type not in self.objectspace.variable_objects[0]["types"] + ): raise Exception( f'unknown "return_type" in {attribute} of variable "{self.path}"' ) @@ -624,7 +696,13 @@ class Collect(CollectType, CollectFamily, CollectVariable): else: obj[attribute][index] = calc - def set_identifier_calculation_in_default_attribut(self, attribute: str, calculation_object: dict, inside_list: bool, index: Optional[int]) -> None: + def set_identifier_calculation_in_default_attribut( + self, + attribute: str, + calculation_object: dict, + inside_list: bool, + index: Optional[int], + ) -> None: if attribute != "default" or "identifier" not in calculation_object: return identifier = calculation_object["identifier"] @@ -634,7 +712,13 @@ class Collect(CollectType, CollectFamily, CollectVariable): attributes_types=self.objectspace.variable_objects[0]["attributes_types"], inside_list=inside_list, ): - self.set_calculation("identifier", identifier, obj=calculation_object, inside_list=inside_list, index=index) + self.set_calculation( + "identifier", + identifier, + obj=calculation_object, + inside_list=inside_list, + index=index, + ) def set_params_calculation(self, calculation_object: dict, attribute: str) -> None: if "params" not in calculation_object: @@ -686,12 +770,18 @@ class Collect(CollectType, CollectFamily, CollectVariable): val["type"] = list(param_typ)[0] def is_redefine(self): - if self.path in self.objectspace.paths and self.option_type == "family" and not self.parameters: + if ( + self.path in self.objectspace.paths + and self.option_type == "family" + and not self.parameters + ): # allow loading family with no attribute loaded return True if self.types: return True - return self.parameters.pop("redefine", False) or (self.types and list(self.parameters) in [[], ["default"]]) + return self.parameters.pop("redefine", False) or ( + self.types and list(self.parameters) in [[], ["default"]] + ) def is_exists(self): if self.version == "1.0" and self.option_type == "family": diff --git a/src/rougail/convert/convert.py b/src/rougail/convert/convert.py index a5f7d83f1..d377df00a 100644 --- a/src/rougail/convert/convert.py +++ b/src/rougail/convert/convert.py @@ -188,7 +188,10 @@ class ParserVariable: self.load_unexist_redefine = rougailconfig["load_unexist_redefine"] self.secret_pattern = rougailconfig["secret_manager.pattern"] # change default initkwargs in CONVERT_OPTION - if hasattr(rougailconfig, "config") and rougailconfig.config.option('define_default_params').value.get(): + if ( + hasattr(rougailconfig, "config") + and rougailconfig.config.option("define_default_params").value.get() + ): for sub_od in rougailconfig.config.option("default_params"): for option in sub_od: if option.owner.isdefault(): @@ -219,7 +222,9 @@ class ParserVariable: ) if "Family" in module.__all__: self.family = type( - self.family.__name__ + "_" + structural, (self.family, module.Family), {} + self.family.__name__ + "_" + structural, + (self.family, module.Family), + {}, ) if not self.walker and "Walker" in module.__all__: self.walker = module.Walker @@ -230,8 +235,19 @@ class ParserVariable: 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 [(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.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: @@ -241,11 +257,12 @@ class ParserVariable: else: hint = get_type_hints(obj) types = self.get_types(hint) - return {"object": obj, - "types": types, - "attrs": self.get_option_attrs(hint), - "attributes_types": self.get_attributes_types(hint, variable=is_variable), - } + return { + "object": obj, + "types": types, + "attrs": self.get_option_attrs(hint), + "attributes_types": self.get_attributes_types(hint, variable=is_variable), + } def get_types(self, hint): return hint["type"].__args__ @@ -298,12 +315,13 @@ class ParserVariable: path = option.path redefine = option.redefine exists = option.exists -# if not redefine and not exists and option.user_type in self.custom_family_types: + # if not redefine and not exists and option.user_type in self.custom_family_types: types = option.types if types: - self.add_family(types, - custom_type=True, - ) + self.add_family( + types, + custom_type=True, + ) if path not in self.paths: if not self.load_unexist_redefine and exists is None and redefine: raise Exception( @@ -319,9 +337,7 @@ class ParserVariable: else: if exists in [None, True] and not redefine: msg = _('family "{0}" define multiple time').format(path) - raise DictConsistencyError( - msg, 32, option.sources - ) + raise DictConsistencyError(msg, 32, option.sources) if self.load_unexist_redefine or exists in [None, True]: objects = option.parameters.copy() objects["xmlfiles"] = option.sources @@ -329,7 +345,7 @@ class ParserVariable: option, self.paths[path].model_copy(update=objects), force=True, - ) + ) force_not_first = types == None children = option.children for idx, key in enumerate(self.list_children(option, types)): @@ -394,7 +410,7 @@ class ParserVariable: self, option: Collect, *, - custom_type: bool=False, + custom_type: bool = False, ) -> None: """Add a new family""" path = option.path @@ -415,12 +431,15 @@ class ParserVariable: try: self.paths.add( option, - family_obj(name=option.name, - **data, - ), + family_obj( + name=option.name, + **data, + ), ) except ValidationError as err: - raise Exception(f'invalid family "{path}" in "{display_list(option.sources)}": {err}') from err + raise Exception( + f'invalid family "{path}" in "{display_list(option.sources)}": {err}' + ) from err self.set_name( self.paths[path], "optiondescription_", @@ -448,10 +467,11 @@ class ParserVariable: path = option.path if option.types: redefine = True - self.add_variable(option.types, - first_variable=first_variable, - custom_type=True, - ) + self.add_variable( + option.types, + first_variable=first_variable, + custom_type=True, + ) if path not in self.paths: if not self.load_unexist_redefine and exists is True: # this variable must exist @@ -461,19 +481,18 @@ class ParserVariable: if not self.load_unexist_redefine and redefine: msg = f'cannot redefine the inexisting variable "{path}"' raise DictConsistencyError(msg, 46, option.sources) - self.add_variable(option, - first_variable, - custom_type, - ) + self.add_variable( + option, + first_variable, + custom_type, + ) else: if not self.load_unexist_redefine: if exists is False: return if not redefine: msg = _('variable "{0}" define multiple time').format(path) - raise DictConsistencyError( - msg, 45, option.sources - ) + raise DictConsistencyError(msg, 45, option.sources) objects = option.parameters.copy() objects["xmlfiles"] = option.sources self.paths.add( @@ -499,9 +518,10 @@ class ParserVariable: data["path"] = path data["version"] = option.version try: - variable_obj = option.object["object"](name=option.name, - **data, - ) + variable_obj = option.object["object"]( + name=option.name, + **data, + ) except ValidationError as err: raise Exception( f'invalid variable "{path}" in "{display_list(option.sources)}": {err}' @@ -572,12 +592,13 @@ class ParserVariable: class RougailConvert(ParserVariable): """Main Rougail conversion""" - def __init__(self, - rougailconfig, - *, - custom_variable_types: dict={}, - custom_family_types: dict={}, - ) -> None: + def __init__( + self, + rougailconfig, + *, + custom_variable_types: dict = {}, + custom_family_types: dict = {}, + ) -> None: self.annotator = False self.has_namespace = False self.custom_variable_types = custom_variable_types @@ -588,14 +609,16 @@ class RougailConvert(ParserVariable): def get_attributes_types( self, hint: dict, - variable: bool=False, + variable: bool = False, ) -> dict: """attribute is calculated if typing is like: Union[Calculation, xxx]""" - lists = {"strings": [], - "booleans": [], - "integers": [], - "floats": [], - "calculation": []} + lists = { + "strings": [], + "booleans": [], + "integers": [], + "floats": [], + "calculation": [], + } if variable: lists["calculation"].append("identifier") calculation = ["identifier"] @@ -647,18 +670,21 @@ class RougailConvert(ParserVariable): booleans.append(key) elif "Literal" in value.__class__.__name__: literals[key] = value.__args__ - return {"strings": strings, - "integers": integers, - "booleans": booleans, - "floats": floats, - "literals": literals, - "calculation": calculation, - "lists": lists, - "params": params, - } + return { + "strings": strings, + "integers": integers, + "booleans": booleans, + "floats": floats, + "literals": literals, + "calculation": calculation, + "lists": lists, + "params": params, + } def create_namespace( - self, namespace_description: str, isolated_namespace: bool=True, + self, + namespace_description: str, + isolated_namespace: bool = True, ) -> None: namespace_path = normalize_family(namespace_description) self.has_namespace = True @@ -687,9 +713,7 @@ class RougailConvert(ParserVariable): None, None, ) - self.parse_family( - option - ) + self.parse_family(option) def get_comment( self, diff --git a/src/rougail/convert/object_model.py b/src/rougail/convert/object_model.py index 49261fc9e..620208008 100644 --- a/src/rougail/convert/object_model.py +++ b/src/rougail/convert/object_model.py @@ -35,7 +35,11 @@ from ..utils import ( PROPERTY_ATTRIBUTE, ) from ..i18n import _ -from ..error import DictConsistencyError, VariableCalculationDependencyError, RougailWarning +from ..error import ( + DictConsistencyError, + VariableCalculationDependencyError, + RougailWarning, +) from ..tiramisu import CONVERT_OPTION, RENAME_TYPE, display_xmlfiles, convert_boolean BASETYPE = Union[StrictBool, StrictInt, StrictFloat, StrictStr, None] @@ -60,7 +64,7 @@ def get_convert_option_types(): if key.startswith("_"): continue if "params" in datas and key in datas["params"]: - multi = datas["params"][key].get('multi', False) + multi = datas["params"][key].get("multi", False) description = datas["params"][key]["description"] choices = datas["params"][key].get("choices") else: @@ -111,7 +115,7 @@ class VariableParam(Param): variable: StrictStr propertyerror: bool = True whole: bool = False -# dynamic: bool = True + # dynamic: bool = True optional: bool = False def to_param( @@ -324,9 +328,16 @@ class JinjaCalculation(Calculation): variable = objectspace.paths[path] objectspace.jinja[jinja_path] = self.jinja if return_type in RENAME_TYPE: - warning = _('the variable "{0}" has a depreciated return_type "{1}", please use "{2}" instead in {3}') + warning = _( + 'the variable "{0}" has a depreciated return_type "{1}", please use "{2}" instead in {3}' + ) warn( - warning.format(path, return_type, RENAME_TYPE[return_type], display_xmlfiles(self.xmlfiles)), + warning.format( + path, + return_type, + RENAME_TYPE[return_type], + display_xmlfiles(self.xmlfiles), + ), DeprecationWarning, stacklevel=2, ) @@ -416,19 +427,26 @@ class JinjaCalculation(Calculation): 'variable "{0}" has a calculating "{1}" with an invalid return_type, should be boolean or string, not "{2}"' ).format(path, self.attribute_name, return_type) raise DictConsistencyError(msg, 81, self.xmlfiles) - if return_type == 'boolean': + if return_type == "boolean": description = self.description if description is None: if self.ori_path is not None: opath = self.ori_path else: opath = path - warning = _('the variable "{0}" has a return_type "{1}", for attribute "{2}" but has not description in {3}') + warning = _( + 'the variable "{0}" has a return_type "{1}", for attribute "{2}" but has not description in {3}' + ) warn( - warning.format(opath, return_type, self.attribute_name, display_xmlfiles(self.xmlfiles)), + warning.format( + opath, + return_type, + self.attribute_name, + display_xmlfiles(self.xmlfiles), + ), RougailWarning, ) - self.description = _('value is invalid') + self.description = _("value is invalid") else: description = None return self._jinja_to_function( @@ -437,7 +455,7 @@ class JinjaCalculation(Calculation): False, objectspace, path, - params={'description': description}, + params={"description": description}, ) elif self.attribute_name in PROPERTY_ATTRIBUTE: return_type = self.return_type @@ -491,7 +509,7 @@ class JinjaCalculation(Calculation): class _VariableCalculation(Calculation): variable: StrictStr - propertyerror: bool = True, + propertyerror: bool = (True,) allow_none: bool = False optional: bool = False # FIXME identifier is not available for Properties! @@ -522,7 +540,9 @@ class _VariableCalculation(Calculation): self.namespace, self.xmlfiles, ) - if variable and not isinstance(variable, objectspace.variable_objects[0]["object"]): + if variable and not isinstance( + variable, objectspace.variable_objects[0]["object"] + ): if isinstance(variable, objectspace.family): msg = _( 'a variable "{0}" is needs in attribute "{1}" for "{2}" but it\'s a family' @@ -549,7 +569,13 @@ class _VariableCalculation(Calculation): if variable_in_calculation_identifier: msg = _( 'variable "{0}" has an attribute "{1}" with an identifier "{2}" but the path has also the identifier "{3}"' - ).format(path, self.attribute_name, self.variable, self.identifier, variable_in_calculation_identifier) + ).format( + path, + self.attribute_name, + self.variable, + self.identifier, + variable_in_calculation_identifier, + ) raise DictConsistencyError(msg, 89, self.xmlfiles) variable_in_calculation_identifier = self.identifier identifier_is_a_calculation = True @@ -578,7 +604,11 @@ class _VariableCalculation(Calculation): if self.allow_none: params["allow_none"] = True self.check_multi( - objectspace, path, variable_in_calculation_path, variable_in_calculation, identifier_is_a_calculation, + objectspace, + path, + variable_in_calculation_path, + variable_in_calculation, + identifier_is_a_calculation, ) if path in objectspace.followers: multi = objectspace.multis[path] == "submulti" @@ -589,7 +619,12 @@ class _VariableCalculation(Calculation): return params def check_multi( - self, objectspace, path, variable_in_calculation_path, variable_in_calculation, identifier_is_a_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 = ( @@ -1075,8 +1110,8 @@ class Family(BaseModel): class Dynamic(BaseModel): type: Literal["dynamic"] = "dynamic" -# # None only for format 1.0 -# variable: StrictStr = None + # # None only for format 1.0 + # variable: StrictStr = None dynamic: Union[List[Union[StrictStr, Calculation]], Calculation] diff --git a/src/rougail/convert/tiramisureflector.py b/src/rougail/convert/tiramisureflector.py index ebf0b5e56..8b2e0ec4c 100644 --- a/src/rougail/convert/tiramisureflector.py +++ b/src/rougail/convert/tiramisureflector.py @@ -82,7 +82,7 @@ class TiramisuReflector: continue self.text["header"].append(f"load_functions('{funcs_path}')") if self.objectspace.export_with_import: -# if self.objectspace.has_namespace: + # if self.objectspace.has_namespace: self.text["header"].extend( [ "try:", @@ -343,12 +343,16 @@ class Common: ret = f"ParamSelfOption(whole={whole}" if not dynamic: ret += ", dynamic=False" - return ret + ')' + return ret + ")" if whole: - msg = _('variable param "{0}" has whole attribute but it\'s not allowed for external variable') + msg = _( + 'variable param "{0}" has whole attribute but it\'s not allowed for external variable' + ) raise DictConsistencyError(msg.format(variable.path), 34, self.elt.xmlfiles) if not dynamic: - msg = _('variable param "{0}" has dynamic attribute but it\'s not allowed for external variable') + msg = _( + 'variable param "{0}" has dynamic attribute but it\'s not allowed for external variable' + ) raise DictConsistencyError(msg.format(variable.path), 34, self.elt.xmlfiles) option_name = self.tiramisu.reflector_objects[variable.path].get( self.calls, self.elt.path diff --git a/src/rougail/error.py b/src/rougail/error.py index ac0de0dfa..158d1659a 100644 --- a/src/rougail/error.py +++ b/src/rougail/error.py @@ -68,6 +68,7 @@ class DictConsistencyError(Exception): class NotFoundError(Exception): "not found error" + pass diff --git a/src/rougail/structural_commandline/annotator.py b/src/rougail/structural_commandline/annotator.py index 6339ce55b..7f0790361 100644 --- a/src/rougail/structural_commandline/annotator.py +++ b/src/rougail/structural_commandline/annotator.py @@ -60,7 +60,9 @@ class Annotator(Walk): return alternative_name = variable.alternative_name variable_path = variable.path - self.objectspace.informations.add(variable_path, "alternative_name", alternative_name) + self.objectspace.informations.add( + variable_path, "alternative_name", alternative_name + ) all_letters = "" for letter in alternative_name: all_letters += letter diff --git a/src/rougail/structural_string/__init__.py b/src/rougail/structural_string/__init__.py index ea94f1e2a..a7bdf46e7 100644 --- a/src/rougail/structural_string/__init__.py +++ b/src/rougail/structural_string/__init__.py @@ -16,15 +16,15 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . """ - from typing import List, Optional from itertools import chain from ruamel.yaml import YAML from ..tiramisu import normalize_family from ..convert.path import Paths -#from ..error import DictConsistencyError -#from ..i18n import _ + +# from ..error import DictConsistencyError +# from ..i18n import _ class Walker: @@ -85,9 +85,9 @@ class Walker: return path = self.convert.namespace if path: - name = f'yaml file for {path}' + name = f"yaml file for {path}" else: - name = 'yaml file' + name = "yaml file" version = self.convert.validate_file_version( objects, name, @@ -101,4 +101,3 @@ class Walker: __all__ = ("Walker",) - diff --git a/src/rougail/structural_string/config.py b/src/rougail/structural_string/config.py index a2e5f85d7..e28c3d5d8 100644 --- a/src/rougail/structural_string/config.py +++ b/src/rougail/structural_string/config.py @@ -66,4 +66,3 @@ extra_namespaces: __all__ = "get_rougail_config" - diff --git a/src/rougail/tiramisu.py b/src/rougail/tiramisu.py index 12feb728f..b7556979e 100644 --- a/src/rougail/tiramisu.py +++ b/src/rougail/tiramisu.py @@ -87,90 +87,139 @@ def convert_boolean(value: str) -> bool: return None raise Exception(_('unknown boolean value "{0}"').format(value)) + _ip_params = { - "cidr": {"description": _("IP must be in CIDR format")}, - "private_only": {"description": _("private IP are allowed")}, - "allow_reserved": {"description": _("reserved IP are allowed")}, - } + "cidr": {"description": _("IP must be in CIDR format")}, + "private_only": {"description": _("private IP are allowed")}, + "allow_reserved": {"description": _("reserved IP are allowed")}, +} _network_params = { - "cidr": {"description": _("network must be in CIDR format")}, - "private_only": {"description": _("private network are allowed")}, - "allow_reserved": {"description": _("reserved network are allowed")}, - } + "cidr": {"description": _("network must be in CIDR format")}, + "private_only": {"description": _("private network are allowed")}, + "allow_reserved": {"description": _("reserved network are allowed")}, +} _port_params = { - "allow_range": {"description": _("can be range of port")}, - "allow_protocol": {"description": _("can have the protocol")}, - "allow_zero": {"description": _("port 0 is allowed")}, - "allow_wellknown": {"description": _("well-known ports (1 to 1023) are allowed")}, - "allow_registred": {"description": _("registred ports (1024 to 49151) are allowed")}, - "allow_private": {"description": _("private ports (greater than 49152) are allowed")}, - } + "allow_range": {"description": _("can be range of port")}, + "allow_protocol": {"description": _("can have the protocol")}, + "allow_zero": {"description": _("port 0 is allowed")}, + "allow_wellknown": {"description": _("well-known ports (1 to 1023) are allowed")}, + "allow_registred": { + "description": _("registred ports (1024 to 49151) are allowed") + }, + "allow_private": { + "description": _("private ports (greater than 49152) are allowed") + }, +} _domain_params = { - "type": {"description": _("type of domainname"), "choices": ('domainname', 'netbios', 'hostname'), 'doc': _("type {0}")}, - "allow_startswith_dot": {"description": _("the domain name can starts by a dot")}, - "allow_without_dot": {"description": _("the domain name can be a hostname")}, - "allow_ip": {"description": _("the domain name can be an IP")}, - "allow_cidr_network": {"description": _("the domain name can be network in CIDR format")}, - "test_existence": {"description": _("the domain name must exist")}, - } + "type": { + "description": _("type of domainname"), + "choices": ("domainname", "netbios", "hostname"), + "doc": _("type {0}"), + }, + "allow_startswith_dot": {"description": _("the domain name can starts by a dot")}, + "allow_without_dot": {"description": _("the domain name can be a hostname")}, + "allow_ip": {"description": _("the domain name can be an IP")}, + "allow_cidr_network": { + "description": _("the domain name can be network in CIDR format") + }, + "test_existence": {"description": _("the domain name must exist")}, +} _web_params = _port_params | _domain_params CONVERT_OPTION = { "string": dict(opttype="StrOption", example="example"), - "number": dict(opttype="IntOption", - func=int, - params={ - "min_number": {"description": _("the minimum value"), 'doc': _("the minimum value is {0}")}, - "max_number": {"description": _("the maximum value"), 'doc': _("the maximum value is {0}")}, - }, - example=42), - "integer": dict(opttype="IntOption", - params={ - "min_integer": {"description": _("the minimum value"), 'doc': _("the minimum value is {0}")}, - "max_integer": {"description": _("the maximum value"), 'doc': _("the maximum value is {0}")}, - }, - func=int, - example=42, - ), + "number": dict( + opttype="IntOption", + func=int, + params={ + "min_number": { + "description": _("the minimum value"), + "doc": _("the minimum value is {0}"), + }, + "max_number": { + "description": _("the maximum value"), + "doc": _("the maximum value is {0}"), + }, + }, + example=42, + ), + "integer": dict( + opttype="IntOption", + params={ + "min_integer": { + "description": _("the minimum value"), + "doc": _("the minimum value is {0}"), + }, + "max_integer": { + "description": _("the maximum value"), + "doc": _("the maximum value is {0}"), + }, + }, + func=int, + example=42, + ), "float": dict(opttype="FloatOption", func=float, example=1.42), "boolean": dict(opttype="BoolOption", func=convert_boolean, example=True), - "secret": dict(opttype="PasswordOption", - params={ - "min_len": {"description": _("minimum characters length for the secret"), "doc": _("minimum length for the secret is {0} characters")}, - "max_len": {"description": _("maximum characters length for the secret"), "doc": _("maximum length for the secret is {0} characters")}, - "forbidden_char": {"description": _("forbidden characters"), "doc": _("forbidden characters: {0}")}, - }, - example="secrets"), + "secret": dict( + opttype="PasswordOption", + params={ + "min_len": { + "description": _("minimum characters length for the secret"), + "doc": _("minimum length for the secret is {0} characters"), + }, + "max_len": { + "description": _("maximum characters length for the secret"), + "doc": _("maximum length for the secret is {0} characters"), + }, + "forbidden_char": { + "description": _("forbidden characters"), + "doc": _("forbidden characters: {0}"), + }, + }, + example="secrets", + ), "mail": dict(opttype="EmailOption", example="user@example.net"), - "unix_filename": dict(opttype="FilenameOption", - msg="UNIX filename", - params={ - "allow_relative": {"description": _("this filename could be a relative path")}, - "test_existence": {"description": _("this file must exist")}, - "types": {"description": _("file type allowed"), "doc": _("file type allowed: {0}"), "choices": ("file", "directory"), "multi": True}, - }, - example="/tmp/myfile.txt"), + "unix_filename": dict( + opttype="FilenameOption", + msg="UNIX filename", + params={ + "allow_relative": { + "description": _("this filename could be a relative path") + }, + "test_existence": {"description": _("this file must exist")}, + "types": { + "description": _("file type allowed"), + "doc": _("file type allowed: {0}"), + "choices": ("file", "directory"), + "multi": True, + }, + }, + example="/tmp/myfile.txt", + ), "date": dict(opttype="DateOption", example="2000-01-01"), - "unix_user": dict(opttype="UsernameOption", example="username", - msg="UNIX user" - ), + "unix_user": dict(opttype="UsernameOption", example="username", msg="UNIX user"), "ip": dict( - opttype="IPOption", initkwargs={"allow_reserved": True}, + opttype="IPOption", + initkwargs={"allow_reserved": True}, msg="IP", params=_ip_params, - example="1.1.1.1" + example="1.1.1.1", + ), + "cidr": dict( + opttype="IPOption", + msg="CIDR", + initkwargs={"cidr": True}, + params=_ip_params, + example="1.1.1.0/24", ), - "cidr": dict(opttype="IPOption", msg="CIDR", initkwargs={"cidr": True}, - params=_ip_params, - example="1.1.1.0/24"), "netmask": dict(opttype="NetmaskOption", example="255.255.255.0"), - "network": dict(opttype="NetworkOption", - params=_network_params, - example="1.1.1.0"), + "network": dict(opttype="NetworkOption", params=_network_params, example="1.1.1.0"), "network_cidr": dict( - opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24", - params=_network_params, + opttype="NetworkOption", + initkwargs={"cidr": True}, + example="1.1.1.0/24", + params=_network_params, msg="network CIDR", ), "broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"), @@ -200,9 +249,11 @@ CONVERT_OPTION = { example="https://example.net", ), "port": dict( - opttype="PortOption", initkwargs={"allow_private": True}, + opttype="PortOption", + initkwargs={"allow_private": True}, params=_port_params, - example="111", func=str, + example="111", + func=str, ), "mac": dict(opttype="MACOption", example="00:00:00:00:00"), "unix_permissions": dict( @@ -218,9 +269,10 @@ CONVERT_OPTION = { "symlink": dict(opttype="SymLinkOption"), } # only version 1.1 -RENAME_TYPE = {"number": "integer", - "leadership": "sequence", - } +RENAME_TYPE = { + "number": "integer", + "leadership": "sequence", +} def get_identifier_from_dynamic_family(true_name, name) -> str: @@ -240,7 +292,9 @@ def raise_carry_out_calculation_error(subconfig, *args, **kwargs): ymlfiles = subconfig.config_bag.context.get_values().get_information( subconfig, "ymlfiles", [] ) - raise ConfigError(_("{0} in {1}").format(err, display_xmlfiles(ymlfiles)), subconfig=subconfig) + raise ConfigError( + _("{0} in {1}").format(err, display_xmlfiles(ymlfiles)), subconfig=subconfig + ) errors.raise_carry_out_calculation_error = raise_carry_out_calculation_error @@ -249,7 +303,7 @@ errors.raise_carry_out_calculation_error = raise_carry_out_calculation_error global func dict_env = {} ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined) -ENV.add_extension('jinja2.ext.do') +ENV.add_extension("jinja2.ext.do") func = ENV.filters TMP_TEMPLATE = mkdtemp() @@ -258,6 +312,7 @@ ENV.compile_templates(TMP_TEMPLATE, zip=None) atexit.register(rmtree, TMP_TEMPLATE) + class JinjaError: __slot__ = ("_err",) @@ -327,6 +382,7 @@ def tiramisu_display_name( with_quote: bool = False, ) -> str: """Replace the Tiramisu display_name function to display path + description""" + def get_path(): if description_type in ["description", "name", "name_and_description"]: path = kls.impl_getname() @@ -337,6 +393,7 @@ def tiramisu_display_name( "{{ identifier }}", normalize_family(str(subconfig.identifiers[-1])) ) return path + config_bag = subconfig.config_bag context = config_bag.context values = context.get_values() @@ -344,12 +401,23 @@ def tiramisu_display_name( description_type = values.get_information( context_subconfig, "description_type", "name_and_description" ) - if description_type in ["description", "name_and_description", "path_and_description"]: + if description_type in [ + "description", + "name_and_description", + "path_and_description", + ]: doc = values.get_information(subconfig, "doc", None) description = doc if doc and doc != kls.impl_getname() else "" if "{{ identifier }}" in description and subconfig.identifiers: - description = description.replace("{{ identifier }}", str(subconfig.identifiers[-1])) - if description_type in ["name", "path", "name_and_description", "path_and_description"]: + description = description.replace( + "{{ identifier }}", str(subconfig.identifiers[-1]) + ) + if description_type in [ + "name", + "path", + "name_and_description", + "path_and_description", + ]: path = get_path() if description_type in ["name_and_description", "path_and_description"]: if description: @@ -414,15 +482,15 @@ def jinja_to_function( for v in value: if isinstance(v, PropertiesOptionError): v = JinjaError(v) -# if v is None: -# v = '' + # if v is None: + # v = '' val.append(v) value = val else: if isinstance(value, PropertiesOptionError): value = JinjaError(value) -# if value is None: -# value = '' + # if value is None: + # value = '' if "." in key: c_kw = kw path, var = key.rsplit(".", 1) @@ -446,12 +514,14 @@ def jinja_to_function( except Exception as err: kw_str = ", ".join(kw_to_string(kw)) prefix = _('cannot calculate the variable "{0}"').format(__internal_variable) - msg = _('the attribute "{0}" in {1} with the parameters "{2}" causes the error: {3}').format( - __internal_attribute, - display_xmlfiles(__internal_files), - kw_str, - err, - ) + msg = _( + 'the attribute "{0}" in {1} with the parameters "{2}" causes the error: {3}' + ).format( + __internal_attribute, + display_xmlfiles(__internal_files), + kw_str, + err, + ) raise ConfigError(msg, prefix=prefix) from err convert = CONVERT_OPTION[__internal_type].get("func", str) if __internal_multi: @@ -468,10 +538,10 @@ def jinja_to_function( msg = _('"{0}" is an invalid {1}').format(values, __internal_type) if __internal_attribute != "default": msg = _('the attribute "{0}" in {1} causes the error: {2}').format( - __internal_attribute, - display_xmlfiles(__internal_files), - msg, - ) + __internal_attribute, + display_xmlfiles(__internal_files), + msg, + ) raise ConfigError(msg, prefix=prefix) from err values = values if values != "" and values != "None" else None if values is None and __default_value is not None: diff --git a/src/rougail/types.py b/src/rougail/types.py index 41d55b25d..d61cabfcc 100644 --- a/src/rougail/types.py +++ b/src/rougail/types.py @@ -15,6 +15,7 @@ details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . """ + from .config import StaticRougailConvert from .i18n import _ from .error import DictConsistencyError @@ -27,17 +28,21 @@ class TypeRougailConvert(StaticRougailConvert): secret_pattern: str, default_structural_format_version: str, ) -> None: - super().__init__(False, {"sort_structural_files_all": True, - "main_namespace": None, - "main_structural_directories": main_structural_directories, - }) + super().__init__( + False, + { + "sort_structural_files_all": True, + "main_namespace": None, + "main_structural_directories": main_structural_directories, + }, + ) self.default_structural_format_version = default_structural_format_version self.secret_pattern = secret_pattern self.loaded_custom_types = {} def load_config(self) -> None: super().load_config() -# self.add_extra_options = self.add_extra_options + # self.add_extra_options = self.add_extra_options self.sort_structural_files_all = False self.structurals = ["directory"] @@ -46,10 +51,11 @@ def rougail_type(rougailconfig): types = rougailconfig["types"] if not types: return {"custom_variable_types": {}, "custom_family_types": {}} - convert = TypeRougailConvert(types, - rougailconfig["secret_manager.pattern"], - rougailconfig["default_structural_format_version"], - ) + convert = TypeRougailConvert( + types, + rougailconfig["secret_manager.pattern"], + rougailconfig["default_structural_format_version"], + ) convert.init() convert.parse_directories() loaded_custom_types_keys = list(convert.loaded_custom_types) @@ -68,10 +74,11 @@ def rougail_type(rougailconfig): custom_variable_types = {} custom_family_types = {} for typ, data in convert.loaded_custom_types.items(): - if data.option_type == 'variable': + if data.option_type == "variable": custom_variable_types[typ] = data else: custom_family_types[typ] = data - return {"custom_variable_types": custom_variable_types, - "custom_family_types": custom_family_types, - } + return { + "custom_variable_types": custom_variable_types, + "custom_family_types": custom_family_types, + } diff --git a/src/rougail/user_data.py b/src/rougail/user_data.py index 993059786..b4cfa0ff4 100644 --- a/src/rougail/user_data.py +++ b/src/rougail/user_data.py @@ -82,11 +82,12 @@ class UserData: source = datas["source"] for name, data in datas.get("values", {}).items(): self.values.setdefault(name, []).append( - { - "source": source, - "values": data, - "options": options.copy(), - }) + { + "source": source, + "values": data, + "options": options.copy(), + } + ) self.errors.extend(datas.get("errors", [])) self.warnings.extend(datas.get("warnings", [])) @@ -102,7 +103,7 @@ class UserData: if self.invalid_user_data_error: msg = str(err) else: - msg = _('{0}, it will be ignored').format(err) + msg = _("{0}, it will be ignored").format(err) self.invalids.append({msg: err.subconfig}) def _auto_configure_dynamics(self): @@ -211,7 +212,9 @@ class UserData: if option.issubmulti(): for idx, val in enumerate(value): if isinstance(val, list): - value[idx] = [convert_value(option, v, needs_convert) for v in val] + value[idx] = [ + convert_value(option, v, needs_convert) for v in val + ] elif isinstance(value, list): value = [convert_value(option, val, needs_convert) for val in value] if needs_convert: @@ -236,21 +239,26 @@ class UserData: if option.type() == "password": one_is_in_error = False for values in self.values[values_path]: - if values.get("options", {}).get("allow_secrets_variables", True) is False: + if ( + values.get("options", {}).get( + "allow_secrets_variables", True + ) + is False + ): one_is_in_error = True - self.errors.append({ - _( - 'the variable contains secrets and should not be defined in {0}' - ).format(values["source"]): option._subconfig} + self.errors.append( + { + _( + "the variable contains secrets and should not be defined in {0}" + ).format(values["source"]): option._subconfig + } ) if one_is_in_error: self.values.pop(values_path) continue values = self.values[values_path][-1] options = values.get("options", {}) - value = self.convert_value( - path, option, options, values["values"] - ) + value = self.convert_value(path, option, options, values["values"]) index = option.index() if index is not None: if isinstance(value, tuple): @@ -278,8 +286,8 @@ class UserData: value_is_set = True except Exception as err: pass -# if path != option.path(): -# self.values[option.path()] = self.values.pop(values_path) + # if path != option.path(): + # self.values[option.path()] = self.values.pop(values_path) else: # value is correctly set, remove variable to the set if index is not None: @@ -326,34 +334,51 @@ class UserData: if value: if self.invalid_user_data_error: msg = _( - 'it\'s a family so we cannot set the value {0}, it has been loading from {1}' - ) + "it's a family so we cannot set the value {0}, it has been loading from {1}" + ) else: msg = _( - 'it\'s a family so we cannot set the value {0}, it will be ignored when loading from {1}' - ) - self.invalids.append({msg.format( - self._display_value(option, value), - options["source"], - ): option._subconfig} + "it's a family so we cannot set the value {0}, it will be ignored when loading from {1}" + ) + self.invalids.append( + { + msg.format( + self._display_value(option, value), + options["source"], + ): option._subconfig + } ) continue if option.issymlinkoption(): - err = _('it\'s a symlink option so we cannot set the value {0}').format(self._display_value(option, value)) + err = _( + "it's a symlink option so we cannot set the value {0}" + ).format(self._display_value(option, value)) if self.invalid_user_data_error: - msg = _('{0}, it has been loading from {1}').format(err, options["source"]) + msg = _("{0}, it has been loading from {1}").format( + err, options["source"] + ) else: - msg = _('{0}, it will be ignored when loading from {1}').format(err, options["source"]) + msg = _("{0}, it will be ignored when loading from {1}").format( + err, options["source"] + ) self.unknowns.append({msg: option._subconfig}) continue except ConfigError as err: - self.invalids.append({ - _("{0}, it has been loaded from {1}").format(err, options["source"]): option._subconfig} + self.invalids.append( + { + _("{0}, it has been loaded from {1}").format( + err, options["source"] + ): option._subconfig + } ) continue except PropertiesOptionError as err: - self.unknowns.append({ - _("{0}, it has been loaded from {1}").format(err, options["source"]): option._subconfig} + self.unknowns.append( + { + _("{0}, it has been loaded from {1}").format( + err, options["source"] + ): option._subconfig + } ) continue @@ -364,20 +389,16 @@ class UserData: subconfig = None child_name = err_path else: - parent_path, child_name = err_path.rsplit('.', 1) + parent_path, child_name = err_path.rsplit(".", 1) subconfig = self.config.option(parent_path) subconfig._set_subconfig() err_msg = _( 'variable or family "{0}" does not exist so cannot load "{1}"' - ).format(child_name, path) + ).format(child_name, path) if self.unknown_user_data_error: - msg = _( - '{0}, it has been loading from {1}' - ) + msg = _("{0}, it has been loading from {1}") else: - msg = _( - '{0}, it will be ignored when loading from {1}' - ) + msg = _("{0}, it will be ignored when loading from {1}") msg = msg.format(err_msg, options["source"]) if subconfig is not None: msg = {msg: subconfig._subconfig} @@ -385,13 +406,19 @@ class UserData: elif err.code == "option-dynamic": if self.invalid_user_data_error: msg = _( - '"{0}" is the name of a dynamic family, it has been loading from {1}' + '"{0}" is the name of a dynamic family, it has been loading from {1}' ) else: msg = _( - '"{0}" is the name of a dynamic family, it will be ignored when loading from {1}' + '"{0}" is the name of a dynamic family, it will be ignored when loading from {1}' ) - self.invalids.append({msg.format(option.description(with_quote=True), options["source"]): option._subconfig}) + self.invalids.append( + { + msg.format( + option.description(with_quote=True), options["source"] + ): option._subconfig + } + ) else: self.invalids.append( _("{0} loaded from {1}").format(err, options["source"]) @@ -430,7 +457,9 @@ class UserData: [_(prop) for prop in err.proptype], add_quote=False ) err_path = err.subconfig.path - err_description = err.subconfig.option.impl_get_display_name(err.subconfig, with_quote=True) + err_description = err.subconfig.option.impl_get_display_name( + err.subconfig, with_quote=True + ) display_name = option.description(with_quote=True) if index is not None: if path == err_path: @@ -442,13 +471,15 @@ class UserData: msg = _( 'variable {0} at index "{1}" is {2}, it will be ignored when loading from {3}' ) - self.unknowns.append({ - msg.format( - display_name, - index, - properties, - options["source"], - ): option._subconfig} + self.unknowns.append( + { + msg.format( + display_name, + index, + properties, + options["source"], + ): option._subconfig + } ) else: if self.unknown_user_data_error: @@ -459,14 +490,16 @@ class UserData: msg = _( 'family {0} is {1}, {2} at index "{3}", it will be ignored when loading from {4}' ) - self.unknowns.append({ - msg.format( - err_description, - properties, - display_name, - index, - options["source"], - ): option._subconfig} + self.unknowns.append( + { + msg.format( + err_description, + properties, + display_name, + index, + options["source"], + ): option._subconfig + } ) else: if path == err_path: @@ -478,13 +511,17 @@ class UserData: msg = _( "variable has property {0}, it will be ignored when loading from {1}" ) - self.unknowns.append({ - msg.format( - properties, options["source"] - ): option._subconfig} + self.unknowns.append( + { + msg.format( + properties, options["source"] + ): option._subconfig + } ) else: - if not options.get("options", {}).get("secret_manager", False): + if not options.get("options", {}).get( + "secret_manager", False + ): if self.unknown_user_data_error: msg = _( "family {0} has property {1}, so cannot access to {2}, it has been loading from {3}" @@ -493,57 +530,59 @@ class UserData: msg = _( "family {0} has property {1}, so cannot access to {2}, it will be ignored when loading from {3}" ) - self.unknowns.append({ - msg.format( - err_description, - properties, - display_name, - options["source"], - ): option._subconfig} + self.unknowns.append( + { + msg.format( + err_description, + properties, + display_name, + options["source"], + ): option._subconfig + } ) else: if self.unknown_user_data_error: - msg = _( - "{0}, it has been loading from {1}" - ) + msg = _("{0}, it has been loading from {1}") else: - msg = _( - "{0}, it will be ignored when loading from {1}" - ) - self.unknowns.append({ - msg.format(err, options["source"]): option._subconfig} + msg = _("{0}, it will be ignored when loading from {1}") + self.unknowns.append( + {msg.format(err, options["source"]): option._subconfig} ) except LeadershipError as err: if self.unknown_user_data_error: - msg = _( - "{0}, it has been loading from {1}" - ) + msg = _("{0}, it has been loading from {1}") else: - msg = _( - "{0}, it will be ignored when loading from {1}" - ) - self.unknowns.append({ - msg.format(err, options["source"]): option._subconfig} + msg = _("{0}, it will be ignored when loading from {1}") + self.unknowns.append( + {msg.format(err, options["source"]): option._subconfig} ) except ConfigError as err: err.prefix = "" if self.invalid_user_data_error: - msg = _('{0}, it has been loading from {1}').format(err, options["source"]) + msg = _("{0}, it has been loading from {1}").format( + err, options["source"] + ) else: - msg = _('{0}, it will be ignored when loading from {1}').format(err, options["source"]) + msg = _("{0}, it will be ignored when loading from {1}").format( + err, options["source"] + ) self.invalids.append({msg: option._subconfig}) except ValueError as err: err.prefix = "" type_ = option.type(translation=True) - msg = _('the value {0} is an invalid {1}, {2}').format( - self._display_value(option, value), - type_, - err, - ) + msg = _("the value {0} is an invalid {1}, {2}").format( + self._display_value(option, value), + type_, + err, + ) if self.invalid_user_data_error: - msg += _(', it has been loading from {0}').format(options["source"]) + msg += _(", it has been loading from {0}").format( + options["source"] + ) else: - msg += _(', it will be ignored when loading from {0}').format(options["source"]) + msg += _(", it will be ignored when loading from {0}").format( + options["source"] + ) self.invalids.append({msg: option._subconfig}) except AttributeOptionError as err: err.prefix = "" @@ -557,10 +596,12 @@ class UserData: if is_secret_manager and isinstance(value, tuple): # it's a function params = tuple([ParamValue(val) for val in value[1:]]) - option.information.set('secret_manager', True) + option.information.set("secret_manager", True) if index is not None: option = option.forcepermissive.index(index) - value = Calculation(value[0], Params(params, kwargs={"option": ParamValue(option)})) + value = Calculation( + value[0], Params(params, kwargs={"option": ParamValue(option)}) + ) option = option.forcepermissive add_validation = True else: @@ -586,9 +627,7 @@ class UserData: key = f"loaded_from_{index}" else: key = "loaded_from" - value = _("loaded from {0}").format( - self.values[path][-1]["source"] - ) + value = _("loaded from {0}").format(self.values[path][-1]["source"]) if options.get("secret_manager"): # FIXME (true_config ???) default = option.value.default() @@ -658,12 +697,18 @@ def _populate_mandatory(option, errors: list) -> None: if index is None: msg = _("mandatory variable but has no value") else: - msg = _('mandatory variable at index "{0}" but has no value').format(index) + msg = _('mandatory variable at index "{0}" but has no value').format( + index + ) else: if index is None: - msg = _("mandatory variable but is inaccessible and has no value or has null in value") + msg = _( + "mandatory variable but is inaccessible and has no value or has null in value" + ) else: - msg = _('mandatory variable at index "{0}" but is inaccessible and has no value or has null in value').format(index) + msg = _( + 'mandatory variable at index "{0}" but is inaccessible and has no value or has null in value' + ).format(index) else: proptype = option.value.mandatory(return_type=True) if proptype == "empty": diff --git a/src/rougail/utils.py b/src/rougail/utils.py index 6e287b8f1..97c281a9a 100644 --- a/src/rougail/utils.py +++ b/src/rougail/utils.py @@ -85,7 +85,7 @@ def get_jinja_variable_to_param( ): try: env = SandboxedEnvironment(loader=DictLoader({"tmpl": jinja_text})) - env.add_extension('jinja2.ext.do') + env.add_extension("jinja2.ext.do") env.filters = functions parsed_content = Parser(env, jinja_text, "", "").parse()