2024-11-15 08:13:45 +01:00
|
|
|
"""
|
|
|
|
|
Silique (https://www.silique.fr)
|
2026-01-04 19:16:18 +01:00
|
|
|
Copyright (C) 2024-2026
|
2026-01-14 13:56:51 +01:00
|
|
|
|
2024-11-15 08:13:45 +01:00
|
|
|
This program is free software: you can redistribute it and/or modify it
|
|
|
|
|
under the terms of the GNU Lesser General Public License as published by the
|
|
|
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
|
|
|
option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
|
|
|
details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
"""
|
|
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
from typing import Tuple, List, Optional
|
2024-11-15 08:13:45 +01:00
|
|
|
|
|
|
|
|
from io import BytesIO
|
|
|
|
|
from ruamel.yaml import YAML
|
|
|
|
|
import tabulate as tabulate_module
|
|
|
|
|
from tabulate import tabulate
|
|
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
from rougail.tiramisu import normalize_family
|
|
|
|
|
from tiramisu import undefined
|
2025-11-27 22:17:17 +01:00
|
|
|
from tiramisu.error import PropertiesOptionError, display_list
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-11-27 22:17:17 +01:00
|
|
|
try:
|
|
|
|
|
from tiramisu_cmdline_parser.api import gen_argument_name
|
|
|
|
|
except:
|
|
|
|
|
gen_argument_name = None
|
2025-10-14 12:58:39 +02:00
|
|
|
|
2024-11-15 08:13:45 +01:00
|
|
|
from .i18n import _
|
2025-11-29 22:21:06 +01:00
|
|
|
from .config import Tabulars, ROUGAIL_VARIABLE_TYPE
|
2024-11-15 08:13:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
ENTER = "\n\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_yaml = YAML()
|
|
|
|
|
_yaml.indent(mapping=2, sequence=4, offset=2)
|
|
|
|
|
|
|
|
|
|
|
2025-03-02 13:38:14 +01:00
|
|
|
def dump(informations):
|
2024-11-15 08:13:45 +01:00
|
|
|
"""Dump variable, means transform bool, ... to yaml string"""
|
|
|
|
|
with BytesIO() as ymlfh:
|
2025-03-02 13:38:14 +01:00
|
|
|
_yaml.dump(informations, ymlfh)
|
2024-11-15 08:13:45 +01:00
|
|
|
ret = ymlfh.getvalue().decode("utf-8").strip()
|
|
|
|
|
if ret.endswith("..."):
|
|
|
|
|
ret = ret[:-3].strip()
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
def to_phrase(msg, type_="variable"):
|
2025-10-15 09:44:22 +02:00
|
|
|
"""Add maj for the first character and ends with dot"""
|
2026-06-28 14:51:37 +02:00
|
|
|
msg = str(msg).strip()
|
2024-11-15 08:13:45 +01:00
|
|
|
if not msg:
|
|
|
|
|
# replace None to empty string
|
|
|
|
|
return ""
|
|
|
|
|
# a phrase must ends with a dot
|
2025-10-15 09:44:22 +02:00
|
|
|
if type_ == "variable":
|
2026-03-29 12:42:01 +02:00
|
|
|
msg = add_dot(msg)
|
2025-10-29 10:46:57 +01:00
|
|
|
elif type_ in ["family", "description"]:
|
2025-10-14 12:58:39 +02:00
|
|
|
if msg.endswith("."):
|
|
|
|
|
msg = msg[:-1]
|
|
|
|
|
else:
|
2025-10-15 09:44:22 +02:00
|
|
|
raise Exception("unknown type")
|
2024-11-15 08:13:45 +01:00
|
|
|
# and start with a maj
|
|
|
|
|
return msg[0].upper() + msg[1:]
|
|
|
|
|
|
|
|
|
|
|
2026-03-29 12:42:01 +02:00
|
|
|
def add_dot(msg):
|
|
|
|
|
msg = str(msg).strip()
|
|
|
|
|
last_char = msg[-1]
|
|
|
|
|
if last_char not in [".", "?", "!", ",", ":", ";"]:
|
|
|
|
|
msg += "."
|
|
|
|
|
return msg
|
|
|
|
|
|
|
|
|
|
|
2025-11-29 22:21:06 +01:00
|
|
|
class CommonTabular:
|
|
|
|
|
"""Class with common function for tabular"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, formatter: "CommonFormatter") -> None:
|
|
|
|
|
self.formatter = formatter
|
|
|
|
|
self.clear()
|
|
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
|
self.columns = []
|
|
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
|
columns = list(self.get_columns())
|
|
|
|
|
self.clear()
|
|
|
|
|
return columns
|
|
|
|
|
|
2026-03-29 11:01:15 +02:00
|
|
|
def add(
|
|
|
|
|
self,
|
|
|
|
|
informations: dict,
|
|
|
|
|
modified_attributes: dict,
|
|
|
|
|
force_identifiers: Optional[str],
|
|
|
|
|
) -> tuple:
|
2025-11-29 22:21:06 +01:00
|
|
|
self.informations = informations
|
|
|
|
|
self.modified_attributes = modified_attributes
|
|
|
|
|
self.force_identifiers = force_identifiers
|
|
|
|
|
self.calculated_properties = []
|
|
|
|
|
self.set_description()
|
|
|
|
|
self.set_type()
|
|
|
|
|
self.set_choices()
|
|
|
|
|
self.set_properties()
|
|
|
|
|
self.set_default()
|
|
|
|
|
self.set_examples()
|
|
|
|
|
self.set_paths()
|
|
|
|
|
self.set_commandline()
|
|
|
|
|
self.set_environment()
|
|
|
|
|
self.set_validators()
|
|
|
|
|
self.set_tags()
|
|
|
|
|
self.columns.append(self._add())
|
|
|
|
|
|
|
|
|
|
def set_description(self):
|
|
|
|
|
if "description" in self.informations:
|
|
|
|
|
self.description = self.formatter.get_description(
|
2026-03-29 11:01:15 +02:00
|
|
|
self.informations,
|
|
|
|
|
self.modified_attributes,
|
2026-04-30 06:58:12 +02:00
|
|
|
force_identifiers=self.force_identifiers,
|
2025-11-29 22:21:06 +01:00
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
self.description = None
|
2026-03-29 11:01:15 +02:00
|
|
|
self.help_ = self.formatter.convert_list_to_string(
|
|
|
|
|
"help", self.informations, self.modified_attributes
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
|
|
|
|
|
def set_choices(self):
|
2026-03-29 11:01:15 +02:00
|
|
|
self.default_is_already_set, self.choices = (
|
|
|
|
|
self.formatter.convert_choices_to_string(
|
|
|
|
|
self.informations, self.modified_attributes
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def set_type(self):
|
|
|
|
|
self.multi = self.informations.get("multiple", True)
|
|
|
|
|
self.type = self.informations["variable_type"]
|
|
|
|
|
|
|
|
|
|
def set_default(self):
|
|
|
|
|
if "default" in self.informations:
|
|
|
|
|
self.default = self.formatter.convert_section_to_string(
|
2026-03-29 11:01:15 +02:00
|
|
|
"default", self.informations, self.modified_attributes, multi=self.multi
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
else:
|
|
|
|
|
self.default = None
|
|
|
|
|
|
|
|
|
|
def set_examples(self):
|
|
|
|
|
self.examples = self.formatter.convert_section_to_string(
|
|
|
|
|
"examples", self.informations, self.modified_attributes, multi=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def set_paths(self):
|
2026-03-29 11:01:15 +02:00
|
|
|
self.paths = self.formatter.join(
|
|
|
|
|
self.formatter.display_paths(
|
|
|
|
|
self.informations,
|
|
|
|
|
self.modified_attributes,
|
|
|
|
|
self.force_identifiers,
|
|
|
|
|
is_variable=True,
|
|
|
|
|
)
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
|
|
|
|
|
def set_commandline(self):
|
2026-03-29 11:01:15 +02:00
|
|
|
if self.formatter.with_commandline and not self.informations.get(
|
|
|
|
|
"not_for_commandline", False
|
|
|
|
|
):
|
|
|
|
|
commandlines = self.formatter.display_paths(
|
|
|
|
|
self.informations,
|
|
|
|
|
self.modified_attributes,
|
|
|
|
|
self.force_identifiers,
|
|
|
|
|
is_variable=True,
|
|
|
|
|
is_bold=False,
|
|
|
|
|
variable_prefix="--",
|
|
|
|
|
with_anchor=False,
|
|
|
|
|
)
|
|
|
|
|
if self.type == "boolean":
|
|
|
|
|
for path in self.formatter.display_paths(
|
|
|
|
|
self.informations,
|
|
|
|
|
self.modified_attributes,
|
|
|
|
|
self.force_identifiers,
|
|
|
|
|
is_variable=True,
|
|
|
|
|
is_bold=False,
|
|
|
|
|
is_upper=False,
|
|
|
|
|
with_anchor=False,
|
|
|
|
|
variable_prefix="--",
|
|
|
|
|
):
|
|
|
|
|
commandlines.append(
|
|
|
|
|
"--" + gen_argument_name(path[2:], False, True, False)
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
if "alternative_name" in self.informations:
|
|
|
|
|
alternative_name = self.informations["alternative_name"]
|
|
|
|
|
commandlines[0] = f"-{alternative_name}, {commandlines[0]}"
|
2026-03-29 11:01:15 +02:00
|
|
|
if self.type == "boolean":
|
|
|
|
|
commandlines[1] = (
|
|
|
|
|
"-"
|
|
|
|
|
+ gen_argument_name(alternative_name, True, True, False)
|
|
|
|
|
+ f", {commandlines[1]}"
|
|
|
|
|
)
|
2026-06-21 14:42:34 +02:00
|
|
|
if "full_path" in self.informations:
|
|
|
|
|
full_path = self.informations["full_path"]
|
|
|
|
|
else:
|
|
|
|
|
full_path = self.informations["path"]
|
2026-03-29 11:01:15 +02:00
|
|
|
self.commandlines = self.formatter.section(
|
2026-06-21 14:42:34 +02:00
|
|
|
full_path, _("Command line"), commandlines, force_enter=True
|
2026-03-29 11:01:15 +02:00
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
else:
|
|
|
|
|
self.commandlines = None
|
|
|
|
|
|
|
|
|
|
def set_environment(self):
|
|
|
|
|
if self.formatter.with_environment:
|
2026-03-29 11:01:15 +02:00
|
|
|
environments = self.formatter.display_paths(
|
|
|
|
|
self.informations,
|
|
|
|
|
self.modified_attributes,
|
|
|
|
|
self.force_identifiers,
|
|
|
|
|
is_variable=True,
|
|
|
|
|
is_bold=False,
|
|
|
|
|
is_upper=True,
|
|
|
|
|
variable_prefix=self.formatter.prefix,
|
|
|
|
|
with_anchor=False,
|
|
|
|
|
)
|
2026-06-21 14:42:34 +02:00
|
|
|
if "full_path" in self.informations:
|
|
|
|
|
full_path = self.informations["full_path"]
|
|
|
|
|
else:
|
|
|
|
|
full_path = self.informations["path"]
|
2026-03-29 11:01:15 +02:00
|
|
|
self.environments = self.formatter.section(
|
2026-06-21 14:42:34 +02:00
|
|
|
full_path, _("Environment variable"), environments
|
2026-03-29 11:01:15 +02:00
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
else:
|
|
|
|
|
self.environments = None
|
|
|
|
|
|
|
|
|
|
def set_properties(self):
|
|
|
|
|
self.properties = self.formatter.property_to_string(
|
2026-03-29 11:01:15 +02:00
|
|
|
self.informations,
|
|
|
|
|
self.calculated_properties,
|
|
|
|
|
self.modified_attributes,
|
2025-11-29 22:21:06 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def set_validators(self):
|
|
|
|
|
self.validators = self.formatter.convert_section_to_string(
|
|
|
|
|
"validators", self.informations, self.modified_attributes, multi=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def set_tags(self):
|
|
|
|
|
self.tags = self.formatter.convert_section_to_string(
|
|
|
|
|
"tags", self.informations, self.modified_attributes, multi=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def get_column(self, *args):
|
|
|
|
|
contents = [arg for arg in args if arg]
|
|
|
|
|
self.formatter.columns(contents)
|
|
|
|
|
return self.formatter.join(contents)
|
|
|
|
|
|
|
|
|
|
|
2025-10-27 21:59:39 +01:00
|
|
|
class CommonFormatter:
|
|
|
|
|
"""Class with common function for formatter"""
|
2024-11-15 08:13:45 +01:00
|
|
|
|
2025-11-29 22:21:06 +01:00
|
|
|
enter_tabular = "\n"
|
2026-04-30 06:58:12 +02:00
|
|
|
format_in_title = True
|
2024-11-15 08:13:45 +01:00
|
|
|
# tabulate module name
|
|
|
|
|
name = None
|
|
|
|
|
|
2026-04-30 06:58:12 +02:00
|
|
|
def __init__(self, rougailconfig, support_namespace, document_a_type, **kwargs):
|
2024-11-15 08:13:45 +01:00
|
|
|
tabulate_module.PRESERVE_WHITESPACE = True
|
|
|
|
|
self.header_setted = False
|
2025-10-30 21:14:34 +01:00
|
|
|
self.rougailconfig = rougailconfig
|
2025-11-27 22:17:17 +01:00
|
|
|
self.support_namespace = support_namespace
|
2026-04-30 06:58:12 +02:00
|
|
|
self.document_a_type = document_a_type
|
2025-10-30 21:14:34 +01:00
|
|
|
|
2026-03-29 11:01:15 +02:00
|
|
|
def run(self, informations: dict, *, dico_is_already_treated=False) -> str:
|
2025-10-30 21:14:34 +01:00
|
|
|
"""Transform to string"""
|
|
|
|
|
if informations:
|
|
|
|
|
level = self.rougailconfig["doc.title_level"]
|
|
|
|
|
self.options()
|
|
|
|
|
return self._run(informations, level, dico_is_already_treated)
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def options(self):
|
2025-11-29 22:21:06 +01:00
|
|
|
self.with_commandline = self.rougailconfig["doc.tabulars.with_commandline"]
|
|
|
|
|
self.with_environment = self.rougailconfig["doc.tabulars.with_environment"]
|
2025-11-27 22:17:17 +01:00
|
|
|
if self.with_environment and not gen_argument_name:
|
2026-03-29 11:01:15 +02:00
|
|
|
raise Exception("please install tiramisu_cmdline_parser")
|
2025-11-27 22:17:17 +01:00
|
|
|
if not self.rougailconfig["main_namespace"] and self.with_environment:
|
2026-06-11 08:07:02 +02:00
|
|
|
environment_prefix = self.rougailconfig["doc.tabulars.environment_prefix"]
|
|
|
|
|
if environment_prefix:
|
2026-06-21 17:05:44 +02:00
|
|
|
self.prefix = environment_prefix + "_"
|
2025-11-29 22:21:06 +01:00
|
|
|
self.with_family = not self.rougailconfig["doc.tabulars.without_family"]
|
2026-06-21 17:05:44 +02:00
|
|
|
self.other_root_filenames = dict(
|
|
|
|
|
self.rougailconfig["doc.other_root_filenames"].items()
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
tabular_template = self.rougailconfig["doc.tabular_template"]
|
|
|
|
|
self.tabular_datas = Tabulars().get()[tabular_template](self)
|
2025-10-30 21:14:34 +01:00
|
|
|
|
|
|
|
|
def compute(self, data):
|
2026-04-30 06:58:12 +02:00
|
|
|
return ENTER.join([d for d in data if d])
|
2024-11-15 08:13:45 +01:00
|
|
|
|
2025-10-27 21:59:39 +01:00
|
|
|
# Class you needs implement to your Formatter
|
2024-11-15 08:13:45 +01:00
|
|
|
def title(
|
|
|
|
|
self,
|
|
|
|
|
title: str,
|
|
|
|
|
level: int,
|
2026-06-21 17:05:44 +02:00
|
|
|
collapse: bool = True,
|
2024-11-15 08:13:45 +01:00
|
|
|
) -> str:
|
|
|
|
|
"""Display family name as a title"""
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
def join(
|
|
|
|
|
self,
|
|
|
|
|
lst: List[str],
|
|
|
|
|
) -> str:
|
2025-11-29 22:21:06 +01:00
|
|
|
"""Display line in tabular from a list"""
|
2024-11-15 08:13:45 +01:00
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
def bold(
|
|
|
|
|
self,
|
|
|
|
|
msg: str,
|
|
|
|
|
) -> str:
|
|
|
|
|
"""Set a text to bold"""
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
2025-10-29 10:46:57 +01:00
|
|
|
def underline(
|
|
|
|
|
self,
|
|
|
|
|
msg: str,
|
|
|
|
|
) -> str:
|
|
|
|
|
"""Set a text to underline"""
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
2026-03-29 11:01:15 +02:00
|
|
|
def anchor(
|
|
|
|
|
self,
|
|
|
|
|
path: str,
|
|
|
|
|
true_path: str,
|
|
|
|
|
) -> str:
|
2025-10-29 10:46:57 +01:00
|
|
|
"""Set a text to a link anchor"""
|
|
|
|
|
return path
|
|
|
|
|
|
2026-03-29 11:01:15 +02:00
|
|
|
def link_variable(
|
|
|
|
|
self,
|
|
|
|
|
path: str,
|
|
|
|
|
true_path: str,
|
|
|
|
|
description: str,
|
|
|
|
|
filename: Optional[str],
|
|
|
|
|
) -> str:
|
2025-10-29 10:46:57 +01:00
|
|
|
"""Set a text link to variable anchor"""
|
2026-06-21 14:42:34 +02:00
|
|
|
if not description:
|
|
|
|
|
return f'"{path}"'
|
2026-04-01 17:01:24 +02:00
|
|
|
return f'"{description}" ({path})'
|
2025-10-29 10:46:57 +01:00
|
|
|
|
2024-11-15 08:13:45 +01:00
|
|
|
def stripped(
|
|
|
|
|
self,
|
|
|
|
|
text: str,
|
|
|
|
|
) -> str:
|
|
|
|
|
"""Return stripped text (as help)"""
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
def list(
|
|
|
|
|
self,
|
|
|
|
|
choices: list,
|
2025-11-12 19:33:56 +01:00
|
|
|
*,
|
2026-03-29 11:01:15 +02:00
|
|
|
inside_tabular: bool = True,
|
|
|
|
|
type_: str = "variable",
|
2025-11-29 22:21:06 +01:00
|
|
|
with_enter: bool = False,
|
2024-11-15 08:13:45 +01:00
|
|
|
) -> str:
|
|
|
|
|
"""Display a liste of element"""
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
def prop(
|
|
|
|
|
self,
|
|
|
|
|
prop: str,
|
|
|
|
|
italic: bool,
|
2025-11-05 21:43:10 +01:00
|
|
|
delete: bool,
|
|
|
|
|
underline: bool,
|
2024-11-15 08:13:45 +01:00
|
|
|
) -> str:
|
|
|
|
|
"""Display property"""
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
def link(
|
|
|
|
|
self,
|
|
|
|
|
comment: str,
|
|
|
|
|
link: str,
|
2025-11-05 21:43:10 +01:00
|
|
|
underline: bool,
|
2024-11-15 08:13:45 +01:00
|
|
|
) -> str:
|
|
|
|
|
"""Add a link"""
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
2026-06-21 17:05:44 +02:00
|
|
|
def yaml(self, _dump: str, yaml_version: str = "1.1"):
|
2026-04-30 06:58:12 +02:00
|
|
|
output = f"---\n{_dump}"
|
|
|
|
|
if yaml_version == "1.2":
|
2026-06-21 17:05:44 +02:00
|
|
|
output = f"%YAML 1.2\n{output}\n..."
|
2026-04-30 06:58:12 +02:00
|
|
|
return self._yaml(output)
|
|
|
|
|
|
2024-11-15 08:13:45 +01:00
|
|
|
##################
|
|
|
|
|
|
2025-10-02 08:19:18 +02:00
|
|
|
def end_family_informations(self) -> str:
|
2026-04-30 06:58:12 +02:00
|
|
|
return None
|
2025-10-02 08:19:18 +02:00
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
def display_paths(
|
2025-10-02 08:19:18 +02:00
|
|
|
self,
|
2025-10-14 12:58:39 +02:00
|
|
|
informations: dict,
|
|
|
|
|
modified_attributes: dict,
|
2025-10-15 09:53:54 +02:00
|
|
|
force_identifiers: Optional[str],
|
2025-10-29 10:46:57 +01:00
|
|
|
*,
|
2025-11-27 22:17:17 +01:00
|
|
|
is_variable=False,
|
2026-03-29 11:01:15 +02:00
|
|
|
variable_prefix: str = "",
|
|
|
|
|
is_bold: bool = True,
|
|
|
|
|
is_upper: bool = False,
|
|
|
|
|
with_anchor: bool = True,
|
2025-10-02 08:19:18 +02:00
|
|
|
) -> str:
|
2025-11-29 22:21:06 +01:00
|
|
|
if with_anchor:
|
|
|
|
|
anchor = self.anchor
|
|
|
|
|
else:
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-11-29 22:21:06 +01:00
|
|
|
def anchor(path, true_path):
|
|
|
|
|
return path
|
2026-06-21 17:05:44 +02:00
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
ret_paths = []
|
|
|
|
|
path = informations["path"]
|
2026-01-14 13:56:51 +01:00
|
|
|
if not path:
|
|
|
|
|
return None
|
2025-11-27 22:17:17 +01:00
|
|
|
if is_bold:
|
|
|
|
|
bold = self.bold
|
|
|
|
|
else:
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-11-27 22:17:17 +01:00
|
|
|
def bold(value):
|
|
|
|
|
return value
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-11-27 22:17:17 +01:00
|
|
|
if is_upper:
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-11-27 22:17:17 +01:00
|
|
|
def upper(value):
|
|
|
|
|
return value.upper()
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-11-27 22:17:17 +01:00
|
|
|
else:
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-11-27 22:17:17 +01:00
|
|
|
def upper(value):
|
|
|
|
|
return value
|
2026-03-29 11:01:15 +02:00
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
if "identifiers" in modified_attributes:
|
|
|
|
|
name, previous, new = modified_attributes["identifiers"]
|
2025-10-15 09:44:22 +02:00
|
|
|
ret_paths.extend(
|
|
|
|
|
[
|
2026-03-29 11:01:15 +02:00
|
|
|
bold(
|
|
|
|
|
self.delete(
|
|
|
|
|
upper(
|
|
|
|
|
variable_prefix
|
|
|
|
|
+ calc_path(
|
|
|
|
|
path, formatter=self, identifiers=identifier
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
2025-10-15 09:44:22 +02:00
|
|
|
for identifier in previous
|
|
|
|
|
]
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
|
|
|
|
new = []
|
2026-04-30 06:58:12 +02:00
|
|
|
if "full_path" in informations:
|
|
|
|
|
full_path = informations["full_path"]
|
|
|
|
|
else:
|
2026-06-21 14:42:34 +02:00
|
|
|
full_path = informations["path"]
|
2025-10-14 12:58:39 +02:00
|
|
|
if "identifiers" in informations:
|
2025-10-29 10:46:57 +01:00
|
|
|
for idx, identifier in enumerate(informations["identifiers"]):
|
2025-10-15 09:53:54 +02:00
|
|
|
if force_identifiers and identifier != force_identifiers:
|
|
|
|
|
continue
|
2026-03-29 11:01:15 +02:00
|
|
|
path_ = calc_path(path, formatter=self, identifiers=identifier)
|
2025-11-27 22:17:17 +01:00
|
|
|
if variable_prefix:
|
|
|
|
|
path_ = variable_prefix + upper(path_)
|
2025-10-29 10:46:57 +01:00
|
|
|
if not idx:
|
2026-04-30 06:58:12 +02:00
|
|
|
path_ = anchor(path_, full_path)
|
2025-10-14 12:58:39 +02:00
|
|
|
if identifier in new:
|
|
|
|
|
path_ = self.underline(path_)
|
2025-11-27 22:17:17 +01:00
|
|
|
ret_paths.append(bold(path_))
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
2026-04-30 06:58:12 +02:00
|
|
|
ret_paths.append(bold(anchor(variable_prefix + upper(path), full_path)))
|
2025-10-14 12:58:39 +02:00
|
|
|
return ret_paths
|
2025-10-02 08:19:18 +02:00
|
|
|
|
2025-11-29 22:21:06 +01:00
|
|
|
def tabular_header(
|
2024-11-15 08:13:45 +01:00
|
|
|
self,
|
|
|
|
|
lst: list,
|
|
|
|
|
) -> tuple:
|
2025-11-29 22:21:06 +01:00
|
|
|
"""Manage the header of a tabular"""
|
2024-11-15 08:13:45 +01:00
|
|
|
return lst
|
|
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
def _run(self, dico: dict, level: int, dico_is_already_treated: bool) -> str:
|
|
|
|
|
"""Parse the dict to transform to dict"""
|
|
|
|
|
if dico_is_already_treated:
|
2026-04-30 06:58:12 +02:00
|
|
|
return ENTER.join(dico)
|
|
|
|
|
return ENTER.join([msg for msg in self.dict_to_dict(dico, level, init=True)])
|
2025-10-14 12:58:39 +02:00
|
|
|
|
2025-10-15 09:44:22 +02:00
|
|
|
def dict_to_dict(
|
|
|
|
|
self,
|
|
|
|
|
dico: dict,
|
|
|
|
|
level: int,
|
|
|
|
|
*,
|
|
|
|
|
init: bool = False,
|
|
|
|
|
) -> str:
|
2024-11-15 08:13:45 +01:00
|
|
|
"""Parse the dict to transform to dict"""
|
2025-03-29 15:10:03 +01:00
|
|
|
msg = []
|
|
|
|
|
for value in dico.values():
|
2025-10-14 12:58:39 +02:00
|
|
|
if value["type"] == "variable":
|
2025-11-29 22:21:06 +01:00
|
|
|
self.variable_to_string(value)
|
|
|
|
|
elif self.with_family:
|
|
|
|
|
if init and value["type"] == "namespace":
|
|
|
|
|
namespace = True
|
2024-11-15 08:13:45 +01:00
|
|
|
else:
|
2025-11-29 22:21:06 +01:00
|
|
|
namespace = False
|
|
|
|
|
if self.tabular_datas.columns:
|
|
|
|
|
msg.append(self.tabular())
|
2026-03-29 11:01:15 +02:00
|
|
|
msg.extend(
|
|
|
|
|
self.family_to_string(value["informations"], level, namespace)
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
msg.extend(self.dict_to_dict(value["children"], level + 1))
|
2026-04-30 06:58:12 +02:00
|
|
|
end = self.end_family(level)
|
|
|
|
|
if end:
|
|
|
|
|
msg.append(end)
|
2025-11-29 22:21:06 +01:00
|
|
|
else:
|
|
|
|
|
self.dict_to_dict(
|
2026-03-29 11:01:15 +02:00
|
|
|
value["children"],
|
|
|
|
|
level + 1,
|
2025-11-29 22:21:06 +01:00
|
|
|
)
|
|
|
|
|
if self.tabular_datas.columns and (init or self.with_family):
|
|
|
|
|
msg.append(self.tabular())
|
2024-11-15 08:13:45 +01:00
|
|
|
return msg
|
|
|
|
|
|
|
|
|
|
# FAMILY
|
2025-03-29 15:10:03 +01:00
|
|
|
def namespace_to_title(self, informations: dict, level: int) -> str:
|
2024-11-15 08:13:45 +01:00
|
|
|
"""manage namespace family"""
|
|
|
|
|
return self.title(
|
2026-04-30 06:58:12 +02:00
|
|
|
self.get_description(informations, {}, title=True),
|
2025-03-02 13:38:14 +01:00
|
|
|
level,
|
2024-11-15 08:13:45 +01:00
|
|
|
)
|
|
|
|
|
|
2025-11-12 19:33:56 +01:00
|
|
|
def family_to_string(self, informations: dict, level: int, namespace: bool) -> str:
|
2024-11-15 08:13:45 +01:00
|
|
|
"""manage other family type"""
|
2025-11-12 19:33:56 +01:00
|
|
|
if namespace:
|
|
|
|
|
ret = [self.namespace_to_title(informations, level)]
|
|
|
|
|
else:
|
2026-03-29 11:01:15 +02:00
|
|
|
ret = [
|
|
|
|
|
self.title(
|
2026-06-21 17:05:44 +02:00
|
|
|
self.get_description(informations, {}, title=True),
|
|
|
|
|
level,
|
2026-03-29 11:01:15 +02:00
|
|
|
)
|
|
|
|
|
]
|
2025-11-29 22:21:06 +01:00
|
|
|
msg = []
|
2025-03-02 13:38:14 +01:00
|
|
|
helps = informations.get("help")
|
2024-11-15 08:13:45 +01:00
|
|
|
if helps:
|
|
|
|
|
for help_ in helps:
|
2026-03-29 11:01:15 +02:00
|
|
|
msg.extend([to_phrase(h) for h in help_.strip().split("\n")])
|
|
|
|
|
path = self.display_paths(
|
|
|
|
|
informations, {}, None, with_anchor=False, is_bold=False
|
|
|
|
|
)
|
2026-01-14 13:56:51 +01:00
|
|
|
if path:
|
2026-06-21 14:42:34 +02:00
|
|
|
if "full_path" in informations:
|
|
|
|
|
full_path = informations["full_path"]
|
|
|
|
|
else:
|
|
|
|
|
full_path = informations["path"]
|
|
|
|
|
msg.append(self.section(full_path, _("Path"), path, type_="family"))
|
2025-10-02 08:19:18 +02:00
|
|
|
calculated_properties = []
|
2025-11-29 22:21:06 +01:00
|
|
|
property_str = self.property_to_string(informations, calculated_properties, {})
|
2025-11-10 14:01:45 +01:00
|
|
|
if property_str:
|
|
|
|
|
msg.append(property_str)
|
2025-10-02 08:19:18 +02:00
|
|
|
if calculated_properties:
|
2026-03-29 11:01:15 +02:00
|
|
|
msg.append(self.join(calculated_properties))
|
2025-10-14 12:58:39 +02:00
|
|
|
if "identifier" in informations:
|
2026-06-21 14:42:34 +02:00
|
|
|
if "full_path" in informations:
|
|
|
|
|
full_path = informations["full_path"]
|
|
|
|
|
else:
|
|
|
|
|
full_path = informations["path"]
|
2025-05-11 19:13:12 +02:00
|
|
|
msg.append(
|
2026-03-29 11:01:15 +02:00
|
|
|
self.section(
|
2026-06-21 17:05:44 +02:00
|
|
|
full_path,
|
|
|
|
|
_("Identifiers"),
|
|
|
|
|
informations["identifier"],
|
|
|
|
|
type_="family",
|
2026-03-29 11:01:15 +02:00
|
|
|
)
|
2025-05-11 19:13:12 +02:00
|
|
|
)
|
2026-01-14 13:56:51 +01:00
|
|
|
if msg:
|
2026-04-01 17:01:24 +02:00
|
|
|
ret.append(self.display_family_informations(msg))
|
2026-04-30 06:58:12 +02:00
|
|
|
end = self.end_family_informations()
|
|
|
|
|
if end:
|
|
|
|
|
ret.append(end)
|
2025-11-12 19:33:56 +01:00
|
|
|
return ret
|
|
|
|
|
|
2026-04-01 17:01:24 +02:00
|
|
|
def display_family_informations(self, msg) -> str:
|
|
|
|
|
fam_info = self.family_informations()
|
2026-04-30 06:58:12 +02:00
|
|
|
msg = self.family_informations_ends_line().join(msg)
|
|
|
|
|
if fam_info:
|
|
|
|
|
msg = fam_info + msg
|
|
|
|
|
return msg
|
2026-04-01 17:01:24 +02:00
|
|
|
|
|
|
|
|
def family_informations(self) -> str:
|
2026-04-30 06:58:12 +02:00
|
|
|
return None
|
2026-04-01 17:01:24 +02:00
|
|
|
|
2025-11-12 19:33:56 +01:00
|
|
|
def family_informations_starts_line(self) -> str:
|
2026-04-30 06:58:12 +02:00
|
|
|
return None
|
2025-11-12 19:33:56 +01:00
|
|
|
|
|
|
|
|
def family_informations_ends_line(self) -> str:
|
2025-10-15 09:44:22 +02:00
|
|
|
return ""
|
2025-10-02 08:19:18 +02:00
|
|
|
|
2026-06-21 17:05:44 +02:00
|
|
|
def end_family(self, level: int, collapse: bool = True) -> str:
|
2026-04-30 06:58:12 +02:00
|
|
|
return None
|
|
|
|
|
|
2025-10-15 09:44:22 +02:00
|
|
|
def convert_list_to_string(
|
|
|
|
|
self, attribute: str, informations: dict, modified_attributes: dict
|
|
|
|
|
) -> str():
|
2025-10-14 12:58:39 +02:00
|
|
|
datas = []
|
|
|
|
|
if attribute in modified_attributes:
|
|
|
|
|
name, previous, new = modified_attributes[attribute]
|
|
|
|
|
for data in previous:
|
|
|
|
|
datas.append(self.delete(self.to_phrase(data)))
|
|
|
|
|
else:
|
|
|
|
|
new = []
|
|
|
|
|
if attribute in informations:
|
|
|
|
|
for data in informations[attribute]:
|
|
|
|
|
if isinstance(data, dict):
|
2025-10-15 09:44:22 +02:00
|
|
|
if attribute.endswith("s"):
|
2025-10-14 12:58:39 +02:00
|
|
|
attr = attribute[:-1]
|
|
|
|
|
else:
|
|
|
|
|
attr = attribute
|
2025-10-15 09:44:22 +02:00
|
|
|
data = data[attr].replace(
|
|
|
|
|
"{{ identifier }}", self.italic(data["identifier"])
|
|
|
|
|
)
|
2025-10-14 13:50:02 +02:00
|
|
|
data = self.to_phrase(data)
|
2025-10-14 12:58:39 +02:00
|
|
|
if data in new:
|
|
|
|
|
data = self.underline(data)
|
2025-10-14 13:50:02 +02:00
|
|
|
datas.append(data)
|
2025-10-14 12:58:39 +02:00
|
|
|
return self.stripped(self.join(datas))
|
|
|
|
|
|
2025-10-15 09:44:22 +02:00
|
|
|
def get_description(
|
2026-03-29 11:01:15 +02:00
|
|
|
self,
|
|
|
|
|
informations: dict,
|
|
|
|
|
modified_attributes: dict,
|
2026-03-29 12:42:01 +02:00
|
|
|
*,
|
2026-06-21 17:05:44 +02:00
|
|
|
force_identifiers: Optional[list] = None,
|
|
|
|
|
with_to_phrase: bool = True,
|
|
|
|
|
title: bool = False,
|
2026-03-30 22:28:05 +02:00
|
|
|
) -> str:
|
2026-03-31 12:27:08 +02:00
|
|
|
add_new_description = True
|
2026-06-21 17:05:44 +02:00
|
|
|
|
|
|
|
|
def _get_description(
|
|
|
|
|
description,
|
|
|
|
|
identifiers,
|
|
|
|
|
delete=False,
|
|
|
|
|
new=[],
|
|
|
|
|
previous_identifiers=[],
|
|
|
|
|
new_identifiers=[],
|
|
|
|
|
its_a_name=False,
|
|
|
|
|
):
|
2025-11-05 21:43:10 +01:00
|
|
|
if identifiers and "{{ identifier }}" in description:
|
2026-04-30 06:58:12 +02:00
|
|
|
if its_a_name:
|
|
|
|
|
information_type = "name"
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
2026-04-30 06:58:12 +02:00
|
|
|
information_type = "description"
|
|
|
|
|
if isinstance(informations["path"], dict):
|
|
|
|
|
info = informations["path"]
|
|
|
|
|
else:
|
|
|
|
|
info = informations
|
|
|
|
|
path = informations["path"]
|
|
|
|
|
if isinstance(path, str):
|
|
|
|
|
identifier_type = "many"
|
|
|
|
|
else:
|
|
|
|
|
identifier_type = path["identifier_type"]
|
|
|
|
|
if previous_identifiers:
|
|
|
|
|
pass
|
|
|
|
|
if not title or self.format_in_title:
|
|
|
|
|
formatter = self
|
|
|
|
|
else:
|
|
|
|
|
formatter = None
|
2026-06-21 17:05:44 +02:00
|
|
|
description = get_path_from_identifiers(
|
|
|
|
|
description,
|
|
|
|
|
identifiers,
|
|
|
|
|
previous_identifiers,
|
|
|
|
|
new_identifiers,
|
|
|
|
|
identifier_type,
|
|
|
|
|
formatter=formatter,
|
|
|
|
|
information_type=information_type,
|
|
|
|
|
)
|
2026-03-29 12:42:01 +02:00
|
|
|
elif with_to_phrase:
|
2025-10-14 12:58:39 +02:00
|
|
|
description = self.to_phrase(description)
|
|
|
|
|
if description in new:
|
|
|
|
|
description = self.underline(description)
|
|
|
|
|
if delete:
|
|
|
|
|
description = self.delete(description)
|
|
|
|
|
return description
|
2025-10-15 09:44:22 +02:00
|
|
|
|
2026-04-30 06:58:12 +02:00
|
|
|
if force_identifiers:
|
|
|
|
|
all_identifiers = force_identifiers
|
|
|
|
|
else:
|
|
|
|
|
all_identifiers = informations.get("identifiers", [])
|
2025-10-14 12:58:39 +02:00
|
|
|
if "description" in modified_attributes:
|
|
|
|
|
name, previous, new = modified_attributes["description"]
|
2025-11-05 21:43:10 +01:00
|
|
|
if previous:
|
2026-03-30 22:28:05 +02:00
|
|
|
identifiers = modified_attributes.get("identifiers", [])
|
2026-03-31 12:27:08 +02:00
|
|
|
# if modified_attributes has no description
|
2026-03-30 22:28:05 +02:00
|
|
|
if not identifiers:
|
2026-04-30 06:58:12 +02:00
|
|
|
identifiers = all_identifiers
|
2025-11-05 21:43:10 +01:00
|
|
|
modified_description = _get_description(
|
2026-03-30 22:28:05 +02:00
|
|
|
previous[0], identifiers, delete=True
|
2025-11-05 21:43:10 +01:00
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
modified_description = None
|
2026-06-21 17:05:44 +02:00
|
|
|
elif (
|
|
|
|
|
"identifiers" in modified_attributes
|
|
|
|
|
and "{{ identifier }}" in informations["description"]
|
|
|
|
|
):
|
2026-04-30 06:58:12 +02:00
|
|
|
# FIXME aussi au dessus !
|
2026-03-31 12:27:08 +02:00
|
|
|
name, previous, new = modified_attributes["identifiers"]
|
|
|
|
|
previous_identifiers = previous[-1] if previous else []
|
|
|
|
|
new_identifiers = new[-1] if new else []
|
2026-04-30 06:58:12 +02:00
|
|
|
if new_identifiers:
|
2026-06-21 17:05:44 +02:00
|
|
|
all_identifiers = [
|
|
|
|
|
identifier
|
|
|
|
|
for identifier in all_identifiers
|
|
|
|
|
if identifier != new_identifiers
|
|
|
|
|
]
|
2026-03-31 12:27:08 +02:00
|
|
|
modified_description = _get_description(
|
2026-06-21 17:05:44 +02:00
|
|
|
informations["description"],
|
|
|
|
|
all_identifiers,
|
|
|
|
|
previous_identifiers=previous_identifiers,
|
|
|
|
|
new_identifiers=new_identifiers,
|
2026-03-31 12:27:08 +02:00
|
|
|
)
|
|
|
|
|
add_new_description = False
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
|
|
|
|
modified_description = None
|
|
|
|
|
new = []
|
2026-03-31 12:27:08 +02:00
|
|
|
if add_new_description:
|
|
|
|
|
if "description" in informations:
|
|
|
|
|
description = _get_description(
|
2026-04-30 06:58:12 +02:00
|
|
|
informations["description"], all_identifiers, new=new
|
2026-03-31 12:27:08 +02:00
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
description = _get_description(
|
2026-06-21 17:05:44 +02:00
|
|
|
informations["name"],
|
|
|
|
|
all_identifiers,
|
|
|
|
|
new=new,
|
|
|
|
|
its_a_name=True,
|
2026-03-31 12:27:08 +02:00
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
description = None
|
2025-10-14 12:58:39 +02:00
|
|
|
if modified_description:
|
|
|
|
|
if description:
|
|
|
|
|
description = self.join([modified_description, description])
|
|
|
|
|
else:
|
|
|
|
|
description = modified_description
|
|
|
|
|
if not description:
|
|
|
|
|
return None
|
|
|
|
|
return self.stripped(description)
|
|
|
|
|
|
2024-11-15 08:13:45 +01:00
|
|
|
# VARIABLE
|
2025-10-15 09:44:22 +02:00
|
|
|
def variable_to_string(
|
2026-03-29 11:01:15 +02:00
|
|
|
self,
|
|
|
|
|
informations: dict,
|
|
|
|
|
modified_attributes: dict = {},
|
|
|
|
|
force_identifiers: Optional[str] = None,
|
2025-10-15 09:44:22 +02:00
|
|
|
) -> None:
|
2024-11-15 08:13:45 +01:00
|
|
|
"""Manage variable"""
|
2025-11-29 22:21:06 +01:00
|
|
|
self.tabular_datas.add(informations, modified_attributes, force_identifiers)
|
2025-10-14 12:58:39 +02:00
|
|
|
|
2025-10-15 09:44:22 +02:00
|
|
|
def convert_section_to_string(
|
2026-03-29 11:01:15 +02:00
|
|
|
self,
|
|
|
|
|
attribute: str,
|
|
|
|
|
informations: dict,
|
|
|
|
|
modified_attributes: dict,
|
|
|
|
|
multi: bool,
|
|
|
|
|
*,
|
|
|
|
|
section_name: bool = True,
|
|
|
|
|
with_to_phrase=False,
|
2025-10-15 09:44:22 +02:00
|
|
|
) -> str():
|
2025-10-14 12:58:39 +02:00
|
|
|
values = []
|
|
|
|
|
submessage = ""
|
2026-06-21 14:42:34 +02:00
|
|
|
if "full_path" in informations:
|
|
|
|
|
full_path = informations["full_path"]
|
|
|
|
|
else:
|
|
|
|
|
full_path = informations["path"]
|
2025-10-14 12:58:39 +02:00
|
|
|
if modified_attributes and attribute in modified_attributes:
|
|
|
|
|
name, previous, new = modified_attributes[attribute]
|
|
|
|
|
if isinstance(previous, list):
|
|
|
|
|
for p in previous:
|
2026-06-21 14:42:34 +02:00
|
|
|
submessage, m = self.message_to_string(full_path, p, submessage)
|
2025-10-14 12:58:39 +02:00
|
|
|
values.append(self.delete(m))
|
|
|
|
|
else:
|
2026-06-21 17:05:44 +02:00
|
|
|
submessage, old_values = self.message_to_string(
|
|
|
|
|
full_path, previous, submessage
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
values.append(self.delete(old_values))
|
2024-11-15 08:13:45 +01:00
|
|
|
else:
|
2025-10-14 12:58:39 +02:00
|
|
|
new = []
|
|
|
|
|
if attribute in informations:
|
|
|
|
|
old = informations[attribute]
|
|
|
|
|
name = old["name"]
|
|
|
|
|
if isinstance(old["values"], list):
|
|
|
|
|
for value in old["values"]:
|
2026-06-21 17:05:44 +02:00
|
|
|
if "identifiers" in informations and (
|
|
|
|
|
not isinstance(value, dict) or "identifiers" not in value
|
|
|
|
|
):
|
2026-06-21 14:42:34 +02:00
|
|
|
identifiers = informations["identifiers"]
|
|
|
|
|
else:
|
|
|
|
|
identifiers = []
|
2026-06-21 17:05:44 +02:00
|
|
|
submessage, old_value = self.message_to_string(
|
|
|
|
|
full_path, value, submessage, force_identifiers=identifiers
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
if value in new:
|
|
|
|
|
old_value = self.underline(old_value)
|
|
|
|
|
values.append(old_value)
|
|
|
|
|
if multi:
|
2025-11-29 22:21:06 +01:00
|
|
|
values = self.list(values, with_enter=section_name)
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
|
|
|
|
values = self.join(values)
|
|
|
|
|
elif values:
|
|
|
|
|
old_values = old["values"]
|
2026-06-21 17:05:44 +02:00
|
|
|
submessage, old_values = self.message_to_string(
|
|
|
|
|
full_path, old_values, submessage
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
if old["values"] in new:
|
|
|
|
|
old_values = self.underline(old_values)
|
|
|
|
|
values.append(old_values)
|
|
|
|
|
values = self.join(values)
|
2024-11-15 08:13:45 +01:00
|
|
|
else:
|
2026-06-21 14:42:34 +02:00
|
|
|
old_values = old["values"]
|
2026-06-21 17:05:44 +02:00
|
|
|
if "identifiers" in informations and (
|
|
|
|
|
not isinstance(old_values, dict) or "identifiers" not in old_values
|
|
|
|
|
):
|
2026-06-21 14:42:34 +02:00
|
|
|
identifiers = informations["identifiers"]
|
|
|
|
|
else:
|
|
|
|
|
identifiers = []
|
2026-06-21 17:05:44 +02:00
|
|
|
submessage, values = self.message_to_string(
|
|
|
|
|
full_path, old_values, submessage, force_identifiers=identifiers
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
if old["values"] in new:
|
|
|
|
|
values = self.underline(values)
|
|
|
|
|
if values != []:
|
2026-03-29 11:01:15 +02:00
|
|
|
return self.section(
|
2026-06-21 14:42:34 +02:00
|
|
|
full_path,
|
2026-03-29 11:01:15 +02:00
|
|
|
name,
|
|
|
|
|
values,
|
|
|
|
|
submessage=submessage,
|
|
|
|
|
section_name=section_name,
|
|
|
|
|
with_to_phrase=with_to_phrase,
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
|
2025-10-15 09:44:22 +02:00
|
|
|
def convert_choices_to_string(
|
2026-03-29 11:01:15 +02:00
|
|
|
self,
|
|
|
|
|
informations: dict,
|
|
|
|
|
modified_attributes: dict,
|
|
|
|
|
with_default: bool = True,
|
2025-10-15 09:44:22 +02:00
|
|
|
) -> str():
|
2025-10-14 12:58:39 +02:00
|
|
|
default_is_already_set = False
|
2025-03-02 13:38:14 +01:00
|
|
|
if "choices" in informations:
|
2025-09-22 09:42:46 +02:00
|
|
|
choices = informations["choices"]
|
2025-10-14 12:58:39 +02:00
|
|
|
choices_values = choices["values"]
|
|
|
|
|
if not isinstance(choices_values, list):
|
|
|
|
|
choices_values = [choices_values]
|
|
|
|
|
default_is_a_list = False
|
2024-11-15 08:13:45 +01:00
|
|
|
else:
|
2025-10-14 12:58:39 +02:00
|
|
|
default_is_a_list = True
|
2026-06-21 14:42:34 +02:00
|
|
|
if "full_path" in informations:
|
|
|
|
|
full_path = informations["full_path"]
|
|
|
|
|
else:
|
|
|
|
|
full_path = informations["path"]
|
2025-10-29 10:46:57 +01:00
|
|
|
for idx, choice in enumerate(choices_values.copy()):
|
|
|
|
|
if isinstance(choice, dict):
|
2026-06-21 17:05:44 +02:00
|
|
|
choices_values[idx] = self.message_to_string(
|
|
|
|
|
full_path, choice, None
|
|
|
|
|
)[1]
|
2025-10-14 12:58:39 +02:00
|
|
|
if "default" in modified_attributes:
|
|
|
|
|
name, old_default, new_default = modified_attributes["default"]
|
|
|
|
|
if not old_default:
|
|
|
|
|
old_default = [None]
|
|
|
|
|
if not isinstance(old_default, list):
|
|
|
|
|
old_default = [old_default]
|
|
|
|
|
for value in old_default.copy():
|
2025-10-15 09:44:22 +02:00
|
|
|
if (
|
|
|
|
|
isinstance(value, str)
|
|
|
|
|
and value.endswith(".")
|
|
|
|
|
and value not in choices_values
|
|
|
|
|
):
|
2025-10-14 12:58:39 +02:00
|
|
|
old_default.remove(value)
|
|
|
|
|
old_default.append(value[:-1])
|
|
|
|
|
else:
|
|
|
|
|
old_default = new_default = []
|
|
|
|
|
# check if all default values are in choices (could be from a calculation)
|
|
|
|
|
if "default" in informations:
|
|
|
|
|
default = informations["default"]["values"]
|
|
|
|
|
else:
|
2025-11-29 07:59:33 +01:00
|
|
|
default = [None]
|
2025-10-14 12:58:39 +02:00
|
|
|
if not isinstance(default, list):
|
|
|
|
|
default = [default]
|
2025-10-29 10:46:57 +01:00
|
|
|
for idx, value in enumerate(default.copy()):
|
|
|
|
|
if isinstance(value, dict):
|
2026-06-21 14:42:34 +02:00
|
|
|
default[idx] = self.message_to_string(full_path, value, None)[1]
|
2025-10-14 12:58:39 +02:00
|
|
|
default_value_not_in_choices = set(default) - set(choices_values)
|
|
|
|
|
if default_value_not_in_choices:
|
|
|
|
|
default_is_changed = False
|
|
|
|
|
for val in default_value_not_in_choices.copy():
|
2025-10-15 09:44:22 +02:00
|
|
|
if (
|
|
|
|
|
isinstance(val, str)
|
|
|
|
|
and val.endswith(".")
|
|
|
|
|
and val[:-1] in choices_values
|
|
|
|
|
):
|
2025-10-14 12:58:39 +02:00
|
|
|
default.remove(val)
|
|
|
|
|
default.append(val[:-1])
|
|
|
|
|
default_is_changed = True
|
|
|
|
|
if val in new_default:
|
|
|
|
|
new_default.remove(val)
|
|
|
|
|
new_default.append(val[:-1])
|
|
|
|
|
if default_is_changed:
|
|
|
|
|
default_value_not_in_choices = set(default) - set(choices_values)
|
|
|
|
|
if default_value_not_in_choices:
|
|
|
|
|
old_default = []
|
|
|
|
|
new_default = []
|
|
|
|
|
default = []
|
|
|
|
|
else:
|
|
|
|
|
default_is_already_set = True
|
|
|
|
|
if "choices" in modified_attributes:
|
|
|
|
|
name, previous, new = modified_attributes["choices"]
|
|
|
|
|
for choice in reversed(previous):
|
2025-10-29 10:46:57 +01:00
|
|
|
if isinstance(choice, dict):
|
2026-06-21 14:42:34 +02:00
|
|
|
choice = self.message_to_string(full_path, choice, None)[1]
|
2025-11-29 22:21:06 +01:00
|
|
|
if with_default and choice in old_default:
|
2025-10-15 09:44:22 +02:00
|
|
|
choices_values.insert(
|
|
|
|
|
0, self.delete(dump(choice) + " ← " + _("(default)"))
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
|
|
|
|
choices_values.insert(0, self.delete(dump(choice)))
|
|
|
|
|
else:
|
|
|
|
|
new = []
|
|
|
|
|
for idx, val in enumerate(choices_values):
|
2025-11-29 22:21:06 +01:00
|
|
|
if with_default and val in old_default:
|
2025-10-15 09:44:22 +02:00
|
|
|
choices_values[idx] = (
|
|
|
|
|
dump(val) + " " + self.delete("← " + _("(default)"))
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
elif with_default and val in default:
|
2025-10-14 12:58:39 +02:00
|
|
|
if val in new_default:
|
|
|
|
|
if val in new:
|
2025-10-15 09:44:22 +02:00
|
|
|
choices_values[idx] = self.underline(
|
|
|
|
|
dump(val) + " " + self.bold("← " + _("(default)"))
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
2025-10-15 09:44:22 +02:00
|
|
|
choices_values[idx] = (
|
|
|
|
|
dump(val)
|
|
|
|
|
+ " "
|
|
|
|
|
+ self.underline(self.bold("← " + _("(default)")))
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
2025-10-15 09:44:22 +02:00
|
|
|
choices_values[idx] = (
|
|
|
|
|
dump(val) + " " + self.bold("← " + _("(default)"))
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
elif val in new:
|
|
|
|
|
choices_values[idx] = self.underline(dump(val))
|
|
|
|
|
# if old value and new value is a list, display a list
|
|
|
|
|
if not default_is_a_list and len(choices_values) == 1:
|
|
|
|
|
choices_values = choices_values[0]
|
2026-06-21 17:05:44 +02:00
|
|
|
return default_is_already_set, self.section(
|
|
|
|
|
full_path, choices["name"], choices_values
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
return default_is_already_set, None
|
2024-11-15 08:13:45 +01:00
|
|
|
|
|
|
|
|
# OTHERs
|
2025-10-14 12:58:39 +02:00
|
|
|
def to_phrase(self, text: str) -> str:
|
|
|
|
|
return text
|
|
|
|
|
|
2025-03-02 13:38:14 +01:00
|
|
|
def property_to_string(
|
2025-10-15 09:44:22 +02:00
|
|
|
self,
|
|
|
|
|
informations: dict,
|
|
|
|
|
calculated_properties: list,
|
|
|
|
|
modified_attributes: dict,
|
2026-03-29 11:01:15 +02:00
|
|
|
contents: list = ["type", "properties", "mode", "access_control", "validator"],
|
2025-03-02 13:38:14 +01:00
|
|
|
) -> str:
|
2024-11-15 08:13:45 +01:00
|
|
|
"""Transform properties to string"""
|
|
|
|
|
properties = []
|
2025-11-29 22:21:06 +01:00
|
|
|
modified_properties = []
|
|
|
|
|
if "type" in contents:
|
|
|
|
|
if "type" in modified_attributes:
|
2026-03-29 11:01:15 +02:00
|
|
|
properties.append(
|
|
|
|
|
self.prop(
|
|
|
|
|
modified_attributes["type"],
|
|
|
|
|
italic=False,
|
|
|
|
|
delete=True,
|
|
|
|
|
underline=False,
|
|
|
|
|
)
|
|
|
|
|
)
|
2026-04-30 06:58:12 +02:00
|
|
|
if "multiple" in modified_attributes:
|
2026-06-21 17:05:44 +02:00
|
|
|
if (
|
|
|
|
|
modified_attributes["multiple"][1]
|
|
|
|
|
and modified_attributes["multiple"][1][0]
|
|
|
|
|
):
|
2026-04-30 06:58:12 +02:00
|
|
|
properties.append(
|
2026-06-21 17:05:44 +02:00
|
|
|
self.prop(
|
|
|
|
|
"multiple", italic=False, delete=True, underline=False
|
|
|
|
|
)
|
2026-04-30 06:58:12 +02:00
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
properties.append(
|
2026-06-21 17:05:44 +02:00
|
|
|
self.prop(
|
|
|
|
|
"multiple", italic=False, delete=False, underline=True
|
|
|
|
|
)
|
2026-04-30 06:58:12 +02:00
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
if "properties" not in contents and "properties" in modified_attributes:
|
|
|
|
|
for prop in modified_attributes["properties"]:
|
|
|
|
|
if prop["ori_name"] == "mandatory":
|
2026-03-29 11:01:15 +02:00
|
|
|
properties.append(
|
|
|
|
|
self.prop(
|
|
|
|
|
prop["ori_name"],
|
|
|
|
|
italic=False,
|
|
|
|
|
delete=True,
|
|
|
|
|
underline=False,
|
|
|
|
|
)
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
break
|
|
|
|
|
if "mode" in contents and "mode" in modified_attributes:
|
2026-03-14 20:51:52 +01:00
|
|
|
name, previous, new = modified_attributes["mode"]
|
|
|
|
|
if previous:
|
2026-03-29 11:01:15 +02:00
|
|
|
properties.append(
|
|
|
|
|
self.prop(previous[0], italic=False, delete=True, underline=False)
|
|
|
|
|
)
|
2026-03-14 20:51:52 +01:00
|
|
|
if new:
|
2026-03-29 11:01:15 +02:00
|
|
|
properties.append(
|
|
|
|
|
self.prop(new[0], italic=False, delete=False, underline=True)
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
if "properties" in modified_attributes:
|
2025-11-29 22:21:06 +01:00
|
|
|
if "properties" in contents:
|
|
|
|
|
for props in modified_attributes["properties"]:
|
|
|
|
|
if not props:
|
|
|
|
|
continue
|
|
|
|
|
for prop in props:
|
|
|
|
|
if prop.get("access_control"):
|
|
|
|
|
if "access_control" in contents:
|
|
|
|
|
modified_properties.append(prop)
|
|
|
|
|
elif prop["ori_name"] != "unique" or "unique" in contents:
|
|
|
|
|
modified_properties.append(prop)
|
|
|
|
|
elif "access_control" in contents:
|
|
|
|
|
for prop in modified_attributes["properties"]:
|
|
|
|
|
if prop.get("access_control"):
|
|
|
|
|
modified_properties.append(prop)
|
|
|
|
|
elif "validator" in contents:
|
|
|
|
|
for prop in modified_attributes["properties"]:
|
|
|
|
|
if prop["name"] == "unique":
|
|
|
|
|
modified_properties.append(prop)
|
|
|
|
|
local_calculated_properties = {}
|
|
|
|
|
if "properties" in contents and "properties" in modified_attributes:
|
2025-10-15 09:44:22 +02:00
|
|
|
previous, new = self.get_modified_properties(
|
|
|
|
|
*modified_attributes["properties"][1:]
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
for p, data in previous.items():
|
|
|
|
|
if "type" not in contents and data[0] == "mandatory":
|
|
|
|
|
continue
|
|
|
|
|
if "validator" not in contents and data[0] == "unique":
|
|
|
|
|
continue
|
2025-10-14 12:58:39 +02:00
|
|
|
if p not in new:
|
2026-03-29 11:01:15 +02:00
|
|
|
properties.append(
|
|
|
|
|
self.prop(p, italic=False, delete=True, underline=False)
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
if data[1] is not None:
|
2026-03-29 11:01:15 +02:00
|
|
|
local_calculated_properties[p] = [
|
|
|
|
|
{"annotation": data[1], "delete": True}
|
|
|
|
|
]
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
|
|
|
|
previous = new = []
|
2026-04-30 06:58:12 +02:00
|
|
|
if "type" in contents and "variable_type" in modified_attributes:
|
|
|
|
|
previous, new = modified_attributes["variable_type"][1:]
|
|
|
|
|
properties.append(
|
|
|
|
|
self.prop(previous[0], italic=False, delete=True, underline=False)
|
|
|
|
|
)
|
2025-11-29 22:21:06 +01:00
|
|
|
others = []
|
|
|
|
|
if "type" in contents and "variable_type" in informations:
|
|
|
|
|
others.append({"name": informations["variable_type"], "type": "type"})
|
2026-04-30 06:58:12 +02:00
|
|
|
if informations.get("multiple") and not "multiple" in modified_attributes:
|
2025-11-29 22:21:06 +01:00
|
|
|
others.append({"name": "multiple", "type": "multiple"})
|
|
|
|
|
if "properties" not in contents and "properties" in informations:
|
|
|
|
|
for prop in informations["properties"]:
|
|
|
|
|
if prop["ori_name"] == "mandatory":
|
|
|
|
|
others.append(prop)
|
|
|
|
|
break
|
|
|
|
|
if "mode" in contents and "mode" in informations:
|
|
|
|
|
others.append({"name": informations["mode"], "type": "mode"})
|
|
|
|
|
if "properties" in informations:
|
|
|
|
|
if "properties" in contents:
|
|
|
|
|
for prop in informations["properties"]:
|
|
|
|
|
if prop.get("access_control"):
|
|
|
|
|
if "access_control" in contents:
|
|
|
|
|
others.append(prop)
|
|
|
|
|
elif prop["ori_name"] != "unique" or "validator" in contents:
|
|
|
|
|
others.append(prop)
|
|
|
|
|
elif "access_control" in contents:
|
|
|
|
|
for prop in informations["properties"]:
|
|
|
|
|
if prop.get("access_control"):
|
|
|
|
|
others.append(prop)
|
|
|
|
|
elif "validator" in contents:
|
|
|
|
|
for prop in informations["properties"]:
|
|
|
|
|
if prop["name"] == "unique":
|
|
|
|
|
others.append(prop)
|
|
|
|
|
for prop in others:
|
2025-11-05 21:43:10 +01:00
|
|
|
prop_name = prop["name"]
|
2026-03-29 11:01:15 +02:00
|
|
|
if (
|
|
|
|
|
"type" not in contents
|
|
|
|
|
and prop.get("ori_name", prop_name) == "mandatory"
|
|
|
|
|
):
|
2025-11-29 22:21:06 +01:00
|
|
|
continue
|
2025-11-05 21:43:10 +01:00
|
|
|
if prop_name not in previous and prop_name in new:
|
|
|
|
|
underline = True
|
|
|
|
|
else:
|
|
|
|
|
underline = False
|
2024-11-20 21:12:56 +01:00
|
|
|
if prop["type"] == "type":
|
2026-03-29 11:01:15 +02:00
|
|
|
properties.append(
|
|
|
|
|
self.link(prop_name, ROUGAIL_VARIABLE_TYPE, underline=underline)
|
|
|
|
|
)
|
2024-11-15 08:13:45 +01:00
|
|
|
else:
|
|
|
|
|
if "annotation" in prop:
|
|
|
|
|
italic = True
|
2025-10-14 12:58:39 +02:00
|
|
|
prop_annotation = prop["annotation"]
|
2025-10-15 09:44:22 +02:00
|
|
|
if prop_name in new and (
|
|
|
|
|
prop_name not in previous
|
|
|
|
|
or new[prop_name] != previous[prop_name]
|
|
|
|
|
):
|
2025-11-21 08:15:00 +01:00
|
|
|
underline_ = True
|
|
|
|
|
else:
|
|
|
|
|
underline_ = False
|
2025-10-15 09:44:22 +02:00
|
|
|
local_calculated_properties.setdefault(prop["name"], []).append(
|
2026-03-29 11:01:15 +02:00
|
|
|
{"annotation": prop_annotation, "underline": underline_}
|
2025-10-15 09:44:22 +02:00
|
|
|
)
|
2024-11-15 08:13:45 +01:00
|
|
|
else:
|
|
|
|
|
italic = False
|
2026-03-29 11:01:15 +02:00
|
|
|
properties.append(
|
|
|
|
|
self.prop(
|
|
|
|
|
prop_name, italic=italic, delete=False, underline=underline
|
|
|
|
|
)
|
|
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
if local_calculated_properties:
|
2026-06-21 14:42:34 +02:00
|
|
|
if "full_path" in informations:
|
|
|
|
|
full_path = informations["full_path"]
|
|
|
|
|
else:
|
|
|
|
|
full_path = informations["path"]
|
2025-10-15 09:44:22 +02:00
|
|
|
for (
|
|
|
|
|
calculated_property_name,
|
|
|
|
|
calculated_property,
|
|
|
|
|
) in local_calculated_properties.items():
|
2025-11-21 08:15:00 +01:00
|
|
|
data = []
|
|
|
|
|
for calc in calculated_property:
|
2026-06-21 17:05:44 +02:00
|
|
|
annotation = self.message_to_string(
|
|
|
|
|
full_path, calc["annotation"], None
|
|
|
|
|
)[1]
|
2025-11-21 08:15:00 +01:00
|
|
|
if calc.get("underline", False):
|
|
|
|
|
annotation = self.underline(annotation)
|
|
|
|
|
if calc.get("delete", False):
|
|
|
|
|
annotation = self.delete(annotation)
|
|
|
|
|
data.append(annotation)
|
2025-10-14 12:58:39 +02:00
|
|
|
if len(calculated_property) > 1:
|
2025-11-21 08:15:00 +01:00
|
|
|
calculated_property = self.join(data)
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
2025-11-21 08:15:00 +01:00
|
|
|
calculated_property = data[0]
|
2025-10-14 12:58:39 +02:00
|
|
|
calculated_properties.append(
|
2025-10-15 09:44:22 +02:00
|
|
|
self.section(
|
2026-06-21 17:05:44 +02:00
|
|
|
full_path,
|
|
|
|
|
calculated_property_name.capitalize(),
|
|
|
|
|
calculated_property,
|
2025-10-15 09:44:22 +02:00
|
|
|
)
|
2025-10-14 12:58:39 +02:00
|
|
|
)
|
2024-11-15 08:13:45 +01:00
|
|
|
if not properties:
|
2025-11-29 22:21:06 +01:00
|
|
|
return ""
|
|
|
|
|
return " ".join(properties)
|
2025-10-14 12:58:39 +02:00
|
|
|
|
2025-10-15 09:44:22 +02:00
|
|
|
def get_modified_properties(
|
|
|
|
|
self, previous: List[dict], new: List[dict]
|
|
|
|
|
) -> Tuple[dict, dict]:
|
2025-10-14 12:58:39 +02:00
|
|
|
def modified_properties_parser(dico):
|
2025-11-29 22:21:06 +01:00
|
|
|
return {d["name"]: (d["ori_name"], d.get("annotation")) for d in dico}
|
2025-10-15 09:44:22 +02:00
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
return modified_properties_parser(previous), modified_properties_parser(new)
|
2024-11-15 08:13:45 +01:00
|
|
|
|
|
|
|
|
def columns(
|
|
|
|
|
self,
|
|
|
|
|
col: List[str], # pylint: disable=unused-argument
|
|
|
|
|
) -> None:
|
|
|
|
|
"""Manage column"""
|
|
|
|
|
return
|
|
|
|
|
|
2025-11-29 22:21:06 +01:00
|
|
|
def tabular(self, with_header: bool = True) -> str:
|
|
|
|
|
"""Transform list to a tabular in string format"""
|
2025-10-14 16:42:39 +02:00
|
|
|
if with_header:
|
2025-11-29 22:21:06 +01:00
|
|
|
headers = self.tabular_header(self.tabular_datas.headers())
|
2025-10-14 16:42:39 +02:00
|
|
|
else:
|
|
|
|
|
headers = ()
|
2026-06-21 17:05:44 +02:00
|
|
|
msg = tabulate(
|
|
|
|
|
self.tabular_datas.get(),
|
|
|
|
|
headers=headers,
|
|
|
|
|
tablefmt=self._tabular_name,
|
2024-11-15 08:13:45 +01:00
|
|
|
)
|
|
|
|
|
return msg
|
|
|
|
|
|
2026-06-21 14:42:34 +02:00
|
|
|
def message_to_string(self, full_path, msg, ret, *, force_identifiers=[]):
|
2025-10-14 12:58:39 +02:00
|
|
|
if isinstance(msg, dict):
|
|
|
|
|
if "submessage" in msg:
|
|
|
|
|
ret += msg["submessage"]
|
|
|
|
|
msg = msg["values"]
|
|
|
|
|
elif "message" in msg:
|
2025-10-29 10:46:57 +01:00
|
|
|
filename = None
|
|
|
|
|
if self.other_root_filenames:
|
|
|
|
|
path = msg["path"]["path"]
|
|
|
|
|
for root in self.other_root_filenames:
|
2026-03-29 11:01:15 +02:00
|
|
|
if path == root or path.startswith(f"{root}."):
|
2025-10-29 10:46:57 +01:00
|
|
|
filename = self.other_root_filenames[root]
|
|
|
|
|
break
|
2026-03-29 12:42:01 +02:00
|
|
|
else:
|
|
|
|
|
if "." in self.other_root_filenames:
|
|
|
|
|
filename = self.other_root_filenames["."]
|
2025-11-17 15:46:24 +01:00
|
|
|
if "identifiers" in msg["path"]:
|
2026-04-30 06:58:12 +02:00
|
|
|
msg["identifiers"] = msg["path"]["identifiers"]
|
2026-06-21 17:05:44 +02:00
|
|
|
calculated_paths = calc_path(
|
|
|
|
|
msg["path"], formatter=self, identifiers=force_identifiers
|
|
|
|
|
)
|
2026-06-21 14:42:34 +02:00
|
|
|
if self.support_namespace and self.document_a_type:
|
|
|
|
|
namespace = full_path.split(".", 1)[0]
|
|
|
|
|
else:
|
|
|
|
|
namespace = None
|
2026-04-30 06:58:12 +02:00
|
|
|
if isinstance(calculated_paths, list):
|
2026-06-21 17:05:44 +02:00
|
|
|
msgs = [
|
|
|
|
|
msg["message"].format(
|
|
|
|
|
self.link_variable(
|
|
|
|
|
doc_path(
|
|
|
|
|
calculated_path, self.document_a_type, namespace
|
|
|
|
|
),
|
|
|
|
|
msg["path"]["path"],
|
|
|
|
|
self.get_description(
|
|
|
|
|
msg,
|
|
|
|
|
{},
|
|
|
|
|
force_identifiers=[msg["path"]["identifiers"][idx]],
|
|
|
|
|
with_to_phrase=False,
|
|
|
|
|
),
|
|
|
|
|
filename=filename,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
for idx, calculated_path in enumerate(calculated_paths)
|
|
|
|
|
]
|
2026-04-30 06:58:12 +02:00
|
|
|
msg = self.list(msgs)
|
|
|
|
|
else:
|
|
|
|
|
path = self.link_variable(
|
2026-06-21 14:42:34 +02:00
|
|
|
doc_path(calculated_paths, self.document_a_type, namespace),
|
2026-04-30 06:58:12 +02:00
|
|
|
msg["path"]["path"],
|
|
|
|
|
self.get_description(msg, {}, with_to_phrase=False),
|
|
|
|
|
filename=filename,
|
|
|
|
|
)
|
|
|
|
|
msg = msg["message"].format(path)
|
2025-11-21 08:15:00 +01:00
|
|
|
elif "description" in msg:
|
|
|
|
|
if "variables" in msg:
|
|
|
|
|
paths = []
|
|
|
|
|
for variable in msg["variables"]:
|
|
|
|
|
filename = None
|
|
|
|
|
if self.other_root_filenames:
|
2026-03-29 12:42:01 +02:00
|
|
|
path = variable["path"]
|
2025-11-21 08:15:00 +01:00
|
|
|
for root in self.other_root_filenames:
|
2026-03-29 11:01:15 +02:00
|
|
|
if path == root or path.startswith(f"{root}."):
|
2025-11-21 08:15:00 +01:00
|
|
|
filename = self.other_root_filenames[root]
|
|
|
|
|
break
|
2026-03-29 12:42:01 +02:00
|
|
|
else:
|
|
|
|
|
if "." in self.other_root_filenames:
|
|
|
|
|
filename = self.other_root_filenames["."]
|
2025-11-21 08:15:00 +01:00
|
|
|
identifiers = variable.get("identifiers")
|
2026-06-21 14:42:34 +02:00
|
|
|
if identifiers is None and force_identifiers:
|
|
|
|
|
identifiers = force_identifiers
|
2026-04-30 06:58:12 +02:00
|
|
|
if self.format_in_title:
|
|
|
|
|
formatter = self
|
|
|
|
|
else:
|
|
|
|
|
formatter = None
|
2026-03-29 11:01:15 +02:00
|
|
|
path = calc_path(
|
|
|
|
|
variable, formatter=self, identifiers=identifiers
|
|
|
|
|
)
|
|
|
|
|
paths.append(
|
|
|
|
|
self.link_variable(
|
|
|
|
|
path,
|
|
|
|
|
variable["path"],
|
|
|
|
|
self.get_description(
|
|
|
|
|
variable,
|
|
|
|
|
{},
|
|
|
|
|
force_identifiers=identifiers,
|
2026-03-29 12:42:01 +02:00
|
|
|
with_to_phrase=False,
|
2026-03-29 11:01:15 +02:00
|
|
|
),
|
|
|
|
|
filename=filename,
|
|
|
|
|
)
|
|
|
|
|
)
|
2025-11-21 08:15:00 +01:00
|
|
|
msg = msg["description"].format(*paths)
|
|
|
|
|
else:
|
|
|
|
|
msg = msg["description"]
|
2025-10-14 12:58:39 +02:00
|
|
|
return ret, msg
|
|
|
|
|
|
2024-11-15 08:13:45 +01:00
|
|
|
def section(
|
|
|
|
|
self,
|
2026-06-21 14:42:34 +02:00
|
|
|
full_path: str,
|
2024-11-15 08:13:45 +01:00
|
|
|
name: str,
|
|
|
|
|
msg: str,
|
2025-10-14 12:58:39 +02:00
|
|
|
submessage: str = "",
|
2026-03-29 11:01:15 +02:00
|
|
|
type_="variable",
|
2025-11-29 22:21:06 +01:00
|
|
|
section_name=True,
|
2025-12-29 18:47:37 +01:00
|
|
|
with_to_phrase=False,
|
|
|
|
|
force_enter=False,
|
2024-11-15 08:13:45 +01:00
|
|
|
) -> str:
|
|
|
|
|
"""Return something like Name: msg"""
|
2026-06-21 14:42:34 +02:00
|
|
|
submessage, msg = self.message_to_string(full_path, msg, submessage)
|
2024-11-15 08:13:45 +01:00
|
|
|
if isinstance(msg, list):
|
|
|
|
|
if len(msg) == 1:
|
2026-06-21 14:42:34 +02:00
|
|
|
submessage, elt = self.message_to_string(full_path, msg[0], submessage)
|
2025-10-18 06:40:23 +02:00
|
|
|
if isinstance(elt, list):
|
2025-11-29 22:21:06 +01:00
|
|
|
submessage += self.list(elt, type_=type_, with_enter=section_name)
|
2025-12-29 18:47:37 +01:00
|
|
|
elif force_enter:
|
|
|
|
|
submessage += self.enter_tabular + elt
|
2025-10-18 06:40:23 +02:00
|
|
|
else:
|
|
|
|
|
submessage += elt
|
2024-11-15 08:13:45 +01:00
|
|
|
else:
|
2025-10-14 12:58:39 +02:00
|
|
|
lst = []
|
|
|
|
|
for p in msg:
|
2026-06-21 14:42:34 +02:00
|
|
|
submessage, elt = self.message_to_string(full_path, p, submessage)
|
2025-10-14 12:58:39 +02:00
|
|
|
lst.append(elt)
|
2025-11-29 22:21:06 +01:00
|
|
|
submessage += self.list(lst, type_=type_, with_enter=section_name)
|
2025-10-16 20:58:39 +02:00
|
|
|
msg = ""
|
2024-11-15 08:13:45 +01:00
|
|
|
if not isinstance(msg, str):
|
2025-10-14 12:58:39 +02:00
|
|
|
submessage += dump(msg)
|
|
|
|
|
else:
|
|
|
|
|
submessage += msg
|
2025-11-29 22:21:06 +01:00
|
|
|
if section_name:
|
|
|
|
|
return _("{0}: {1}").format(self.bold(name), submessage)
|
|
|
|
|
if with_to_phrase:
|
|
|
|
|
return to_phrase(submessage)
|
|
|
|
|
return submessage
|
2025-10-14 12:58:39 +02:00
|
|
|
|
|
|
|
|
|
2026-03-29 11:01:15 +02:00
|
|
|
def calc_path(path, *, formatter=None, identifiers: List[str] = None) -> str:
|
2025-10-14 12:58:39 +02:00
|
|
|
def _path_with_identifier(path, identifier):
|
2026-03-29 11:01:15 +02:00
|
|
|
if identifier is None:
|
|
|
|
|
identifier = "{{ __identifier__ }}"
|
|
|
|
|
else:
|
|
|
|
|
identifier = normalize_family(str(identifier))
|
2025-10-27 21:59:39 +01:00
|
|
|
if formatter:
|
|
|
|
|
identifier = formatter.italic(identifier)
|
2025-10-15 09:44:22 +02:00
|
|
|
return path.replace("{{ identifier }}", identifier, 1)
|
2026-06-21 17:05:44 +02:00
|
|
|
|
2025-10-14 12:58:39 +02:00
|
|
|
if isinstance(path, dict):
|
|
|
|
|
path_ = path["path"]
|
2025-10-29 10:46:57 +01:00
|
|
|
if "identifiers" in path:
|
2026-06-21 17:05:44 +02:00
|
|
|
path_ = get_path_from_identifiers(
|
|
|
|
|
path["path"],
|
|
|
|
|
path["identifiers"],
|
|
|
|
|
[],
|
|
|
|
|
[],
|
|
|
|
|
path["identifier_type"],
|
|
|
|
|
formatter,
|
|
|
|
|
)
|
2026-06-21 14:42:34 +02:00
|
|
|
elif identifiers:
|
|
|
|
|
for identifier in identifiers[0]:
|
|
|
|
|
path_ = _path_with_identifier(path_, identifier)
|
2025-10-14 12:58:39 +02:00
|
|
|
elif identifiers:
|
|
|
|
|
path_ = path
|
|
|
|
|
for identifier in identifiers:
|
|
|
|
|
path_ = _path_with_identifier(path_, identifier)
|
2026-03-29 11:01:15 +02:00
|
|
|
path_ = path_.replace("{{ __identifier__ }}", "{{ identifier }}")
|
2025-10-14 12:58:39 +02:00
|
|
|
else:
|
|
|
|
|
path_ = path
|
|
|
|
|
return path_
|
2026-04-30 06:58:12 +02:00
|
|
|
|
|
|
|
|
|
2026-06-21 17:05:44 +02:00
|
|
|
def doc_path(path, document_a_type, namespace: Optional[str] = None) -> str:
|
2026-04-30 06:58:12 +02:00
|
|
|
if document_a_type:
|
|
|
|
|
if "." not in path:
|
|
|
|
|
return None
|
2026-06-21 17:05:44 +02:00
|
|
|
if not namespace or path.startswith(namespace + "."):
|
2026-06-21 14:42:34 +02:00
|
|
|
return path.split(".", 1)[-1]
|
2026-04-30 06:58:12 +02:00
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
2026-06-21 17:05:44 +02:00
|
|
|
def get_path_from_identifiers(
|
|
|
|
|
text: str,
|
|
|
|
|
all_identifiers: list,
|
|
|
|
|
previous_identifiers: list,
|
|
|
|
|
new_identifiers: list,
|
|
|
|
|
identifier_type: str,
|
|
|
|
|
formatter: Optional[object] = None,
|
|
|
|
|
information_type="path",
|
|
|
|
|
) -> str:
|
2026-04-30 06:58:12 +02:00
|
|
|
if not isinstance(all_identifiers, list):
|
2026-06-21 17:05:44 +02:00
|
|
|
raise Exception("hu1?")
|
2026-04-30 06:58:12 +02:00
|
|
|
if all_identifiers:
|
|
|
|
|
for i in all_identifiers:
|
|
|
|
|
if not isinstance(i, list):
|
2026-06-21 17:05:44 +02:00
|
|
|
raise Exception("hu2?")
|
2026-04-30 06:58:12 +02:00
|
|
|
for j in i:
|
|
|
|
|
if isinstance(j, list):
|
2026-06-21 17:05:44 +02:00
|
|
|
raise Exception("hu3?")
|
2026-04-30 06:58:12 +02:00
|
|
|
if not isinstance(new_identifiers, list):
|
2026-06-21 17:05:44 +02:00
|
|
|
raise Exception("hu?")
|
|
|
|
|
|
2026-04-30 06:58:12 +02:00
|
|
|
def _text_with_identifier(information, identifier, delete=False, underline=False):
|
|
|
|
|
if identifier is None:
|
|
|
|
|
identifier = "{{ __identifier__ }}"
|
|
|
|
|
elif information_type == "path":
|
|
|
|
|
identifier = normalize_family(str(identifier))
|
|
|
|
|
else:
|
|
|
|
|
identifier = str(identifier)
|
|
|
|
|
if formatter:
|
|
|
|
|
if delete:
|
|
|
|
|
identifier = formatter.delete(identifier)
|
|
|
|
|
if underline:
|
|
|
|
|
identifier = formatter.underline(identifier)
|
|
|
|
|
identifier = formatter.italic(identifier)
|
|
|
|
|
return information.replace("{{ identifier }}", identifier, 1)
|
2026-06-21 17:05:44 +02:00
|
|
|
|
2026-04-30 06:58:12 +02:00
|
|
|
if identifier_type == "outside":
|
|
|
|
|
separator = "and"
|
|
|
|
|
else:
|
|
|
|
|
separator = "or"
|
|
|
|
|
if information_type == "description":
|
|
|
|
|
ori_text = "{{ identifier }}"
|
|
|
|
|
else:
|
|
|
|
|
ori_text = text
|
|
|
|
|
paths = []
|
|
|
|
|
identifiers_done = []
|
|
|
|
|
for identifiers in all_identifiers:
|
|
|
|
|
if information_type != "path":
|
|
|
|
|
identifier = identifiers[-1]
|
|
|
|
|
if identifier in identifiers_done:
|
|
|
|
|
continue
|
|
|
|
|
text_ = _text_with_identifier(ori_text, identifiers[-1])
|
|
|
|
|
identifiers_done.append(identifier)
|
|
|
|
|
else:
|
|
|
|
|
text_ = ori_text
|
|
|
|
|
for identifier in identifiers:
|
|
|
|
|
text_ = _text_with_identifier(text_, identifier)
|
|
|
|
|
paths.append(text_)
|
|
|
|
|
if formatter:
|
|
|
|
|
for identifier in previous_identifiers:
|
|
|
|
|
paths.append(_text_with_identifier(ori_text, identifier, delete=True))
|
|
|
|
|
for identifier in new_identifiers:
|
|
|
|
|
paths.append(_text_with_identifier(ori_text, identifier, underline=True))
|
|
|
|
|
if information_type == "description":
|
|
|
|
|
if identifier_type == "outside":
|
|
|
|
|
paths = [text.replace("{{ identifier }}", path) for path in paths]
|
|
|
|
|
return display_list(
|
|
|
|
|
paths,
|
|
|
|
|
separator=separator,
|
|
|
|
|
sort=False,
|
|
|
|
|
)
|
|
|
|
|
identifiers_text = display_list(
|
|
|
|
|
paths,
|
|
|
|
|
separator=separator,
|
|
|
|
|
sort=False,
|
|
|
|
|
)
|
2026-06-21 17:05:44 +02:00
|
|
|
return text.replace("{{ identifier }}", identifiers_text)
|
|
|
|
|
if identifier_type == "outside":
|
2026-04-30 06:58:12 +02:00
|
|
|
return paths
|
|
|
|
|
return display_list(paths, separator=separator, sort=False)
|