feat: add rougail secret_manager

This commit is contained in:
egarette@silique.fr 2025-03-19 11:43:04 +01:00
parent d35fe16cd9
commit 999b53889c
53 changed files with 652 additions and 64 deletions

View file

@ -43,7 +43,7 @@ def tiramisu_display_name(
"""Replace the Tiramisu display_name function to display path + description"""
doc = kls._get_information(subconfig, "doc", None)
comment = f" ({doc})" if doc and doc != kls.impl_getname() else ""
if "{{ identifier }}" in comment:
if "{{ identifier }}" in comment and subconfig.identifiers:
comment = comment.replace("{{ identifier }}", str(subconfig.identifiers[-1]))
path = kls.impl_getpath()
if "{{ identifier }}" in path and subconfig.identifiers:

View file

@ -136,7 +136,9 @@ class Annotator(Walk):
)
if family.version == "1.0" and "{{ suffix }}" in path:
path = path.replace("{{ suffix }}", "{{ identifier }}")
self.objectspace.dynamics_variable.setdefault(path, []).append(family.path)
self.objectspace.dynamics_variable.setdefault(path, []).append(
family.path
)
self.objectspace.informations.add(family.path, "dynamic_variable", path)
def change_modes(self):
@ -341,7 +343,7 @@ class Annotator(Walk):
if self._has_mode(variable):
msg = _(
'the variable "{0}" is in "{1}" mode but family has the higher family mode "{2}"'
).format(variable.name, variable_mode, family_mode)
).format(variable.path, variable_mode, family_mode)
raise DictConsistencyError(msg, 61, variable.xmlfiles)
self._set_auto_mode(variable, family_mode)
if not variable.mode:

View file

@ -69,12 +69,28 @@ class Annotator(Walk): # pylint: disable=R0903
bool: "boolean",
float: "float",
}
self.verify_secret_managers()
self.verify_choices()
self.convert_variable()
self.convert_test()
self.convert_examples()
self.convert_help()
def verify_secret_managers(self):
for variable in self.get_variables():
if not variable.secret_manager:
continue
path = variable.path
if variable.type not in ["unix_user", "secret"]:
msg = _('only "unix_user" or "secret" variable type can have "secret_manager" attribute, but "{0}" has type "{1}"')
raise DictConsistencyError(msg.format(path, variable.type), 56, variable.xmlfiles)
if variable.multi and path not in self.objectspace.leaders:
msg = _('the variable "{0}" has attribute "secret_manager" but is a multi variable')
raise DictConsistencyError(msg.format(path), 57, variable.xmlfiles)
if variable.default is not None:
msg = _('the variable "{0}" has attribute "secret_manager" so must not have default value')
raise DictConsistencyError(msg.format(path), 59, variable.xmlfiles)
def convert_variable(self):
"""convert variable"""
for variable in self.get_variables():
@ -130,7 +146,9 @@ class Annotator(Walk): # pylint: disable=R0903
):
return
# copy type and params
calculated_variable, identifier = variable.default.get_variable(self.objectspace)
calculated_variable, identifier = variable.default.get_variable(
self.objectspace
)
if calculated_variable is None:
return
variable.type = calculated_variable.type

View file

@ -73,8 +73,7 @@ def get_level(module):
class _RougailConfig:
def __init__(self, backward_compatibility: bool,
add_extra_options: bool):
def __init__(self, backward_compatibility: bool, add_extra_options: bool):
self.backward_compatibility = backward_compatibility
self.add_extra_options = add_extra_options
self.root = None
@ -86,7 +85,9 @@ class _RougailConfig:
)
if self.root:
rougailconfig.config.value.importation(self.config.value.exportation())
rougailconfig.config.property.importation(self.config.property.exportation())
rougailconfig.config.property.importation(
self.config.property.exportation()
)
rougailconfig.config.property.read_only()
rougailconfig.root = self.root
rougailconfig.config = self.config
@ -99,7 +100,9 @@ class _RougailConfig:
return rougailconfig
def generate_config(self):
root, extra_vars = _rougail_config(self.backward_compatibility, self.add_extra_options)
root, extra_vars = _rougail_config(
self.backward_compatibility, self.add_extra_options
)
self.root = root
self.config = Config(
self.root,
@ -343,6 +346,13 @@ load_unexist_redefine:
commandline: false
default: False
secret_manager:
pattern:
description: {_("The secret pattern to build item name in Bitwarden")}
help: {_("The pattern is in Jinja format")}
default: "{{{{ project }}}} - {{{{ environment }}}} - {{{{ service }}}} - {{{{ user }}}}"
"""
processes = {
"structural": [],
@ -367,14 +377,22 @@ load_unexist_redefine:
{NAME}:
description: Select for {NAME}
choices:
""".format(
NAME=normalize_family(process),
)
if process != "structural":
rougail_process += """
alternative_name: {NAME[0]}
""".format(
NAME=normalize_family(process),
)
rougail_process += """
choices:
"""
for obj in objects:
rougail_process += f" - {obj['name']}\n"
if process == "structural":
# rougail_process += """ commandline: false
# rougail_process += """ commandline: false
rougail_process += """ multi: true
default:
- directory
@ -391,11 +409,11 @@ load_unexist_redefine:
jinja: |
"""
for hidden_output in hidden_outputs:
rougail_process += """ {% if _.output == 'NAME' %}
rougail_process += """ {% if _.output is not propertyerror and _.output == 'NAME' %}
Cannot load structural for NAME output
{% endif %}""".replace(
"NAME", hidden_output
)
{% endif %}
""".replace("NAME", hidden_output
)
elif process == "user data":
rougail_process += """ multi: true
mandatory: false"""
@ -411,7 +429,7 @@ load_unexist_redefine:
jinja: |
"""
for hidden_output in hidden_outputs:
rougail_process += """ {% if _.output == 'NAME' %}
rougail_process += """ {% if _.output is not propertyerror and _.output == 'NAME' %}
Cannot load user data for NAME output
{% endif %}""".replace(
"NAME", hidden_output
@ -455,10 +473,7 @@ default_params:
mandatory: false
default: {value}
"""
for process_empty in processes_empty:
rougail_process += process_empty
rougail_options += rougail_process
# print(rougail_options)
convert = FakeRougailConvert(add_extra_options)
convert.init()
convert.namespace = None
@ -468,6 +483,13 @@ default_params:
"1.1",
YAML().load(rougail_options),
)
for process_empty in processes_empty:
convert.parse_root_file(
"rougail.config",
"",
"1.1",
YAML().load(process_empty),
)
extra_vars = {}
objects = []
for obj in sorted(

View file

@ -179,12 +179,16 @@ class ParserVariable:
]
self.structurals = rougailconfig["step.structural"]
self.user_datas = rougailconfig["step.user_data"]
self.output = rougailconfig["step.output"]
try:
self.output = rougailconfig["step.output"]
except:
self.output = None
self.tiramisu_cache = rougailconfig["tiramisu_cache"]
self.load_unexist_redefine = rougailconfig["load_unexist_redefine"]
self.secret_pattern = rougailconfig['secret_manager.pattern']
# change default initkwargs in CONVERT_OPTION
if hasattr(rougailconfig, 'config'):
for sub_od in rougailconfig.config.option('default_params'):
if hasattr(rougailconfig, "config"):
for sub_od in rougailconfig.config.option("default_params"):
for option in sub_od:
if option.owner.isdefault():
continue
@ -216,9 +220,7 @@ class ParserVariable:
family = type(
family.__name__ + "_" + structural, (family, module.Family), {}
)
if "Walker" in module.__all__:
if self.walker:
raise Exception("multiple walker defined!")
if not self.walker and "Walker" in module.__all__:
self.walker = module.Walker
self.variable = variable
self.family = family
@ -393,7 +395,7 @@ class ParserVariable:
exists = obj.pop("exists", None)
else:
exists = None
force_to_attrs = list(self.list_attributes(obj))
force_to_attrs = list(self.list_attributes(obj, filename))
for key, value in obj.items():
if key in force_to_attrs:
if key.startswith("_"):
@ -406,7 +408,9 @@ class ParserVariable:
if family_obj:
if exists in [None, True] and not obj.pop("redefine", False):
msg = _('family "{0}" define multiple time').format(path)
raise DictConsistencyError(msg, 32, self.paths[path].xmlfiles + [filename])
raise DictConsistencyError(
msg, 32, self.paths[path].xmlfiles + [filename]
)
# convert to Calculation objects
self.parse_parameters(
path,
@ -499,10 +503,17 @@ class ParserVariable:
def list_attributes(
self,
obj: Dict[str, Any],
filename: str,
) -> Iterator[str]:
"""List attributes"""
force_to_variable = []
for key, value in obj.items():
if not isinstance(key, str):
raise DictConsistencyError(
f'a key is not in string format: {key}',
103,
[filename],
)
if key in force_to_variable:
continue
if key.startswith("_"):
@ -656,13 +667,17 @@ class ParserVariable:
version,
)
self.parse_params(path, obj, filename)
self.parse_secret_manager(path, obj, filename, version, family_is_dynamic)
exists = obj.pop("exists", None)
if path in self.paths:
if not self.load_unexist_redefine and exists is False:
return
if not obj.pop("redefine", False):
msg = _('variable "{0}" define multiple time').format(path)
raise DictConsistencyError(msg, 45, self.paths[path].xmlfiles + [filename])
if not self.load_unexist_redefine:
if exists is False:
return
if not obj.pop("redefine", False):
msg = _('variable "{0}" define multiple time').format(path)
raise DictConsistencyError(
msg, 45, self.paths[path].xmlfiles + [filename]
)
self.paths.add(
path,
self.paths[path].model_copy(update=obj),
@ -764,10 +779,11 @@ class ParserVariable:
if "params" not in obj:
return
if not isinstance(obj["params"], dict):
raise DictConsistencyError(_("params must be a dict for {0}").format(path),
55,
[filename],
)
raise DictConsistencyError(
_("params must be a dict for {0}").format(path),
55,
[filename],
)
params = []
for key, val in obj["params"].items():
try:
@ -780,17 +796,45 @@ class ParserVariable:
is_follower=None,
attribute=None,
family_is_dynamic=None,
namespace=self.namespace,
xmlfiles=[filename],
)
)
except ValidationError as err:
raise DictConsistencyError(
_('"{0}" has an invalid "params" for {1}: {2}').format(key, path, err),
_('"{0}" has an invalid "params" for {1}: {2}').format(
key, path, err
),
54,
[filename],
) from err
obj["params"] = params
def parse_secret_manager(self, path, obj, filename, version, family_is_dynamic):
"""Parse variable secret_manager"""
if "secret_manager" not in obj:
return
if not isinstance(obj["secret_manager"], dict):
raise DictConsistencyError(
_("secret_manager must be a dict for {0}").format(path),
64,
[filename],
)
secret_manager = {"type": "jinja",
"jinja": self.secret_pattern,
"params": obj["secret_manager"],
}
self.set_calculation(
obj,
"secret_manager",
secret_manager,
path,
family_is_dynamic,
False,
version,
[filename],
)
def add_variable(
self,
name: str,
@ -878,6 +922,9 @@ class ParserVariable:
calculations = calculations[1]
if not isinstance(value, dict) or attribute not in calculations:
return False
return self.check_auto_type(value)
def check_auto_type(self, value):
if "type" in value:
return value["type"] in CALCULATION_TYPES
# auto set type
@ -943,6 +990,7 @@ class ParserVariable:
val["family_is_dynamic"] = family_is_dynamic
val["is_follower"] = is_follower
val["attribute"] = attribute
val["namespace"] = self.namespace
val["xmlfiles"] = xmlfiles
if param_typ not in PARAM_TYPES:
raise DictConsistencyError(
@ -968,7 +1016,7 @@ class ParserVariable:
)
#
if typ == "identifier" and not family_is_dynamic:
msg = f'identifier calculation for "{attribute}" in "{path}" cannot be set none dynamic family'
msg = f'identifier calculation for "{attribute}" in "{path}" cannot be set variable is not in dynamic family'
raise DictConsistencyError(msg, 53, xmlfiles)
if attribute in PROPERTY_ATTRIBUTE:
calc = CALCULATION_PROPERTY_TYPES[typ](**calculation_object)
@ -1106,7 +1154,9 @@ class RougailConvert(ParserVariable):
def parse_directories(self) -> None:
if not self.walker:
msg = _('invalid "structural" definition ({0}), we cannot load any structural file!').format(self.structurals)
msg = _(
'invalid "structural" definition ({0}), we cannot load any structural file!'
).format(self.structurals)
raise DictConsistencyError(msg, 51, None)
self.init()
self.walker(self)

View file

@ -113,23 +113,23 @@ def get_convert_option_types():
if obj == tiramisu.SymLinkOption:
continue
if obj == tiramisu.ChoiceOption:
inst = obj('a', 'a', ('a',), **initkwargs)
inst = obj("a", "a", ("a",), **initkwargs)
else:
inst = obj('a', 'a', **initkwargs)
extra = getattr(inst, '_extra', {})
inst = obj("a", "a", **initkwargs)
extra = getattr(inst, "_extra", {})
if not extra:
continue
params = []
for key, value in extra.items():
if key.startswith('_'):
if key.startswith("_"):
continue
multi = False
if isinstance(value, bool):
key_type = 'boolean'
key_type = "boolean"
elif isinstance(value, str):
key_type = 'string'
key_type = "string"
elif isinstance(value, list):
key_type = 'string'
key_type = "string"
multi = True
params.append((key, key_type, multi, value))
yield typ, params
@ -137,6 +137,7 @@ def get_convert_option_types():
class Param(BaseModel):
key: str
namespace: Optional[str]
model_config = ConfigDict(extra="forbid")
def __init__(
@ -191,19 +192,24 @@ class IndexParam(Param):
self,
**kwargs,
) -> None:
if not kwargs["is_follower"]:
msg = f'the variable "{kwargs["path"]}" is not a follower, so cannot have index type for param in "{kwargs["attribute"]}"'
raise DictConsistencyError(msg, 25, kwargs["xmlfiles"])
super().__init__(**kwargs)
class NamespaceParam(Param):
type: str
namespace: str
PARAM_TYPES = {
"any": AnyParam,
"variable": VariableParam,
"identifier": IdentifierParam,
"information": InformationParam,
"index": IndexParam,
"namespace": NamespaceParam,
}
@ -238,7 +244,7 @@ class Calculation(BaseModel):
)
if not variable:
if not param.get("optional"):
msg = f'cannot find variable "{param["variable"]}" defined attribute in "{self.attribute_name}" for "{self.path}"'
msg = f'cannot find variable "{param["variable"]}" defined in attribute "{self.attribute_name}" for "{self.path}"'
raise DictConsistencyError(msg, 22, self.xmlfiles)
continue
if not isinstance(variable, objectspace.variable):
@ -288,6 +294,7 @@ class JinjaCalculation(Calculation):
"validators",
"choices",
"dynamic",
"secret_manager",
]
jinja: StrictStr
params: Optional[List[Param]] = None
@ -366,7 +373,7 @@ class JinjaCalculation(Calculation):
self,
objectspace,
) -> dict:
if self.attribute_name == "default":
if self.attribute_name in ["default", "secret_manager"]:
if self.return_type:
raise Exception("return_type not allowed!")
variable = objectspace.paths[self.path]
@ -474,7 +481,8 @@ class _VariableCalculation(Calculation):
"variable": variable,
"propertyerror": self.propertyerror,
}
if isinstance(self, VariableCalculation) and self.optional:
is_variable_calculation = isinstance(self, VariableCalculation)
if is_variable_calculation and self.optional:
param["optional"] = self.optional
if identifier:
param["identifier"] = identifier
@ -520,9 +528,10 @@ class _VariableCalculation(Calculation):
variable.multi
or variable.path.rsplit(".", 1)[0] != self.path.rsplit(".", 1)[0]
):
# it's not a follower or not in same leadership
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi'
raise DictConsistencyError(msg, 21, self.xmlfiles)
if is_variable_calculation:
# it's not a follower or not in same leadership
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi'
raise DictConsistencyError(msg, 21, self.xmlfiles)
else:
params[None][0]["index"] = {"index": {"type": "index"}}
if self.path in objectspace.followers:
@ -598,9 +607,12 @@ class VariablePropertyCalculation(_VariableCalculation):
when = self.when_not
inverse = True
else:
if variable.type != "boolean":
raise Exception("only boolean!")
when = True
if variable.multi:
when = []
else:
if variable.type != "boolean":
raise Exception("only boolean!")
when = True
inverse = False
params["when"] = when
params["inverse"] = inverse
@ -737,13 +749,31 @@ class IndexCalculation(Calculation):
}
class NamespaceCalculation(Calculation):
attribute_name: Literal["default", "secret_manager"]
def to_function(
self,
objectspace,
) -> dict:
namespace = objectspace.namespace
if namespace:
namespace = objectspace.paths[namespace].description
return {
"function": "calc_value",
"params": {None: [namespace]},
}
CALCULATION_TYPES = {
"jinja": JinjaCalculation,
"information": InformationCalculation,
"variable": VariableCalculation,
"identifier": IdentifierCalculation,
# FOR VERSION 1.0
"suffix": IdentifierCalculation,
"index": IndexCalculation,
"namespace": NamespaceCalculation,
}
CALCULATION_PROPERTY_TYPES = {
"jinja": JinjaCalculation,
@ -753,6 +783,7 @@ CALCULATION_PROPERTY_TYPES = {
"index": IndexCalculation,
}
BASETYPE_CALC = Union[StrictBool, StrictInt, StrictFloat, StrictStr, Calculation, None]
SECRET_BASETYPE_CALC = Union[StrictStr, JinjaCalculation]
class Family(BaseModel):
@ -799,6 +830,7 @@ class Variable(BaseModel):
validators: Optional[List[Calculation]] = None
# value
default: Union[List[BASETYPE_CALC], BASETYPE_CALC] = None
secret_manager: Optional[JinjaCalculation] = None
# properties
auto_save: bool = False
mandatory: Union[None, bool, Calculation] = None

View file

@ -86,8 +86,10 @@ def test_propertyerror(value: Any) -> bool:
ENV.tests["propertyerror"] = test_propertyerror
def load_functions(path):
def load_functions(path, dict_func=None):
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
if dict_func is None:
dict_func = func
loader = _SourceFileLoader("func", path)
spec = _spec_from_loader(loader.name, loader)
func_ = _module_from_spec(spec)
@ -95,7 +97,7 @@ def load_functions(path):
for function in dir(func_):
if function.startswith("_"):
continue
func[function] = getattr(func_, function)
dict_func[function] = getattr(func_, function)
def rougail_calc_value(*args, __default_value=None, __internal_multi=False, **kwargs):
@ -107,6 +109,21 @@ def rougail_calc_value(*args, __default_value=None, __internal_multi=False, **kw
return values
def kw_to_string(kw, root=None):
# {'_': {'interfaces': {'ip': ['192.168.44.19', '192.168.44.12'], 'domain_name': ['nginx-reverse-proxy.reverseproxy.test.net', 'nginx-reverse-proxy.localdns.test.net']}, 'dns_client_address': 'nginx-reverse-proxy.localdns.test.net'}}
for name, data in kw.items():
if root is None:
path = name
else:
path = root + '.' + name
if isinstance(data, dict):
yield from kw_to_string(data, root=path)
else:
yield f"{path}={data}"
pass
@function_waiting_for_error
def jinja_to_function(
__internal_variable,
@ -144,12 +161,13 @@ def jinja_to_function(
try:
values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
except Exception as err:
kw_str = ", ".join(kw_to_string(kw))
raise ConfigError(
f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}'
f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)} with parameters "{kw_str}": {err}'
) from err
convert = CONVERT_OPTION[__internal_type].get("func", str)
if __internal_multi:
values = [convert(val) for val in values.split("\n") if val != ""]
values = [convert(val.strip()) for val in values.split("\n") if val.strip() != ""]
if not values and __default_value is not None:
return __default_value
return values
@ -204,6 +222,7 @@ func["jinja_to_property"] = jinja_to_property
func["jinja_to_property_help"] = jinja_to_property_help
func["variable_to_property"] = variable_to_property
func["valid_with_jinja"] = valid_with_jinja
func["normalize_family"] = normalize_family
class ConvertDynOptionDescription(DynOptionDescription):

View file

@ -350,6 +350,11 @@ class Common:
else:
value = str(param["value"])
return "ParamValue(" + value + ")"
if param["type"] == "namespace":
namespace = param["namespace"]
if namespace:
namespace = self.objectspace.paths[param["namespace"]].description
return f"ParamValue('{namespace}')"
raise Exception("pfff")
def build_option_param(

View file

@ -23,7 +23,12 @@ from typing import List
from re import findall
from tiramisu import undefined, Calculation
from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError, CancelParam
from tiramisu.error import (
PropertiesOptionError,
LeadershipError,
ConfigError,
CancelParam,
)
from .i18n import _
from .object_model import CONVERT_OPTION
@ -151,8 +156,15 @@ class UserDatas:
if path not in self.values:
continue
options = self.values[path].get("options", {})
if options.get('allow_secrets_variables', True) is False and option.type() == 'password':
self.errors.append(_('the variable "{0}" contains secrets and should not be defined in {1}').format(path, self.values[path]["source"]))
if (
options.get("allow_secrets_variables", True) is False
and option.type() == "password"
):
self.errors.append(
_(
'the variable "{0}" contains secrets and should not be defined in {1}'
).format(path, self.values[path]["source"])
)
continue
value = self.values[path]["values"]
needs_convert = options.get("needs_convert", False)
@ -212,7 +224,9 @@ class UserDatas:
option = self.config.option(path)
if option.isoptiondescription():
self.errors.warnings(
_('the option "{0}" is an option description').format(option.path())
_('the option "{0}" is an option description').format(
option.path()
)
)
continue
value = data["values"]

View file

@ -0,0 +1,6 @@
{
"rougail.variable": {
"owner": "default",
"value": "Rougail"
}
}

View file

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

View file

@ -0,0 +1,6 @@
{
"rougail.variable": {
"owner": "default",
"value": "Rougail"
}
}

View file

@ -0,0 +1,15 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="variable", doc="a variable", default=Calculation(func['calc_value'], Params((ParamValue("Rougail")))), properties=frozenset({"standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,6 @@
{
"rougail.variable": {
"owner": "default",
"value": "Rougail"
}
}

View file

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

View file

@ -0,0 +1,6 @@
{
"rougail.variable": {
"owner": "default",
"value": "Rougail"
}
}

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.variable'] = "{{ namespace }}"
option_2 = StrOption(name="variable", doc="a variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.variable"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['../rougail-tests/structures/00_8calculation_param_namespace/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.variable"), 'namespace': ParamValue('Rougail')})), properties=frozenset({"standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,6 @@
{
"rougail.condition": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1,3 @@
{
"rougail.condition": []
}

View file

@ -0,0 +1,6 @@
{
"rougail.condition": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1 @@
["rougail.condition"]

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="condition", doc="a condition", multi=True, properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_3 = StrOption(name="variable", doc="a variable", multi=True, properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_2)), kwargs={'__internal_multi': ParamValue(True), 'when': ParamValue([]), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="condition", doc="a condition", multi=True, properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_2 = StrOption(name="variable", doc="a variable", multi=True, properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_1)), kwargs={'__internal_multi': ParamValue(True), 'when': ParamValue([]), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,13 @@
{
"rougail.condition": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.variable": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1,7 @@
{
"rougail.condition": [
"val1",
"val2"
],
"rougail.variable": []
}

View file

@ -0,0 +1,13 @@
{
"rougail.condition": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.variable": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1 @@
["rougail.variable"]

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="condition", doc="a condition", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="variable", doc="a variable", multi=True, properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_2)), kwargs={'__internal_multi': ParamValue(True), 'when': ParamValue([]), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="condition", doc="a condition", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="variable", doc="a variable", multi=True, properties=frozenset({"basic", "mandatory", Calculation(func['variable_to_property'], Params((ParamValue("disabled"), ParamOption(option_1)), kwargs={'__internal_multi': ParamValue(True), 'when': ParamValue([]), 'inverse': ParamValue(False)}), help_function=func['variable_to_property'])}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,25 @@
{
"rougail.var": {
"owner": "default",
"value": [
"val.1",
"val.2"
]
},
"rougail.dynval_1.var1": {
"owner": "default",
"value": "val.1"
},
"rougail.dynval_1.var2": {
"owner": "default",
"value": "val.1"
},
"rougail.dynval_2.var1": {
"owner": "default",
"value": "val.2"
},
"rougail.dynval_2.var2": {
"owner": "default",
"value": "val.2"
}
}

View file

@ -0,0 +1,10 @@
{
"rougail.var": [
"val.1",
"val.2"
],
"rougail.dynval_1.var1": "val.1",
"rougail.dynval_1.var2": "val.1",
"rougail.dynval_2.var1": "val.2",
"rougail.dynval_2.var2": "val.2"
}

View file

@ -0,0 +1,25 @@
{
"rougail.var": {
"owner": "default",
"value": [
"val.1",
"val.2"
]
},
"rougail.dynval_1.var1": {
"owner": "default",
"value": "val.1"
},
"rougail.dynval_1.var2": {
"owner": "default",
"value": "val.1"
},
"rougail.dynval_2.var1": {
"owner": "default",
"value": "val.2"
},
"rougail.dynval_2.var2": {
"owner": "default",
"value": "val.2"
}
}

View file

@ -0,0 +1,19 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.dyn{{ identifier }}.var2'] = "{{ identifier }}"
option_2 = StrOption(name="var", doc="A suffix variable", multi=True, default=["val.1", "val.2"], default_multi="val.1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="var1", doc="A dynamic variable", default=Calculation(func['calc_value'], Params((ParamIdentifier()))), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_5 = StrOption(name="var2", doc="A dynamic variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.dyn{{ identifier }}.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['../rougail-tests/structures/60_0family_dynamic_forbidden_char/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.dyn{{ identifier }}.var2"), 'identifier': ParamIdentifier()})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_3 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="A dynamic family", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_2)))), children=[option_4, option_5], properties=frozenset({"standard"}), informations={'dynamic_variable': 'rougail.var'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, optiondescription_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,14 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_dyn{{ identifier }}.var2'] = "{{ identifier }}"
option_1 = StrOption(name="var", doc="A suffix variable", multi=True, default=["val.1", "val.2"], default_multi="val.1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="var1", doc="A dynamic variable", default=Calculation(func['calc_value'], Params((ParamIdentifier()))), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="var2", doc="A dynamic variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_dyn{{ identifier }}.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['../rougail-tests/structures/60_0family_dynamic_forbidden_char/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("dyn{{ identifier }}.var2"), 'identifier': ParamIdentifier()})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_2 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="A dynamic family", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_1)))), children=[option_3, option_4], properties=frozenset({"standard"}), informations={'dynamic_variable': 'var'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, optiondescription_2])

View file

@ -0,0 +1,10 @@
{
"rougail.var1": {
"owner": "default",
"value": []
},
"rougail.var2": {
"owner": "default",
"value": null
}
}

View file

@ -0,0 +1,4 @@
{
"rougail.var1": [],
"rougail.var2": null
}

View file

@ -0,0 +1,10 @@
{
"rougail.var1": {
"owner": "default",
"value": []
},
"rougail.var2": {
"owner": "default",
"value": null
}
}

View file

@ -0,0 +1 @@
["rougail.var2"]

View file

@ -0,0 +1,18 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="var1", doc="A suffix variable", multi=True, properties=frozenset({"standard"}), informations={'type': 'string', 'test': ('val1',)})
option_4 = StrOption(name="var", doc="A dynamic variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_3 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="dyn{{ identifier }}", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_2)))), children=[option_4], properties=frozenset({"basic"}), informations={'dynamic_variable': 'rougail.var1'})
option_5 = StrOption(name="var2", doc="A variable calculated", default=Calculation(func['calc_value'], Params((ParamDynOption(option_4, ["val1"], optional=True)))), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, optiondescription_3, option_5], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,10 @@
{
"rougail.var2": {
"owner": "default",
"value": null
},
"rougail.var1": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1,4 @@
{
"rougail.var2": null,
"rougail.var1": []
}

View file

@ -0,0 +1,10 @@
{
"rougail.var2": {
"owner": "default",
"value": null
},
"rougail.var1": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1 @@
["rougail.var2"]

View file

@ -0,0 +1,18 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_5 = StrOption(name="var", doc="A dynamic variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_2 = StrOption(name="var2", doc="A variable calculated", default=Calculation(func['calc_value'], Params((ParamDynOption(option_5, ["val1"], optional=True)))), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="var1", doc="A suffix variable", multi=True, properties=frozenset({"standard"}), informations={'type': 'string', 'test': ('val1', 'val2')})
optiondescription_4 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="dyn{{ identifier }}", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_3)))), children=[option_5], properties=frozenset({"basic"}), informations={'dynamic_variable': 'rougail.var1'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3, optiondescription_4], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,24 @@
{
"rougail.var": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.my_dyn_family_val1.var": {
"owner": "default",
"value": "val1"
},
"rougail.my_dyn_family_val2.var": {
"owner": "default",
"value": "val2"
},
"rougail.var2": {
"owner": "default",
"value": [
"val1",
"val2"
]
}
}

View file

@ -0,0 +1,12 @@
{
"rougail.var": [
"val1",
"val2"
],
"rougail.my_dyn_family_val1.var": "val1",
"rougail.my_dyn_family_val2.var": "val2",
"rougail.var2": [
"val1",
"val2"
]
}

View file

@ -0,0 +1,24 @@
{
"rougail.var": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.my_dyn_family_val1.var": {
"owner": "default",
"value": "val1"
},
"rougail.my_dyn_family_val2.var": {
"owner": "default",
"value": "val2"
},
"rougail.var2": {
"owner": "default",
"value": [
"val1",
"val2"
]
}
}

View file

@ -0,0 +1,18 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="var", doc="a suffix variable", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="var", doc="a variable inside a dynamic family", default=Calculation(func['calc_value'], Params((ParamIdentifier()))), properties=frozenset({"standard"}), informations={'type': 'string'})
optiondescription_3 = ConvertDynOptionDescription(name="my_dyn_family_{{ identifier }}", doc="a dynamic family", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_2, notraisepropertyerror=True)), kwargs={'allow_none': ParamValue(True)})), children=[option_4], properties=frozenset({"standard"}), informations={'dynamic_variable': 'rougail.var'})
option_5 = StrOption(name="var2", doc="a variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_4)), kwargs={'__internal_multi': ParamValue(True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, optiondescription_3, option_5], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -45,7 +45,7 @@ excludes = set([
])
test_ok -= excludes
test_raise -= excludes
# test_ok = ['00_9default_calculation_multi_optional']
# test_ok = ['00_8calculation_param_namespace']
#test_ok = []
#test_raise = ['88valid_enum_invalid_default']
#test_raise = []