Compare commits

..

No commits in common. "49063e107d31510c90b115ac2ebc8c2ec7951bf0" and "5251554b50769add5f5fcdd1cc56b0f321af6b2d" have entirely different histories.

28 changed files with 38 additions and 336 deletions

View file

@ -1,9 +1,3 @@
## 0.1.0a25 (2026-04-30)
### Fix
- better path detection
## 0.1.0a24 (2025-12-30)
### Feat

View file

@ -4,7 +4,7 @@ requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail.output_formatter"
version = "0.1.0a25"
version = "0.1.0a24"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "Rougail output formatter"

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2026
Copyright (C) 2024-2025
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
@ -119,6 +119,7 @@ class RougailOutputFormatter:
_('the "step.output" is not set to "{0}"').format(self.output_name)
)
# yaml.top_level_colon_align = True
self.main_namespace = normalize_family(self.rougailconfig["main_namespace"])
self.has_default_structural_format_version = (
self.rougailconfig["default_structural_format_version"] is not None
)
@ -134,7 +135,7 @@ class RougailOutputFormatter:
def run(self):
self.upgrade()
self.families = {self.rougail.namespace: CommentedMap()}
self.families = {self.main_namespace: CommentedMap()}
self.parse()
self.yaml.indent(mapping=2, sequence=4, offset=2)
self.yaml.version = "1.2"
@ -142,7 +143,7 @@ class RougailOutputFormatter:
self.yaml.explicit_end = True
self.default_flow_style = False
with BytesIO() as ymlfh:
families = self.families[self.rougail.namespace]
families = self.families[self.main_namespace]
if not families:
self.yaml.dump("", ymlfh)
else:
@ -161,14 +162,7 @@ class RougailOutputFormatter:
return self.attributes[type_name]
def upgrade(self) -> None:
namespace = self.rougailconfig["main_namespace"]
if namespace and self.rougailconfig["extra_namespaces.names"]:
namespace = self.rougailconfig["extra_namespaces.names"][0]
filenames = self.rougailconfig["extra_namespaces"]["directories"][0]
extra = True
else:
filenames = self.rougailconfig["main_structural_directories"]
extra = False
if len(filenames) > 1:
raise ExtensionError(_('only one filename is allowed, not "{0}"').format(filenames))
filename = Path(filenames[0])
@ -183,11 +177,11 @@ class RougailOutputFormatter:
self.rougail.load_config()
self.rougail.init()
self.filename_str = str(filename)
if namespace is None:
if self.main_namespace is None:
self.rougail.namespace = None
else:
self.rougail.namespace = normalize_family(namespace)
self.rougail.create_namespace(namespace)
self.rougail.namespace = normalize_family(self.main_namespace)
self.rougail.create_namespace(self.main_namespace)
self.rougail.validate_file_version(
datas,
self.filename_str,
@ -205,25 +199,26 @@ class RougailOutputFormatter:
return ret
def parse(self):
self.families[self.rougail.namespace][self.version_name] = float(
self.families[self.main_namespace][self.version_name] = float(
self.rougail.version
)
self.remaining = len(self.rougail.paths._data)
for path, obj in self.rougail.paths._data.items():
self.remaining -= 1
if path == self.rougail.namespace:
# self.families[path] = self.families[None]
continue
if isinstance(obj, Family):
self.parse_family(path, obj)
elif isinstance(obj, Variable):
self.parse_variable(path, obj)
if list(self.families[self.rougail.namespace]) != [self.version_name]:
if list(self.families[self.main_namespace]) != [self.version_name]:
# just to add an empty line space after "version"
self.families[self.rougail.namespace].yaml_value_comment_extend(
self.families[self.main_namespace].yaml_value_comment_extend(
self.version_name, [CommentToken("\n\n", CommentMark(0)), None]
)
if self.has_default_structural_format_version:
del self.families[self.rougail.namespace][self.version_name]
del self.families[self.main_namespace][self.version_name]
def parse_family(self, path, obj):
children = [p.rsplit(".", 1)[-1] for p in self.rougail.parents[path]]
@ -360,8 +355,6 @@ class RougailOutputFormatter:
if attr not in force_keys and value == default_value:
continue
value = self.object_to_yaml(attr, type_, value, multi, path)
if isinstance(value, dict) and "identifier" in value:
value["identifier"] = self.object_to_yaml("identifier", type_, value["identifier"], True, path)
variable[attr] = value
if variable.get("mandatory") is True and None not in variable.get(
"choices", []
@ -612,7 +605,7 @@ class RougailOutputFormatter:
def calc_variable_path(self, object_path, variable_path):
if not variable_path.startswith("_"):
common_path = get_common_path(object_path, variable_path)
if not self.rougail.namespace:
if not self.rougail.namespace or common_path:
if not common_path:
len_common_path = 0
else:
@ -624,15 +617,6 @@ class RougailOutputFormatter:
+ "."
+ variable_path[len_common_path:]
)
if common_path:
len_common_path = len(common_path) + 1
relative_object_path = object_path[len_common_path:]
final_path = "_" * (relative_object_path.count(".") + 1) + "."
return (
"_" * (relative_object_path.count(".") + 1)
+ "."
+ variable_path[len_common_path:]
)
return variable_path
def get_parent_name(self, path):
@ -652,7 +636,7 @@ class RougailOutputFormatter:
name = search_name
return _yaml(y[name])
if self.rougail.namespace:
if self.main_namespace:
subpath = path.split(".")[1:]
else:
subpath = path.split(".")

View file

@ -1 +1 @@
__version__ = "0.1.0a25"
__version__ = "0.1.0a24"

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2026
Copyright (C) 2024-2025
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

View file

@ -1,6 +1,6 @@
"""Internationalisation utilities
Silique (https://www.silique.fr)
Copyright (C) 2025-2026
Copyright (C) 2025
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

View file

@ -4,7 +4,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2026
Copyright (C) 2022-2025
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

View file

@ -7,6 +7,6 @@ var1: # a first variable
var2:
description: a second variable
default:
description: value of a variable!
variable: _.var1
description: value of a variable!
...

View file

@ -7,12 +7,12 @@ var1: # a first variable
var2:
description: a second variable
default:
variable: _.var1
description: |-
value
of
a
variable!
variable: _.var1
var3: # a new variable
...

View file

@ -10,7 +10,7 @@ var1:
var2:
description: an IP in CIDR format
examples:
- 192.168.0.129/25
- 192.168.0.128/25
type: ip
params:
cidr: true

View file

@ -4,8 +4,6 @@ version: 1.1
secret1:
description: the first variable
examples:
- ALongS4cr4t
type: secret
params:
min_len: 10

View file

@ -1,18 +0,0 @@
%YAML 1.2
---
version: 1.1
var1:
description: A first variable
type: boolean
default:
jinja: >-
true
description: A description
hidden: true
var2:
description: A second variable
disabled:
variable: _.var1
...

View file

@ -1,15 +0,0 @@
%YAML 1.2
---
version: 1.1
condition:
description: a condition
default: true
disabled: true
variable:
description: a variable
disabled:
variable: _.condition
propertyerror: transitive
...

View file

@ -1,17 +0,0 @@
%YAML 1.2
---
version: 1.1
condition: true # a condition
variable1:
description: a variable
disabled:
variable: _.condition
variable2:
description: a second variable
disabled:
variable: _.variable1
propertyerror: transitive
...

View file

@ -1,15 +0,0 @@
%YAML 1.2
---
version: 1.1
condition:
description: a condition
default: true
disabled: true
variable:
description: a variable
disabled:
variable: _.condition
propertyerror: transitive
...

View file

@ -1,19 +0,0 @@
%YAML 1.2
---
version: 1.1
condition: false # a condition
variable1:
description: a variable
default: disabled
disabled:
variable: _.condition
variable2:
description: a second variable
disabled:
variable: _.variable1
propertyerror: transitive
when: disabled
...

View file

@ -1,19 +0,0 @@
%YAML 1.2
---
version: 1.1
condition: true # a condition
variable1:
description: a variable
default: not_disabled
disabled:
variable: _.condition
variable2:
description: a second variable
disabled:
variable: _.variable1
propertyerror: transitive
when: disabled
...

View file

@ -8,7 +8,7 @@ leadership:
leader:
description: a leader
examples:
test:
- val1
- val2
default:

View file

@ -1,29 +0,0 @@
%YAML 1.2
---
version: 1.1
var:
description: a suffix variable
test:
- 1
- 2
type: integer
multi: true
mandatory: false
dyn{{ identifier }}:
description: a dynamic family
dynamic:
variable: _.var
var: val # a variable inside dynamic family from "{{ identifier }}"
var2:
description: a variable
default:
jinja: >-
{% if rougail.dyn1 is defined %}
{{ rougail.dyn1.var }}
{% endif %}
description: get the value of "rougail.dyn1.var"
...

View file

@ -3,21 +3,21 @@
version: 1.1
dyn{{ identifier }}:
description: a dynamic famify for {{ identifier }}
description: A dynamic famify for {{ identifier }}
dynamic:
- val1
- val2
var: # a dynamic variable for {{ identifier }}
var: # A dynamic variable for {{ identifier }}
var1:
description: a new variable
description: A new variable
disabled:
variable: _.dynval1.var
when: val
var2:
description: a new variable
description: A new variable
default:
variable: _.dyn{{ identifier }}.var
unique: false

View file

@ -1,26 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # A suffix variable
- val1
- val2
var2: val1 # A suffix variable2
dyn{{ identifier }}:
dynamic:
variable: _.var1
var:
description: A dynamic variable
default:
type: identifier
var3:
description: A variable calculated
default:
variable: _.dyn{{ identifier }}.var
identifier:
variable: _.var2
...

View file

@ -1,24 +0,0 @@
%YAML 1.2
---
version: 1.1
var1: # A suffix variable
- val1
- val2
var2: val1 # A suffix variable2
dyn{{ identifier }}:
dynamic:
variable: _.var1
var: # A dynamic variable
- type: identifier
var3:
description: A variable calculated
default:
variable: _.dyn{{ identifier }}.var
identifier:
variable: _.var2
...

View file

@ -7,8 +7,7 @@ var1:
test:
- val1
- val2
default:
- val1
multi: true
mandatory: false
dyn{{ identifier }}:
@ -23,5 +22,5 @@ var2:
description: A variable calculated
default:
variable: _.dynval1.var
propertyerror: false
optional: true
...

View file

@ -1,26 +0,0 @@
%YAML 1.2
---
version: 1.1
var1:
description: A suffix variable
test:
- val1
- val2
multi: true
mandatory: false
dyn{{ identifier }}:
dynamic:
variable: _.var1
var:
description: A dynamic variable
disabled: true
var2:
description: A variable calculated
default:
variable: _.dynval1.var
optional: true
...

View file

@ -4,7 +4,7 @@ version: 1.1
var:
description: a suffix variable
examples:
test:
- val1
- val2
- val3

View file

@ -1,33 +0,0 @@
%YAML 1.2
---
version: 1.1
var: # a suffix variable
- val1
- val2
'{{ identifier }}_dyn':
description: a dynamic family
dynamic:
variable: _.var
var1:
description: value is suffix for {{ identifier }}
default:
type: identifier
var2:
description: value is first variable
default:
variable: _.var1
var3:
description: value is relative first variable
default:
variable: _.var1
var4:
description: value is first variable of val1
default:
variable: __.val1_dyn.var1
...

View file

@ -1,24 +0,0 @@
%YAML 1.2
---
version: 1.1
var: # A suffix variable
- val1
- val2
dyn{{ identifier }}:
dynamic:
variable: _.var
dyn{{ identifier }}:
dynamic:
variable: __.var
var1: # A dynamic variable
var2:
description: A variable calculated
default:
variable: ___.dynval2.dyn{{ identifier }}.var1
unique: false
...

View file

@ -68,26 +68,18 @@ def test_structural_files_formatter_namespace(test_dir):
rougailconfig = get_rougail_config(test_dir, namespace)
if not rougailconfig:
return
if rougailconfig["extra_namespaces.names"]:
for n_idx, namespace in enumerate(rougailconfig['extra_namespaces.names']):
for dir_name in rougailconfig["extra_namespaces"]["directories"][n_idx]:
for file_name in Path(dir_name).iterdir():
if file_name.suffix in [".yml", ".yaml"]:
rougailconfig["extra_namespaces"].set_follower("directories", n_idx, [str(file_name)])
_test_structural_files(file_name, namespace, rougailconfig)
rougailconfig["extra_namespaces"].reset()
for dir_name in rougailconfig['main_structural_directories']:
for file_name in Path(dir_name).iterdir():
if file_name.suffix in [".yml", ".yaml"]:
rougailconfig["main_structural_directories"] = [str(file_name)]
_test_structural_files(file_name, namespace, rougailconfig)
# for namespace, dirs_name in rougailconfig['extra_namespaces'].items():
# rougailconfig["main_namespace"] = namespace
# for dir_name in dirs_name:
# for file_name in Path(dir_name).iterdir():
# if file_name.suffix in [".yml", ".yaml"]:
# rougailconfig["main_structural_directories"] = [str(file_name)]
# _test_structural_files(file_name, namespace, rougailconfig)
for namespace, dirs_name in rougailconfig['extra_namespaces'].items():
rougailconfig["main_namespace"] = namespace
for dir_name in dirs_name:
for file_name in Path(dir_name).iterdir():
if file_name.suffix in [".yml", ".yaml"]:
rougailconfig["main_structural_directories"] = [str(file_name)]
_test_structural_files(file_name, namespace, rougailconfig)
def test_structural_files_formatter_load(test_dir):