test
This commit is contained in:
parent
62fb0eab60
commit
55dab35d29
8 changed files with 156 additions and 58 deletions
|
|
@ -17,18 +17,71 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from rougail.utils import load_modules
|
||||
|
||||
from .i18n import _
|
||||
|
||||
|
||||
OUTPUTS = None
|
||||
|
||||
|
||||
def get_outputs() -> None:
|
||||
"""Load all outputs"""
|
||||
module_name = f"rougail.output_display.output"
|
||||
outputs = {}
|
||||
names = []
|
||||
for path in (Path(__file__).parent / "output").iterdir():
|
||||
name = path.name
|
||||
if not name.endswith(".py") or name.endswith("__.py"):
|
||||
continue
|
||||
module = load_modules(module_name + "." + name[:-3], str(path))
|
||||
if "OutputFamily" not in dir(module):
|
||||
continue
|
||||
obj_class = module.OutputFamily
|
||||
level = obj_class.level
|
||||
if level in outputs:
|
||||
raise ImportError(
|
||||
_('duplicated level 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(
|
||||
_('duplicated name "{0}" in rougail-output-doc').format(
|
||||
obj_class.name
|
||||
)
|
||||
)
|
||||
names.append(obj_class.name)
|
||||
outputs[level] = obj_class
|
||||
return {outputs[level].name: outputs[level] for level in sorted(outputs)}
|
||||
|
||||
|
||||
class OutPuts: # pylint: disable=R0903
|
||||
"""Transformations applied on a object instance"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
) -> None:
|
||||
global OUTPUTS
|
||||
if OUTPUTS is None:
|
||||
OUTPUTS = get_outputs()
|
||||
|
||||
def get(self) -> dict:
|
||||
"""Get all outputs"""
|
||||
return OUTPUTS
|
||||
|
||||
|
||||
def get_rougail_config(
|
||||
*,
|
||||
backward_compatibility=True,
|
||||
) -> dict:
|
||||
outputs = list(OutPuts().get())
|
||||
output_format_default = outputs[0]
|
||||
options = f"""
|
||||
display:
|
||||
description: {_('Display variables and values')}
|
||||
help: {_('Find all the variables and their values in your configuration (structural and user datas). Additional informations are available, such as the default value, the location where the value is loaded, etc.')}
|
||||
help: |-
|
||||
{_('Find all the variables and their values in your configuration (structural and user datas). Additional informations are available, such as the default value, the location where the value is loaded, etc.')}
|
||||
disabled:
|
||||
jinja: |-
|
||||
{{% if step.output is propertyerror or step.output != 'display' %}}
|
||||
|
|
@ -39,6 +92,14 @@ display:
|
|||
return_type: boolean
|
||||
description: {_('if display is not set in "step.output"')}
|
||||
|
||||
output_format:
|
||||
description: {_('The output format for displaying variables')}
|
||||
default: { output_format_default }
|
||||
choices:
|
||||
"""
|
||||
for output in outputs:
|
||||
options += f" - {output}\n"
|
||||
options += f"""
|
||||
show_secrets: false # {_('Show secrets instead of obscuring them')}
|
||||
|
||||
mandatory:
|
||||
|
|
@ -53,13 +114,19 @@ display:
|
|||
{{% endif %}}
|
||||
description: {_('do not test if "cli.read_write" is true')}
|
||||
|
||||
max_width:
|
||||
description: {_("Maximum number of characters per line")}
|
||||
help: {_('null means unlimited')}
|
||||
type: integer
|
||||
mandatory: false
|
||||
params:
|
||||
min_integer: 50
|
||||
console:
|
||||
description: {_("Specific configuration when variables are displayed")}
|
||||
disabled:
|
||||
variable: _.output_format
|
||||
when_not: console
|
||||
|
||||
max_width:
|
||||
description: {_("Maximum number of characters per line")}
|
||||
help: {_('null means unlimited')}
|
||||
type: integer
|
||||
mandatory: false
|
||||
params:
|
||||
min_integer: 50
|
||||
"""
|
||||
return {
|
||||
"name": "display",
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ from ruamel.yaml import YAML
|
|||
|
||||
from tiramisu.error import PropertiesOptionError, ConfigError
|
||||
|
||||
from .config import OutPuts
|
||||
from .i18n import _
|
||||
from .output.console import OutputFamily
|
||||
|
||||
|
||||
class RougailOutputDisplay:
|
||||
|
|
@ -66,14 +66,13 @@ class RougailOutputDisplay:
|
|||
return self.output.run()
|
||||
|
||||
def print(self) -> None:
|
||||
ret = self.exporter()
|
||||
self.output.print()
|
||||
return ret
|
||||
return self.output.print()
|
||||
|
||||
def get_root(self) -> None:
|
||||
yaml = YAML()
|
||||
yaml.indent(mapping=2, sequence=4, offset=2)
|
||||
self.output = OutputFamily(
|
||||
output_format = self.rougailconfig["display.output_format"]
|
||||
self.output = OutPuts().get()[output_format](
|
||||
_("Variables:"),
|
||||
None,
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -26,23 +26,28 @@ from ..util import CommonOutput
|
|||
|
||||
|
||||
class OutputFamily(CommonOutput):
|
||||
level = 10
|
||||
name = "console"
|
||||
variable_hidden_color = "orange1"
|
||||
variable_normal_color = None
|
||||
value_unmodified_color = "gold1"
|
||||
value_modified_color = "green"
|
||||
value_default_color = None
|
||||
error_color = 'bright_red'
|
||||
|
||||
|
||||
def run(self):
|
||||
max_width = self.root.rougailconfig["display.max_width"]
|
||||
max_width = self.root.rougailconfig["display.console.max_width"]
|
||||
self.console = Console(force_terminal=True, width=max_width)
|
||||
with self.console.capture() as capture:
|
||||
ret = self.root.print()
|
||||
return ret, capture.get()
|
||||
|
||||
def print(self) -> None:
|
||||
ret = self.root.exporter()
|
||||
for out in self.out:
|
||||
self.console.print(out)
|
||||
return ret
|
||||
|
||||
def header(self):
|
||||
caption_line = ""
|
||||
|
|
@ -52,7 +57,7 @@ class OutputFamily(CommonOutput):
|
|||
caption_line += f'[{self.variable_hidden_color}]{_("Unmodifiable variable")}[/{self.variable_hidden_color}]\n'
|
||||
header_value = ""
|
||||
if self.root_family.value_unmodified_enable:
|
||||
header_value = f'[{self.value_unmodified_color}]{_("Default value")}[/{self.value_unmodified_color}]\n'
|
||||
header_value += f'[{self.value_unmodified_color}]{_("Default value")}[/{self.value_unmodified_color}]\n'
|
||||
if self.root_family.value_modified_enable:
|
||||
header_value += f'[{self.value_modified_color}]{_("Modified value")}[/{self.value_modified_color}]\n'
|
||||
if self.root_family.value_default_enable:
|
||||
|
|
@ -82,12 +87,14 @@ class OutputFamily(CommonOutput):
|
|||
self.out.append(Panel.fit(layers, title=_("Layers")))
|
||||
|
||||
def error_header(self):
|
||||
return Tree(
|
||||
f"[bold][bright_red]:stop_sign: {_('ERRORS')}[/bright_red][/bold]",
|
||||
guide_style="bold bright_red",
|
||||
tree = Tree(
|
||||
f"[bold][{self.error_color}]:stop_sign: {_('ERRORS')}[/{self.error_color}][/bold]",
|
||||
guide_style=f"bold {self.error_color}",
|
||||
)
|
||||
self.out.append(tree)
|
||||
return tree
|
||||
|
||||
def display_error(self, tree, error):
|
||||
def display_error(self, tree, error, level):
|
||||
return tree.add(error)
|
||||
|
||||
def display_warnings(
|
||||
|
|
|
|||
|
|
@ -66,23 +66,22 @@ class CommonOutput:
|
|||
tree = self.error_header()
|
||||
for error in errors:
|
||||
self.parse_error(tree, error)
|
||||
self.out.append(tree)
|
||||
|
||||
def parse_error(self, tree, error):
|
||||
def parse_error(self, tree, error, level=-1):
|
||||
if isinstance(error, list):
|
||||
for err in error:
|
||||
self.parse_error(tree, err)
|
||||
self.parse_error(tree, err, level+1)
|
||||
return tree
|
||||
elif isinstance(error, dict):
|
||||
for key, value in error.items():
|
||||
if key is None:
|
||||
# it's variables, no more families
|
||||
self.parse_error(tree, value)
|
||||
self.parse_error(tree, value, level+1)
|
||||
else:
|
||||
sub_tree = self.parse_error(tree, key)
|
||||
self.parse_error(sub_tree, value)
|
||||
sub_tree = self.parse_error(tree, key, level+1)
|
||||
self.parse_error(sub_tree, value, level+1)
|
||||
else:
|
||||
return self.display_error(tree, error)
|
||||
return self.display_error(tree, error, level)
|
||||
|
||||
def add_family(
|
||||
self,
|
||||
|
|
|
|||
21
test.md
Normal file
21
test.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<pre>
|
||||
Variables:
|
||||
┗━ 📂 A family
|
||||
┣━ 📓 The first variable: string1 ◀ loaded from rougail-test
|
||||
┗━ 📓 The second variable: string1 ◀ loaded from rougail-test
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
Variables:
|
||||
<span style="color: #5c5cff">┣━━ </span>📓 <span style="color: #ff0000">Configure Proxy Access to the Internet</span>: <span style="color: #ffd700">No proxy</span>
|
||||
<span style="color: #5c5cff">┗━━ </span>📂 Manual proxy configuration
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff">┗━━ </span>📂 HTTP Proxy
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff"> </span><span style="color: #5c5cff">┗━━ </span>📓 <span style="color: #ff0000">HTTP address</span>: <span style="color: #00aa00">example.net</span> ◀ loaded from the YAML file
|
||||
<span style="color: #5c5cff"> </span><span style="color: #5c5cff"> </span><span style="color: #5c5cff"> </span>"config/03/config.yml"
|
||||
</pre>
|
||||
|
||||
|
||||
Variables:
|
||||
- 📂 A family
|
||||
- 📓 The first variable: string1 ◀ loaded from rougail-test
|
||||
- 📓 The second variable: <span style="color: #5c5cff">string1</span> ◀ loaded from rougail-test
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[1;91m🛑 ERRORS[0m
|
||||
[91m┗━━ [0mThe following variables are inaccessible but are empty and mandatory:
|
||||
[91m [0m[91m┗━━ [0mmandatory_variable (please set a value)
|
||||
4
tests/errors-results/display.md
Normal file
4
tests/errors-results/display.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
> [!CAUTION]
|
||||
> :stop_sign: ERRORS:
|
||||
> - The following variables are inaccessible but are empty and mandatory:
|
||||
> - please set a value
|
||||
|
|
@ -4,6 +4,8 @@ from rougail.output_display import RougailOutputDisplay as RougailOutput
|
|||
|
||||
from rougail_tests.utils import get_rougail_config
|
||||
|
||||
EXT = {'console': 'sh', 'github': 'md'}
|
||||
|
||||
|
||||
def test_error_mandatory_hidden():
|
||||
rougailconfig = get_rougail_config(Path("tests/errors/"), namespace=False)
|
||||
|
|
@ -12,37 +14,39 @@ def test_error_mandatory_hidden():
|
|||
config = rougail.run()
|
||||
config.information.set("description_type", "description")
|
||||
config.property.read_only()
|
||||
no_pb, generated_output = RougailOutput(config, rougailconfig=rougailconfig).run()
|
||||
assert no_pb == False
|
||||
output_file = Path(__file__).parent / 'errors-results' / 'display.sh'
|
||||
if not output_file.is_file():
|
||||
if not output_file.parent.is_dir():
|
||||
output_file.parent.mkdir()
|
||||
with output_file.open('w') as outfh:
|
||||
outfh.write(generated_output)
|
||||
with output_file.open() as outfh:
|
||||
attented_output = outfh.read()
|
||||
assert generated_output == attented_output, f'filename {output_file}'
|
||||
for output_format, ext in EXT.items():
|
||||
rougailconfig['display.output_format'] = output_format
|
||||
no_pb, generated_output = RougailOutput(config, rougailconfig=rougailconfig).run()
|
||||
assert no_pb == False
|
||||
output_file = Path(__file__).parent / 'errors-results' / f'display.{ext}'
|
||||
if not output_file.is_file():
|
||||
if not output_file.parent.is_dir():
|
||||
output_file.parent.mkdir()
|
||||
with output_file.open('w') as outfh:
|
||||
outfh.write(generated_output)
|
||||
with output_file.open() as outfh:
|
||||
attented_output = outfh.read()
|
||||
assert generated_output == attented_output, f'filename {output_file}'
|
||||
|
||||
|
||||
def test_error_mandatory_family_hidden():
|
||||
rougailconfig = get_rougail_config(Path("tests/errors2/"), namespace=False)
|
||||
rougailconfig['step.output'] = 'display'
|
||||
rougail = Rougail(rougailconfig)
|
||||
config = rougail.run()
|
||||
config.information.set("description_type", "description")
|
||||
config.property.read_only()
|
||||
no_pb, generated_output = RougailOutput(config, rougailconfig=rougailconfig).run()
|
||||
assert no_pb == False
|
||||
output_file = Path(__file__).parent / 'errors2-results' / 'display.sh'
|
||||
if not output_file.is_file():
|
||||
if not output_file.parent.is_dir():
|
||||
output_file.parent.mkdir()
|
||||
with output_file.open('w') as outfh:
|
||||
outfh.write(generated_output)
|
||||
with output_file.open() as outfh:
|
||||
attented_output = outfh.read()
|
||||
assert generated_output == attented_output, f'filename {output_file}'
|
||||
def test_error_mandatory_family_hidden():
|
||||
rougailconfig = get_rougail_config(Path("tests/errors2/"), namespace=False)
|
||||
rougailconfig['step.output'] = 'display'
|
||||
rougail = Rougail(rougailconfig)
|
||||
config = rougail.run()
|
||||
config.information.set("description_type", "description")
|
||||
config.property.read_only()
|
||||
no_pb, generated_output = RougailOutput(config, rougailconfig=rougailconfig).run()
|
||||
assert no_pb == False
|
||||
output_file = Path(__file__).parent / 'errors2-results' / 'display.sh'
|
||||
if not output_file.is_file():
|
||||
if not output_file.parent.is_dir():
|
||||
output_file.parent.mkdir()
|
||||
with output_file.open('w') as outfh:
|
||||
outfh.write(generated_output)
|
||||
with output_file.open() as outfh:
|
||||
attented_output = outfh.read()
|
||||
assert generated_output == attented_output, f'filename {output_file}'
|
||||
|
||||
|
||||
def test_error_mandatory_family():
|
||||
|
|
|
|||
Loading…
Reference in a new issue