fix: black

This commit is contained in:
egarette@silique.fr 2025-10-15 09:44:22 +02:00
parent 6dd6df77a1
commit b4ce22a0af
9 changed files with 341 additions and 154 deletions

View file

@ -28,7 +28,7 @@ class Changelog: # pylint: disable=no-member,too-few-public-methods
def gen_doc_changelog(self): def gen_doc_changelog(self):
"""Return changelog""" """Return changelog"""
with Path(self.previous_json_file).open() as outfh: with Path(self.previous_json_file).open() as outfh:
previous_doc = loads(outfh.read()) previous_doc = loads(outfh.read())
self.load() self.load()
self._added_variables = [] self._added_variables = []
self._modified_variables = [] self._modified_variables = []
@ -39,6 +39,7 @@ class Changelog: # pylint: disable=no-member,too-few-public-methods
def parser(self, previous_families, new_families): def parser(self, previous_families, new_families):
def add(new): def add(new):
self.formater.variable_to_string(new, self._added_variables) self.formater.variable_to_string(new, self._added_variables)
def remove(previous): def remove(previous):
self._removed_variables.append(element) self._removed_variables.append(element)
@ -66,7 +67,7 @@ class Changelog: # pylint: disable=no-member,too-few-public-methods
else: else:
add(new) add(new)
self.parser(previous["children"], {}) self.parser(previous["children"], {})
elif previous["type"] != 'variable': elif previous["type"] != "variable":
self.parser(previous["children"], new["children"]) self.parser(previous["children"], new["children"])
else: else:
modified_attributes = {} modified_attributes = {}
@ -75,14 +76,21 @@ class Changelog: # pylint: disable=no-member,too-few-public-methods
prop_new = new.get(prop, []) prop_new = new.get(prop, [])
if prop_previous != prop_new: if prop_previous != prop_new:
name = None name = None
if isinstance(prop_previous, dict) and "values" in prop_previous: if (
isinstance(prop_previous, dict)
and "values" in prop_previous
):
name = prop_previous["name"] name = prop_previous["name"]
local_prop_previous = prop_previous = prop_previous["values"] local_prop_previous = prop_previous = prop_previous[
"values"
]
if not isinstance(prop_previous, list): if not isinstance(prop_previous, list):
if prop == "default": if prop == "default":
local_prop_previous = [prop_previous] local_prop_previous = [prop_previous]
else: else:
local_prop_previous = prop_previous = [prop_previous] local_prop_previous = prop_previous = [
prop_previous
]
else: else:
local_prop_previous = prop_previous local_prop_previous = prop_previous
if isinstance(prop_new, dict) and "values" in prop_new: if isinstance(prop_new, dict) and "values" in prop_new:
@ -95,36 +103,63 @@ class Changelog: # pylint: disable=no-member,too-few-public-methods
else: else:
prop_new = [prop_new] prop_new = [prop_new]
if isinstance(prop_previous, list): if isinstance(prop_previous, list):
prop_previous = [p for p in prop_previous if p not in prop_new] prop_previous = [
p for p in prop_previous if p not in prop_new
]
elif prop_previous in prop_new: elif prop_previous in prop_new:
prop_new.remove(prop_previous) prop_new.remove(prop_previous)
prop_previous = [] prop_previous = []
prop_new = [p for p in prop_new if p not in local_prop_previous] prop_new = [p for p in prop_new if p not in local_prop_previous]
if prop_previous not in [None, []] or prop_new not in [None, []]: if prop_previous not in [None, []] or prop_new not in [
None,
[],
]:
modified_attributes[prop] = (name, prop_previous, prop_new) modified_attributes[prop] = (name, prop_previous, prop_new)
if not modified_attributes: if not modified_attributes:
continue continue
self.formater.variable_to_string(new, self._modified_variables, modified_attributes) self.formater.variable_to_string(
new, self._modified_variables, modified_attributes
)
def display(self) -> str: def display(self) -> str:
msg = '' msg = ""
if self._added_variables: if self._added_variables:
if len(self._added_variables) == 1: if len(self._added_variables) == 1:
title = _('New variable') title = _("New variable")
else: else:
title = _('New variables') title = _("New variables")
msg += self.formater.run([self.formater.title(title, self.level), self.formater.table(self._added_variables)], self.level, dico_is_already_treated=True) msg += self.formater.run(
[
self.formater.title(title, self.level),
self.formater.table(self._added_variables),
],
self.level,
dico_is_already_treated=True,
)
if self._modified_variables: if self._modified_variables:
if len(self._modified_variables) == 1: if len(self._modified_variables) == 1:
title = _('Modified variable') title = _("Modified variable")
else: else:
title = _('Modified variables') title = _("Modified variables")
msg += self.formater.run([self.formater.title(title, self.level), self.formater.table(self._modified_variables)], self.level, dico_is_already_treated=True) msg += self.formater.run(
[
self.formater.title(title, self.level),
self.formater.table(self._modified_variables),
],
self.level,
dico_is_already_treated=True,
)
if self._removed_variables: if self._removed_variables:
if len(self._removed_variables) == 1: if len(self._removed_variables) == 1:
title = _('Deleted variable') title = _("Deleted variable")
else: else:
title = _('Deleted variables') title = _("Deleted variables")
msg += self.formater.run([self.formater.title(title, self.level), self.formater.list(self._removed_variables)], self.level, dico_is_already_treated=True) msg += self.formater.run(
[
self.formater.title(title, self.level),
self.formater.list(self._removed_variables),
],
self.level,
dico_is_already_treated=True,
)
return msg return msg

View file

@ -35,9 +35,9 @@ from .changelog import Changelog
HIDDEN_PROPERTIES = [ HIDDEN_PROPERTIES = [
"hidden", "hidden",
"disabled", "disabled",
] ]
class RougailOutputDoc(Examples, Changelog): class RougailOutputDoc(Examples, Changelog):
@ -91,7 +91,7 @@ class RougailOutputDoc(Examples, Changelog):
else: else:
self.with_family = True self.with_family = True
if "changelog" in self.contents: if "changelog" in self.contents:
self.previous_json_file = rougailconfig['doc.previous_json_file'] self.previous_json_file = rougailconfig["doc.previous_json_file"]
self.formater = outputs[output_format](self.with_family) self.formater = outputs[output_format](self.with_family)
self.informations = None self.informations = None
try: try:
@ -105,7 +105,7 @@ class RougailOutputDoc(Examples, Changelog):
def run(self) -> str: def run(self) -> str:
"""Print documentation in stdout""" """Print documentation in stdout"""
self.load() self.load()
return_string = '' return_string = ""
if "variables" in self.contents: if "variables" in self.contents:
return_string += self.formater.run(self.informations, self.level) return_string += self.formater.run(self.informations, self.level)
if "example" in self.contents: if "example" in self.contents:
@ -144,14 +144,19 @@ class RougailOutputDoc(Examples, Changelog):
new_name = True new_name = True
description = obj.description(uncalculated=True) description = obj.description(uncalculated=True)
name = obj.name(uncalculated=True) name = obj.name(uncalculated=True)
self.dynamic_paths[path] = {"names": [], self.dynamic_paths[path] = {
"identifiers": [], "names": [],
"path": path, "identifiers": [],
} "path": path,
}
if not obj.information.get("forced_description", False): if not obj.information.get("forced_description", False):
self.dynamic_paths[path]["description"] = self._convert_description(description, obj, type_, its_a_path=False) self.dynamic_paths[path]["description"] = self._convert_description(
description, obj, type_, its_a_path=False
)
elif obj.isoptiondescription(): elif obj.isoptiondescription():
self.dynamic_paths[path]["description"] = self._convert_description(description, obj, type_, its_a_path=True) self.dynamic_paths[path]["description"] = self._convert_description(
description, obj, type_, its_a_path=True
)
dynamic_obj = self.dynamic_paths[path] dynamic_obj = self.dynamic_paths[path]
dynamic_obj["names"].append(obj.name()) dynamic_obj["names"].append(obj.name())
dynamic_obj["identifiers"].append(obj.identifiers()) dynamic_obj["identifiers"].append(obj.identifiers())
@ -212,19 +217,20 @@ class RougailOutputDoc(Examples, Changelog):
sub_informations = self._parse_families(family) sub_informations = self._parse_families(family)
if not sub_informations: if not sub_informations:
return return
# if self.with_family: # if self.with_family:
family_informations = self._populate_family( family_informations = self._populate_family(
family, family,
path, path,
) )
if family_informations is not False: if family_informations is not False:
informations[name] = { informations[name] = {
"type": self._get_family_type(family), "type": self._get_family_type(family),
"informations": family_informations, "informations": family_informations,
"children": sub_informations, "children": sub_informations,
} }
# else:
# informations.update(sub_informations) # else:
# informations.update(sub_informations)
def parse_variable( def parse_variable(
self, self,
@ -266,7 +272,7 @@ class RougailOutputDoc(Examples, Changelog):
if not self._populate_variable( if not self._populate_variable(
variable, variable,
sub_informations, sub_informations,
): ):
return None return None
if self.example: if self.example:
self._add_examples(variable, sub_informations, leader) self._add_examples(variable, sub_informations, leader)
@ -319,7 +325,7 @@ class RougailOutputDoc(Examples, Changelog):
informations = self.dynamic_paths[path] informations = self.dynamic_paths[path]
else: else:
informations = {} informations = {}
if not self._populate(family, informations, 'family'): if not self._populate(family, informations, "family"):
return False return False
if family.isleadership(): if family.isleadership():
informations.setdefault("help", []).append( informations.setdefault("help", []).append(
@ -352,7 +358,7 @@ class RougailOutputDoc(Examples, Changelog):
variable, variable,
informations, informations,
) )
if not self._populate(variable, informations, 'variable'): if not self._populate(variable, informations, "variable"):
return False return False
if variable.ismulti(): if variable.ismulti():
multi = not variable.isfollower() or variable.issubmulti() multi = not variable.isfollower() or variable.issubmulti()
@ -389,21 +395,34 @@ class RougailOutputDoc(Examples, Changelog):
return False return False
name = child.name(uncalculated=True) name = child.name(uncalculated=True)
if child.information.get("forced_description", False): if child.information.get("forced_description", False):
if not child.isoptiondescription() or not self.support_namespace or child.group_type() is not groups.namespace: if (
if child.isoptiondescription() or not child.isfollower() or not child.index(): not child.isoptiondescription()
or not self.support_namespace
or child.group_type() is not groups.namespace
):
if (
child.isoptiondescription()
or not child.isfollower()
or not child.index()
):
warning = _('No attribute "description" for "{0}" in {1}').format( warning = _('No attribute "description" for "{0}" in {1}').format(
child.path(uncalculated=True), child.path(uncalculated=True),
display_xmlfiles(child.information.get("ymlfiles")), display_xmlfiles(child.information.get("ymlfiles")),
) )
warn(warning, warn(
RougailWarning, warning,
) RougailWarning,
)
if child.isoptiondescription(): if child.isoptiondescription():
description = self._convert_description(child.description(uncalculated=True), child, type_, its_a_path=True) description = self._convert_description(
child.description(uncalculated=True), child, type_, its_a_path=True
)
else: else:
description = None description = None
else: else:
description = self._convert_description(child.description(uncalculated=True), child, type_, its_a_path=False) description = self._convert_description(
child.description(uncalculated=True), child, type_, its_a_path=False
)
if not child.isdynamic(): if not child.isdynamic():
informations["path"] = child.path(uncalculated=True) informations["path"] = child.path(uncalculated=True)
informations["names"] = [child.name()] informations["names"] = [child.name()]
@ -421,10 +440,10 @@ class RougailOutputDoc(Examples, Changelog):
def _convert_description(self, description, obj, type_, its_a_path=False): def _convert_description(self, description, obj, type_, its_a_path=False):
if not its_a_path: if not its_a_path:
description = to_phrase(description, type_) description = to_phrase(description, type_)
# if "{{ identifier }}" in description: # if "{{ identifier }}" in description:
# description = {"description": description, # description = {"description": description,
# "identifier": obj.identifiers()[-1], # "identifier": obj.identifiers()[-1],
# } # }
return description return description
def _add_examples(self, variable, informations: dict, leader) -> None: def _add_examples(self, variable, informations: dict, leader) -> None:
@ -528,9 +547,7 @@ class RougailOutputDoc(Examples, Changelog):
break break
if child.information.get("type") == "regexp": if child.information.get("type") == "regexp":
validators.append( validators.append(
_('text based with regular expressions "{0}"').format( _('text based with regular expressions "{0}"').format(child.pattern())
child.pattern()
)
) )
if validators: if validators:
if len(validators) == 1: if len(validators) == 1:
@ -675,9 +692,10 @@ class RougailOutputDoc(Examples, Changelog):
child.path(), child.path(),
display_xmlfiles(child.information.get("ymlfiles")), display_xmlfiles(child.information.get("ymlfiles")),
) )
warn(warning, warn(
RougailWarning, warning,
) RougailWarning,
)
return values return values
def _calculation_variable_to_string(self, child, calculation, prop): def _calculation_variable_to_string(self, child, calculation, prop):
@ -696,7 +714,12 @@ class RougailOutputDoc(Examples, Changelog):
except VariableCalculationDependencyError: except VariableCalculationDependencyError:
msg = _("depends on an undocumented variable") msg = _("depends on an undocumented variable")
else: else:
if condition == "when" and value == variable_value or condition == "when_not" and value != variable_value: if (
condition == "when"
and value == variable_value
or condition == "when_not"
and value != variable_value
):
if prop in HIDDEN_PROPERTIES: if prop in HIDDEN_PROPERTIES:
return return
# always "{prop}" (but depends on an undocumented variable) # always "{prop}" (but depends on an undocumented variable)
@ -707,12 +730,16 @@ class RougailOutputDoc(Examples, Changelog):
if not calculation["optional"]: if not calculation["optional"]:
msg = _('when the variable "{0}" hasn\'t the value "{1}"') msg = _('when the variable "{0}" hasn\'t the value "{1}"')
else: else:
msg = _('when the variable "{0}" is defined and hasn\'t the value "{1}"') msg = _(
'when the variable "{0}" is defined and hasn\'t the value "{1}"'
)
else: else:
if not calculation["optional"]: if not calculation["optional"]:
msg = _('when the variable "{0}" has the value "{1}"') msg = _('when the variable "{0}" has the value "{1}"')
else: else:
msg = _('when the variable "{0}" is defined and has the value "{1}"') msg = _(
'when the variable "{0}" is defined and has the value "{1}"'
)
if not isinstance(value, str): if not isinstance(value, str):
value = dump(value) value = dump(value)
values = msg.format(variable_path, value) values = msg.format(variable_path, value)
@ -738,16 +765,14 @@ class RougailOutputDoc(Examples, Changelog):
else: else:
regexp = compile( regexp = compile(
"^" "^"
+ calculation["ori_path"].replace( + calculation["ori_path"].replace("{{ identifier }}", "(.*)")
"{{ identifier }}", "(.*)"
)
+ "$" + "$"
) )
informations = [self.dynamic_paths[calculation["value"]]] informations = [self.dynamic_paths[calculation["value"]]]
values = [] values = []
all_is_undocumented = None all_is_undocumented = None
for information in informations: for information in informations:
# if calculation["ori_path"] == information['path']: # if calculation["ori_path"] == information['path']:
path = information["path"] path = information["path"]
for identifiers in information["identifiers"]: for identifiers in information["identifiers"]:
cpath = calc_path(path, identifiers=identifiers) cpath = calc_path(path, identifiers=identifiers)
@ -759,9 +784,13 @@ class RougailOutputDoc(Examples, Changelog):
msg = hidden_msg msg = hidden_msg
else: else:
if "{{ identifier }}" in path: if "{{ identifier }}" in path:
msg = {"message": true_msg, msg = {
"path": {"path": path, "identifiers": identifiers.copy()}, "message": true_msg,
} "path": {
"path": path,
"identifiers": identifiers.copy(),
},
}
else: else:
msg = true_msg.format(path) msg = true_msg.format(path)
all_is_undocumented = False all_is_undocumented = False
@ -786,9 +815,12 @@ class RougailOutputDoc(Examples, Changelog):
uncalculated, Calculation uncalculated, Calculation
): ):
if isinstance(uncalculated, list): if isinstance(uncalculated, list):
true_msg = {"submessage": _("(from an undocumented variable)"), true_msg = {
"values": uncalculated, "submessage": _(
} "(from an undocumented variable)"
),
"values": uncalculated,
}
else: else:
if not isinstance(uncalculated, str): if not isinstance(uncalculated, str):
uncalculated = dump(uncalculated) uncalculated = dump(uncalculated)

View file

@ -118,6 +118,7 @@ class Examples: # pylint: disable=no-member,too-few-public-methods
examples_mandatories[name] = ret_m examples_mandatories[name] = ret_m
if ret_e: if ret_e:
examples[name] = ret_e examples[name] = ret_e
ori_path = family["informations"]["path"] ori_path = family["informations"]["path"]
if "identifiers" in family["informations"]: if "identifiers" in family["informations"]:
for idx, identifiers in enumerate(family["informations"]["identifiers"]): for idx, identifiers in enumerate(family["informations"]["identifiers"]):

View file

@ -112,7 +112,7 @@ class Formater(CommonFormater):
"""Dump yaml part of documentation""" """Dump yaml part of documentation"""
return f"[,yaml]\n----\n---\n{dump(_dump)}\n----\n" return f"[,yaml]\n----\n---\n{dump(_dump)}\n----\n"
def table(self, datas: list, with_header: bool=True) -> str: def table(self, datas: list, with_header: bool = True) -> str:
"""Transform list to a table in string format """Transform list to a table in string format
we change the first line because we want that col has the same width we change the first line because we want that col has the same width
""" """

View file

@ -154,7 +154,7 @@ class Formater(CommonFormater):
for l in line.split(self.enter_table): for l in line.split(self.enter_table):
self.max_line = max(self.max_line, len(l) + 1) self.max_line = max(self.max_line, len(l) + 1)
def table(self, datas: list, with_header: bool=True) -> str: def table(self, datas: list, with_header: bool = True) -> str:
"""Transform list to a table in string format""" """Transform list to a table in string format"""
table = self.rich_table(show_lines=True) table = self.rich_table(show_lines=True)
if with_header: if with_header:

View file

@ -98,9 +98,9 @@ class Formater(CommonFormater):
def table_header(self, lst): def table_header(self, lst):
"""Manage the header of a table""" """Manage the header of a table"""
return lst[0] + " " * (self.max_line_variable - len(lst[0])), lst[1] + " " * ( return lst[0] + " " * (self.max_line_variable - len(lst[0])), lst[
self.max_line_description - len(lst[1]) 1
) ] + " " * (self.max_line_description - len(lst[1]))
def yaml(self, _dump): def yaml(self, _dump):
"""Dump yaml part of documentation""" """Dump yaml part of documentation"""

View file

@ -35,11 +35,11 @@ class Formater(GithubFormater):
) )
def title(self, title: str, level: int) -> str: def title(self, title: str, level: int) -> str:
# self.max_line_variable = 0 # self.max_line_variable = 0
return '<details><summary>' + title + '</summary>\n\n' return "<details><summary>" + title + "</summary>\n\n"
def end_family(self, level): def end_family(self, level):
return '</details>\n\n' return "</details>\n\n"
def columns( def columns(
self, self,
@ -52,6 +52,7 @@ class Formater(GithubFormater):
def end_family_informations(self) -> str: def end_family_informations(self) -> str:
return f"\n>>>\n" return f"\n>>>\n"
def after_family_paths(self) -> str: def after_family_paths(self) -> str:
return "<br>" return "<br>"

View file

@ -45,10 +45,10 @@ class Formater(CommonFormater):
previous = "" previous = ""
for line in lst: for line in lst:
if string: if string:
# if self.is_list(previous.split("\n", 1)[-1]): # if self.is_list(previous.split("\n", 1)[-1]):
# string += "<br/><br/>" # string += "<br/><br/>"
# else: # else:
string += "<br/>" string += "<br/>"
string += line string += line
previous = line previous = line
@ -96,7 +96,11 @@ class Formater(CommonFormater):
"""Display a liste of element""" """Display a liste of element"""
prefix = "<ul>" prefix = "<ul>"
char = "\n" char = "\n"
return "<ul>" + char.join(["<li>" + dump(choice) + "</li>" for choice in choices]) + "</ul>" return (
"<ul>"
+ char.join(["<li>" + dump(choice) + "</li>" for choice in choices])
+ "</ul>"
)
def prop( def prop(
self, self,

View file

@ -127,21 +127,20 @@ def dump(informations):
def to_phrase(msg, type_="variable"): def to_phrase(msg, type_="variable"):
"""Add maj for the first character and ends with dot """Add maj for the first character and ends with dot"""
"""
if not msg: if not msg:
# replace None to empty string # replace None to empty string
return "" return ""
msg = str(msg).strip() msg = str(msg).strip()
# a phrase must ends with a dot # a phrase must ends with a dot
if type_ == 'variable': if type_ == "variable":
if not msg.endswith("."): if not msg.endswith("."):
msg += "." msg += "."
elif type_ == 'family': elif type_ == "family":
if msg.endswith("."): if msg.endswith("."):
msg = msg[:-1] msg = msg[:-1]
else: else:
raise Exception('unknown type') raise Exception("unknown type")
# and start with a maj # and start with a maj
return msg[0].upper() + msg[1:] return msg[0].upper() + msg[1:]
@ -214,10 +213,10 @@ class CommonFormater:
################## ##################
def family_informations(self) -> str: def family_informations(self) -> str:
return '' return ""
def end_family_informations(self) -> str: def end_family_informations(self) -> str:
return '' return ""
def display_paths( def display_paths(
self, self,
@ -228,7 +227,12 @@ class CommonFormater:
path = informations["path"] path = informations["path"]
if "identifiers" in modified_attributes: if "identifiers" in modified_attributes:
name, previous, new = modified_attributes["identifiers"] name, previous, new = modified_attributes["identifiers"]
ret_paths.extend([self.bold(self.delete(calc_path(path, self, identifier))) for identifier in previous]) ret_paths.extend(
[
self.bold(self.delete(calc_path(path, self, identifier)))
for identifier in previous
]
)
else: else:
new = [] new = []
if "identifiers" in informations: if "identifiers" in informations:
@ -254,7 +258,9 @@ class CommonFormater:
"""Manage the header of a table""" """Manage the header of a table"""
return lst return lst
def run(self, informations: dict, level: int, *, dico_is_already_treated=False) -> str: def run(
self, informations: dict, level: int, *, dico_is_already_treated=False
) -> str:
"""Transform to string""" """Transform to string"""
if informations: if informations:
return self._run(informations, level, dico_is_already_treated) return self._run(informations, level, dico_is_already_treated)
@ -266,7 +272,14 @@ class CommonFormater:
return "".join(dico) return "".join(dico)
return "".join([msg for msg in self.dict_to_dict(dico, level, init=True)]) return "".join([msg for msg in self.dict_to_dict(dico, level, init=True)])
def dict_to_dict(self, dico: dict, level: int, *, ori_table_datas: list = None, init: bool = False) -> str: def dict_to_dict(
self,
dico: dict,
level: int,
*,
ori_table_datas: list = None,
init: bool = False,
) -> str:
"""Parse the dict to transform to dict""" """Parse the dict to transform to dict"""
msg = [] msg = []
if ori_table_datas is not None: if ori_table_datas is not None:
@ -288,7 +301,9 @@ class CommonFormater:
msg.append(self.family_informations()) msg.append(self.family_informations())
msg.extend(self.display_paths(informations, {})) msg.extend(self.display_paths(informations, {}))
msg.append(self.after_family_paths()) msg.append(self.after_family_paths())
msg.append(self.property_to_string(informations, {}, {})[1] + ENTER) msg.append(
self.property_to_string(informations, {}, {})[1] + ENTER
)
msg.append(self.end_family_informations()) msg.append(self.end_family_informations())
msg.extend(self.dict_to_dict(value["children"], level)) msg.extend(self.dict_to_dict(value["children"], level))
msg.append(self.end_namespace(ori_level)) msg.append(self.end_namespace(ori_level))
@ -300,7 +315,9 @@ class CommonFormater:
msg.extend(self.dict_to_dict(value["children"], level + 1)) msg.extend(self.dict_to_dict(value["children"], level + 1))
msg.append(self.end_family(level)) msg.append(self.end_family(level))
else: else:
self.dict_to_dict(value["children"], level + 1, ori_table_datas=table_datas) self.dict_to_dict(
value["children"], level + 1, ori_table_datas=table_datas
)
if (init or ori_table_datas is None) and table_datas: if (init or ori_table_datas is None) and table_datas:
msg.append(self.table(table_datas)) msg.append(self.table(table_datas))
return msg return msg
@ -309,7 +326,9 @@ class CommonFormater:
def namespace_to_title(self, informations: dict, level: int) -> str: def namespace_to_title(self, informations: dict, level: int) -> str:
"""manage namespace family""" """manage namespace family"""
return self.title( return self.title(
_('Variables for "{0}"').format(self.get_description("family", informations)), _('Variables for "{0}"').format(
self.get_description("family", informations)
),
level, level,
) )
@ -324,24 +343,31 @@ class CommonFormater:
for help_ in helps: for help_ in helps:
msg.append(self.display_family_help(help_.strip())) msg.append(self.display_family_help(help_.strip()))
msg.append(self.family_informations()) msg.append(self.family_informations())
msg.append(self.join(self.display_paths(informations, {}) msg.append(
) + self.after_family_paths() self.join(self.display_paths(informations, {})) + self.after_family_paths()
) )
calculated_properties = [] calculated_properties = []
msg.append(self.property_to_string(informations, calculated_properties, {})[1] + ENTER) msg.append(
self.property_to_string(informations, calculated_properties, {})[1] + ENTER
)
if calculated_properties: if calculated_properties:
msg.append(self.join(calculated_properties) + self.after_family_properties()) msg.append(
self.join(calculated_properties) + self.after_family_properties()
)
if "identifier" in informations: if "identifier" in informations:
msg.append( msg.append(
self.section(_("Identifiers"), informations["identifier"]) + self.after_family_properties() self.section(_("Identifiers"), informations["identifier"])
+ self.after_family_properties()
) )
msg.append(self.end_family_informations()) msg.append(self.end_family_informations())
return msg return msg
def end_family(self, level: int) -> str: def end_family(self, level: int) -> str:
return '' return ""
def convert_list_to_string(self, attribute: str, informations: dict, modified_attributes: dict) -> str(): def convert_list_to_string(
self, attribute: str, informations: dict, modified_attributes: dict
) -> str():
datas = [] datas = []
if attribute in modified_attributes: if attribute in modified_attributes:
name, previous, new = modified_attributes[attribute] name, previous, new = modified_attributes[attribute]
@ -352,27 +378,37 @@ class CommonFormater:
if attribute in informations: if attribute in informations:
for data in informations[attribute]: for data in informations[attribute]:
if isinstance(data, dict): if isinstance(data, dict):
if attribute.endswith('s'): if attribute.endswith("s"):
attr = attribute[:-1] attr = attribute[:-1]
else: else:
attr = attribute attr = attribute
data = data[attr].replace('{{ identifier }}', self.italic(data["identifier"])) data = data[attr].replace(
"{{ identifier }}", self.italic(data["identifier"])
)
data = self.to_phrase(data) data = self.to_phrase(data)
if data in new: if data in new:
data = self.underline(data) data = self.underline(data)
datas.append(data) datas.append(data)
return self.stripped(self.join(datas)) return self.stripped(self.join(datas))
def get_description(self, type_: str, informations: dict, modified_attributes: dict={}) -> str(): def get_description(
self, type_: str, informations: dict, modified_attributes: dict = {}
) -> str():
def _get_description(description, identifiers, delete=False, new=[]): def _get_description(description, identifiers, delete=False, new=[]):
if "{{ identifier }}" in description: if "{{ identifier }}" in description:
if type_ == "variable": if type_ == "variable":
identifiers_text = display_list([self.italic(i[-1]) for i in identifiers], separator="or") identifiers_text = display_list(
description = description.replace('{{ identifier }}', identifiers_text) [self.italic(i[-1]) for i in identifiers], separator="or"
)
description = description.replace(
"{{ identifier }}", identifiers_text
)
else: else:
d = [] d = []
for i in identifiers: for i in identifiers:
new_description = description.replace('{{ identifier }}', self.italic(i[-1])) new_description = description.replace(
"{{ identifier }}", self.italic(i[-1])
)
if new_description not in d: if new_description not in d:
d.append(self.to_phrase(new_description)) d.append(self.to_phrase(new_description))
description = display_list(d, separator="or") description = display_list(d, separator="or")
@ -383,13 +419,18 @@ class CommonFormater:
if delete: if delete:
description = self.delete(description) description = self.delete(description)
return description return description
if "description" in modified_attributes: if "description" in modified_attributes:
name, previous, new = modified_attributes["description"] name, previous, new = modified_attributes["description"]
modified_description = _get_description(previous, modified_attributes.get("identifiers", []), delete=True) modified_description = _get_description(
previous, modified_attributes.get("identifiers", []), delete=True
)
else: else:
modified_description = None modified_description = None
new = [] new = []
description = _get_description(informations["description"], informations.get("identifiers"), new=new) description = _get_description(
informations["description"], informations.get("identifiers"), new=new
)
if modified_description: if modified_description:
if description: if description:
description = self.join([modified_description, description]) description = self.join([modified_description, description])
@ -399,78 +440,110 @@ class CommonFormater:
return None return None
return self.stripped(description) return self.stripped(description)
# VARIABLE # VARIABLE
def variable_to_string(self, informations: dict, table_datas: list, modified_attributes: dict={}) -> None: def variable_to_string(
self, informations: dict, table_datas: list, modified_attributes: dict = {}
) -> None:
"""Manage variable""" """Manage variable"""
calculated_properties = [] calculated_properties = []
multi, first_column = self.variable_first_column(informations, calculated_properties, modified_attributes) multi, first_column = self.variable_first_column(
informations, calculated_properties, modified_attributes
)
table_datas.append( table_datas.append(
[ [
self.join(first_column), self.join(first_column),
self.join( self.join(
self.variable_second_column(informations, calculated_properties, modified_attributes, multi=multi) self.variable_second_column(
informations,
calculated_properties,
modified_attributes,
multi=multi,
)
), ),
] ]
) )
def variable_first_column( def variable_first_column(
self, informations: dict, calculated_properties: list, modified_attributes: Optional[dict] self,
informations: dict,
calculated_properties: list,
modified_attributes: Optional[dict],
) -> list: ) -> list:
"""Collect string for the first column""" """Collect string for the first column"""
multi, properties = self.property_to_string(informations, calculated_properties, modified_attributes) multi, properties = self.property_to_string(
informations, calculated_properties, modified_attributes
)
first_col = [ first_col = [
self.join( self.join(self.display_paths(informations, modified_attributes)),
self.display_paths(informations, modified_attributes) properties,
), properties
] ]
self.columns(first_col) self.columns(first_col)
return multi, first_col return multi, first_col
def variable_second_column( def variable_second_column(
self, informations: dict, calculated_properties: list, modified_attributes: dict, multi: bool self,
informations: dict,
calculated_properties: list,
modified_attributes: dict,
multi: bool,
) -> list: ) -> list:
"""Collect string for the second column""" """Collect string for the second column"""
second_col = [] second_col = []
# #
if "description" in informations: if "description" in informations:
description = self.get_description("variable", informations, modified_attributes) description = self.get_description(
"variable", informations, modified_attributes
)
second_col.append(description) second_col.append(description)
# #
help_ = self.convert_list_to_string("help", informations, modified_attributes) help_ = self.convert_list_to_string("help", informations, modified_attributes)
if help_: if help_:
second_col.append(help_) second_col.append(help_)
# #
validators = self.convert_section_to_string("validators", informations, modified_attributes, multi=True) validators = self.convert_section_to_string(
"validators", informations, modified_attributes, multi=True
)
if validators: if validators:
second_col.append(validators) second_col.append(validators)
default_is_already_set, choices = self.convert_choices_to_string(informations, modified_attributes) default_is_already_set, choices = self.convert_choices_to_string(
informations, modified_attributes
)
if choices: if choices:
second_col.append(choices) second_col.append(choices)
if not default_is_already_set and "default" in informations: if not default_is_already_set and "default" in informations:
self.convert_section_to_string("default", informations, modified_attributes, multi=multi) self.convert_section_to_string(
second_col.append(self.convert_section_to_string("default", informations, modified_attributes, multi=multi)) "default", informations, modified_attributes, multi=multi
examples = self.convert_section_to_string("examples", informations, modified_attributes, multi=True) )
second_col.append(
self.convert_section_to_string(
"default", informations, modified_attributes, multi=multi
)
)
examples = self.convert_section_to_string(
"examples", informations, modified_attributes, multi=True
)
if examples: if examples:
second_col.append(examples) second_col.append(examples)
second_col.extend(calculated_properties) second_col.extend(calculated_properties)
self.columns(second_col) self.columns(second_col)
return second_col return second_col
def convert_section_to_string(self, attribute: str, informations: dict, modified_attributes: dict, multi: bool) -> str(): def convert_section_to_string(
self, attribute: str, informations: dict, modified_attributes: dict, multi: bool
) -> str():
values = [] values = []
submessage = "" submessage = ""
if modified_attributes and attribute in modified_attributes: if modified_attributes and attribute in modified_attributes:
name, previous, new = modified_attributes[attribute] name, previous, new = modified_attributes[attribute]
# if "identifiers" in modified_attributes: # if "identifiers" in modified_attributes:
# iname, iprevious, inew = modified_attributes["identifiers"] # iname, iprevious, inew = modified_attributes["identifiers"]
# identifiers = iprevious.copy() # identifiers = iprevious.copy()
# for identifier in informations.get("identifiers", []): # for identifier in informations.get("identifiers", []):
# if identifier not in inew: # if identifier not in inew:
# identifiers.append(identifier) # identifiers.append(identifier)
# #
# else: # else:
# identifiers = informations.get("identifiers", []) # identifiers = informations.get("identifiers", [])
if isinstance(previous, list): if isinstance(previous, list):
for p in previous: for p in previous:
submessage, m = self.message_to_string(p, submessage) submessage, m = self.message_to_string(p, submessage)
@ -507,7 +580,9 @@ class CommonFormater:
if values != []: if values != []:
return self.section(name, values, submessage=submessage) return self.section(name, values, submessage=submessage)
def convert_choices_to_string(self, informations: dict, modified_attributes: dict) -> str(): def convert_choices_to_string(
self, informations: dict, modified_attributes: dict
) -> str():
default_is_already_set = False default_is_already_set = False
if "choices" in informations: if "choices" in informations:
choices = informations["choices"] choices = informations["choices"]
@ -524,7 +599,11 @@ class CommonFormater:
if not isinstance(old_default, list): if not isinstance(old_default, list):
old_default = [old_default] old_default = [old_default]
for value in old_default.copy(): for value in old_default.copy():
if isinstance(value, str) and value.endswith(".") and value not in choices_values: if (
isinstance(value, str)
and value.endswith(".")
and value not in choices_values
):
old_default.remove(value) old_default.remove(value)
old_default.append(value[:-1]) old_default.append(value[:-1])
else: else:
@ -540,7 +619,11 @@ class CommonFormater:
if default_value_not_in_choices: if default_value_not_in_choices:
default_is_changed = False default_is_changed = False
for val in default_value_not_in_choices.copy(): for val in default_value_not_in_choices.copy():
if isinstance(val, str) and val.endswith('.') and val[:-1] in choices_values: if (
isinstance(val, str)
and val.endswith(".")
and val[:-1] in choices_values
):
default.remove(val) default.remove(val)
default.append(val[:-1]) default.append(val[:-1])
default_is_changed = True default_is_changed = True
@ -559,22 +642,34 @@ class CommonFormater:
name, previous, new = modified_attributes["choices"] name, previous, new = modified_attributes["choices"]
for choice in reversed(previous): for choice in reversed(previous):
if choice in old_default: if choice in old_default:
choices_values.insert(0, self.delete(dump(choice) + "" + _("(default)"))) choices_values.insert(
0, self.delete(dump(choice) + "" + _("(default)"))
)
else: else:
choices_values.insert(0, self.delete(dump(choice))) choices_values.insert(0, self.delete(dump(choice)))
else: else:
new = [] new = []
for idx, val in enumerate(choices_values): for idx, val in enumerate(choices_values):
if val in old_default: if val in old_default:
choices_values[idx] = dump(val) + " " + self.delete("" + _("(default)")) choices_values[idx] = (
dump(val) + " " + self.delete("" + _("(default)"))
)
elif val in default: elif val in default:
if val in new_default: if val in new_default:
if val in new: if val in new:
choices_values[idx] = self.underline(dump(val) + " " + self.bold("" + _("(default)"))) choices_values[idx] = self.underline(
dump(val) + " " + self.bold("" + _("(default)"))
)
else: else:
choices_values[idx] = dump(val) + " " + self.underline(self.bold("" + _("(default)"))) choices_values[idx] = (
dump(val)
+ " "
+ self.underline(self.bold("" + _("(default)")))
)
else: else:
choices_values[idx] = dump(val) + " " + self.bold("" + _("(default)")) choices_values[idx] = (
dump(val) + " " + self.bold("" + _("(default)"))
)
elif val in new: elif val in new:
choices_values[idx] = self.underline(dump(val)) choices_values[idx] = self.underline(dump(val))
# if old value and new value is a list, display a list # if old value and new value is a list, display a list
@ -591,14 +686,19 @@ class CommonFormater:
return self.to_phrase(help_) + ENTER return self.to_phrase(help_) + ENTER
def property_to_string( def property_to_string(
self, informations: dict, calculated_properties: list, modified_attributes: dict, self,
informations: dict,
calculated_properties: list,
modified_attributes: dict,
) -> str: ) -> str:
"""Transform properties to string""" """Transform properties to string"""
properties = [] properties = []
local_calculated_properties = {} local_calculated_properties = {}
multi = False multi = False
if "properties" in modified_attributes: if "properties" in modified_attributes:
previous, new = self.get_modified_properties(*modified_attributes["properties"][1:]) previous, new = self.get_modified_properties(
*modified_attributes["properties"][1:]
)
for p, annotation in previous.items(): for p, annotation in previous.items():
if p not in new: if p not in new:
properties.append(self.prop(self.delete(p), italic=False)) properties.append(self.prop(self.delete(p), italic=False))
@ -617,30 +717,43 @@ class CommonFormater:
if "annotation" in prop: if "annotation" in prop:
italic = True italic = True
prop_annotation = prop["annotation"] prop_annotation = prop["annotation"]
if prop_name in new and (prop_name not in previous or new[prop_name] != previous[prop_name]): if prop_name in new and (
prop_name not in previous
or new[prop_name] != previous[prop_name]
):
prop_annotation = self.underline(prop_annotation) prop_annotation = self.underline(prop_annotation)
local_calculated_properties.setdefault(prop["name"], []).append(prop_annotation) local_calculated_properties.setdefault(prop["name"], []).append(
prop_annotation
)
else: else:
italic = False italic = False
if prop_name not in previous and prop_name in new: if prop_name not in previous and prop_name in new:
prop_name = self.underline(prop_name) prop_name = self.underline(prop_name)
properties.append(self.prop(prop_name, italic=italic)) properties.append(self.prop(prop_name, italic=italic))
if local_calculated_properties: if local_calculated_properties:
for calculated_property_name, calculated_property in local_calculated_properties.items(): for (
calculated_property_name,
calculated_property,
) in local_calculated_properties.items():
if len(calculated_property) > 1: if len(calculated_property) > 1:
calculated_property = self.join(calculated_property) calculated_property = self.join(calculated_property)
else: else:
calculated_property = calculated_property[0] calculated_property = calculated_property[0]
calculated_properties.append( calculated_properties.append(
self.section(calculated_property_name.capitalize(), calculated_property) self.section(
calculated_property_name.capitalize(), calculated_property
)
) )
if not properties: if not properties:
return multi, "" return multi, ""
return multi, " ".join(properties) return multi, " ".join(properties)
def get_modified_properties(self, previous: List[dict], new: List[dict]) -> Tuple[dict, dict]: def get_modified_properties(
self, previous: List[dict], new: List[dict]
) -> Tuple[dict, dict]:
def modified_properties_parser(dico): def modified_properties_parser(dico):
return {d["name"]: d.get("annotation") for d in dico} return {d["name"]: d.get("annotation") for d in dico}
return modified_properties_parser(previous), modified_properties_parser(new) return modified_properties_parser(previous), modified_properties_parser(new)
def columns( def columns(
@ -650,7 +763,7 @@ class CommonFormater:
"""Manage column""" """Manage column"""
return return
def table(self, datas: list, with_header: bool=True) -> str: def table(self, datas: list, with_header: bool = True) -> str:
"""Transform list to a table in string format""" """Transform list to a table in string format"""
if with_header: if with_header:
headers = self.table_header([_("Variable"), _("Description")]) headers = self.table_header([_("Variable"), _("Description")])
@ -702,12 +815,13 @@ class CommonFormater:
return _("{0}: {1}").format(self.bold(name), submessage) return _("{0}: {1}").format(self.bold(name), submessage)
def calc_path(path, formater=None, identifiers: List[str]=None) -> str: def calc_path(path, formater=None, identifiers: List[str] = None) -> str:
def _path_with_identifier(path, identifier): def _path_with_identifier(path, identifier):
identifier = normalize_family(str(identifier)) identifier = normalize_family(str(identifier))
if formater: if formater:
identifier = formater.italic(identifier) identifier = formater.italic(identifier)
return path.replace('{{ identifier }}', identifier, 1) return path.replace("{{ identifier }}", identifier, 1)
if isinstance(path, dict): if isinstance(path, dict):
path_ = path["path"] path_ = path["path"]
for identifier in path["identifiers"]: for identifier in path["identifiers"]: