Compare commits

..

No commits in common. "0.1.0a8" and "main" have entirely different histories.

88 changed files with 121 additions and 713 deletions

View file

@ -1,65 +0,0 @@
## 0.1.0a8 (2025-04-01)
### Fix
- update tests
## 0.1.0a7 (2025-03-30)
### Feat
- support multi lines for help
## 0.1.0a6 (2025-03-28)
### Fix
- do not add multi \n at ends of export
## 0.1.0a5 (2025-03-27)
### Fix
- if and for in 3 lines
## 0.1.0a4 (2025-03-27)
### Feat
- format jinja template
## 0.1.0a3 (2025-03-27)
### Feat
- add secret_manager support
- add Namespace(Param|Calculation) support
### Fix
- do not add namespace in param
- an empty variable is []
## 0.1.0a2 (2025-03-26)
### Fix
- pyproject.toml
## 0.1.0a1 (2025-03-26)
### Fix
- add pyproject.toml
## 0.1.0a0 (2025-02-10)
### Feat
- output return status too
## 0.0.1a0 (2025-01-04)
### Fix
- remove prefix_path

View file

@ -1,43 +0,0 @@
[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail.output_formatter"
version = "0.1.0a8"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "Rougail output formatter"
requires-python = ">=3.8"
license = {file = "LICENSE"}
classifiers = [
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Natural Language :: English",
"Natural Language :: French",
]
dependencies = [
"rougail >= 1.1,<2",
"djlint == 1.36.4",
]
[project.urls]
Home = "https://forge.cloud.silique.fr/stove/rougail-output-formatter"
[tool.commitizen]
name = "cz_conventional_commits"
tag_format = "$version"
version_scheme = "pep440"
version_provider = "pep621"
update_changelog_on_bump = true
changelog_merge_prerelease = true

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
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
@ -25,16 +25,13 @@ from ruamel.yaml import YAML, CommentedMap
from ruamel.yaml.tokens import CommentToken
from ruamel.yaml.error import CommentMark
from ruamel.yaml.comments import CommentedSeq
from ruamel.yaml.scalarstring import LiteralScalarString, FoldedScalarString, ScalarString
from djlint.settings import Config
from djlint.reformat import formatter
from ruamel.yaml.scalarstring import LiteralScalarString, FoldedScalarString
from tiramisu import undefined
from tiramisu.config import get_common_path
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, IdentifierParam, IndexCalculation, IndexParam, Param
from rougail.utils import normalize_family
from .upgrade import RougailUpgrade
@ -75,12 +72,6 @@ class RougailOutputFormatter:
filename = Path(filenames[0])
if not filename.is_file():
raise Exception(_('only a file is allowed'))
self.config = Config()
self.config.profile = 'jinja'
self.config.line_break_after_multiline_tag = True
self.config.indent = " "
self.original_yaml = RougailUpgrade(rougailconfig).run(filename)
datas = RougailUpgrade(rougailconfig).run(filename)
self.rougail = RougailConvert(rougailconfig)
@ -115,13 +106,11 @@ class RougailOutputFormatter:
self.default_flow_style = False
with BytesIO() as ymlfh:
self.yaml.dump(self.families[None], ymlfh)
ret = ymlfh.getvalue().decode("utf-8").strip()
return True, ret
ret = ymlfh.getvalue().decode("utf-8").strip() + '\n'
return ret
def print(self):
ret, data = self.run()
print(data)
return ret
print(self.run())
def parse(self):
# FIXME path to relative !
@ -170,7 +159,7 @@ class RougailOutputFormatter:
else:
attributes = self.families_attributes
for attr, default_value in attributes.items():
if attr in ["name", "path", "namespace", "version", "xmlfiles"]:
if attr in ["name", "path", "namespace", "version", "path_prefix", "xmlfiles"]:
continue
try:
value = getattr(obj, attr)
@ -215,7 +204,7 @@ class RougailOutputFormatter:
multi = obj.multi or isinstance(obj.default, list)
type_ = obj.type
for attr, default_value in self.variables_attributes.items():
if attr in ["name", "path", "namespace", "version", "xmlfiles"]:
if attr in ["name", "path", "namespace", "version", "path_prefix", "xmlfiles"]:
continue
try:
value = getattr(obj, attr)
@ -249,9 +238,6 @@ class RougailOutputFormatter:
# if boolean, the default value is True
del variable["type"]
variable["default"] = True
if "default" not in variable and variable.get("multi") is True and not set(variable) - {'default', 'description', "multi"}:
variable["default"] = []
del(variable['multi'])
if not isinstance(variable.get("default"), dict) and not set(variable) - {'default', 'description'}:
# shorthand notation
default = variable.get('default')
@ -285,16 +271,12 @@ class RougailOutputFormatter:
return _get_last_obj(o[param], o, param, 'seq')
return typ, parent, param
param = list(obj)[-1]
if isinstance(obj[param], ScalarString):
enter = '\n'
else:
enter = '\n\n'
typ, parent, param = _get_last_obj(obj[param], obj, param, 'map')
if typ == 'seq':
func = parent.yaml_key_comment_extend
else:
func = parent.yaml_value_comment_extend
func(param, [CommentToken(enter, CommentMark(0)), None])
func(param, [CommentToken('\n\n', CommentMark(0)), None])
def object_to_yaml(self, key, type_, value, multi, object_path):
if isinstance(value, list):
@ -311,18 +293,11 @@ class RougailOutputFormatter:
return new_values
if isinstance(value, JinjaCalculation):
jinja = CommentedMap()
jinja_values = formatter(self.config, value.jinja.strip())[:-1]
# replace \n to space a add index of \n (now a space) to fold_pos
jinja_values = value.jinja.strip()
if key == 'default' and not multi:
jinja["jinja"] = FoldedScalarString(jinja_values)
fold_pos = []
old_i = 0
for i, ltr in enumerate(jinja_values):
if ltr == '\n':
fold_pos.append(i - old_i)
old_i = 1
jinja["jinja"].fold_pos = fold_pos
elif key == 'secret_manager':
return self.object_to_yaml("params", type_, value.params, multi, object_path)
jinja["jinja"] = FoldedScalarString(jinja_values.replace('\n', ' '))
jinja["jinja"].fold_pos = [i for i, ltr in enumerate(jinja_values) if ltr == '\n']
else:
jinja["jinja"] = LiteralScalarString(jinja_values)
if value.return_type:
@ -337,10 +312,8 @@ class RougailOutputFormatter:
variable = CommentedMap()
if isinstance(value, (IdentifierCalculation, IdentifierPropertyCalculation)):
variable["type"] = "identifier"
elif isinstance(value, IndexCalculation):
if isinstance(value, IndexCalculation):
variable["type"] = "index"
elif isinstance(value, NamespaceCalculation):
variable["type"] = "namespace"
for key, default in variable_attributes.items():
val = getattr(value, key)
if val != default and val is not undefined:
@ -351,17 +324,15 @@ class RougailOutputFormatter:
del variable["type"]
return variable
elif isinstance(value, Param):
param_attributes = self.get_object_informations(value, ["type", "key", "namespace"])
param_attributes = self.get_object_informations(value, ["type", "key"])
if list(param_attributes) == ['value']:
variable = value.value
else:
variable = CommentedMap()
if isinstance(value, IdentifierParam):
variable["type"] = "identifier"
elif isinstance(value, IndexParam):
if isinstance(value, IndexParam):
variable["type"] = "index"
elif isinstance(value, NamespaceParam):
variable["type"] = "namespace"
for key, default in param_attributes.items():
val = getattr(value, key)
if val != default and val is not undefined:
@ -373,8 +344,6 @@ class RougailOutputFormatter:
return {value.key: variable}
elif type_ == 'port' and isinstance(value, str) and value.isnumeric():
return int(value)
elif key == 'help' and '\n' in value:
return LiteralScalarString(value)
return value
def calc_variable_path(self, object_path, variable_path):

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2025
Copyright (C) 2024
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
@ -29,14 +29,14 @@ load_unexist_redefine:
type: boolean
default:
jinja: >-
{% if step.output is not propertyerror and step.output == 'formatter' %}
{% if step.output == 'formatter' %}
true
{% else %}
false
{% endif %}
hidden:
jinja: >-
{% if step.output is not propertyerror and step.output == 'formatter' %}
{% if step.output == 'formatter' %}
load_unexist_redefine is always true with 'formatter' output
{% endif %}
"""

View file

@ -4,7 +4,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2025
Copyright (C) 2022-2024
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,14 +0,0 @@
---
version: 1.1
var1:
description: the first variable
choices:
- a
- b
- c
var2:
description: the second variable
default:
variable: _.var1

View file

@ -1,18 +0,0 @@
---
version: 1.1
var1: # a second variable
- a
- b
- c
var2:
description: a first variable
choices:
variable: _.var1
default: a
var3:
description: a third variable
default:
variable: _.var2

View file

@ -1,20 +0,0 @@
---
version: 1.1
var1: # a second variable
- a
- b
- c
var2:
description: a first variable
choices:
variable: _.var1
default: a
family:
var3:
description: a third variable
default:
variable: __.var2

View file

@ -1,18 +0,0 @@
---
version: 1.1
var1:
description: a first variable
test:
- '#b1b1b1'
- '#b2b2b2'
regexp: ^#(?:[0-9a-f]{3}){1,2}$
default: '#a1a1a1'
var2:
description: a second variable
test:
- '#b2b1b1'
- '#b3b2b2'
default:
variable: _.var1

View file

@ -1,11 +0,0 @@
---
version: 1.1
secret1:
description: the first variable
type: secret
secret2:
description: the second variable
type: secret
default: value

View file

@ -1,27 +0,0 @@
---
version: 1.1
secret1:
description: the first variable
type: secret
params:
min_len: 10
secret2:
description: the second variable
type: secret
params:
max_len: 10
forbidden_char:
- $
- ^
default: value
secret3:
description: the third variable
type: secret
params:
max_len: 10
forbidden_char:
- $
default: value

View file

@ -1,18 +0,0 @@
---
version: 1.1
var1:
description: the first variable
help: |-
Multi line
Help
With useful information
var2:
description: the second variable
help: |-
Multi line
Help
With useful information

View file

@ -1,18 +0,0 @@
---
version: 1.1
var1:
description: the first <variable>
help: |-
Multi line
<Help>
With useful information
var2:
description: the second <variable>
help: |-
Multi line
<Help>
With useful information

View file

@ -5,7 +5,7 @@ variable:
description: a variable
default:
jinja: >-
{{ test_information }}
{{test_information }}
description: get information test_information
params:
test_information:

View file

@ -1,8 +0,0 @@
---
version: 1.1
variable:
description: a variable
default:
type: namespace
mandatory: false

View file

@ -1,12 +0,0 @@
---
version: 1.1
variable:
description: a variable
default:
jinja: >-
{{ namespace }}
params:
namespace:
type: namespace
mandatory: false

View file

@ -5,15 +5,8 @@ var1:
description: a first variable
default:
jinja: >-
{% if var2 is defined %}
{{ var2 }}
{% elif var3 is defined %}
{{ var3 }}
{% elif var4 is defined %}
{{ var4 }}
{% else %}
{{ _.var2 }}
{% endif %}
{% if var2 is defined %} {{ var2 }} {% elif var3 is defined %} {{ var3 }} {%
elif var4 is defined %} {{ var4 }} {% else %} {{ _.var2 }} {% endif %}
description: returns a value
params:
var2:

View file

@ -1,24 +0,0 @@
---
version: 1.1
condition: no # a conditional variable
variable1:
description: a first variable
multi: true
disabled:
jinja: |-
{% if _.condition == "yes" %}
condition is yes
{% endif %}
description: if condition is egal to "yes"
variable2:
description: a second variable
multi: true
disabled:
jinja: |-
{% if _.condition == "yes" %}
condition is yes
{% endif %}
description: if condition is egal to "yes"

View file

@ -1,10 +0,0 @@
---
version: 1.1
condition: false # a condition
variable:
description: a variable
multi: true
disabled:
variable: _.condition

View file

@ -1,10 +0,0 @@
---
version: 1.1
condition: [] # a condition
variable:
description: a variable
multi: true
disabled:
variable: _.condition

View file

@ -1,12 +0,0 @@
---
version: 1.1
condition: # a condition
- val1
- val2
variable:
description: a variable
multi: true
disabled:
variable: _.condition

View file

@ -1,7 +0,0 @@
---
version: 1.1
family:
exists: true
variable:

View file

@ -1,36 +1,27 @@
---
version: 1.1
var1: # first variable
var1: # a variable
family: # a family
var2:
description: a second variable
test:
- string6
var2: # a second variable
subfamily: # a sub family
variable: # third variable
variable: # a variable
- variable: ___.var1
- variable: __.var2
family2: # a family
var2:
description: a variable2
default:
variable: __.family.var2
var3:
test:
- string5
default: string4
subfamily: # a sub family
variable: # fourth variable
variable: # a variable
- variable: ___.var1
- variable: ___.family.var2
- variable: __.var3
- variable: __.var2

View file

@ -5,7 +5,9 @@ leader:
description: a leadership
type: leadership
leader: [] # the leader
leader:
description: the leader
multi: true
follower1: # the follower1

View file

@ -5,9 +5,13 @@ leadership:
description: A leadership
type: leadership
leader: [] # The leader
leader:
description: The leader
multi: true
follower1: [] # The first follower
follower1:
description: The first follower
multi: true
follower2: # The second follower
- value

View file

@ -8,11 +8,7 @@ int1:
type: number
default:
jinja: >-
{% if rougail.bool %}
1
{% else %}
2
{% endif %}
{% if rougail.bool %}1{% else %}2{% endif %}
description: if bool returns 1 otherwise return 2
int2:
@ -20,9 +16,5 @@ int2:
type: number
default:
jinja: >-
{% if not rougail.bool %}
3
{% else %}
4
{% endif %}
{% if not rougail.bool %}3{% else %}4{% endif %}
description: if bool returns 3 otherwise return 4

View file

@ -1,22 +0,0 @@
---
version: 1.1
leader:
description: a leadership
type: leadership
leader: # a leader
- value1
- value2
follower1: val11 # a follower
follower2: val21 # an other follower
calculate:
description: a calculated variable
multi: true
default:
jinja: |-
{{ _.leader.follower1[0] }}
unique: false

View file

@ -1,22 +0,0 @@
---
version: 1.1
leader:
description: a leadership
type: leadership
leader: # a leader
- value1
- value2
follower1: val11 # a follower
follower2: val21 # an other follower
calculate:
description: a calculated variable
multi: true
default:
jinja: |-
{{ _.leader.follower1[-1] }}
unique: false

View file

@ -1,21 +0,0 @@
---
version: 1.1
leader:
description: a leadership
type: leadership
leader: # a leader
- value1
- value2
follower1: val11 # a follower
follower2: val21 # an other follower
calculate:
description: a calculated variable
multi: true
default:
variable: _.leader.follower1
unique: false

View file

@ -1,20 +0,0 @@
---
version: 1.1
leader:
description: a leadership
type: leadership
leader: # a leader
- value1
- value2
follower1: val11 # a follower
follower2: val21 # an other follower
calculate:
description: a calculated variable
default:
jinja: >-
{{ _.leader.leader[0] }}

View file

@ -1,20 +0,0 @@
---
version: 1.1
leader:
description: a leadership
type: leadership
leader: # a leader
- value1
- value2
follower1: val11 # a follower
follower2: val21 # an other follower
calculate:
description: a calculated variable
default:
jinja: >-
{{ _.leader.leader[-1] }}

View file

@ -1,19 +0,0 @@
---
version: 1.1
leader:
description: a leadership
type: leadership
leader: # a leader
- value1
- value2
follower1: val11 # a follower
follower2: val21 # an other follower
calculate:
description: a calculated variable
default:
variable: _.leader.leader

View file

@ -5,7 +5,9 @@ leader:
description: a leadership
type: leadership
leader: [] # a leader
leader:
description: a leader
multi: true
follower1:
description: a follower

View file

@ -7,7 +7,9 @@ leader:
description: a leadership
type: leadership
leader: [] # a leader
leader:
description: a leader
multi: true
follower:
description: a follower

View file

@ -1,25 +0,0 @@
---
version: 1.1
var: # A suffix variable
- val.1
- val.2
dyn{{ identifier }}:
description: A dynamic family
dynamic:
variable: _.var
var1:
description: A dynamic variable
default:
type: identifier
var2:
description: A dynamic variable
default:
jinja: >-
{{ identifier }}
params:
identifier:
type: identifier

View file

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

View file

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

View file

@ -1,24 +0,0 @@
---
version: 1.1
var: # a suffix variable
- val1
- val2
my_dyn_family_{{ identifier }}:
description: a dynamic family
dynamic:
variable: _.var
propertyerror: false
var:
description: a variable inside a dynamic family
default:
type: identifier
mandatory: false
var2:
description: a variable
multi: true
default:
variable: _.my_dyn_family_{{ identifier }}.var

View file

@ -14,7 +14,9 @@ dyn{{ identifier }}:
description: a leadership
type: leadership
leader: [] # a leader
leader:
description: a leader
multi: true
follower1:
description: a follower1

View file

@ -18,7 +18,9 @@ dyn{{ identifier }}:
description: a leadership
type: leadership
leader: [] # a leader
leader:
description: a leader
multi: true
follower1:
description: a follower1

View file

@ -7,11 +7,11 @@ from rougail_tests.utils import get_structures_list, get_rougail_config, config_
excludes = [
# "16_6exists_family",
# "24_0family_hidden_condition_sub_family",
]
test_ok = get_structures_list(excludes)
# test_ok = [Path('../rougail-tests/structures/00_7help')]
# test_ok = [Path('../rougail-tests/structures/20_9family_absolute')]
def idfn(fixture_value):
@ -32,7 +32,7 @@ def _test_structural_files(file_name, namespace, rougailconfig):
rougailconfig['step.output'] = 'formatter'
##################################
config = None
generated_output = RougailOutput(config, rougailconfig=rougailconfig).run()[1] + '\n'
generated_output = RougailOutput(config, rougailconfig=rougailconfig).run()
output_file = get_output_director(namespace) / file_name.parent.parent.name / file_name.parent.name / file_name.name
if not output_file.is_file():
if not output_file.parent.is_dir():