WIP: Expand the developer documentation #27

Draft
gremond wants to merge 62 commits from develop into developer_docs
3476 changed files with 14614 additions and 23586 deletions
Showing only changes of commit cd0187d328 - Show all commits

View file

@ -34,13 +34,19 @@ from .convert import RougailConvert
from .config import RougailConfig
from .update import RougailUpgrade
from .object_model import CONVERT_OPTION
from .utils import normalize_family
def tiramisu_display_name(kls, subconfig) -> str:
"""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 ""
return f"{kls.impl_getpath()}{comment}"
if "{{ suffix }}" in comment:
comment = comment.replace('{{ suffix }}', subconfig.suffixes[-1])
path = kls.impl_getpath()
if "{{ suffix }}" in path:
path = path.replace('{{ suffix }}', normalize_family(subconfig.suffixes[-1]))
return f"{path}{comment}"
class Rougail:

View file

@ -45,7 +45,7 @@ def get_annotators(annotators, module_name):
path = str(pathobj)
if not path.endswith(".py") or path.endswith("__.py"):
continue
module = load_modules(path)
module = load_modules(module_name, path)
if "Annotator" not in dir(module):
continue
annotators[module_name].append(module.Annotator)
@ -62,21 +62,26 @@ class SpaceAnnotator: # pylint: disable=R0903
if ANNOTATORS is None:
ANNOTATORS = {}
get_annotators(ANNOTATORS, "rougail.annotator")
for extra_annotator in objectspace.rougailconfig["extra_annotators"]:
for extra_annotator in objectspace.extra_annotators:
if extra_annotator in ANNOTATORS:
continue
get_annotators(ANNOTATORS, extra_annotator)
for plugin in objectspace.plugins:
try:
get_annotators(ANNOTATORS, f'rougail.{plugin}.annotator')
except ModuleNotFoundError:
pass
annotators = ANNOTATORS["rougail.annotator"].copy()
for extra_annotator in objectspace.rougailconfig["extra_annotators"]:
for extra_annotator in objectspace.extra_annotators:
annotators.extend(ANNOTATORS[extra_annotator])
for plugin in objectspace.plugins:
annotators.extend(ANNOTATORS[f'rougail.{plugin}.annotator'])
annotators = sorted(annotators, key=get_level)
functions = {}
functions_files = objectspace.rougailconfig["functions_file"]
if not isinstance(functions_files, list):
functions_files = [functions_files]
functions_files = objectspace.functions_files
for functions_file in functions_files:
if isfile(functions_file):
loaded_modules = load_modules(functions_file)
loaded_modules = load_modules('function_file', functions_file)
for function in dir(loaded_modules):
if function.startswith("_"):
continue

View file

@ -65,13 +65,16 @@ class Annotator(Walk):
self.objectspace = objectspace
if not self.objectspace.paths:
return
self.modes = {
name: Mode(idx)
for idx, name in enumerate(self.objectspace.rougailconfig["modes_level"])
}
self.check_leadership()
self.remove_empty_families()
self.family_names()
if self.objectspace.modes_level:
self.modes = {
name: Mode(idx)
for idx, name in enumerate(self.objectspace.modes_level)
}
self.default_variable_mode = self.objectspace.default_variable_mode
self.default_family_mode = self.objectspace.default_family_mode
self.change_modes()
self.convert_help()
@ -93,7 +96,7 @@ class Annotator(Walk):
if isinstance(family, self.objectspace.family) and not self._has_variable(
family.path
):
if "." in family.path:
if self.objectspace.paths.default_namespace is None or "." in family.path:
removed_families.append(family.path)
removed_families.reverse()
for family in removed_families:
@ -119,15 +122,15 @@ class Annotator(Walk):
def change_modes(self):
"""change the mode of variables"""
modes_level = self.objectspace.rougailconfig["modes_level"]
default_variable_mode = self.objectspace.rougailconfig["default_variable_mode"]
modes_level = self.objectspace.modes_level
default_variable_mode = self.default_variable_mode
if default_variable_mode not in modes_level:
msg = _(
f'default variable mode "{default_variable_mode}" is not a valid mode, '
f"valid modes are {modes_level}"
)
raise DictConsistencyError(msg, 72, None)
default_family_mode = self.objectspace.rougailconfig["default_family_mode"]
default_family_mode = self.default_family_mode
if default_family_mode not in modes_level:
msg = _(
f'default family mode "{default_family_mode}" is not a valid mode, '
@ -141,12 +144,21 @@ class Annotator(Walk):
families.reverse()
for family in families:
self._change_family_mode(family)
if self.objectspace.paths.default_namespace is None:
for variable_path in self.objectspace.parents['.']:
variable = self.objectspace.paths[variable_path]
if variable.type == "symlink" or variable_path in self.objectspace.families:
continue
self._set_default_mode_variable(variable,
self.default_variable_mode,
check_level=False,
)
def valid_mode(
self,
obj,
) -> None:
modes_level = self.objectspace.rougailconfig["modes_level"]
modes_level = self.objectspace.modes_level
if self._has_mode(obj) and obj.mode not in modes_level:
msg = _(
f'mode "{obj.mode}" for "{obj.name}" is not a valid mode, '
@ -194,11 +206,12 @@ class Annotator(Walk):
self,
variable: "self.objectspace.variable",
family_mode: Optional[str],
check_level: bool=True,
) -> None:
# auto_save variable is set to 'basic' mode
# if its mode is not defined by the user
if not self._has_mode(variable) and variable.auto_save is True:
variable.mode = self.objectspace.rougailconfig["modes_level"][0]
variable.mode = self.objectspace.modes_level[0]
# mandatory variable without value is a basic variable
elif (
not self._has_mode(variable)
@ -206,8 +219,8 @@ class Annotator(Walk):
and variable.default is None
and variable.path not in self.objectspace.default_multi
):
variable_mode = self.objectspace.rougailconfig["modes_level"][0]
if family_mode and self.modes[variable_mode] < self.modes[family_mode]:
variable_mode = self.objectspace.modes_level[0]
if check_level and family_mode and self.modes[variable_mode] < self.modes[family_mode]:
msg = _(
f'the variable "{variable.name}" is mandatory so in "{variable_mode}" mode '
f'but family has the higher family mode "{family_mode}"'
@ -238,13 +251,13 @@ class Annotator(Walk):
# it's a leader
if not leader.mode:
self._set_auto_mode(
leader, self.objectspace.rougailconfig["default_variable_mode"]
leader, self.default_variable_mode
)
return
if self._has_mode(follower):
follower_mode = follower.mode
else:
follower_mode = self.objectspace.rougailconfig["default_variable_mode"]
follower_mode = self.default_variable_mode
if self.modes[leader.mode] > self.modes[follower_mode]:
if self._has_mode(follower) and not self._has_mode(leader):
# if follower has mode but not the leader
@ -266,8 +279,8 @@ class Annotator(Walk):
if family.mode:
family_mode = family.mode
else:
family_mode = self.objectspace.rougailconfig["default_family_mode"]
min_variable_mode = self.objectspace.rougailconfig["modes_level"][-1]
family_mode = self.default_family_mode
min_variable_mode = self.objectspace.modes_level[-1]
# change variable mode, but not if variables are not in a family
is_leadership = family.type == "leadership"
if family.path in self.objectspace.parents:
@ -277,9 +290,7 @@ class Annotator(Walk):
continue
if variable_path in self.objectspace.families:
if not variable.mode:
variable.mode = self.objectspace.rougailconfig[
"default_family_mode"
]
variable.mode = self.default_family_mode
else:
self._change_variable_mode(variable, family_mode, is_leadership)
if self.modes[min_variable_mode] > self.modes[variable.mode]:
@ -301,7 +312,7 @@ class Annotator(Walk):
if variable.mode:
variable_mode = variable.mode
else:
variable_mode = self.objectspace.rougailconfig["default_variable_mode"]
variable_mode = self.default_variable_mode
# none basic variable in high level family has to be in high level
if not is_follower and self.modes[variable_mode] < self.modes[family_mode]:
if self._has_mode(variable):
@ -314,21 +325,6 @@ class Annotator(Walk):
if not variable.mode:
variable.mode = variable_mode
def dynamic_families(self):
"""link dynamic families to object"""
for family in self.get_families():
if family.type != "dynamic":
continue
for variable in self.objectspace.parents[family.path]:
if (
isinstance(variable, self.objectspace.family)
and not variable.leadership
):
msg = _(
f'dynamic family "{family.name}" cannot contains another family'
)
raise DictConsistencyError(msg, 22, family.xmlfiles)
def convert_help(self):
"""Convert variable help"""
for family in self.get_families():

View file

@ -112,21 +112,21 @@ class Annotator(Walk):
self._convert_property(variable)
if variable.hidden:
if variable.hidden is True:
self.frozen[variable.path] = True
elif self.frozen.get(variable.path) is not True:
self.frozen.setdefault(variable.path, []).append(variable.hidden)
if variable.path in self.frozen:
frozen = self.frozen[variable.path]
self.frozen[path] = True
elif self.frozen.get(path) is not True:
self.frozen.setdefault(path, []).append(variable.hidden)
if path in self.frozen:
frozen = self.frozen[path]
if frozen is True:
value = True
else:
value = []
for calculation in frozen:
calculation_object = calculation.__class__
calculation_dict = calculation.model_dump().copy()
calculation_dict["attribute_name"] = "frozen"
calculation_dict["path"] = variable.path
value.append(calculation_object(**calculation_dict))
calculation_copy = calculation.copy()
calculation_copy.attribute_name = 'frozen'
calculation_copy.ori_path = calculation_copy.path
calculation_copy.path = path
value.append(calculation_copy)
if len(value) == 1:
value = value[0]
self.objectspace.properties.add(path, "frozen", value)
@ -142,7 +142,7 @@ class Annotator(Walk):
if variable.unique is False:
self.objectspace.properties.add(path, "notunique", True)
if variable.auto_save:
self.objectspace.properties.add(variable.path, "force_store_value", True)
self.objectspace.properties.add(path, "force_store_value", True)
def _convert_property(
self,

View file

@ -108,7 +108,7 @@ class Annotator(Walk): # pylint: disable=R0903
if variable.choices is None:
msg = f'the variable "{variable.path}" is a "choice" variable but don\'t have any choice'
raise DictConsistencyError(msg, 19, variable.xmlfiles)
if not variable.mandatory:
if not variable.mandatory and not variable.multi:
self.add_choice_nil(variable)
def add_choice_nil(self, variable) -> None:

View file

@ -65,12 +65,14 @@ class Annotator(Walk): # pylint: disable=R0903
if not objectspace.paths:
return
self.objectspace = objectspace
if self.objectspace.main_namespace:
self.forbidden_name = [
"services",
self.objectspace.rougailconfig["variable_namespace"],
self.objectspace.main_namespace
]
for extra in self.objectspace.rougailconfig["extra_dictionaries"]:
for extra in self.objectspace.extra_dictionaries:
self.forbidden_name.append(extra)
else:
self.forbidden_name = []
# default type inference from a default value with :term:`basic types`
self.basic_types = {str: "string", int: "number", bool: "boolean", float: "float"}
self.convert_variable()
@ -89,6 +91,9 @@ class Annotator(Walk): # pylint: disable=R0903
variable.multi = False
if variable.type is None:
variable.type = "string"
self.objectspace.informations.add(
variable.path, "type", variable.type
)
self._convert_variable(variable)
def _convert_variable_inference(
@ -144,6 +149,8 @@ class Annotator(Walk): # pylint: disable=R0903
def convert_test(self):
"""Convert variable tests value"""
for variable in self.get_variables():
if variable.type == "symlink":
continue
if variable.test is None:
# with we want remove test, we set "" has test value
continue
@ -161,7 +168,7 @@ class Annotator(Walk): # pylint: disable=R0903
def verify_choices(self):
for variable in self.get_variables():
if variable.default is None or variable.type != 'choice':
if variable.type != 'choice' or variable.default is None:
continue
if not isinstance(variable.choices, list):
continue

View file

@ -28,52 +28,329 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from os.path import abspath, dirname, join
ROUGAILROOT = "/srv/rougail"
DTDDIR = join(dirname(abspath(__file__)), "data")
from pathlib import Path
from tiramisu import Config
from ruamel.yaml import YAML
from .utils import _, load_modules, normalize_family
from .convert import RougailConvert
RougailConfig = {
"default_dictionary_format_version": None,
"dictionaries_dir": [join(ROUGAILROOT, "dictionaries")],
"extra_dictionaries": {},
"services_dir": [join(ROUGAILROOT, "services")],
"patches_dir": join(ROUGAILROOT, "patches"),
"templates_dir": join(ROUGAILROOT, "templates"),
"destinations_dir": join(ROUGAILROOT, "destinations"),
"tmp_dir": join(ROUGAILROOT, "tmp"),
"functions_file": join(ROUGAILROOT, "functions.py"),
"system_service_directory": "/usr/lib/systemd/system",
"systemd_service_destination_directory": "/usr/local/lib",
"systemd_service_directory": "/systemd",
"systemd_service_file": "rougail.conf",
"systemd_service_ip_file": "rougail_ip.conf",
"systemd_tmpfile_factory_dir": "/usr/local/lib",
"systemd_tmpfile_directory": "/tmpfiles.d",
"systemd_tmpfile_file": "0rougail.conf",
"systemd_tmpfile_delete_before_create": False,
"variable_namespace": "rougail",
"variable_namespace_description": "Rougail",
"auto_freeze_variable": "server_deployed",
"internal_functions": [],
"multi_functions": [],
"extra_annotators": [],
"modes_level": ["basic", "standard", "advanced"],
"default_family_mode": "basic",
"default_variable_mode": "standard",
"default_files_engine": "jinja",
"default_files_mode": 644,
"default_files_owner": "root",
"default_files_group": "root",
"default_files_included": "no",
"default_overrides_engine": "jinja",
"default_service_names_engine": "none",
"default_certificate_domain": "rougail.server_name",
"base_option_name": "baseoption",
"export_with_import": True,
"force_convert_dyn_option_description": False,
"suffix": "",
"tiramisu_cache": None,
"custom_types": {},
}
RENAMED = {'dictionaries_dir': 'main_dictionaries',
'variable_namespace': 'main_namespace',
'functions_file': 'functions_files',
}
NOT_IN_TIRAMISU = {'custom_types': {},
}
SUBMODULES = None
def get_sub_modules():
global SUBMODULES
if SUBMODULES is None:
SUBMODULES = {}
for submodule in Path(__file__).parent.iterdir():
if submodule.name.startswith('_') or not submodule.is_dir():
continue
config_file = submodule / 'config.py'
if config_file.is_file():
SUBMODULES[submodule.name] = load_modules('rougail.' + submodule.name + '.config', str(config_file))
return SUBMODULES
def get_level(module):
return module['level']
class _RougailConfig:
def __init__(self,
backward_compatibility: bool,
root,
):
self.backward_compatibility = backward_compatibility
self.root = root
self.config = Config(
self.root,
)
self.config.property.read_only()
for variable, default_value in NOT_IN_TIRAMISU.items():
if not isinstance(default_value, str):
default_value = default_value.copy()
setattr(self, variable, default_value)
def copy(self):
rougailconfig = _RougailConfig(self.backward_compatibility, self.root)
rougailconfig.config.value.importation(self.config.value.exportation())
rougailconfig.config.property.importation(self.config.property.exportation())
rougailconfig.config.property.read_only()
for variable in NOT_IN_TIRAMISU:
value = getattr(self, variable)
if not isinstance(value, str):
value = value.copy()
setattr(rougailconfig, variable, value)
return rougailconfig
def __setitem__(self,
key,
value,
) -> None:
if key in NOT_IN_TIRAMISU:
setattr(self, key, value)
else:
self.config.property.read_write()
if key == 'export_with_import':
key = 'not_export_with_import'
key = RENAMED.get(key, key)
option = self.config.option(key)
if option.isoptiondescription() and option.isleadership():
leader = list(value)
option.leader().value.set(leader)
follower = option.followers()[0]
for idx, val in enumerate(value.values()):
self.config.option(follower.path(), idx).value.set(val)
elif key == 'not_export_with_import':
option.value.set(not value)
else:
option.value.set(value)
self.config.property.read_only()
def __getitem__(self,
key,
) -> None:
if key in NOT_IN_TIRAMISU:
return getattr(self, key)
if key == 'export_with_import':
key = 'not_export_with_import'
option = self.config.option(key)
if option.isoptiondescription() and option.isleadership():
return self.get_leadership(option)
ret = self.config.option(key).value.get()
if key == 'not_export_with_import':
return not ret
return ret
def get_leadership(self,
option
) -> dict:
leader, *followers = option.value.get().values()
return dict(zip(leader, followers))
class FakeRougailConvert(RougailConvert):
def load_config(self,
rougailconfig: 'RougailConfig',
) -> None:
self.main_namespace = None
self.suffix = ''
self.custom_types = {}
self.functions_files = []
self.modes_level = []
self.extra_annotators = []
self.base_option_name = "baseoption"
self.export_with_import = True
self.internal_functions = []
self.plugins = ['structural_commandline']
def get_rougail_config(*,
backward_compatibility=True,
) -> _RougailConfig:
if backward_compatibility:
main_namespace_default = 'rougail'
else:
main_namespace_default = 'null'
rougail_options = """default_dictionary_format_version:
description: Dictionary format version by default, if not specified in dictionary file
alternative_name: v
choices:
- '1.0'
- '1.1'
mandatory: false
main_dictionaries:
description: 'Directories where dictionary files are placed'
type: unix_filename
alternative_name: m
params:
allow_relative: True
test_existence: True
types:
- directory
multi: true
main_namespace:
description: Main namespace name
default: MAIN_MAMESPACE_DEFAULT
alternative_name: n
mandatory: false
extra_dictionaries:
description: Extra namespaces
type: leadership
disabled:
type: jinja
jinja: |
{% if not main_namespace %}
main_namespace not available
{% endif %}
names:
description: 'Extra namespace name'
# alternative_name: e
multi: true
mandatory: false
directories:
description: Directories where extra dictionary files are placed
# alternative_name: d
type: unix_filename
params:
allow_relative: true
test_existence: true
types:
- directory
multi: true
functions_files:
description: File with functions
alternative_name: f
type: unix_filename
params:
allow_relative: true
test_existence: true
types:
- file
multi: true
mandatory: false
modes_level:
description: All modes level available
default:
- basic
- standard
- advanced
commandline: false
default_family_mode:
description: Default mode for a family
default:
type: jinja
jinja: |
{{ modes_level[0] }}
validators:
- type: jinja
jinja: |
{% if default_family_mode not in modes_level %}
not in modes_level ({modes_level})
{% endif %}
commandline: false
default_variable_mode:
description: Default mode for a variable
default:
type: jinja
jinja: |
{{ modes_level[1] }}
validators:
- type: jinja
jinja: |
{% if default_variable_mode not in modes_level %}
not in modes_level ({modes_level})
{% endif %}
commandline: false
base_option_name:
description: Option name for the base option
default: baseoption
commandline: false
not_export_with_import:
description: In cache file, do not importation of Tiramisu and other dependencies
default: false
commandline: false
tiramisu_cache:
description: Tiramisu cache filename
alternative_name: t
type: unix_filename
mandatory: false
params:
allow_relative: true
internal_functions:
description: Name of internal functions that we can use as a function
multi: true
mandatory: false
commandline: false
extra_annotators:
description: Name of extra annotators
multi: true
mandatory: false
commandline: false
suffix:
description: Suffix add to generated option name
default: ''
mandatory: false
commandline: false
""".replace('MAIN_MAMESPACE_DEFAULT', main_namespace_default)
processes = {'output': [],
'user data': [],
# 'structural': [],
}
for module in get_sub_modules().values():
data = module.get_rougail_config()
processes[data['process']].append(data)
# reorder
for process in processes:
processes[process] = list(sorted(processes[process], key=get_level))
rougail_process = 'step: # Load and exporter steps'
for process in processes:
if processes[process]:
objects = processes[process]
rougail_process += """
{NAME}:
description: Select for {NAME}
alternative_name: {NAME[0]}
choices:
""".format(NAME=normalize_family(process),
)
for obj in objects:
rougail_process += f" - {obj['name']}\n"
if process == 'user data':
rougail_process +=""" multi: true
mandatory: false
"""
hidden_outputs = [process['name'] for process in processes['output'] if not process.get('allow_user_data', True)]
if hidden_outputs:
rougail_process +=""" hidden:
type: jinja
jinja: |
"""
for hidden_output in hidden_outputs:
rougail_process += """ {% if _.output == 'NAME' %}
Cannot load user data for NAME output
{% endif %}
""".replace('NAME', hidden_output)
else:
rougail_process += ' default: {DEFAULT}'.format(DEFAULT=objects[0]['name'])
else:
rougail_process += """
{NAME}:
description: Select for {NAME}
hidden: true
""".format(NAME=normalize_family(process),
)
rougail_options += rougail_process
convert = FakeRougailConvert({})
convert._init()
convert.namespace = None
convert.parse_root_file(
'rougail.config',
'',
'1.1',
YAML().load(rougail_options),
)
for process in processes:
for obj in processes[process]:
if not 'options' in obj:
continue
convert.parse_root_file(
f'rougail.config.{obj["name"]}',
'',
'1.1',
YAML().load(obj['options']),
)
tiram_obj = convert.save('a')
optiondescription = {}
exec(tiram_obj, {}, optiondescription) # pylint: disable=W0122
return _RougailConfig(backward_compatibility, optiondescription["option_0"])
RougailConfig = get_rougail_config()

View file

@ -47,6 +47,10 @@ from typing import (
from pydantic import ValidationError
from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap
from pydantic import ValidationError
from warnings import warn
from tiramisu.error import display_list
from .annotator import SpaceAnnotator
@ -65,7 +69,8 @@ from .object_model import (
VariableCalculation,
)
from .tiramisureflector import TiramisuReflector
from .utils import get_realpath
from .utils import get_realpath, normalize_family, load_modules
from .error import DictConsistencyError
property_types = Union[Literal[True], Calculation]
properties_types = Dict[str, property_types]
@ -97,7 +102,7 @@ class Property:
class Paths:
_regexp_relative = compile(r"^_*\.(.*)$")
regexp_relative = compile(r"^_*\.(.*)$")
def __init__(
self,
@ -105,6 +110,8 @@ class Paths:
) -> None:
self._data: Dict[str, Union[Variable, Family]] = {}
self._dynamics: Dict[str:str] = {}
if default_namespace is not None:
default_namespace = normalize_family(default_namespace)
self.default_namespace = default_namespace
self.path_prefix = None
@ -124,6 +131,18 @@ class Paths:
if not force and is_dynamic:
self._dynamics[path] = dynamic
def get_relative_path(self,
path: str,
current_path: str,
):
relative, subpath = path.split(".", 1)
relative_len = len(relative)
path_len = current_path.count(".")
if path_len + 1 == relative_len:
return subpath
parent_path = current_path.rsplit(".", relative_len)[0]
return parent_path + "." + subpath
def get_with_dynamic(
self,
path: str,
@ -134,12 +153,10 @@ class Paths:
xmlfiles: List[str],
) -> Any:
suffix = None
if version != "1.0" and self._regexp_relative.search(path):
relative, subpath = path.split(".", 1)
relative_len = len(relative)
path_len = current_path.count(".")
parent_path = current_path.rsplit(".", relative_len)[0]
path = parent_path + "." + subpath
if version != '1.0' and self.regexp_relative.search(path):
path = self.get_relative_path(path,
current_path,
)
else:
path = get_realpath(path, suffix_path)
dynamic = None
@ -159,7 +176,11 @@ class Paths:
new_path = name
continue
for dynamic_path in self._dynamics:
if '.' in dynamic_path:
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
else:
parent_dynamic = None
name_dynamic = dynamic_path
if (
version == "1.0"
and parent_dynamic == parent_path
@ -192,7 +213,11 @@ class Paths:
new_path = name
continue
for dynamic_path in self._dynamics:
if '.' in dynamic_path:
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
else:
parent_dynamic = None
name_dynamic = dynamic_path
if (
"{{ suffix }}" not in name_dynamic
or parent_path != parent_dynamic
@ -203,6 +228,9 @@ class Paths:
if len(finded) != 1 or not finded[0]:
continue
suffixes.append(finded[0])
if new_path is None:
new_path = name_dynamic
else:
new_path += "." + name_dynamic
break
else:
@ -274,7 +302,7 @@ class Informations:
if path not in self._data:
self._data[path] = {}
if key in self._data[path]:
raise Exception(f"already key {key} in {path}")
raise Exception(f'an information "{key}" is already present in "{path}"')
self._data[path][key] = data
def get(
@ -286,7 +314,8 @@ class Informations:
class ParserVariable:
def __init__(self, rougailconfig):
self.paths = Paths(rougailconfig["variable_namespace"])
self.load_config(rougailconfig)
self.paths = Paths(self.main_namespace)
self.families = []
self.variables = []
self.parents = {".": []}
@ -297,13 +326,12 @@ class ParserVariable:
self.multis = {}
self.default_multi = {}
self.jinja = {}
self.rougailconfig = rougailconfig
#
self.convert_options = list(CONVERT_OPTION)
self.convert_options.extend(self.rougailconfig["custom_types"])
self.convert_options.extend(self.custom_types)
#
self.family = Family
self.dynamic = Dynamic
self.choice = Variable # Choice
#
self.exclude_imports = []
self.informations = Informations()
@ -314,10 +342,42 @@ class ParserVariable:
self.is_init = False
super().__init__()
def init(self):
def load_config(self,
rougailconfig: 'RougailConfig',
) -> None:
self.rougailconfig = rougailconfig
self.main_namespace = rougailconfig["main_namespace"]
self.main_dictionaries = rougailconfig["main_dictionaries"]
if self.main_namespace:
self.extra_dictionaries = rougailconfig["extra_dictionaries"]
self.suffix = rougailconfig["suffix"]
self.default_dictionary_format_version = rougailconfig["default_dictionary_format_version"]
self.custom_types = rougailconfig["custom_types"]
self.functions_files = rougailconfig["functions_files"]
self.modes_level = rougailconfig["modes_level"]
self.default_variable_mode = rougailconfig["default_variable_mode"]
self.default_family_mode = rougailconfig["default_family_mode"]
self.extra_annotators = rougailconfig["extra_annotators"]
self.base_option_name = rougailconfig["base_option_name"]
self.export_with_import = rougailconfig["export_with_import"]
self.internal_functions = rougailconfig["internal_functions"]
self.plugins = []
def _init(self):
if self.is_init:
return
self.variable = Variable
variable = Variable
if self.plugins:
root = Path(__file__).parent
for plugin in self.plugins:
module_path = root / plugin / 'object_model.py'
if not module_path.is_file():
continue
module = load_modules(f'rougail.{plugin}.object_model', str(module_path))
if 'Variable' not in module.__all__:
continue
variable = type(variable.__name__ + '_' + plugin, (Variable, module.Variable), {})
self.variable = variable
hint = get_type_hints(self.dynamic)
# FIXME: only for format 1.0
hint["variable"] = str
@ -330,16 +390,14 @@ class ParserVariable:
)
#
hint = get_type_hints(self.variable)
self.variable_types = (
self.convert_options
) # hint["type"].__args__ # pylint: disable=W0201
#
hint = get_type_hints(self.choice)
self.choice_attrs = frozenset( # pylint: disable=W0201
self.variable_attrs = frozenset( # pylint: disable=W0201
set(hint) - {"name", "path", "xmlfiles"} | {"redefine", "exists"}
)
self.choice_calculations = self.search_calculation( # pylint: disable=W0201
self.variable_calculations = self.search_calculation( # pylint: disable=W0201
hint
)
self.is_init = True
@ -379,13 +437,13 @@ class ParserVariable:
# all attributes are in variable object
# and values in attributes are not dict is not Calculation
if isinstance(obj, dict):
extra_keys = set(obj) - self.choice_attrs
extra_keys = set(obj) - self.variable_attrs
if not extra_keys:
for key, value in obj.items():
if isinstance(value, dict) and not self.is_calculation(
key,
value,
self.choice_calculations,
self.variable_calculations,
False,
):
break
@ -432,6 +490,9 @@ class ParserVariable:
if name.startswith("_"):
msg = f'the variable or family name "{name}" is incorrect, it must not starts with "_" character'
raise DictConsistencyError(msg, 16, [filename])
if not subpath:
path = name
else:
path = f"{subpath}.{name}"
if version == "0.1" and not isinstance(obj, dict) and obj is not None:
msg = f'the variable "{path}" has a wrong type "{type(obj)}"'
@ -480,7 +541,7 @@ class ParserVariable:
return
family_obj = {}
subfamily_obj = {}
force_to_attrs = list(self.list_attributes(obj, version))
force_to_attrs = list(self.list_attributes(obj))
for key, value in obj.items():
if key in force_to_attrs:
if key.startswith("_"):
@ -493,7 +554,17 @@ class ParserVariable:
if family_obj:
if not obj.pop("redefine", False):
raise Exception(
f"The family {path} already exists and she is not redefined in {filemane}"
f"The family {path} already exists and she is not redefined in {filename}"
)
# convert to Calculation objects
self.parse_parameters(
path,
obj,
filename,
family_is_dynamic,
False,
version,
typ="family",
)
self.paths.add(
path,
@ -518,14 +589,15 @@ class ParserVariable:
if self.get_family_or_variable_type(family_obj) == "dynamic":
family_is_dynamic = True
parent_dynamic = path
if version == "1.0" and "{{ suffix }}" not in name:
name += "{{ suffix }}"
path += "{{ suffix }}"
if "{{ suffix }}" not in name:
if '{{ suffix }}' not in name:
if "variable" in family_obj:
name += '{{ suffix }}'
path += '{{ suffix }}'
else:
msg = f'dynamic family name must have "{{{{ suffix }}}}" in his name for "{path}"'
raise DictConsistencyError(msg, 13, [filename])
if version != "1.0" and not family_obj and comment:
family_obj["description"] = comment
if version != '1.0' and not family_obj and comment:
family_obj['description'] = comment
self.add_family(
path,
name,
@ -558,7 +630,6 @@ class ParserVariable:
def list_attributes(
self,
obj: Dict[str, Any],
version: str,
) -> Iterator[str]:
"""List attributes"""
force_to_variable = []
@ -581,7 +652,8 @@ class ParserVariable:
):
# it's a dict, so a new variables!
continue
if version == '1.0' and key == "variable" and obj.get("type") != "dynamic" and obj.get("_type") != "dynamic":
# 'variable' for compatibility to format 1.0
if key == "variable" and obj.get("type") != "dynamic" and obj.get("_type") != "dynamic":
continue
if key in self.family_attrs:
yield key
@ -599,6 +671,7 @@ class ParserVariable:
"""Add a new family"""
family["path"] = path
family["namespace"] = self.namespace
family["version"] = version
family["xmlfiles"] = [filename]
obj_type = self.get_family_or_variable_type(family)
if obj_type == "dynamic":
@ -625,9 +698,17 @@ class ParserVariable:
del family["variable"]
# FIXME only for 1.0
if "variable" in family:
raise Exception(
f'dynamic family must not have "variable" attribute for "{family["path"]}" in {family["xmlfiles"]}'
)
family['dynamic'] = {'type': 'variable',
'variable': family['variable'],
'propertyerror': False,
'allow_none': True,
}
del family['variable']
if version != "1.0":
warning = f'"variable" attribute in dynamic family "{ path }" is depreciated in {filename}'
warn(warning)
if "variable" in family:
raise Exception(f'dynamic family must not have "variable" attribute for "{family["path"]}" in {family["xmlfiles"]}')
else:
family_obj = self.family
# convert to Calculation objects
@ -679,7 +760,7 @@ class ParserVariable:
if version == "1.0" or isinstance(obj, dict):
if obj is None:
obj = {}
extra_attrs = set(obj) - self.choice_attrs
extra_attrs = set(obj) - self.variable_attrs
else:
extra_attrs = []
obj = {"default": obj}
@ -720,7 +801,7 @@ class ParserVariable:
# so do nothing
return
if "redefine" in obj and obj["redefine"]:
msg = f'cannot redefine the inexisting variable "{path}" in {filename}'
msg = f'cannot redefine the inexisting variable "{path}"'
raise DictConsistencyError(msg, 46, [filename])
obj["path"] = path
self.add_variable(
@ -745,7 +826,7 @@ class ParserVariable:
):
"""Parse variable or family parameters"""
if typ == "variable":
calculations = self.choice_calculations
calculations = self.variable_calculations
else:
calculations = self.family_calculations
for key, value in obj.items():
@ -846,7 +927,7 @@ class ParserVariable:
variable_type = self.get_family_or_variable_type(variable)
obj = {
"symlink": SymLink,
"choice": self.choice,
"choice": self.variable,
}.get(variable_type, self.variable)
try:
variable_obj = obj(name=name, **variable)
@ -861,7 +942,11 @@ class ParserVariable:
parent_dynamic,
)
self.variables.append(variable["path"])
self.parents[variable["path"].rsplit(".", 1)[0]].append(variable["path"])
if '.' in variable["path"]:
parent_path = variable["path"].rsplit(".", 1)[0]
else:
parent_path = "."
self.parents[parent_path].append(variable["path"])
self.set_name(
variable_obj,
"option_",
@ -875,7 +960,10 @@ class ParserVariable:
del self.paths[path]
self.families.remove(path)
del self.parents[path]
if '.' in path:
parent = path.rsplit(".", 1)[0]
else:
parent = '.'
self.parents[parent].remove(path)
###############################################################################################
@ -890,7 +978,7 @@ class ParserVariable:
self.index += 1
self.reflector_names[
obj.path
] = f'{option_prefix}{self.index}{self.rougailconfig["suffix"]}'
] = f'{option_prefix}{self.index}{self.suffix}'
###############################################################################################
# calculations
@ -1025,7 +1113,7 @@ class RougailConvert(ParserVariable):
path_prefix: Optional[str] = None,
) -> None:
"""Parse directories content"""
self.init()
self._init()
if path_prefix:
if path_prefix in self.parents:
raise Exception("pfffff")
@ -1039,28 +1127,54 @@ class RougailConvert(ParserVariable):
"",
False,
None,
None,
'',
)
else:
root_parent = "."
if self.main_namespace:
directory_dict = chain(
(
(
self.rougailconfig["variable_namespace"],
self.rougailconfig["dictionaries_dir"],
self.main_namespace,
self.main_dictionaries,
),
),
self.rougailconfig["extra_dictionaries"].items(),
self.extra_dictionaries.items(),
)
for namespace, extra_dirs in directory_dict:
if namespace is None:
self.namespace = namespace
else:
self.namespace = normalize_family(namespace)
if root_parent == ".":
namespace_path = self.namespace
else:
namespace_path = f"{root_parent}.{self.namespace}"
if namespace_path in self.parents:
raise Exception("pfff")
for filename in self.get_sorted_filename(extra_dirs):
for idx, filename in enumerate(self.get_sorted_filename(extra_dirs)):
if not idx:
self.parse_family(
'',
self.namespace,
namespace_path,
{'description': namespace,
},
'',
)
self.parse_variable_file(
filename,
namespace_path,
)
else:
self.namespace = None
if root_parent == ".":
namespace_path = ''
else:
namespace_path = f"{root_parent}"
if namespace_path in self.parents:
raise Exception("pfff")
for filename in self.get_sorted_filename(self.main_dictionaries):
self.parse_variable_file(
filename,
namespace_path,
@ -1093,13 +1207,18 @@ class RougailConvert(ParserVariable):
objects,
filename,
)
self.parse_family(
filename,
self.namespace,
self.parse_root_file(filename,
path,
{},
version,
objects,
)
def parse_root_file(self,
filename: str,
path: str,
version: str,
objects: dict,
) -> None:
for name, obj in objects.items():
comment = self.get_comment(name, objects)
self.family_or_variable(
@ -1124,7 +1243,7 @@ class RougailConvert(ParserVariable):
continue
filenames = {}
for file_path in directory.iterdir():
if not file_path.suffix == ".yml":
if file_path.suffix not in [".yml", ".yaml"]:
continue
if file_path.name in filenames:
raise DictConsistencyError(
@ -1149,7 +1268,7 @@ class RougailConvert(ParserVariable):
break
else:
# the `version` attribute is not mandatory
default_version = self.rougailconfig["default_dictionary_format_version"]
default_version = self.default_dictionary_format_version
if default_version is not None:
version = default_version
else:
@ -1176,15 +1295,12 @@ class RougailConvert(ParserVariable):
def reflect(self) -> None:
"""Apply TiramisuReflector"""
functions_file = self.rougailconfig["functions_file"]
if not isinstance(functions_file, list):
functions_file = [functions_file]
functions_file = [
func for func in functions_file if func not in self.exclude_imports
functions_files = [
func for func in self.functions_files if func not in self.exclude_imports
]
self.reflector = TiramisuReflector(
self,
functions_file,
functions_files,
)
def save(
@ -1192,6 +1308,7 @@ class RougailConvert(ParserVariable):
filename: str,
):
"""Return tiramisu object declaration as a string"""
self._init()
self.annotate()
self.reflect()
output = self.reflector.get_text() + "\n"

View file

@ -51,40 +51,45 @@ def convert_boolean(value: str) -> bool:
CONVERT_OPTION = {
"string": dict(opttype="StrOption"),
"number": dict(opttype="IntOption", func=int),
"float": dict(opttype="FloatOption", func=float),
"string": dict(opttype="StrOption", example="xxx"),
"number": dict(opttype="IntOption", func=int, example=42),
"float": dict(opttype="FloatOption", func=float, example=1.42),
"boolean": dict(opttype="BoolOption", func=convert_boolean),
"secret": dict(opttype="PasswordOption"),
"mail": dict(opttype="EmailOption"),
"unix_filename": dict(opttype="FilenameOption"),
"date": dict(opttype="DateOption"),
"unix_user": dict(opttype="UsernameOption"),
"ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}),
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}),
"netmask": dict(opttype="NetmaskOption"),
"network": dict(opttype="NetworkOption"),
"network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}),
"broadcast": dict(opttype="BroadcastOption"),
"secret": dict(opttype="PasswordOption", example="xxx"),
"mail": dict(opttype="EmailOption", example="user@example.net"),
"unix_filename": dict(opttype="FilenameOption", example="/tmp/myfile.txt"),
"date": dict(opttype="DateOption", example="2000-01-01"),
"unix_user": dict(opttype="UsernameOption", example="xxx"),
"ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}, example="1.1.1.1"),
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}, example="1.1.1.0/24"),
"netmask": dict(opttype="NetmaskOption", example="255.255.255.0"),
"network": dict(opttype="NetworkOption", example="1.1.1.0"),
"network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24"),
"broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"),
"netbios": dict(
opttype="DomainnameOption",
initkwargs={"type": "netbios", "warnings_only": True},
example="example"
),
"domainname": dict(
opttype="DomainnameOption", initkwargs={"type": "domainname", "allow_ip": False}
opttype="DomainnameOption", initkwargs={"type": "domainname", "allow_ip": False},
example="example.net"
),
"hostname": dict(
opttype="DomainnameOption", initkwargs={"type": "hostname", "allow_ip": False}
opttype="DomainnameOption", initkwargs={"type": "hostname", "allow_ip": False},
example="example"
),
"web_address": dict(
opttype="URLOption", initkwargs={"allow_ip": False, "allow_without_dot": True}
opttype="URLOption", initkwargs={"allow_ip": False, "allow_without_dot": True},
example="https://example.net"
),
"port": dict(opttype="PortOption", initkwargs={"allow_private": True}),
"mac": dict(opttype="MACOption"),
"port": dict(opttype="PortOption", initkwargs={"allow_private": True}, example="111"),
"mac": dict(opttype="MACOption", example="00:00:00:00:00"),
"unix_permissions": dict(
opttype="PermissionsOption", initkwargs={"warnings_only": True}, func=int
opttype="PermissionsOption", initkwargs={"warnings_only": True}, func=int,
example="644"
),
"choice": dict(opttype="ChoiceOption"),
"choice": dict(opttype="ChoiceOption", example="xxx"),
#
"symlink": dict(opttype="SymLinkOption"),
}
@ -107,7 +112,7 @@ class Param(BaseModel):
class AnyParam(Param):
type: str
value: BASETYPE
value: Union[BASETYPE, List[BASETYPE]]
class VariableParam(Param):
@ -164,7 +169,9 @@ class Calculation(BaseModel):
path: str
inside_list: bool
version: str
namespace: str
ori_path: Optional[str]=None
default_values: Any=None
namespace: Optional[str]
xmlfiles: List[str]
model_config = ConfigDict(extra="forbid")
@ -182,12 +189,17 @@ class Calculation(BaseModel):
for param_obj in self.params:
param = param_obj.model_dump()
if param.get("type") == "variable":
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic(
param["variable"], self.path_prefix, self.path, self.version, self.namespace, self.xmlfiles
param["variable"], self.path_prefix, path, self.version, self.namespace, self.xmlfiles
)
if not variable:
if not param.get("optional"):
raise Exception(f"cannot find {param['variable']}")
msg = f'cannot find variable "{param["variable"]}" defined attribute in "{self.attribute_name}" for "{self.path}"'
raise DictConsistencyError(msg, 22, self.xmlfiles)
continue
if not isinstance(variable, objectspace.variable):
raise Exception("pfff it's a family")
@ -196,8 +208,12 @@ class Calculation(BaseModel):
param["suffix"] = suffix
if param.get("type") == "information":
if param["variable"]:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic(
param["variable"], self.path_prefix, self.path, self.version, self.namespace, self.xmlfiles
param["variable"], self.path_prefix, path, self.version, self.namespace, self.xmlfiles
)
if not variable:
msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"'
@ -219,6 +235,7 @@ class JinjaCalculation(Calculation):
jinja: StrictStr
params: Optional[List[Param]] = None
return_type: BASETYPE = None
description: Optional[StrictStr] = None
def _jinja_to_function(
self,
@ -245,14 +262,20 @@ class JinjaCalculation(Calculation):
"__internal_multi": multi,
},
}
if self.default_values:
default["params"]['__default_value'] = self.default_values
if add_help:
default["help"] = function + "_help"
if self.params:
default["params"] |= self.get_params(objectspace)
if params:
default["params"] |= params
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
for sub_variable, suffix, true_path in get_jinja_variable_to_param(
self.path,
path,
self.jinja,
objectspace,
variable.xmlfiles,
@ -261,7 +284,14 @@ class JinjaCalculation(Calculation):
self.version,
self.namespace,
):
if sub_variable.path in objectspace.variables:
if true_path in default["params"]:
continue
if isinstance(sub_variable, dict):
default["params"][true_path] = {
"type": "value",
"value": sub_variable,
}
else:
default["params"][true_path] = {
"type": "variable",
"variable": sub_variable,
@ -343,8 +373,12 @@ class VariableCalculation(Calculation):
self,
objectspace,
) -> dict:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic(
self.variable, self.path_prefix, self.path, self.version, self.namespace, self.xmlfiles
self.variable, self.path_prefix, path, self.version, self.namespace, self.xmlfiles
)
if not variable:
msg = f'Variable not found "{self.variable}" for attribut "{self.attribute_name}" for variable "{self.path}"'
@ -357,17 +391,20 @@ class VariableCalculation(Calculation):
"variable": variable,
"propertyerror": self.propertyerror,
}
if suffix:
param["suffix"] = suffix
params = {None: [param]}
function = "calc_value"
help_function = None
if self.default_values:
params['__default_value'] = self.default_values
if self.attribute_name in PROPERTY_ATTRIBUTE:
function = "variable_to_property"
help_function = "variable_to_property"
if variable.type != "boolean":
raise Exception("only boolean!")
params[None].insert(0, self.attribute_name)
else:
function = "calc_value"
help_function = None
if suffix:
param["suffix"] = suffix
if self.allow_none:
params["allow_none"] = True
# current variable is a multi
@ -377,7 +414,16 @@ class VariableCalculation(Calculation):
needs_multi = True
else:
needs_multi = self.path in objectspace.multis
calc_variable_is_multi = variable.path in objectspace.multis or (variable.path in objectspace.paths._dynamics and (suffix is None or suffix[-1] is None) and objectspace.paths._dynamics[variable.path] != objectspace.paths._dynamics.get(self.path))
calc_variable_is_multi = variable.path in objectspace.multis
if not calc_variable_is_multi:
if variable.path in objectspace.paths._dynamics and (suffix is None or suffix[-1] is None):
self_dyn_path = objectspace.paths._dynamics.get(self.path)
if self_dyn_path is not None:
var_dyn_path = objectspace.paths._dynamics[variable.path]
if self_dyn_path != var_dyn_path and not self_dyn_path.startswith(f'{var_dyn_path}.'):
calc_variable_is_multi = True
else:
calc_variable_is_multi = True
if needs_multi:
if calc_variable_is_multi:
if self.inside_list:
@ -410,20 +456,27 @@ class InformationCalculation(Calculation):
self,
objectspace,
) -> dict:
param = {
params = {None: [{
"type": "information",
"information": self.information,
}]
}
if self.variable:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic(
self.variable, self.path_prefix, self.path, self.version, self.namespace, self.xmlfiles
self.variable, self.path_prefix, path, self.version, self.namespace, self.xmlfiles
)
if variable is None or suffix is not None:
raise Exception("pfff")
param["variable"] = variable
params[None][0]["variable"] = variable
if self.default_values:
params['__default_value'] = self.default_values
return {
"function": "calc_value",
"params": {None: [param]},
"params": params,
}
@ -480,14 +533,15 @@ class Family(BaseModel):
hidden: Union[bool, Calculation] = False
disabled: Union[bool, Calculation] = False
namespace: Optional[str]
version: str
xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
class Dynamic(Family):
variable: str=None
# None only for format 1.0
variable: str=None
dynamic: Union[List[Union[StrictStr, Calculation]], Calculation]
@ -510,7 +564,7 @@ class Variable(BaseModel):
mode: Optional[str] = None
test: Optional[list] = None
path: str
namespace: str
namespace: Optional[str]
version: str
xmlfiles: List[str] = []
@ -523,10 +577,12 @@ class Variable(BaseModel):
class SymLink(BaseModel):
name: str
type: Literal["symlink"] = "symlink"
opt: Variable
xmlfiles: List[str] = []
name: str
path: str
opt: Variable
namespace: Optional[str]
version: str
xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid")

View file

@ -35,13 +35,13 @@ from importlib.machinery import SourceFileLoader as _SourceFileLoader
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail import CONVERT_OPTION
from rougail.object_model import CONVERT_OPTION
from tiramisu.error import ValueWarning
from .utils import normalize_family
global func
func = {'calc_value': calc_value}
func = {}
dict_env = {}
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
ENV.filters = func
@ -60,7 +60,14 @@ def load_functions(path):
func[function] = getattr(func_, function)
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
def rougail_calc_value(*args, __default_value=None, **kwargs):
values = calc_value(*args, **kwargs)
if __default_value is not None and values in [None, []]:
return __default_value
return values
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, __default_value=None, **kwargs):
global ENV, CONVERT_OPTION
kw = {}
for key, value in kwargs.items():
@ -75,9 +82,15 @@ def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwa
values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
convert = CONVERT_OPTION[__internal_type].get('func', str)
if __internal_multi:
return [convert(val) for val in values.split()]
values = [convert(val) for val in values.split()]
if not values and __default_value is not None:
return __default_value
return values
values = convert(values)
return values if values != '' and values != 'None' else None
values = values if values != '' and values != 'None' else None
if values is None and __default_value is not None:
return __default_value
return values
def variable_to_property(prop, value):
@ -104,6 +117,7 @@ def valid_with_jinja(warnings_only=False, **kwargs):
raise ValueError(value)
func['calc_value'] = rougail_calc_value
func['jinja_to_function'] = jinja_to_function
func['jinja_to_property'] = jinja_to_property
func['jinja_to_property_help'] = jinja_to_property_help
@ -135,3 +149,12 @@ class ConvertDynOptionDescription(DynOptionDescription):
if "{{ suffix }}" in name:
return name.replace("{{ suffix }}", path_suffix)
return name + path_suffix
def impl_get_display_name(
self,
subconfig,
) -> str:
display = super().impl_get_display_name(subconfig)
if "{{ suffix }}" in display:
return display.replace("{{ suffix }}", self.convert_suffix_to_path(self.get_suffixes(subconfig)[-1]))
return display

View file

@ -60,15 +60,15 @@ class TiramisuReflector:
funcs_paths,
):
self.informations_idx = -1
self.rougailconfig = objectspace.rougailconfig
self.reflector_objects = {}
self.text = {
"header": [],
"option": [],
}
if self.rougailconfig["export_with_import"]:
if self.rougailconfig["internal_functions"]:
for func in self.rougailconfig["internal_functions"]:
self.objectspace = objectspace
if self.objectspace.export_with_import:
if self.objectspace.internal_functions:
for func in self.objectspace.internal_functions:
self.text["header"].append(f"func[func] = func")
self.text["header"].extend(
[
@ -76,19 +76,18 @@ class TiramisuReflector:
"from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
]
)
if funcs_paths:
if self.rougailconfig["export_with_import"]:
if self.objectspace.export_with_import:
self.text["header"].extend(
["from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"]
)
if funcs_paths:
for funcs_path in sorted(funcs_paths, key=sorted_func_name):
if not isfile(funcs_path):
continue
self.text["header"].append(f"load_functions('{funcs_path}')")
if self.rougailconfig["export_with_import"]:
for mode in self.rougailconfig["modes_level"]:
if self.objectspace.export_with_import:
for mode in self.objectspace.modes_level:
self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
self.objectspace = objectspace
self.make_tiramisu_objects()
for key, value in self.objectspace.jinja.items():
self.add_jinja_to_function(key, value)
@ -106,14 +105,11 @@ class TiramisuReflector:
baseelt = BaseElt()
self.objectspace.reflector_names[
baseelt.path
] = f'option_0{self.rougailconfig["suffix"]}'
] = f'option_0{self.objectspace.suffix}'
basefamily = Family(
baseelt,
self,
)
# FIXMEif not self.objectspace.paths.has_path_prefix():
if 1:
# for elt in self.reorder_family(self.objectspace.space):
for elt in self.objectspace.paths.get():
if elt.path in self.objectspace.families:
Family(
@ -125,35 +121,35 @@ class TiramisuReflector:
elt,
self,
)
else:
path_prefixes = self.objectspace.paths.get_path_prefixes()
for path_prefix in path_prefixes:
space = self.objectspace.space.variables[path_prefix]
self.set_name(space)
baseprefix = Family(
space,
self,
)
basefamily.add(baseprefix)
for elt in self.reorder_family(space):
self.populate_family(
baseprefix,
elt,
)
if not hasattr(baseprefix.elt, "information"):
baseprefix.elt.information = self.objectspace.information(
baseprefix.elt.xmlfiles
)
for key, value in self.objectspace.paths.get_providers_path(
path_prefix
).items():
setattr(baseprefix.elt.information, key, value)
for key, value in self.objectspace.paths.get_suppliers_path(
path_prefix
).items():
setattr(baseprefix.elt.information, key, value)
baseelt.name = normalize_family(self.rougailconfig["base_option_name"])
baseelt.description = self.rougailconfig["base_option_name"]
# else:
# path_prefixes = self.objectspace.paths.get_path_prefixes()
# for path_prefix in path_prefixes:
# space = self.objectspace.space.variables[path_prefix]
# self.set_name(space)
# baseprefix = Family(
# space,
# self,
# )
# basefamily.add(baseprefix)
# for elt in self.reorder_family(space):
# self.populate_family(
# baseprefix,
# elt,
# )
# if not hasattr(baseprefix.elt, "information"):
# baseprefix.elt.information = self.objectspace.information(
# baseprefix.elt.xmlfiles
# )
# for key, value in self.objectspace.paths.get_providers_path(
# path_prefix
# ).items():
# setattr(baseprefix.elt.information, key, value)
# for key, value in self.objectspace.paths.get_suppliers_path(
# path_prefix
# ).items():
# setattr(baseprefix.elt.information, key, value)
baseelt.name = normalize_family(self.objectspace.base_option_name)
baseelt.description = self.objectspace.base_option_name
self.reflector_objects[baseelt.path].get(
[], baseelt.description
) # pylint: disable=E1101
@ -292,6 +288,8 @@ class Common:
else:
value = param
return f"ParamValue({value})"
if param["type"] == "value":
return f"ParamValue({param['value']})"
if param["type"] == "information":
if self.elt.multi:
default = []
@ -428,8 +426,8 @@ class Variable(Common):
tiramisu,
):
super().__init__(elt, tiramisu)
if elt.type in self.tiramisu.objectspace.rougailconfig['custom_types']:
self.object_type = self.tiramisu.objectspace.rougailconfig['custom_types'][elt.type].__name__
if elt.type in self.tiramisu.objectspace.custom_types:
self.object_type = self.tiramisu.objectspace.custom_types[elt.type].__name__
else:
self.object_type = CONVERT_OPTION[elt.type]["opttype"]
@ -441,6 +439,7 @@ class Variable(Common):
keys["opt"] = self.tiramisu.reflector_objects[self.elt.opt.path].get(
self.calls, self.elt.path
)
return
if self.elt.type == "choice":
keys["values"] = self.populate_calculation(self.elt.choices, return_a_tuple=True)
if self.elt.path in self.objectspace.multis:

View file

@ -577,7 +577,7 @@ class RougailUpgrade:
):
if extra_dstfolder is None:
extra_dstfolder = dstfolder
dict_dirs = self.rougailconfig["dictionaries_dir"]
dict_dirs = self.rougailconfig["main_dictionaries"]
if not isinstance(dict_dirs, list):
dict_dirs = [dict_dirs]
for dict_dir in dict_dirs:
@ -585,7 +585,7 @@ class RougailUpgrade:
dict_dir,
dstfolder,
services_dstfolder,
self.rougailconfig["variable_namespace"],
normalize_family(self.rougailconfig["main_namespace"]),
)
for namespace, extra_dirs in self.rougailconfig["extra_dictionaries"].items():
extra_dstsubfolder = join(extra_dstfolder, namespace)
@ -596,7 +596,7 @@ class RougailUpgrade:
extra_dir,
extra_dstsubfolder,
None,
namespace,
normalize_family(namespace),
)
def _load_dictionaries(

View file

@ -37,7 +37,9 @@ from importlib.util import spec_from_loader, module_from_spec
from jinja2 import DictLoader, TemplateSyntaxError
from jinja2.sandbox import SandboxedEnvironment
from jinja2.parser import Parser
from jinja2.nodes import Getattr
from jinja2.nodes import Name, Getattr
from tiramisu.config import get_common_path
from .i18n import _
from .error import DictConsistencyError
@ -62,15 +64,16 @@ def normalize_family(family_name: str) -> str:
"""replace space, accent, uppercase, ... by valid character"""
if not family_name:
return
family_name = family_name.lower()
family_name = family_name.replace("-", "_").replace(" ", "_").replace(".", "_")
nfkd_form = normalize("NFKD", family_name)
family_name = "".join([c for c in nfkd_form if not combining(c)])
return family_name.lower()
def load_modules(eosfunc_file) -> List[str]:
"""list all functions in eosfunc"""
loader = SourceFileLoader("eosfunc", eosfunc_file)
def load_modules(name, module) -> List[str]:
"""list all functions in a module"""
loader = SourceFileLoader(name, module)
spec = spec_from_loader(loader.name, loader)
eosfunc = module_from_spec(spec)
loader.exec_module(eosfunc)
@ -107,6 +110,9 @@ def get_jinja_variable_to_param(
return g.node.name + "." + g.attr
variables = set()
if objectspace.namespace is None:
for n in parsed_content.find_all(Name):
variables.add(n.name)
for g in parsed_content.find_all(Getattr):
variables.add(recurse_getattr(g))
except TemplateSyntaxError as err:
@ -114,6 +120,8 @@ def get_jinja_variable_to_param(
raise Exception(msg) from err
variables = list(variables)
variables.sort()
founded_variables = {}
unknown_variables = []
for variable_path in variables:
variable, suffix = objectspace.paths.get_with_dynamic(
variable_path,
@ -124,4 +132,14 @@ def get_jinja_variable_to_param(
xmlfiles,
)
if variable and variable.path in objectspace.variables:
yield variable, suffix, variable_path
founded_variables[variable_path] = (suffix, variable)
else:
unknown_variables.append(variable_path)
for variable_path in unknown_variables:
for v in founded_variables:
if get_common_path(v, variable_path) == v:
break
else:
yield {}, None, variable_path.rsplit('.', 1)[0]
for variable_path, data in founded_variables.items():
yield data[1], data[0], variable_path

View file

@ -0,0 +1,8 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[])

View file

@ -0,0 +1,3 @@
---
_version: '1.1'
version: # a variable

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2], properties=frozenset({"basic"}))
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 rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3], properties=frozenset({"basic"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"basic"}))
option_6 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", children=[option_6], properties=frozenset({"basic"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -0,0 +1,9 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])

View file

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

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2], properties=frozenset({"basic"}))
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 rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3], properties=frozenset({"basic"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"basic"}))
option_6 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", children=[option_6], properties=frozenset({"basic"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -0,0 +1,9 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])

View file

@ -0,0 +1,11 @@
---
version: 1.1
var1: "no" # a first variable
var2:
description: a second variable
multi: true
default:
type: jinja
jinja: |
{{ _.var1 }}
description: the value of var1

View file

@ -0,0 +1,12 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.var2'] = "{{ _.var1 }}\n"
option_2 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_.var1': ParamOption(option_2)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2, option_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,18 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_1.rougail.var2'] = "{{ _.var1 }}\n"
dict_env['default_2.rougail.var2'] = "{{ _.var1 }}\n"
option_3 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_1.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_.var1': ParamOption(option_3)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_7 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_8 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_2.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_.var1': ParamOption(option_7)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_7, option_8], properties=frozenset({"standard"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_var2'] = "{{ _.var1 }}\n"
option_1 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_': ParamValue({}), '_.var1': ParamOption(option_1)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,16 @@
---
version: 1.1
var1: # a first variable
- 'no'
- 'yes'
- maybe
var2:
description: a second variable
multi: true
default:
type: jinja
jinja: |
{% for val in _.var1 %}
{{ val }}
{% endfor %}
description: the value of _.var1

View file

@ -0,0 +1,12 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
option_2 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_.var1': ParamOption(option_2)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2, option_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,18 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_1.rougail.var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
dict_env['default_2.rougail.var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
option_3 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_1.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_.var1': ParamOption(option_3)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_7 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_8 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_2.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_.var1': ParamOption(option_7)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_7, option_8], properties=frozenset({"standard"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
option_1 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '_': ParamValue({}), 'val': ParamValue({}), '_.var1': ParamOption(option_1)})), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,4 @@
---
version: '1.0'
var1:
description: a variable

View file

@ -0,0 +1,4 @@
---
version: "1.0"
var2:
description: a variable

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="var1", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_3 = StrOption(name="var2", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2, option_3], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="var1", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_4 = StrOption(name="var2", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"basic"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"basic"}))
option_7 = StrOption(name="var1", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_8 = StrOption(name="var2", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_7, option_8], properties=frozenset({"basic"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="var1", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_2 = StrOption(name="var2", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,5 @@
---
version: '1.0'
without_type:
description: a variable
default: non

View file

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

View file

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

View file

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

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="without_type", doc="a variable", default="non", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2], 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 rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="without_type", doc="a variable", default="non", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_6 = StrOption(name="without_type", doc="a variable", default="non", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", children=[option_6], properties=frozenset({"standard"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -0,0 +1,9 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="without_type", doc="a variable", default="non", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])

View file

@ -0,0 +1,18 @@
---
version: '1.1'
var1: true # the first variable
var2:
description: the second variable
default: true
var3:
description: the third variable
type: boolean
default: true
var4: false # the forth variable
var5:
description: the fifth variable
default: false
var6:
description: the sixth variable
type: boolean
default: false

View file

@ -0,0 +1,26 @@
{
"rougail.var1": {
"owner": "default",
"value": true
},
"rougail.var2": {
"owner": "default",
"value": true
},
"rougail.var3": {
"owner": "default",
"value": true
},
"rougail.var4": {
"owner": "default",
"value": false
},
"rougail.var5": {
"owner": "default",
"value": false
},
"rougail.var6": {
"owner": "default",
"value": false
}
}

View file

@ -0,0 +1,8 @@
{
"rougail.var1": true,
"rougail.var2": true,
"rougail.var3": true,
"rougail.var4": false,
"rougail.var5": false,
"rougail.var6": false
}

View file

@ -0,0 +1,26 @@
{
"rougail.var1": {
"owner": "default",
"value": true
},
"rougail.var2": {
"owner": "default",
"value": true
},
"rougail.var3": {
"owner": "default",
"value": true
},
"rougail.var4": {
"owner": "default",
"value": false
},
"rougail.var5": {
"owner": "default",
"value": false
},
"rougail.var6": {
"owner": "default",
"value": false
}
}

View file

@ -0,0 +1,15 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = BoolOption(name="var1", doc="the first variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_3 = BoolOption(name="var2", doc="the second variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_4 = BoolOption(name="var3", doc="the third variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_5 = BoolOption(name="var4", doc="the forth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_6 = BoolOption(name="var5", doc="the fifth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_7 = BoolOption(name="var6", doc="the sixth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2, option_3, option_4, option_5, option_6, option_7], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,24 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = BoolOption(name="var1", doc="the first variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_4 = BoolOption(name="var2", doc="the second variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_5 = BoolOption(name="var3", doc="the third variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_6 = BoolOption(name="var4", doc="the forth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_7 = BoolOption(name="var5", doc="the fifth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_8 = BoolOption(name="var6", doc="the sixth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4, option_5, option_6, option_7, option_8], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_11 = BoolOption(name="var1", doc="the first variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_12 = BoolOption(name="var2", doc="the second variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_13 = BoolOption(name="var3", doc="the third variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_14 = BoolOption(name="var4", doc="the forth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_15 = BoolOption(name="var5", doc="the fifth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_16 = BoolOption(name="var6", doc="the sixth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
optiondescription_10 = OptionDescription(name="rougail", doc="Rougail", children=[option_11, option_12, option_13, option_14, option_15, option_16], properties=frozenset({"standard"}))
optiondescription_9 = OptionDescription(name="2", doc="2", children=[optiondescription_10], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_9])

View file

@ -0,0 +1,14 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = BoolOption(name="var1", doc="the first variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_2 = BoolOption(name="var2", doc="the second variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_3 = BoolOption(name="var3", doc="the third variable", default=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_4 = BoolOption(name="var4", doc="the forth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_5 = BoolOption(name="var5", doc="the fifth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_6 = BoolOption(name="var6", doc="the sixth variable", default=False, properties=frozenset({"mandatory", "standard"}), informations={'type': 'boolean'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2, option_3, option_4, option_5, option_6])

View file

@ -0,0 +1,6 @@
---
version: '1.1'
variable:
description: a variable
type: boolean
mandatory: false

View file

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

View file

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

View file

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

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = BoolOption(name="variable", doc="a variable", default=True, properties=frozenset({"standard"}), informations={'type': 'boolean'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2], 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 rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = BoolOption(name="variable", doc="a variable", default=True, properties=frozenset({"standard"}), informations={'type': 'boolean'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_6 = BoolOption(name="variable", doc="a variable", default=True, properties=frozenset({"standard"}), informations={'type': 'boolean'})
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", children=[option_6], properties=frozenset({"standard"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -0,0 +1,9 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = BoolOption(name="variable", doc="a variable", default=True, properties=frozenset({"standard"}), informations={'type': 'boolean'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])

View file

@ -0,0 +1,42 @@
---
version: '1.1'
var1:
description: the first variable
choices:
- a
- b
- c
var2:
description: the second variable
choices:
- a
- b
- c
var3:
description: the third variable
choices:
- a
- b
- c
mandatory: false
var4:
description: the forth variable
choices:
- null
- b
- c
mandatory: false
var5:
description: the fifth variable
choices:
- a
- b
- c
default: a
var6:
description: the sixth variable
choices:
- 1
- 2
- 3
default: 1

View file

@ -0,0 +1,26 @@
{
"rougail.var1": {
"owner": "default",
"value": null
},
"rougail.var2": {
"owner": "default",
"value": null
},
"rougail.var3": {
"owner": "default",
"value": null
},
"rougail.var4": {
"owner": "default",
"value": null
},
"rougail.var5": {
"owner": "default",
"value": "a"
},
"rougail.var6": {
"owner": "default",
"value": 1
}
}

View file

@ -0,0 +1,8 @@
{
"rougail.var1": null,
"rougail.var2": null,
"rougail.var3": null,
"rougail.var4": null,
"rougail.var5": "a",
"rougail.var6": 1
}

View file

@ -0,0 +1,26 @@
{
"rougail.var1": {
"owner": "default",
"value": null
},
"rougail.var2": {
"owner": "default",
"value": null
},
"rougail.var3": {
"owner": "default",
"value": null
},
"rougail.var4": {
"owner": "default",
"value": null
},
"rougail.var5": {
"owner": "default",
"value": "a"
},
"rougail.var6": {
"owner": "default",
"value": 1
}
}

View file

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

Some files were not shown because too many files have changed in this diff Show more