Compare commits

..

No commits in common. "8bb9bb7e16a527aeb943e2a979b38a1e8f8ec0d5" and "61dc196e85e6e5a74976596213ab446f0d6cd980" have entirely different histories.

99 changed files with 8 additions and 711 deletions

View file

@ -1,10 +1,3 @@
## 0.2.0a15 (2025-11-06)
### Fix
- update tests
- unknown variable
## 0.2.0a14 (2025-10-10)
### Fix

View file

@ -4,7 +4,7 @@ requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail.user_data_yaml"
version = "0.2.0a15"
version = "0.2.0a14"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "Rougail user_data yaml"

View file

@ -56,8 +56,6 @@ class RougailUserDataYaml:
) -> None:
self.yaml = YAML(typ='safe', pure=True)
user_datas = []
if self.file_with_secrets == "last":
last_filename_idx = len(self.filenames) - 1
for idx, filename in enumerate(self.filenames):
filename = Path(filename)
if filename.is_file():
@ -87,7 +85,9 @@ class RougailUserDataYaml:
elif self.file_with_secrets == "first":
allow_secrets_variables = idx == 0
elif self.file_with_secrets == "last":
allow_secrets_variables = idx == last_filename_idx
if not idx:
last_filenames = len(self.filenames) - 1
allow_secrets_variables = idx == last_filenames
else:
allow_secrets_variables = True
user_datas.append(

View file

@ -1 +1 @@
__version__ = "0.2.0a15"
__version__ = "0.2.0a14"

View file

@ -29,6 +29,7 @@ def get_rougail_config(
yaml:
description: {_("Configuration rougail-user-data-yaml")}
disabled:
type: jinja
jinja: |
{{% if step.user_data is propertyerror or 'yaml' not in step.user_data %}}
disabled

View file

@ -1,3 +0,0 @@
---
a_family:
a_boolean: oups

View file

@ -1,3 +0,0 @@
---
a_str:
- ly

View file

@ -1,2 +0,0 @@
---
a_family: oups

View file

@ -1,4 +0,0 @@
---
a_leadership:
- a_leader: val1
a_follower: 1

View file

@ -1,2 +0,0 @@
---
a_multi: oups

View file

@ -1,5 +0,0 @@
---
a_family:
a_boolean:
- true

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"oups\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), invalid value, it will be ignored when loading from the YAML file \"tests/invalid/invalid/00.yml\""
]
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"cannot set the value \"oups\" to the family \"a_family\" (A family), it will be ignored when loading from the YAML file \"tests/invalid/invalid_family/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"cannot set the value \"oups\" to the family \"a_family\" (A family), it will be ignored when loading from the YAML file \"tests/invalid/invalid_family/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"cannot set the value \"oups\" to the family \"a_family\" (A family), it will be ignored when loading from the YAML file \"tests/invalid/invalid_family/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"cannot set the value \"oups\" to the family \"a_family\" (A family), it will be ignored when loading from the YAML file \"tests/invalid/invalid_family/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"oups\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), invalid value, it will be ignored when loading from the YAML file \"tests/invalid/invalid/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"oups\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), invalid value, it will be ignored when loading from the YAML file \"tests/invalid/invalid/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"1\" is an invalid string for \"a_leadership.a_follower\" (A follower) at index \"0\", which is not a string, it will be ignored when loading from the YAML file \"tests/invalid/invalid_leadership/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"1\" is an invalid string for \"a_leadership.a_follower\" (A follower) at index \"0\", which is not a string, it will be ignored when loading from the YAML file \"tests/invalid/invalid_leadership/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"1\" is an invalid string for \"a_leadership.a_follower\" (A follower) at index \"0\", which is not a string, it will be ignored when loading from the YAML file \"tests/invalid/invalid_leadership/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"1\" is an invalid string for \"a_leadership.a_follower\" (A follower) at index \"0\", which is not a string, it will be ignored when loading from the YAML file \"tests/invalid/invalid_leadership/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"oups\" is an invalid string for \"a_multi\" (A multi), which must be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"[True]\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), which must not be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi2/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"[True]\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), which must not be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi2/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"[True]\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), which must not be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi2/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"[True]\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), which must not be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi2/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"oups\" is an invalid string for \"a_multi\" (A multi), which must be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"the value \"oups\" is an invalid string for \"a_multi\" (A multi), which must be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"oups\" is an invalid string for \"a_multi\" (A multi), which must be a list, it will be ignored when loading from the YAML file \"tests/invalid/invalid_multi/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"the value \"oups\" is an invalid boolean for \"a_family.a_boolean\" (A boolean), invalid value, it will be ignored when loading from the YAML file \"tests/invalid/invalid/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"variable or family \"a_family.unknown\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"variable or family \"an_unkown_family\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown2/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"variable or family \"an_unkown_family\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown2/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"variable or family \"an_unkown_family\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown2/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"variable or family \"an_unkown_family\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown2/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"variable or family \"a_family.unknown\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown/00.yml\""
]
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"variable or family \"a_family.unknown\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown/00.yml\""
],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"errors": [
"variable or family \"a_family.unknown\" does not exist, it will be ignored when loading from the YAML file \"tests/invalid/unknown/00.yml\""
],
"warnings": []
}

View file

@ -1,23 +0,0 @@
%YAML 1.2
---
version: 1.1
a_multi: [] # A multi
a_leadership:
description: A leadership
type: leadership
a_leader: # A leader
a_follower: # A follower
a_str: # A str
- val1
a_family: # A family
a_boolean: true # A boolean
a_fami{{ identifier }}: # A dynamic family
...

View file

@ -1,3 +0,0 @@
---
a_family:
unknown: oups

View file

@ -1,3 +0,0 @@
---
an_unkown_family:
unknown: oups

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,9 +0,0 @@
{
"rougail": {
"var": [
1,
2,
3
]
}
}

View file

@ -1,9 +0,0 @@
{
"rougail": {
"var": [
1,
2,
3
]
}
}

View file

@ -1,9 +0,0 @@
{
"rougail": {
"var": [
1,
2,
3
]
}
}

View file

@ -1,7 +0,0 @@
{
"rougail.var": [
1,
2,
3
]
}

View file

@ -1,7 +0,0 @@
{
"rougail.var": [
1,
2,
3
]
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,6 +0,0 @@
{
"rougail": {
"var1": "string1",
"var2": "string1"
}
}

View file

@ -1,6 +0,0 @@
{
"rougail": {
"var1": "string1",
"var2": "string1"
}
}

View file

@ -1,6 +0,0 @@
{
"rougail": {
"var1": "string1",
"var2": "string1"
}
}

View file

@ -1,4 +0,0 @@
{
"rougail.var1": "string1",
"rougail.var2": "string1"
}

View file

@ -1,4 +0,0 @@
{
"rougail.var1": "string1",
"rougail.var2": "string1"
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,5 +0,0 @@
{
"rougail": {
"int": 1
}
}

View file

@ -1,5 +0,0 @@
{
"rougail": {
"int": 1
}
}

View file

@ -1,3 +0,0 @@
{
"rougail.int": 1
}

View file

@ -1,3 +0,0 @@
{
"rougail.int": 1000
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,5 +0,0 @@
{
"rougail": {
"int": 1
}
}

View file

@ -1,5 +0,0 @@
{
"rougail": {
"int": 1
}
}

View file

@ -1,3 +0,0 @@
{
"rougail.int": 1
}

View file

@ -1,3 +0,0 @@
{
"rougail.int": 1000
}

View file

@ -1,6 +0,0 @@
{
"errors": [],
"warnings": [
"variable \"rougail.var\" (A suffix variable) is hidden, it will be ignored when loading from the YAML file \"tests/results/60_0family_dynamic_source_hidden/file/all.yml\""
]
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,14 +0,0 @@
{
"rougail": {
"var": [
"val1",
"val2"
],
"dynval1": {
"var": "string1"
},
"dynval2": {
"var": "string1"
}
}
}

View file

@ -1,14 +0,0 @@
{
"rougail": {
"var": [
"val1",
"val2"
],
"dynval1": {
"var": "string1"
},
"dynval2": {
"var": "string1"
}
}
}

View file

@ -1,10 +0,0 @@
{
"rougail": {
"dynval1": {
"var": "string1"
},
"dynval2": {
"var": "string1"
}
}
}

View file

@ -1,8 +0,0 @@
{
"rougail.var": [
"val1",
"val2"
],
"rougail.dynval1.var": "string1",
"rougail.dynval2.var": "string1"
}

View file

@ -1,8 +0,0 @@
{
"rougail.var": [
"val1",
"val2"
],
"rougail.dynval1.var": "string1",
"rougail.dynval2.var": "string1"
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,12 +0,0 @@
{
"rougail": {
"dynval1": {
"var1": "string1",
"var2": "string1"
},
"dynval2": {
"var1": "string1",
"var2": "string1"
}
}
}

View file

@ -1,12 +0,0 @@
{
"rougail": {
"dynval1": {
"var1": "string1",
"var2": "string1"
},
"dynval2": {
"var1": "string1",
"var2": "string1"
}
}
}

View file

@ -1,12 +0,0 @@
{
"rougail": {
"dynval1": {
"var1": "string1",
"var2": "string1"
},
"dynval2": {
"var1": "string1",
"var2": "string1"
}
}
}

View file

@ -1,6 +0,0 @@
{
"rougail.dynval1.var1": "string1",
"rougail.dynval1.var2": "string1",
"rougail.dynval2.var1": "string1",
"rougail.dynval2.var2": "string1"
}

View file

@ -1,6 +0,0 @@
{
"rougail.dynval1.var1": "string1",
"rougail.dynval1.var2": "string1",
"rougail.dynval2.var1": "string1",
"rougail.dynval2.var2": "string1"
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,4 +0,0 @@
{
"errors": [],
"warnings": []
}

View file

@ -1,11 +0,0 @@
{
"rougail": {
"dynval1": {
"var1": "string1"
},
"dynval2": {
"var1": "string1"
},
"var2": "string1"
}
}

View file

@ -1,11 +0,0 @@
{
"rougail": {
"dynval1": {
"var1": "string1"
},
"dynval2": {
"var1": "string1"
},
"var2": "string1"
}
}

View file

@ -1,11 +0,0 @@
{
"rougail": {
"dynval1": {
"var1": "string1"
},
"dynval2": {
"var1": "string1"
},
"var2": "string1"
}
}

View file

@ -1,5 +0,0 @@
{
"rougail.dynval1.var1": "string1",
"rougail.dynval2.var1": "string1",
"rougail.var2": "string1"
}

View file

@ -1,5 +0,0 @@
{
"rougail.dynval1.var1": "string1",
"rougail.dynval2.var1": "string1",
"rougail.var2": "string1"
}

View file

@ -1 +0,0 @@
---

View file

@ -1,2 +0,0 @@
---
secret1: my_password

View file

@ -1,68 +0,0 @@
from pathlib import Path
from json import dump, load
from rougail import Rougail, RougailConfig
from rougail.user_data_yaml import RougailUserDataYaml
def _test_invalid_no_error(filename):
rougailconfig = RougailConfig.copy()
rougailconfig["main_namespace"] = None
rougailconfig["main_structural_directories"] = ["tests/invalid/structure"]
rougailconfig['step.user_data'] = ['yaml']
rougailconfig['yaml.filename'] = [f"tests/invalid/{filename}"]
rougail = Rougail(rougailconfig)
config = rougail.run()
for invalid_user_datas_error in [False, True]:
if invalid_user_datas_error:
ifilename = f"{filename}_invalid"
else:
ifilename = filename
for unknown_user_datas_error in [False, True]:
if unknown_user_datas_error:
ufilename = f"{ifilename}_unknown"
else:
ufilename = ifilename
generated_user_data = RougailUserDataYaml(config, rougailconfig=rougailconfig).run()
errors = rougail.user_datas(generated_user_data, invalid_user_datas_error=invalid_user_datas_error, unknown_user_datas_error=unknown_user_datas_error)
print(errors)
#expected output
expected_filename = Path('tests') / 'invalid' / 'results' / ufilename / "errors.json"
if not expected_filename.is_file():
expected_filename.parent.mkdir(parents=True, exist_ok=True)
with open(expected_filename, 'a') as json_file:
dump(errors, json_file, indent=4)
with open(expected_filename) as json_file:
expected_errors = load(json_file)
assert expected_errors == errors, expected_filename
def test_invalid():
_test_invalid_no_error("invalid")
def test_invalid_dyn():
_test_invalid_no_error("invalid_dyn")
def test_invalid_family():
_test_invalid_no_error("invalid_family")
def test_invalid_leadership():
_test_invalid_no_error("invalid_leadership")
def test_invalid_multi():
_test_invalid_no_error("invalid_multi")
def test_invalid_multi2():
_test_invalid_no_error("invalid_multi2")
def test_invalid_unknown():
_test_invalid_no_error("unknown")
def test_invalid_unknown2():
_test_invalid_no_error("unknown2")

View file

@ -8,7 +8,7 @@ from json import load, dump, loads, dumps
from ruamel.yaml import YAML
#########################
from rougail_tests.utils import get_structures_list, get_rougail_config, get_values_for_config, config_to_dict, root_test_dir
from rougail_tests.utils import get_structures_list, get_rougail_config, get_values_for_config, config_to_dict
EXT = "yml"
@ -20,7 +20,7 @@ excludes = [
]
test_ok = get_structures_list(excludes)
# test_ok = [Path('../rougail-tests/structures/60_0family_dynamic_source_hidden')]
# test_ok = [Path('../rougail-tests/structures/20_9family_absolute')]
def idfn(fixture_value):
@ -214,93 +214,3 @@ def test_structural_files_directory():
with open(data_file) as json_file:
expected = load(json_file)
assert expected == data, data_file
def test_secret_all():
root_test_dir / '00_6secret'
rougailconfig = get_rougail_config(root_test_dir / '00_6secret', namespace=False)
rougailconfig['step.user_data'] = ['yaml']
rougailconfig["yaml.file_with_secrets"] = "all"
rougailconfig["yaml.filename"] = ["tests/secrets/secret.yml"]
rougail = Rougail(rougailconfig)
config = rougail.run()
user_data = RougailUserData(config, rougailconfig=rougailconfig).run()
errors = rougail.user_datas(user_data)
assert errors == {'errors': [], 'warnings': []}
config_dict = dict(config_to_dict(config.value.get()))
assert config_dict == {'secret1': "my_password", 'secret2': 'value'}
def test_secret_none():
root_test_dir / '00_6secret'
rougailconfig = get_rougail_config(root_test_dir / '00_6secret', namespace=False)
rougailconfig['step.user_data'] = ['yaml']
rougailconfig["yaml.file_with_secrets"] = "none"
rougailconfig["yaml.filename"] = ["tests/secrets/secret.yml"]
rougail = Rougail(rougailconfig)
config = rougail.run()
user_data = RougailUserData(config, rougailconfig=rougailconfig).run()
errors = rougail.user_datas(user_data)
assert errors == {'errors': ['the variable "secret1" contains secrets and should not be defined in the YAML file "tests/secrets/secret.yml"'], 'warnings': []}
config_dict = dict(config_to_dict(config.value.get()))
assert config_dict == {'secret1': None, 'secret2': 'value'}
def test_secret_first():
root_test_dir / '00_6secret'
rougailconfig = get_rougail_config(root_test_dir / '00_6secret', namespace=False)
rougailconfig['step.user_data'] = ['yaml']
rougailconfig["yaml.file_with_secrets"] = "first"
rougailconfig["yaml.filename"] = ["tests/secrets/secret.yml", "tests/secrets/no_secret.yml"]
rougail = Rougail(rougailconfig)
config = rougail.run()
user_data = RougailUserData(config, rougailconfig=rougailconfig).run()
errors = rougail.user_datas(user_data)
assert errors == {'errors': [], 'warnings': []}
config_dict = dict(config_to_dict(config.value.get()))
assert config_dict == {'secret1': "my_password", 'secret2': 'value'}
def test_secret_first_error():
root_test_dir / '00_6secret'
rougailconfig = get_rougail_config(root_test_dir / '00_6secret', namespace=False)
rougailconfig['step.user_data'] = ['yaml']
rougailconfig["yaml.file_with_secrets"] = "first"
rougailconfig["yaml.filename"] = ["tests/secrets/no_secret.yml", "tests/secrets/secret.yml"]
rougail = Rougail(rougailconfig)
config = rougail.run()
user_data = RougailUserData(config, rougailconfig=rougailconfig).run()
errors = rougail.user_datas(user_data)
assert errors == {'errors': ['the variable "secret1" contains secrets and should not be defined in the YAML file "tests/secrets/secret.yml"'], 'warnings': []}
config_dict = dict(config_to_dict(config.value.get()))
assert config_dict == {'secret1': None, 'secret2': 'value'}
def test_secret_last():
root_test_dir / '00_6secret'
rougailconfig = get_rougail_config(root_test_dir / '00_6secret', namespace=False)
rougailconfig['step.user_data'] = ['yaml']
rougailconfig["yaml.file_with_secrets"] = "last"
rougailconfig["yaml.filename"] = ["tests/secrets/no_secret.yml", "tests/secrets/secret.yml"]
rougail = Rougail(rougailconfig)
config = rougail.run()
user_data = RougailUserData(config, rougailconfig=rougailconfig).run()
errors = rougail.user_datas(user_data)
assert errors == {'errors': [], 'warnings': []}
config_dict = dict(config_to_dict(config.value.get()))
assert config_dict == {'secret1': "my_password", 'secret2': 'value'}
def test_secret_last_error():
root_test_dir / '00_6secret'
rougailconfig = get_rougail_config(root_test_dir / '00_6secret', namespace=False)
rougailconfig['step.user_data'] = ['yaml']
rougailconfig["yaml.file_with_secrets"] = "last"
rougailconfig["yaml.filename"] = ["tests/secrets/secret.yml", "tests/secrets/no_secret.yml"]
rougail = Rougail(rougailconfig)
config = rougail.run()
user_data = RougailUserData(config, rougailconfig=rougailconfig).run()
errors = rougail.user_datas(user_data)
assert errors == {'errors': ['the variable "secret1" contains secrets and should not be defined in the YAML file "tests/secrets/secret.yml"'], 'warnings': []}
config_dict = dict(config_to_dict(config.value.get()))
assert config_dict == {'secret1': None, 'secret2': 'value'}