fix: black

This commit is contained in:
egarette@silique.fr 2025-05-11 19:12:45 +02:00
parent ece9c98782
commit 125cc9546b
2 changed files with 159 additions and 77 deletions

View file

@ -16,7 +16,6 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
from io import BytesIO from io import BytesIO
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
@ -26,7 +25,11 @@ from ruamel.yaml.representer import RoundTripRepresenter
from ruamel.yaml.tokens import CommentToken from ruamel.yaml.tokens import CommentToken
from ruamel.yaml.error import CommentMark from ruamel.yaml.error import CommentMark
from ruamel.yaml.comments import CommentedSeq from ruamel.yaml.comments import CommentedSeq
from ruamel.yaml.scalarstring import LiteralScalarString, FoldedScalarString, ScalarString from ruamel.yaml.scalarstring import (
LiteralScalarString,
FoldedScalarString,
ScalarString,
)
from djlint.settings import Config from djlint.settings import Config
from djlint.reformat import formatter from djlint.reformat import formatter
@ -34,7 +37,20 @@ from djlint.reformat import formatter
from tiramisu.config import get_common_path from tiramisu.config import get_common_path
from rougail.convert import RougailConvert from rougail.convert import RougailConvert
from rougail.object_model import Variable, Family, Calculation, JinjaCalculation, IdentifierCalculation, IdentifierPropertyCalculation, NamespaceCalculation, IdentifierParam, IndexCalculation, IndexParam, NamespaceParam, Param from rougail.object_model import (
Variable,
Family,
Calculation,
JinjaCalculation,
IdentifierCalculation,
IdentifierPropertyCalculation,
NamespaceCalculation,
IdentifierParam,
IndexCalculation,
IndexParam,
NamespaceParam,
Param,
)
from rougail.utils import normalize_family, undefined from rougail.utils import normalize_family, undefined
from .upgrade import RougailUpgrade from .upgrade import RougailUpgrade
@ -44,15 +60,16 @@ from .__version__ import __version__
def _(text): def _(text):
return text return text
# XXX explicit null # XXX explicit null
def represent_none(self, data): def represent_none(self, data):
return self.represent_scalar('tag:yaml.org,2002:null', 'null') return self.represent_scalar("tag:yaml.org,2002:null", "null")
def represent_str(self, data): def represent_str(self, data):
if data == '': if data == "":
return self.represent_scalar('tag:yaml.org,2002:null', "") return self.represent_scalar("tag:yaml.org,2002:null", "")
return self.represent_scalar('tag:yaml.org,2002:str', data) return self.represent_scalar("tag:yaml.org,2002:str", data)
RoundTripRepresenter.add_representer(type(None), represent_none) RoundTripRepresenter.add_representer(type(None), represent_none)
@ -61,7 +78,7 @@ RoundTripRepresenter.add_representer(str, represent_str)
class RougailOutputFormatter: class RougailOutputFormatter:
output_name = 'formatter' output_name = "formatter"
def __init__( def __init__(
self, self,
@ -79,16 +96,21 @@ class RougailOutputFormatter:
} }
if rougailconfig is None: if rougailconfig is None:
from rougail import RougailConfig from rougail import RougailConfig
rougailconfig = RougailConfig rougailconfig = RougailConfig
rougailconfig["step.output"] = self.output_name rougailconfig["step.output"] = self.output_name
self.rougailconfig = rougailconfig self.rougailconfig = rougailconfig
if self.rougailconfig["step.output"] != self.output_name: if self.rougailconfig["step.output"] != self.output_name:
raise ExtentionError(_('the "step.output" is not set to "{0}"').format(self.output_name)) raise ExtentionError(
_('the "step.output" is not set to "{0}"').format(self.output_name)
)
# yaml.top_level_colon_align = True # yaml.top_level_colon_align = True
self.main_namespace = normalize_family(self.rougailconfig["main_namespace"]) self.main_namespace = normalize_family(self.rougailconfig["main_namespace"])
self.has_default_dictionary_format_version = self.rougailconfig["default_dictionary_format_version"] is not None self.has_default_dictionary_format_version = (
self.rougailconfig["default_dictionary_format_version"] is not None
)
self.config = Config() self.config = Config()
self.config.profile = 'jinja' self.config.profile = "jinja"
self.config.line_break_after_multiline_tag = True self.config.line_break_after_multiline_tag = True
self.config.indent = " " self.config.indent = " "
self.attributes = {} self.attributes = {}
@ -100,14 +122,14 @@ class RougailOutputFormatter:
self.families = {self.main_namespace: CommentedMap()} self.families = {self.main_namespace: CommentedMap()}
self.parse() self.parse()
self.yaml.indent(mapping=2, sequence=4, offset=2) self.yaml.indent(mapping=2, sequence=4, offset=2)
self.yaml.version = '1.2' self.yaml.version = "1.2"
self.yaml.explicit_start = True self.yaml.explicit_start = True
self.yaml.explicit_end = True self.yaml.explicit_end = True
self.default_flow_style = False self.default_flow_style = False
with BytesIO() as ymlfh: with BytesIO() as ymlfh:
families = self.families[self.main_namespace] families = self.families[self.main_namespace]
if not families: if not families:
self.yaml.dump('', ymlfh) self.yaml.dump("", ymlfh)
else: else:
self.yaml.dump(families, ymlfh) self.yaml.dump(families, ymlfh)
ret = ymlfh.getvalue().decode("utf-8").strip() ret = ymlfh.getvalue().decode("utf-8").strip()
@ -115,21 +137,27 @@ class RougailOutputFormatter:
def get_attributes(self, obj, excludes=[]) -> dict: def get_attributes(self, obj, excludes=[]) -> dict:
type_name = obj.__name__ type_name = obj.__name__
if type_name == 'Variable' and excludes == []: if type_name == "Variable" and excludes == []:
raise Exception('pff') raise Exception("pff")
if type_name not in self.attributes: if type_name not in self.attributes:
self.attributes[type_name] = {str(attr): o.default for attr, o in obj.model_fields.items() if str(attr) not in excludes} self.attributes[type_name] = {
str(attr): o.default
for attr, o in obj.model_fields.items()
if str(attr) not in excludes
}
return self.attributes[type_name] return self.attributes[type_name]
def upgrade(self) -> None: def upgrade(self) -> None:
filenames = self.rougailconfig["main_dictionaries"] filenames = self.rougailconfig["main_dictionaries"]
if len(filenames) > 1: if len(filenames) > 1:
raise Exception(_('only one file is allowed')) raise Exception(_("only one file is allowed"))
filename = Path(filenames[0]) filename = Path(filenames[0])
if not filename.is_file(): if not filename.is_file():
raise Exception(_('only a file is allowed')) raise Exception(_("only a file is allowed"))
self.version_name, self.original_yaml = RougailUpgrade(self.rougailconfig).run(filename) self.version_name, self.original_yaml = RougailUpgrade(self.rougailconfig).run(
filename
)
self.version_name, datas = RougailUpgrade(self.rougailconfig).run(filename) self.version_name, datas = RougailUpgrade(self.rougailconfig).run(filename)
self.rougail = RougailConvert(self.rougailconfig) self.rougail = RougailConvert(self.rougailconfig)
self.rougail.load_config() self.rougail.load_config()
@ -157,24 +185,28 @@ class RougailOutputFormatter:
return ret return ret
def parse(self): def parse(self):
self.families[self.main_namespace][self.version_name] = float(self.rougail.version) self.families[self.main_namespace][self.version_name] = float(
self.rougail.version
)
self.remaining = len(self.rougail.paths._data) self.remaining = len(self.rougail.paths._data)
for path, obj in self.rougail.paths._data.items(): for path, obj in self.rougail.paths._data.items():
self.remaining -= 1 self.remaining -= 1
if path == self.rougail.namespace: if path == self.rougail.namespace:
# self.families[path] = self.families[None] # self.families[path] = self.families[None]
continue continue
if isinstance(obj, Family): if isinstance(obj, Family):
self.parse_family(path, obj) self.parse_family(path, obj)
if isinstance(obj, Variable): if isinstance(obj, Variable):
self.parse_variable(path, obj) self.parse_variable(path, obj)
if list(self.families[self.main_namespace]) != [self.version_name]: if list(self.families[self.main_namespace]) != [self.version_name]:
self.families[self.main_namespace].yaml_value_comment_extend(self.version_name, [CommentToken('\n\n', CommentMark(0)), None]) self.families[self.main_namespace].yaml_value_comment_extend(
self.version_name, [CommentToken("\n\n", CommentMark(0)), None]
)
if self.has_default_dictionary_format_version: if self.has_default_dictionary_format_version:
del self.families[self.main_namespace][self.version_name] del self.families[self.main_namespace][self.version_name]
def parse_family(self, path, obj): def parse_family(self, path, obj):
children = [p.rsplit('.', 1)[-1] for p in self.rougail.parents[path]] children = [p.rsplit(".", 1)[-1] for p in self.rougail.parents[path]]
parent, name = self.get_parent_name(path) parent, name = self.get_parent_name(path)
ret = self.families[parent] ret = self.families[parent]
family = CommentedMap() family = CommentedMap()
@ -202,27 +234,29 @@ class RougailOutputFormatter:
if attr != "type" and attr not in force_keys and value == default_value: if attr != "type" and attr not in force_keys and value == default_value:
continue continue
if attr in children: if attr in children:
attr = f'_{attr}' attr = f"_{attr}"
value = self.object_to_yaml(attr, type_, value, False, path) value = self.object_to_yaml(attr, type_, value, False, path)
family[attr] = value family[attr] = value
if type_ == "dynamic" or (children and type_ == 'family'): if type_ == "dynamic" or (children and type_ == "family"):
if "_type" in family: if "_type" in family:
del family["_type"] del family["_type"]
else: else:
del family["type"] del family["type"]
if not set(family): if not set(family):
ret[name] = CommentedMap() ret[name] = CommentedMap()
ret.yaml_value_comment_extend(name, [CommentToken('\n\n', CommentMark(0)), None]) ret.yaml_value_comment_extend(
elif not set(family) - {'description'}: name, [CommentToken("\n\n", CommentMark(0)), None]
)
elif not set(family) - {"description"}:
# #
ret[name] = CommentedMap() ret[name] = CommentedMap()
add_column = 3 add_column = 3
path_len = path.count('.') path_len = path.count(".")
if self.rougail.namespace: if self.rougail.namespace:
path_len -= 1 path_len -= 1
column = path_len * 2 + len(name) + add_column column = path_len * 2 + len(name) + add_column
if self.remaining: if self.remaining:
description = family["description"] + '\n\n' description = family["description"] + "\n\n"
else: else:
description = family["description"] description = family["description"]
ret.yaml_add_eol_comment(description, name, column=column) ret.yaml_add_eol_comment(description, name, column=column)
@ -246,7 +280,9 @@ class RougailOutputFormatter:
force_keys = list(yaml_data) force_keys = list(yaml_data)
multi = obj.multi or isinstance(obj.default, list) multi = obj.multi or isinstance(obj.default, list)
type_ = obj.type type_ = obj.type
for attr, default_value in self.get_attributes(self.rougail.variable, ["name", "path", "namespace", "version", "xmlfiles"]).items(): for attr, default_value in self.get_attributes(
self.rougail.variable, ["name", "path", "namespace", "version", "xmlfiles"]
).items():
try: try:
value = getattr(obj, attr) value = getattr(obj, attr)
except AttributeError: except AttributeError:
@ -255,36 +291,54 @@ class RougailOutputFormatter:
continue continue
value = self.object_to_yaml(attr, type_, value, multi, path) value = self.object_to_yaml(attr, type_, value, multi, path)
variable[attr] = value variable[attr] = value
if variable.get("mandatory") is True and None not in variable.get("choices", []): if variable.get("mandatory") is True and None not in variable.get(
"choices", []
):
del variable["mandatory"] del variable["mandatory"]
if "default" in variable: if "default" in variable:
if "type" in variable and variable["type"] in ["string", "boolean", "number", "float"]: if "type" in variable and variable["type"] in [
"string",
"boolean",
"number",
"float",
]:
if variable["default"] and isinstance(variable["default"], list): if variable["default"] and isinstance(variable["default"], list):
tested_value = variable["default"][0] tested_value = variable["default"][0]
else: else:
tested_value = variable["default"] tested_value = variable["default"]
if variable["type"] == self.basic_types.get(type(tested_value), None): if variable["type"] == self.basic_types.get(type(tested_value), None):
del variable["type"] del variable["type"]
if "multi" in variable and variable["multi"] is True and isinstance(variable["default"], list): if (
"multi" in variable
and variable["multi"] is True
and isinstance(variable["default"], list)
):
del variable["multi"] del variable["multi"]
elif variable.get("type") == "choice" and "choices" in variable: elif variable.get("type") == "choice" and "choices" in variable:
del variable["type"] del variable["type"]
elif variable.get("type") == "string": elif variable.get("type") == "string":
# default type is string # default type is string
del variable["type"] del variable["type"]
if set(variable) in [{"multi"}, {'multi', 'description'}]: if set(variable) in [{"multi"}, {"multi", "description"}]:
variable["default"] = [] variable["default"] = []
variable.pop("multi") variable.pop("multi")
elif variable.get("type") == "boolean" and not multi: elif variable.get("type") == "boolean" and not multi:
# if boolean, the default value is True # if boolean, the default value is True
del variable["type"] del variable["type"]
variable["default"] = True variable["default"] = True
if "default" not in variable and variable.get("multi") is True and not set(variable) - {'default', 'description', "multi"}: if (
"default" not in variable
and variable.get("multi") is True
and not set(variable) - {"default", "description", "multi"}
):
variable["default"] = [] variable["default"] = []
del(variable['multi']) del variable["multi"]
if not isinstance(variable.get("default"), dict) and not set(variable) - {'default', 'description'}: if not isinstance(variable.get("default"), dict) and not set(variable) - {
"default",
"description",
}:
# shorthand notation # shorthand notation
default = variable.get('default') default = variable.get("default")
ret[name] = default ret[name] = default
add_column = 3 add_column = 3
if isinstance(default, list): if isinstance(default, list):
@ -303,7 +357,7 @@ class RougailOutputFormatter:
description = variable["description"] description = variable["description"]
if self.remaining and (not multi or not default): if self.remaining and (not multi or not default):
description += "\n\n" description += "\n\n"
path_len = path.count('.') path_len = path.count(".")
if self.rougail.namespace: if self.rougail.namespace:
path_len -= 1 path_len -= 1
column = path_len * 2 + len(name) + add_column column = path_len * 2 + len(name) + add_column
@ -322,18 +376,19 @@ class RougailOutputFormatter:
def _get_last_obj(o, parent, param, typ): def _get_last_obj(o, parent, param, typ):
if isinstance(o, CommentedMap): if isinstance(o, CommentedMap):
param = list(o)[-1] param = list(o)[-1]
return _get_last_obj(o[param], o, param, 'map') return _get_last_obj(o[param], o, param, "map")
if isinstance(o, CommentedSeq): if isinstance(o, CommentedSeq):
param = len(o) - 1 param = len(o) - 1
return _get_last_obj(o[param], o, param, 'seq') return _get_last_obj(o[param], o, param, "seq")
return typ, parent, param return typ, parent, param
param = list(obj)[-1] param = list(obj)[-1]
if isinstance(obj[param], ScalarString): if isinstance(obj[param], ScalarString):
enter = '\n' enter = "\n"
else: else:
enter = '\n\n' enter = "\n\n"
typ, parent, param = _get_last_obj(obj[param], obj, param, 'map') typ, parent, param = _get_last_obj(obj[param], obj, param, "map")
if typ == 'seq': if typ == "seq":
func = parent.yaml_key_comment_extend func = parent.yaml_key_comment_extend
else: else:
func = parent.yaml_value_comment_extend func = parent.yaml_value_comment_extend
@ -342,13 +397,13 @@ class RougailOutputFormatter:
def object_to_yaml(self, key, type_, value, multi, object_path): def object_to_yaml(self, key, type_, value, multi, object_path):
if isinstance(value, list): if isinstance(value, list):
if key == 'params': if key == "params":
new_values = CommentedMap() new_values = CommentedMap()
else: else:
new_values = CommentedSeq() new_values = CommentedSeq()
for v in value: for v in value:
new_value = self.object_to_yaml(key, type_, v, multi, object_path) new_value = self.object_to_yaml(key, type_, v, multi, object_path)
if key == 'params': if key == "params":
new_values.update(new_value) new_values.update(new_value)
else: else:
new_values.append(new_value) new_values.append(new_value)
@ -356,33 +411,49 @@ class RougailOutputFormatter:
if isinstance(value, JinjaCalculation): if isinstance(value, JinjaCalculation):
jinja = CommentedMap() jinja = CommentedMap()
jinja_values = formatter(self.config, value.jinja.strip())[:-1] jinja_values = formatter(self.config, value.jinja.strip())[:-1]
if key == 'default' and not multi: if key == "default" and not multi:
jinja["jinja"] = FoldedScalarString(jinja_values) jinja["jinja"] = FoldedScalarString(jinja_values)
fold_pos = [] fold_pos = []
old_i = 0 old_i = 0
for i, ltr in enumerate(jinja_values): for i, ltr in enumerate(jinja_values):
if ltr == '\n': if ltr == "\n":
fold_pos.append(i - old_i) fold_pos.append(i - old_i)
old_i = 1 old_i = 1
jinja["jinja"].fold_pos = fold_pos jinja["jinja"].fold_pos = fold_pos
elif key == 'secret_manager': elif key == "secret_manager":
return self.object_to_yaml("params", type_, value.params, multi, object_path) return self.object_to_yaml(
"params", type_, value.params, multi, object_path
)
else: else:
jinja["jinja"] = LiteralScalarString(jinja_values) jinja["jinja"] = LiteralScalarString(jinja_values)
if value.return_type: if value.return_type:
jinja["return_type"] = value.return_type jinja["return_type"] = value.return_type
if value.description: if value.description:
if '\n' in value.description: if "\n" in value.description:
jinja["description"] = LiteralScalarString(value.description) jinja["description"] = LiteralScalarString(value.description)
else: else:
jinja["description"] = value.description jinja["description"] = value.description
if value.params: if value.params:
jinja["params"] = self.object_to_yaml("params", type_, value.params, multi, object_path) jinja["params"] = self.object_to_yaml(
"params", type_, value.params, multi, object_path
)
return jinja return jinja
elif isinstance(value, Calculation): elif isinstance(value, Calculation):
variable_attributes = self.get_attributes(value.__class__, ['path', 'inside_list', 'version', 'xmlfiles', 'attribute_name', 'namespace']) variable_attributes = self.get_attributes(
value.__class__,
[
"path",
"inside_list",
"version",
"xmlfiles",
"attribute_name",
"namespace",
],
)
variable = CommentedMap() variable = CommentedMap()
if isinstance(value, (IdentifierCalculation, IdentifierPropertyCalculation)): if isinstance(
value, (IdentifierCalculation, IdentifierPropertyCalculation)
):
variable["type"] = "identifier" variable["type"] = "identifier"
elif isinstance(value, IndexCalculation): elif isinstance(value, IndexCalculation):
variable["type"] = "index" variable["type"] = "index"
@ -393,18 +464,22 @@ class RougailOutputFormatter:
if val != default and val is not undefined: if val != default and val is not undefined:
variable[key] = val variable[key] = val
if "variable" in variable: if "variable" in variable:
variable["variable"] = self.calc_variable_path(object_path, variable["variable"]) variable["variable"] = self.calc_variable_path(
if variable.get('type') == 'identifier' and 'identifier' in variable: object_path, variable["variable"]
)
if variable.get("type") == "identifier" and "identifier" in variable:
del variable["type"] del variable["type"]
if value.description: if value.description:
if '\n' in value.description: if "\n" in value.description:
variable["description"] = LiteralScalarString(value.description) variable["description"] = LiteralScalarString(value.description)
else: else:
variable["description"] = value.description variable["description"] = value.description
return variable return variable
elif isinstance(value, Param): elif isinstance(value, Param):
param_attributes = self.get_attributes(value.__class__, ["type", "key", "namespace"]) param_attributes = self.get_attributes(
if list(param_attributes) == ['value']: value.__class__, ["type", "key", "namespace"]
)
if list(param_attributes) == ["value"]:
variable = value.value variable = value.value
else: else:
variable = CommentedMap() variable = CommentedMap()
@ -418,14 +493,16 @@ class RougailOutputFormatter:
val = getattr(value, key) val = getattr(value, key)
if val != default and val is not undefined: if val != default and val is not undefined:
variable[key] = val variable[key] = val
if variable.get('type') == 'identifier' and 'identifier' in variable: if variable.get("type") == "identifier" and "identifier" in variable:
del variable["type"] del variable["type"]
if "variable" in variable: if "variable" in variable:
variable["variable"] = self.calc_variable_path(object_path, variable["variable"]) variable["variable"] = self.calc_variable_path(
object_path, variable["variable"]
)
return {value.key: variable} return {value.key: variable}
elif type_ == 'port' and isinstance(value, str) and value.isnumeric(): elif type_ == "port" and isinstance(value, str) and value.isnumeric():
return int(value) return int(value)
elif key == 'help' and '\n' in value: elif key == "help" and "\n" in value:
return LiteralScalarString(value) return LiteralScalarString(value)
return value return value
@ -438,8 +515,12 @@ class RougailOutputFormatter:
else: else:
len_common_path = len(common_path) + 1 len_common_path = len(common_path) + 1
relative_object_path = object_path[len_common_path:] relative_object_path = object_path[len_common_path:]
final_path = "_" * (relative_object_path.count(".") + 1) + '.' final_path = "_" * (relative_object_path.count(".") + 1) + "."
return "_" * (relative_object_path.count(".") + 1) + '.' + variable_path[len_common_path:] return (
"_" * (relative_object_path.count(".") + 1)
+ "."
+ variable_path[len_common_path:]
)
return variable_path return variable_path
def get_parent_name(self, path): def get_parent_name(self, path):
@ -452,16 +533,17 @@ class RougailOutputFormatter:
if not subpath: if not subpath:
return y return y
name = subpath.pop(0) name = subpath.pop(0)
if name not in y and name.endswith('{{ identifier }}'): if name not in y and name.endswith("{{ identifier }}"):
search_name = name[:-16] search_name = name[:-16]
if search_name not in y: if search_name not in y:
search_name = name.replace("{{ identifier }}", "{{ suffix }}") search_name = name.replace("{{ identifier }}", "{{ suffix }}")
name = search_name name = search_name
return _yaml(y[name]) return _yaml(y[name])
if self.main_namespace: if self.main_namespace:
subpath = path.split('.')[1:] subpath = path.split(".")[1:]
else: else:
subpath = path.split('.') subpath = path.split(".")
return _yaml(self.original_yaml) return _yaml(self.original_yaml)

View file

@ -51,12 +51,12 @@ class RougailUpgrade:
root = YAML().load(file_fh) root = YAML().load(file_fh)
if not root: if not root:
root = {} root = {}
if '_version' in root: if "_version" in root:
version_name = '_version' version_name = "_version"
format_version = str(root.pop('_version')) format_version = str(root.pop("_version"))
elif 'version' in root: elif "version" in root:
version_name = 'version' version_name = "version"
format_version = str(root.pop('version')) format_version = str(root.pop("version"))
else: else:
version_name = None version_name = None
format_version = self.rougailconfig["default_dictionary_format_version"] format_version = self.rougailconfig["default_dictionary_format_version"]
@ -80,7 +80,7 @@ class RougailUpgrade:
new_root = CommentedMap() new_root = CommentedMap()
for key, value in root.items(): for key, value in root.items():
if not isinstance(value, dict): if not isinstance(value, dict):
if key == 'variable' and "{{ suffix }}" in value: if key == "variable" and "{{ suffix }}" in value:
value = value.replace("{{ suffix }}", "{{ identifier }}") value = value.replace("{{ suffix }}", "{{ identifier }}")
new_root[key] = value new_root[key] = value
continue continue