diff --git a/src/rougail/output_display/__init__.py b/src/rougail/output_display/__init__.py
index 55087656..75fb86d8 100644
--- a/src/rougail/output_display/__init__.py
+++ b/src/rougail/output_display/__init__.py
@@ -1,7 +1,7 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2025-2026
-
+
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
@@ -15,6 +15,7 @@ details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
"""
+
from .display import RougailOutputDisplay
from .__version__ import __version__
diff --git a/src/rougail/output_display/config.py b/src/rougail/output_display/config.py
index 04ecb36a..4fc39aee 100644
--- a/src/rougail/output_display/config.py
+++ b/src/rougail/output_display/config.py
@@ -41,9 +41,9 @@ def get_outputs() -> None:
level = obj_class.level
if level in outputs:
raise ImportError(
- _('duplicated level in rougail-output-display for output "{0}": {1} and {2}').format(
- level, obj_class.name, outputs[level].name
- )
+ _(
+ 'duplicated level in rougail-output-display for output "{0}": {1} and {2}'
+ ).format(level, obj_class.name, outputs[level].name)
)
if obj_class.name in names:
raise ImportError(
diff --git a/src/rougail/output_display/display.py b/src/rougail/output_display/display.py
index a639c754..a500826f 100644
--- a/src/rougail/output_display/display.py
+++ b/src/rougail/output_display/display.py
@@ -20,7 +20,12 @@ from typing import Optional, Any
from ruamel.yaml import YAML
from io import BytesIO
-from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError, AttributeOptionError
+from tiramisu.error import (
+ PropertiesOptionError,
+ LeadershipError,
+ ConfigError,
+ AttributeOptionError,
+)
from tiramisu import owners, groups
from .config import OutPuts
@@ -43,6 +48,7 @@ class RougailOutputDisplay:
) -> None:
if rougailconfig is None:
from rougail import RougailConfig
+
rougailconfig = RougailConfig
self.rougailconfig = rougailconfig
self.config = config
@@ -61,7 +67,7 @@ class RougailOutputDisplay:
if user_data_warnings is None:
user_data_warnings = []
self.user_data_warnings = user_data_warnings
-# self.out = []
+ # self.out = []
self.nodes = None
self.yaml = YAML()
self.yaml.indent(mapping=2, sequence=4, offset=2)
@@ -75,27 +81,36 @@ class RougailOutputDisplay:
errors_warnings_dict = {}
if not errors and self.nodes is None:
show_secrets = self.rougailconfig["display.show_secrets"]
- self.nodes = Node(self.yaml, show_secrets, self.config, self.root_config, self.config_owner_is_path, errors)
+ self.nodes = Node(
+ self.yaml,
+ show_secrets,
+ self.config,
+ self.root_config,
+ self.config_owner_is_path,
+ errors,
+ )
if warnings:
level = "warnings"
- #output.display_warnings(errors_warnings_dict, warnings)
+ # output.display_warnings(errors_warnings_dict, warnings)
for warning in warnings:
- output.error_warn_to_dict(warning, errors_warnings_dict, 'warning')
+ output.error_warn_to_dict(warning, errors_warnings_dict, "warning")
if errors:
level = "errors"
for error in errors:
- output.error_warn_to_dict(error, errors_warnings_dict, 'error')
+ output.error_warn_to_dict(error, errors_warnings_dict, "error")
if level:
if level == "errors":
tree = output.error_header()
else:
tree = output.warning_header()
- ret = output.parse_error_warning(tree, errors_warnings_dict, output.display_error, level)
+ ret = output.parse_error_warning(
+ tree, errors_warnings_dict, output.display_error, level
+ )
if errors:
return False, ret
ret += "\n"
else:
- ret = ''
+ ret = ""
code, run = output.run(self.nodes, self.layer_datas)
return code, ret + run
@@ -116,10 +131,10 @@ class Node:
errors,
*,
node=None,
- values: Optional[dict]=None,
- level: int=0,
- leader_index: Optional[int]=None,
- ) -> None:
+ values: Optional[dict] = None,
+ level: int = 0,
+ leader_index: Optional[int] = None,
+ ) -> None:
self.yaml = yaml
self.show_secrets = show_secrets
self.config = config
@@ -141,7 +156,9 @@ class Node:
if node and node.isoptiondescription() and node.isleadership():
values_iter = iter(values.items())
leader, leader_values = next(values_iter)
- followers_values = {idx: {leader: value} for idx, value in enumerate(leader_values)}
+ followers_values = {
+ idx: {leader: value} for idx, value in enumerate(leader_values)
+ }
for follower, follower_value in values_iter:
followers_values[follower.index()][follower] = follower_value
for idx, fvalues in enumerate(followers_values.values()):
@@ -174,25 +191,33 @@ class Node:
option,
values,
*,
- leader_index: Optional[int]=None,
- ) -> 'Node':
- self.children.append({"type": "node",
- "node": Node(
- self.yaml,
- self.show_secrets,
- self.config,
- self.root_config,
- self.config_owner_is_path,
- self.errors,
- node=option,
- values=values,
- level=self.level + 1,
- leader_index=leader_index,
- ),
- })
+ leader_index: Optional[int] = None,
+ ) -> "Node":
+ self.children.append(
+ {
+ "type": "node",
+ "node": Node(
+ self.yaml,
+ self.show_secrets,
+ self.config,
+ self.root_config,
+ self.config_owner_is_path,
+ self.errors,
+ node=option,
+ values=values,
+ level=self.level + 1,
+ leader_index=leader_index,
+ ),
+ }
+ )
def add_leaf(
- self, option, value: Any, *, leader_index: Optional[int] = None, description: Optional[str] = None
+ self,
+ option,
+ value: Any,
+ *,
+ leader_index: Optional[int] = None,
+ description: Optional[str] = None,
):
properties = option.property.get()
if description is None:
@@ -200,15 +225,23 @@ class Node:
icon = "leaf"
else:
icon = "node"
- self.children.append({"type": "leaf",
- "description": description,
- "values": self.get_values(option, value, leader_index, properties),
- "icon": icon,
- "hidden": "hidden" in properties,
- },
- )
+ self.children.append(
+ {
+ "type": "leaf",
+ "description": description,
+ "values": self.get_values(option, value, leader_index, properties),
+ "icon": icon,
+ "hidden": "hidden" in properties,
+ },
+ )
- def get_values(self, option: "Option", value: Any, leader_index: Optional[int], properties: list[str]) -> None:
+ def get_values(
+ self,
+ option: "Option",
+ value: Any,
+ leader_index: Optional[int],
+ properties: list[str],
+ ) -> None:
if option.isoptiondescription():
return [{"is_default": True, "value": value, "loaded_from": None}]
values = []
@@ -219,7 +252,7 @@ class Node:
loaded_from_key = f"loaded_from_{index}"
else:
loaded_from_key = "loaded_from"
- #default = option.owner.isdefault() or not option.information.get("default_value_makes_sense", True)
+ # default = option.owner.isdefault() or not option.information.get("default_value_makes_sense", True)
force_store_value = "force_store_value" in properties
is_default = option.owner.isdefault()
option_path = option.path()
@@ -230,7 +263,7 @@ class Node:
else:
true_default = is_default and meta_option.owner.get() == default_owner
added = not is_default or true_default
- secret_manager = option.information.get('secret_manager', False)
+ secret_manager = option.information.get("secret_manager", False)
while True:
if values and true_default and (value in [None, []] or secret_manager):
break
@@ -256,7 +289,9 @@ class Node:
if is_default and (not meta_config_path or "." not in meta_config_path):
# we are in root metaconfig and we have default value
break
- new_meta_config = self.get_metaconfig_with_default_value(meta_config, meta_option)
+ new_meta_config = self.get_metaconfig_with_default_value(
+ meta_config, meta_option
+ )
if not new_meta_config:
break
meta_option = new_meta_config.option(option_path, index)
@@ -297,11 +332,7 @@ class Node:
value: Any,
) -> str:
"""Dump variable, means transform bool, ... to yaml string"""
- if (
- value is not None
- and not self.show_secrets
- and option.type() == "password"
- ):
+ if value is not None and not self.show_secrets and option.type() == "password":
return "*" * 10
if isinstance(value, str):
return value
@@ -322,7 +353,7 @@ class Node:
return self.config
if not self.config_owner_is_path:
while True:
- if meta_config.type() != 'metaconfig':
+ if meta_config.type() != "metaconfig":
return None
meta_config = meta_config.parent()
if not meta_config.owner.isdefault():
diff --git a/src/rougail/output_display/output/console.py b/src/rougail/output_display/output/console.py
index 60bb76be..a0323b68 100644
--- a/src/rougail/output_display/output/console.py
+++ b/src/rougail/output_display/output/console.py
@@ -1,7 +1,7 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2022-2026
-
+
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
@@ -33,7 +33,7 @@ class OutputFamily(CommonOutput):
value_unmodified_color = "gold1"
value_modified_color = "green"
value_default_color = None
- error_color = 'bright_red'
+ error_color = "bright_red"
error_icon = "stop_sign"
warning_color = "bright_yellow"
warning_icon = "bell"
@@ -56,14 +56,23 @@ class OutputFamily(CommonOutput):
if self.variable_default_enable:
caption_line += _("Variable") + "\n"
if self.variable_hidden_enable:
- caption_line += self.set_color(self.variable_hidden_color, _("Unmodifiable variable")) + "\n"
+ caption_line += (
+ self.set_color(self.variable_hidden_color, _("Unmodifiable variable"))
+ + "\n"
+ )
header_value = ""
if self.value_unmodified_enable:
- header_value += self.set_color(self.value_unmodified_color, _("Default value")) + "\n"
+ header_value += (
+ self.set_color(self.value_unmodified_color, _("Default value")) + "\n"
+ )
if self.value_modified_enable:
- header_value += self.set_color(self.value_modified_color, _("Modified value")) + "\n"
+ header_value += (
+ self.set_color(self.value_modified_color, _("Modified value")) + "\n"
+ )
if self.value_default_enable:
- header_value += f'(:hourglass_flowing_sand: {_("Original default value")})\n'
+ header_value += (
+ f'(:hourglass_flowing_sand: {_("Original default value")})\n'
+ )
caption = Table.grid(padding=1, collapse_padding=True)
caption.pad_edge = False
caption.add_row(caption_line[:-1], header_value[:-1])
@@ -82,7 +91,7 @@ class OutputFamily(CommonOutput):
f"[bold][{self.error_color}]:{self.error_icon}: {_('Caution')}[/{self.error_color}][/bold]",
guide_style=f"bold {self.error_color}",
)
-# self.out.append(tree)
+ # self.out.append(tree)
return tree
def display_error(self, level, tree, msg, default_color):
@@ -92,7 +101,7 @@ class OutputFamily(CommonOutput):
color = self.warning_color
if isinstance(msg, tuple):
if len(msg) == 3:
- if msg[2] == 'error':
+ if msg[2] == "error":
color = self.error_color
icon = self.error_icon
else:
@@ -100,19 +109,19 @@ class OutputFamily(CommonOutput):
icon = self.warning_icon
msg = f"{msg[0]}: [{color}]:{icon}: {msg[1]}[/{color}]"
else:
- if msg[1] == 'error':
+ if msg[1] == "error":
icon = self.error_icon
else:
color = self.warning_color
icon = self.warning_icon
msg = f"[{color}]:{icon}: {msg[0]}[/{color}]"
- tree.guide_style = f'bold {color}'
+ tree.guide_style = f"bold {color}"
return tree.add(msg, guide_style=f"bold {color}")
def display(self, tree):
console = Console(force_terminal=True, width=self.max_width)
with console.capture() as capture:
- console.print(tree)
+ console.print(tree)
return capture.get()
def warning_header(self):
@@ -120,21 +129,27 @@ class OutputFamily(CommonOutput):
f"[bold][{self.warning_color}]:{self.warning_icon}: {_('Warning')}[/{self.warning_color}][/bold]",
guide_style=f"bold {self.warning_color}",
)
-# self.out.append(tree)
+ # self.out.append(tree)
return tree
-#
-# def display_warning(self, level, tree, msg):
-# if isinstance(msg, tuple):
-# msg = f"{msg[0]}: [{self.warning_color}]:{self.warning_icon}: {msg[1]}[/{self.warning_color}]"
-# return tree.add(msg, guide_style=f"bold {self.warning_color}")
+
+ #
+ # def display_warning(self, level, tree, msg):
+ # if isinstance(msg, tuple):
+ # msg = f"{msg[0]}: [{self.warning_color}]:{self.warning_icon}: {msg[1]}[/{self.warning_color}]"
+ # return tree.add(msg, guide_style=f"bold {self.warning_color}")
def add_variable(
- self, parent, description, value, icon, level,
+ self,
+ parent,
+ description,
+ value,
+ icon,
+ level,
):
- if icon == 'leaf':
- icon = 'notebook'
+ if icon == "leaf":
+ icon = "notebook"
else:
- icon = 'open_file_folder'
+ icon = "open_file_folder"
if isinstance(value, list):
subtree = parent.add(
f":{icon}: " + _("{0}:").format(description),
@@ -150,13 +165,13 @@ class OutputFamily(CommonOutput):
return msg
return f"[{color}]{msg}[/{color}]"
-
def get_parent(self, parent, description, level):
if parent is None:
- return Tree(description,
- guide_style=self.guide_style,
- )
+ return Tree(
+ description,
+ guide_style=self.guide_style,
+ )
return parent.add(
- f":open_file_folder: {description}",
- guide_style=self.guide_style,
- )
+ f":open_file_folder: {description}",
+ guide_style=self.guide_style,
+ )
diff --git a/src/rougail/output_display/output/github.py b/src/rougail/output_display/output/github.py
index a1f1e6f0..be16f9ee 100644
--- a/src/rougail/output_display/output/github.py
+++ b/src/rougail/output_display/output/github.py
@@ -1,7 +1,7 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2025-2026
-
+
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
@@ -42,12 +42,18 @@ class OutputFamily(CommonOutput):
if self.variable_default_enable:
variables.append(_("Variable"))
if self.variable_hidden_enable:
- variables.append(self.set_color(self.variable_hidden_color, _("Unmodifiable variable")))
+ variables.append(
+ self.set_color(self.variable_hidden_color, _("Unmodifiable variable"))
+ )
values = []
if self.value_unmodified_enable:
- values.append(self.set_color(self.value_unmodified_color, _("Default value")))
+ values.append(
+ self.set_color(self.value_unmodified_color, _("Default value"))
+ )
if self.value_modified_enable:
- values.append(self.set_color(self.value_modified_color, _("Modified value")))
+ values.append(
+ self.set_color(self.value_modified_color, _("Modified value"))
+ )
if self.value_default_enable:
values.append(f'(:hourglass_flowing_sand: {_("Original default value")})')
if not variables and not values:
@@ -68,14 +74,14 @@ class OutputFamily(CommonOutput):
def title(self, msg):
caption = "> [!NOTE]" + "\n>\n"
- caption += f'> **{msg}**\n'
+ caption += f"> **{msg}**\n"
return caption
-
+
def error_header(self):
- return ['> [!CAUTION]\n> ']
+ return ["> [!CAUTION]\n> "]
def warning_header(self):
- return ['> [!WARNING]\n> ']
+ return ["> [!WARNING]\n> "]
def error_end(self):
self.out[-1] += "\n"
@@ -93,7 +99,7 @@ class OutputFamily(CommonOutput):
color = self.warning_color
if isinstance(msg, tuple):
if len(msg) == 3:
- if msg[2] == 'error':
+ if msg[2] == "error":
color = self.error_color
icon = self.error_icon
else:
@@ -101,7 +107,7 @@ class OutputFamily(CommonOutput):
icon = self.warning_icon
msg = f"{msg[0]}: :{icon}: {self.set_color(color, msg[1])}"
else:
- if msg[1] == 'error':
+ if msg[1] == "error":
icon = self.error_icon
else:
color = self.warning_color
@@ -111,17 +117,22 @@ class OutputFamily(CommonOutput):
return tree
def add_variable(
- self, parent, description, value, icon, level,
+ self,
+ parent,
+ description,
+ value,
+ icon,
+ level,
):
if parent is None:
parent = []
- if icon == 'leaf':
- icon = 'notebook'
+ if icon == "leaf":
+ icon = "notebook"
else:
- icon = 'open_file_folder'
+ icon = "open_file_folder"
before = " " * (level - 1) * 2 + "- "
if isinstance(value, list):
- description = description.replace('◀', '←')
+ description = description.replace("◀", "←")
subtree = parent.append(
f"{before}:{icon}: " + _("{0}:").format(description),
)
@@ -129,7 +140,9 @@ class OutputFamily(CommonOutput):
for val in value:
parent.append(before + str(val))
else:
- parent.append(before + f":{icon}: " + _("{0}: {1}").format(description, value))
+ parent.append(
+ before + f":{icon}: " + _("{0}: {1}").format(description, value)
+ )
def set_color(self, color, msg):
if not color:
@@ -150,5 +163,7 @@ class OutputFamily(CommonOutput):
parent = []
parent.append(description)
else:
- parent.append(" " * (level - 1) * 2 + "- " + ":open_file_folder: " + description)
+ parent.append(
+ " " * (level - 1) * 2 + "- " + ":open_file_folder: " + description
+ )
return parent
diff --git a/src/rougail/output_display/output/gitlab.py b/src/rougail/output_display/output/gitlab.py
index 8f7e204f..5e8acf30 100644
--- a/src/rougail/output_display/output/gitlab.py
+++ b/src/rougail/output_display/output/gitlab.py
@@ -1,7 +1,7 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2025-2026
-
+
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
@@ -32,7 +32,7 @@ class OutputFamily(GHOutputFamily):
def set_color(self, color, msg):
if not color:
return msg
- return f'[{color} {msg} {color}]'
+ return f"[{color} {msg} {color}]"
def title(self, msg):
return f"> [!note] {msg}" + "\n>\n"
diff --git a/src/rougail/output_display/util.py b/src/rougail/output_display/util.py
index 831559e9..0edce26a 100644
--- a/src/rougail/output_display/util.py
+++ b/src/rougail/output_display/util.py
@@ -1,7 +1,7 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2022-2026
-
+
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
@@ -15,6 +15,7 @@ details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
"""
+
from typing import Any, Optional
# from tiramisu import owners
@@ -28,7 +29,7 @@ class CommonOutput:
def __init__(
self,
rougailconfig,
- ) -> None:
+ ) -> None:
self.set_config(rougailconfig)
self.variable_default_enable = False
self.variable_hidden_enable = False
@@ -44,7 +45,7 @@ class CommonOutput:
if nodes.children:
root = self.parse(nodes)
return self._run(root)
- return 0, ''
+ return 0, ""
def parse(self, node, parent=None, level=0):
if node.hidden:
@@ -55,18 +56,18 @@ class CommonOutput:
self.variable_default_enable = True
color = self.variable_normal_color
family_output = self.colorize(
- [
- {
- "value": node.description,
- "color": color,
- "loaded_from": None,
- }
- ]
- )
+ [
+ {
+ "value": node.description,
+ "color": color,
+ "loaded_from": None,
+ }
+ ]
+ )
subparent = self.get_parent(parent, family_output, level)
for child in node.children:
if child["type"] == "node":
- self.parse(child["node"], subparent, level+1)
+ self.parse(child["node"], subparent, level + 1)
else:
if child["hidden"]:
self.variable_hidden_enable = True
@@ -87,15 +88,17 @@ class CommonOutput:
child["values"],
)
description = self.colorize(
- [
- {
- "value": child["description"],
- "color": variable_color,
- "loaded_from": None,
- }
- ]
- )
- self.add_variable(subparent, description, value, child["icon"], level+1)
+ [
+ {
+ "value": child["description"],
+ "color": variable_color,
+ "loaded_from": None,
+ }
+ ]
+ )
+ self.add_variable(
+ subparent, description, value, child["icon"], level + 1
+ )
return subparent
def header(self):
@@ -105,12 +108,14 @@ class CommonOutput:
if isinstance(error, dict):
for msg, subconfig in error.items():
description = subconfig.option.impl_get_display_name(subconfig)
- self.subconfig_to_dict(subconfig, errors_dict).setdefault(None, {}).setdefault(description, []).append((msg, level))
+ self.subconfig_to_dict(subconfig, errors_dict).setdefault(
+ None, {}
+ ).setdefault(description, []).append((msg, level))
else:
errors_dict.setdefault(None, []).append(error)
def subconfig_to_dict(self, subconfig: "Subconfig", errors_dict: dict) -> dict:
- #FIXME a tester : mandatories dans une arborescence (voir si ca n'ecrase pas)
+ # FIXME a tester : mandatories dans une arborescence (voir si ca n'ecrase pas)
parents = []
parent = subconfig
while True:
@@ -131,18 +136,26 @@ class CommonOutput:
def _parse_error_warning(self, tree, error, display, level, default_color):
if isinstance(error, list):
for err in error:
- self._parse_error_warning(tree, err, display, level+1, default_color)
+ self._parse_error_warning(tree, err, display, level + 1, default_color)
elif isinstance(error, dict):
for key, value in error.items():
if key is None:
# it's variables, no more families
- self._parse_error_warning(tree, value, display, level, default_color)
+ self._parse_error_warning(
+ tree, value, display, level, default_color
+ )
else:
if isinstance(value, list) and len(value) == 1:
- self._parse_error_warning(tree, (key, *value[0]), display, level+1, default_color)
+ self._parse_error_warning(
+ tree, (key, *value[0]), display, level + 1, default_color
+ )
else:
- sub_tree = self._parse_error_warning(tree, key, display, level+1, default_color)
- self._parse_error_warning(sub_tree, value, display, level+1, default_color)
+ sub_tree = self._parse_error_warning(
+ tree, key, display, level + 1, default_color
+ )
+ self._parse_error_warning(
+ sub_tree, value, display, level + 1, default_color
+ )
else:
return display(level, tree, error, default_color)
@@ -153,7 +166,7 @@ class CommonOutput:
self,
family,
level,
- ) -> 'OutputFamily':
+ ) -> "OutputFamily":
properties = family.property.get()
if "hidden" in properties:
self.root_family.variable_hidden_enable = True
@@ -162,20 +175,20 @@ class CommonOutput:
self.root_family.variable_default_enable = True
color = None
family_output = self.colorize(
- [
- {
- "value": family.description(),
- "color": color,
- "loaded_from": None,
- }
- ]
- )
+ [
+ {
+ "value": family.description(),
+ "color": color,
+ "loaded_from": None,
+ }
+ ]
+ )
return self.__class__(
family_output,
self.get_tree(),
self.root,
level + 1,
- root_family = self.root_family,
+ root_family=self.root_family,
)
def colorize(