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 .config import RougailConfig
from .update import RougailUpgrade from .update import RougailUpgrade
from .object_model import CONVERT_OPTION from .object_model import CONVERT_OPTION
from .utils import normalize_family
def tiramisu_display_name(kls, subconfig) -> str: def tiramisu_display_name(kls, subconfig) -> str:
"""Replace the Tiramisu display_name function to display path + description""" """Replace the Tiramisu display_name function to display path + description"""
doc = kls._get_information(subconfig, "doc", None) doc = kls._get_information(subconfig, "doc", None)
comment = f" ({doc})" if doc and doc != kls.impl_getname() else "" 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: class Rougail:

View file

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

View file

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

View file

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

View file

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

View file

@ -65,12 +65,14 @@ class Annotator(Walk): # pylint: disable=R0903
if not objectspace.paths: if not objectspace.paths:
return return
self.objectspace = objectspace self.objectspace = objectspace
if self.objectspace.main_namespace:
self.forbidden_name = [ self.forbidden_name = [
"services", self.objectspace.main_namespace
self.objectspace.rougailconfig["variable_namespace"],
] ]
for extra in self.objectspace.rougailconfig["extra_dictionaries"]: for extra in self.objectspace.extra_dictionaries:
self.forbidden_name.append(extra) self.forbidden_name.append(extra)
else:
self.forbidden_name = []
# default type inference from a default value with :term:`basic types` # default type inference from a default value with :term:`basic types`
self.basic_types = {str: "string", int: "number", bool: "boolean", float: "float"} self.basic_types = {str: "string", int: "number", bool: "boolean", float: "float"}
self.convert_variable() self.convert_variable()
@ -89,6 +91,9 @@ class Annotator(Walk): # pylint: disable=R0903
variable.multi = False variable.multi = False
if variable.type is None: if variable.type is None:
variable.type = "string" variable.type = "string"
self.objectspace.informations.add(
variable.path, "type", variable.type
)
self._convert_variable(variable) self._convert_variable(variable)
def _convert_variable_inference( def _convert_variable_inference(
@ -144,6 +149,8 @@ class Annotator(Walk): # pylint: disable=R0903
def convert_test(self): def convert_test(self):
"""Convert variable tests value""" """Convert variable tests value"""
for variable in self.get_variables(): for variable in self.get_variables():
if variable.type == "symlink":
continue
if variable.test is None: if variable.test is None:
# with we want remove test, we set "" has test value # with we want remove test, we set "" has test value
continue continue
@ -161,7 +168,7 @@ class Annotator(Walk): # pylint: disable=R0903
def verify_choices(self): def verify_choices(self):
for variable in self.get_variables(): 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 continue
if not isinstance(variable.choices, list): if not isinstance(variable.choices, list):
continue 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 along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
""" """
from os.path import abspath, dirname, join from pathlib import Path
from tiramisu import Config
ROUGAILROOT = "/srv/rougail" from ruamel.yaml import YAML
DTDDIR = join(dirname(abspath(__file__)), "data") from .utils import _, load_modules, normalize_family
from .convert import RougailConvert
RougailConfig = { RENAMED = {'dictionaries_dir': 'main_dictionaries',
"default_dictionary_format_version": None, 'variable_namespace': 'main_namespace',
"dictionaries_dir": [join(ROUGAILROOT, "dictionaries")], 'functions_file': 'functions_files',
"extra_dictionaries": {}, }
"services_dir": [join(ROUGAILROOT, "services")], NOT_IN_TIRAMISU = {'custom_types': {},
"patches_dir": join(ROUGAILROOT, "patches"), }
"templates_dir": join(ROUGAILROOT, "templates"), SUBMODULES = None
"destinations_dir": join(ROUGAILROOT, "destinations"),
"tmp_dir": join(ROUGAILROOT, "tmp"),
"functions_file": join(ROUGAILROOT, "functions.py"), def get_sub_modules():
"system_service_directory": "/usr/lib/systemd/system", global SUBMODULES
"systemd_service_destination_directory": "/usr/local/lib", if SUBMODULES is None:
"systemd_service_directory": "/systemd", SUBMODULES = {}
"systemd_service_file": "rougail.conf", for submodule in Path(__file__).parent.iterdir():
"systemd_service_ip_file": "rougail_ip.conf", if submodule.name.startswith('_') or not submodule.is_dir():
"systemd_tmpfile_factory_dir": "/usr/local/lib", continue
"systemd_tmpfile_directory": "/tmpfiles.d", config_file = submodule / 'config.py'
"systemd_tmpfile_file": "0rougail.conf", if config_file.is_file():
"systemd_tmpfile_delete_before_create": False, SUBMODULES[submodule.name] = load_modules('rougail.' + submodule.name + '.config', str(config_file))
"variable_namespace": "rougail", return SUBMODULES
"variable_namespace_description": "Rougail",
"auto_freeze_variable": "server_deployed",
"internal_functions": [], def get_level(module):
"multi_functions": [], return module['level']
"extra_annotators": [],
"modes_level": ["basic", "standard", "advanced"],
"default_family_mode": "basic", class _RougailConfig:
"default_variable_mode": "standard", def __init__(self,
"default_files_engine": "jinja", backward_compatibility: bool,
"default_files_mode": 644, root,
"default_files_owner": "root", ):
"default_files_group": "root", self.backward_compatibility = backward_compatibility
"default_files_included": "no", self.root = root
"default_overrides_engine": "jinja", self.config = Config(
"default_service_names_engine": "none", self.root,
"default_certificate_domain": "rougail.server_name", )
"base_option_name": "baseoption", self.config.property.read_only()
"export_with_import": True, for variable, default_value in NOT_IN_TIRAMISU.items():
"force_convert_dyn_option_description": False, if not isinstance(default_value, str):
"suffix": "", default_value = default_value.copy()
"tiramisu_cache": None, setattr(self, variable, default_value)
"custom_types": {},
} 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 pydantic import ValidationError
from ruamel.yaml import YAML from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap from ruamel.yaml.comments import CommentedMap
from pydantic import ValidationError
from warnings import warn
from tiramisu.error import display_list from tiramisu.error import display_list
from .annotator import SpaceAnnotator from .annotator import SpaceAnnotator
@ -65,7 +69,8 @@ from .object_model import (
VariableCalculation, VariableCalculation,
) )
from .tiramisureflector import TiramisuReflector 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] property_types = Union[Literal[True], Calculation]
properties_types = Dict[str, property_types] properties_types = Dict[str, property_types]
@ -97,7 +102,7 @@ class Property:
class Paths: class Paths:
_regexp_relative = compile(r"^_*\.(.*)$") regexp_relative = compile(r"^_*\.(.*)$")
def __init__( def __init__(
self, self,
@ -105,6 +110,8 @@ class Paths:
) -> None: ) -> None:
self._data: Dict[str, Union[Variable, Family]] = {} self._data: Dict[str, Union[Variable, Family]] = {}
self._dynamics: Dict[str:str] = {} self._dynamics: Dict[str:str] = {}
if default_namespace is not None:
default_namespace = normalize_family(default_namespace)
self.default_namespace = default_namespace self.default_namespace = default_namespace
self.path_prefix = None self.path_prefix = None
@ -124,6 +131,18 @@ class Paths:
if not force and is_dynamic: if not force and is_dynamic:
self._dynamics[path] = 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( def get_with_dynamic(
self, self,
path: str, path: str,
@ -134,12 +153,10 @@ class Paths:
xmlfiles: List[str], xmlfiles: List[str],
) -> Any: ) -> Any:
suffix = None suffix = None
if version != "1.0" and self._regexp_relative.search(path): if version != '1.0' and self.regexp_relative.search(path):
relative, subpath = path.split(".", 1) path = self.get_relative_path(path,
relative_len = len(relative) current_path,
path_len = current_path.count(".") )
parent_path = current_path.rsplit(".", relative_len)[0]
path = parent_path + "." + subpath
else: else:
path = get_realpath(path, suffix_path) path = get_realpath(path, suffix_path)
dynamic = None dynamic = None
@ -159,7 +176,11 @@ class Paths:
new_path = name new_path = name
continue continue
for dynamic_path in self._dynamics: for dynamic_path in self._dynamics:
if '.' in dynamic_path:
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1) parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
else:
parent_dynamic = None
name_dynamic = dynamic_path
if ( if (
version == "1.0" version == "1.0"
and parent_dynamic == parent_path and parent_dynamic == parent_path
@ -192,7 +213,11 @@ class Paths:
new_path = name new_path = name
continue continue
for dynamic_path in self._dynamics: for dynamic_path in self._dynamics:
if '.' in dynamic_path:
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1) parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
else:
parent_dynamic = None
name_dynamic = dynamic_path
if ( if (
"{{ suffix }}" not in name_dynamic "{{ suffix }}" not in name_dynamic
or parent_path != parent_dynamic or parent_path != parent_dynamic
@ -203,6 +228,9 @@ class Paths:
if len(finded) != 1 or not finded[0]: if len(finded) != 1 or not finded[0]:
continue continue
suffixes.append(finded[0]) suffixes.append(finded[0])
if new_path is None:
new_path = name_dynamic
else:
new_path += "." + name_dynamic new_path += "." + name_dynamic
break break
else: else:
@ -274,7 +302,7 @@ class Informations:
if path not in self._data: if path not in self._data:
self._data[path] = {} self._data[path] = {}
if key in 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 self._data[path][key] = data
def get( def get(
@ -286,7 +314,8 @@ class Informations:
class ParserVariable: class ParserVariable:
def __init__(self, rougailconfig): def __init__(self, rougailconfig):
self.paths = Paths(rougailconfig["variable_namespace"]) self.load_config(rougailconfig)
self.paths = Paths(self.main_namespace)
self.families = [] self.families = []
self.variables = [] self.variables = []
self.parents = {".": []} self.parents = {".": []}
@ -297,13 +326,12 @@ class ParserVariable:
self.multis = {} self.multis = {}
self.default_multi = {} self.default_multi = {}
self.jinja = {} self.jinja = {}
self.rougailconfig = rougailconfig #
self.convert_options = list(CONVERT_OPTION) 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.family = Family
self.dynamic = Dynamic self.dynamic = Dynamic
self.choice = Variable # Choice
# #
self.exclude_imports = [] self.exclude_imports = []
self.informations = Informations() self.informations = Informations()
@ -314,10 +342,42 @@ class ParserVariable:
self.is_init = False self.is_init = False
super().__init__() 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: if self.is_init:
return 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) hint = get_type_hints(self.dynamic)
# FIXME: only for format 1.0 # FIXME: only for format 1.0
hint["variable"] = str hint["variable"] = str
@ -330,16 +390,14 @@ class ParserVariable:
) )
# #
hint = get_type_hints(self.variable) hint = get_type_hints(self.variable)
self.variable_types = ( self.variable_types = (
self.convert_options self.convert_options
) # hint["type"].__args__ # pylint: disable=W0201 ) # hint["type"].__args__ # pylint: disable=W0201
# #
hint = get_type_hints(self.choice) self.variable_attrs = frozenset( # pylint: disable=W0201
self.choice_attrs = frozenset( # pylint: disable=W0201
set(hint) - {"name", "path", "xmlfiles"} | {"redefine", "exists"} 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 hint
) )
self.is_init = True self.is_init = True
@ -379,13 +437,13 @@ class ParserVariable:
# all attributes are in variable object # all attributes are in variable object
# and values in attributes are not dict is not Calculation # and values in attributes are not dict is not Calculation
if isinstance(obj, dict): if isinstance(obj, dict):
extra_keys = set(obj) - self.choice_attrs extra_keys = set(obj) - self.variable_attrs
if not extra_keys: if not extra_keys:
for key, value in obj.items(): for key, value in obj.items():
if isinstance(value, dict) and not self.is_calculation( if isinstance(value, dict) and not self.is_calculation(
key, key,
value, value,
self.choice_calculations, self.variable_calculations,
False, False,
): ):
break break
@ -432,6 +490,9 @@ class ParserVariable:
if name.startswith("_"): if name.startswith("_"):
msg = f'the variable or family name "{name}" is incorrect, it must not starts with "_" character' msg = f'the variable or family name "{name}" is incorrect, it must not starts with "_" character'
raise DictConsistencyError(msg, 16, [filename]) raise DictConsistencyError(msg, 16, [filename])
if not subpath:
path = name
else:
path = f"{subpath}.{name}" path = f"{subpath}.{name}"
if version == "0.1" and not isinstance(obj, dict) and obj is not None: 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)}"' msg = f'the variable "{path}" has a wrong type "{type(obj)}"'
@ -480,7 +541,7 @@ class ParserVariable:
return return
family_obj = {} family_obj = {}
subfamily_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(): for key, value in obj.items():
if key in force_to_attrs: if key in force_to_attrs:
if key.startswith("_"): if key.startswith("_"):
@ -493,7 +554,17 @@ class ParserVariable:
if family_obj: if family_obj:
if not obj.pop("redefine", False): if not obj.pop("redefine", False):
raise Exception( 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( self.paths.add(
path, path,
@ -518,14 +589,15 @@ class ParserVariable:
if self.get_family_or_variable_type(family_obj) == "dynamic": if self.get_family_or_variable_type(family_obj) == "dynamic":
family_is_dynamic = True family_is_dynamic = True
parent_dynamic = path parent_dynamic = path
if version == "1.0" and "{{ suffix }}" not in name: if '{{ suffix }}' not in name:
name += "{{ suffix }}" if "variable" in family_obj:
path += "{{ suffix }}" name += '{{ suffix }}'
if "{{ suffix }}" not in name: path += '{{ suffix }}'
else:
msg = f'dynamic family name must have "{{{{ suffix }}}}" in his name for "{path}"' msg = f'dynamic family name must have "{{{{ suffix }}}}" in his name for "{path}"'
raise DictConsistencyError(msg, 13, [filename]) raise DictConsistencyError(msg, 13, [filename])
if version != "1.0" and not family_obj and comment: if version != '1.0' and not family_obj and comment:
family_obj["description"] = comment family_obj['description'] = comment
self.add_family( self.add_family(
path, path,
name, name,
@ -558,7 +630,6 @@ class ParserVariable:
def list_attributes( def list_attributes(
self, self,
obj: Dict[str, Any], obj: Dict[str, Any],
version: str,
) -> Iterator[str]: ) -> Iterator[str]:
"""List attributes""" """List attributes"""
force_to_variable = [] force_to_variable = []
@ -581,7 +652,8 @@ class ParserVariable:
): ):
# it's a dict, so a new variables! # it's a dict, so a new variables!
continue 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 continue
if key in self.family_attrs: if key in self.family_attrs:
yield key yield key
@ -599,6 +671,7 @@ class ParserVariable:
"""Add a new family""" """Add a new family"""
family["path"] = path family["path"] = path
family["namespace"] = self.namespace family["namespace"] = self.namespace
family["version"] = version
family["xmlfiles"] = [filename] family["xmlfiles"] = [filename]
obj_type = self.get_family_or_variable_type(family) obj_type = self.get_family_or_variable_type(family)
if obj_type == "dynamic": if obj_type == "dynamic":
@ -625,9 +698,17 @@ class ParserVariable:
del family["variable"] del family["variable"]
# FIXME only for 1.0 # FIXME only for 1.0
if "variable" in family: if "variable" in family:
raise Exception( family['dynamic'] = {'type': 'variable',
f'dynamic family must not have "variable" attribute for "{family["path"]}" in {family["xmlfiles"]}' '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: else:
family_obj = self.family family_obj = self.family
# convert to Calculation objects # convert to Calculation objects
@ -679,7 +760,7 @@ class ParserVariable:
if version == "1.0" or isinstance(obj, dict): if version == "1.0" or isinstance(obj, dict):
if obj is None: if obj is None:
obj = {} obj = {}
extra_attrs = set(obj) - self.choice_attrs extra_attrs = set(obj) - self.variable_attrs
else: else:
extra_attrs = [] extra_attrs = []
obj = {"default": obj} obj = {"default": obj}
@ -720,7 +801,7 @@ class ParserVariable:
# so do nothing # so do nothing
return return
if "redefine" in obj and obj["redefine"]: 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]) raise DictConsistencyError(msg, 46, [filename])
obj["path"] = path obj["path"] = path
self.add_variable( self.add_variable(
@ -745,7 +826,7 @@ class ParserVariable:
): ):
"""Parse variable or family parameters""" """Parse variable or family parameters"""
if typ == "variable": if typ == "variable":
calculations = self.choice_calculations calculations = self.variable_calculations
else: else:
calculations = self.family_calculations calculations = self.family_calculations
for key, value in obj.items(): for key, value in obj.items():
@ -846,7 +927,7 @@ class ParserVariable:
variable_type = self.get_family_or_variable_type(variable) variable_type = self.get_family_or_variable_type(variable)
obj = { obj = {
"symlink": SymLink, "symlink": SymLink,
"choice": self.choice, "choice": self.variable,
}.get(variable_type, self.variable) }.get(variable_type, self.variable)
try: try:
variable_obj = obj(name=name, **variable) variable_obj = obj(name=name, **variable)
@ -861,7 +942,11 @@ class ParserVariable:
parent_dynamic, parent_dynamic,
) )
self.variables.append(variable["path"]) 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( self.set_name(
variable_obj, variable_obj,
"option_", "option_",
@ -875,7 +960,10 @@ class ParserVariable:
del self.paths[path] del self.paths[path]
self.families.remove(path) self.families.remove(path)
del self.parents[path] del self.parents[path]
if '.' in path:
parent = path.rsplit(".", 1)[0] parent = path.rsplit(".", 1)[0]
else:
parent = '.'
self.parents[parent].remove(path) self.parents[parent].remove(path)
############################################################################################### ###############################################################################################
@ -890,7 +978,7 @@ class ParserVariable:
self.index += 1 self.index += 1
self.reflector_names[ self.reflector_names[
obj.path obj.path
] = f'{option_prefix}{self.index}{self.rougailconfig["suffix"]}' ] = f'{option_prefix}{self.index}{self.suffix}'
############################################################################################### ###############################################################################################
# calculations # calculations
@ -1025,7 +1113,7 @@ class RougailConvert(ParserVariable):
path_prefix: Optional[str] = None, path_prefix: Optional[str] = None,
) -> None: ) -> None:
"""Parse directories content""" """Parse directories content"""
self.init() self._init()
if path_prefix: if path_prefix:
if path_prefix in self.parents: if path_prefix in self.parents:
raise Exception("pfffff") raise Exception("pfffff")
@ -1039,28 +1127,54 @@ class RougailConvert(ParserVariable):
"", "",
False, False,
None, None,
None, '',
) )
else: else:
root_parent = "." root_parent = "."
if self.main_namespace:
directory_dict = chain( directory_dict = chain(
( (
( (
self.rougailconfig["variable_namespace"], self.main_namespace,
self.rougailconfig["dictionaries_dir"], self.main_dictionaries,
), ),
), ),
self.rougailconfig["extra_dictionaries"].items(), self.extra_dictionaries.items(),
) )
for namespace, extra_dirs in directory_dict: for namespace, extra_dirs in directory_dict:
if namespace is None:
self.namespace = namespace self.namespace = namespace
else:
self.namespace = normalize_family(namespace)
if root_parent == ".": if root_parent == ".":
namespace_path = self.namespace namespace_path = self.namespace
else: else:
namespace_path = f"{root_parent}.{self.namespace}" namespace_path = f"{root_parent}.{self.namespace}"
if namespace_path in self.parents: if namespace_path in self.parents:
raise Exception("pfff") 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( self.parse_variable_file(
filename, filename,
namespace_path, namespace_path,
@ -1093,13 +1207,18 @@ class RougailConvert(ParserVariable):
objects, objects,
filename, filename,
) )
self.parse_family( self.parse_root_file(filename,
filename,
self.namespace,
path, path,
{},
version, version,
objects,
) )
def parse_root_file(self,
filename: str,
path: str,
version: str,
objects: dict,
) -> None:
for name, obj in objects.items(): for name, obj in objects.items():
comment = self.get_comment(name, objects) comment = self.get_comment(name, objects)
self.family_or_variable( self.family_or_variable(
@ -1124,7 +1243,7 @@ class RougailConvert(ParserVariable):
continue continue
filenames = {} filenames = {}
for file_path in directory.iterdir(): for file_path in directory.iterdir():
if not file_path.suffix == ".yml": if file_path.suffix not in [".yml", ".yaml"]:
continue continue
if file_path.name in filenames: if file_path.name in filenames:
raise DictConsistencyError( raise DictConsistencyError(
@ -1149,7 +1268,7 @@ class RougailConvert(ParserVariable):
break break
else: else:
# the `version` attribute is not mandatory # 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: if default_version is not None:
version = default_version version = default_version
else: else:
@ -1176,15 +1295,12 @@ class RougailConvert(ParserVariable):
def reflect(self) -> None: def reflect(self) -> None:
"""Apply TiramisuReflector""" """Apply TiramisuReflector"""
functions_file = self.rougailconfig["functions_file"] functions_files = [
if not isinstance(functions_file, list): func for func in self.functions_files if func not in self.exclude_imports
functions_file = [functions_file]
functions_file = [
func for func in functions_file if func not in self.exclude_imports
] ]
self.reflector = TiramisuReflector( self.reflector = TiramisuReflector(
self, self,
functions_file, functions_files,
) )
def save( def save(
@ -1192,6 +1308,7 @@ class RougailConvert(ParserVariable):
filename: str, filename: str,
): ):
"""Return tiramisu object declaration as a string""" """Return tiramisu object declaration as a string"""
self._init()
self.annotate() self.annotate()
self.reflect() self.reflect()
output = self.reflector.get_text() + "\n" output = self.reflector.get_text() + "\n"

View file

@ -51,40 +51,45 @@ def convert_boolean(value: str) -> bool:
CONVERT_OPTION = { CONVERT_OPTION = {
"string": dict(opttype="StrOption"), "string": dict(opttype="StrOption", example="xxx"),
"number": dict(opttype="IntOption", func=int), "number": dict(opttype="IntOption", func=int, example=42),
"float": dict(opttype="FloatOption", func=float), "float": dict(opttype="FloatOption", func=float, example=1.42),
"boolean": dict(opttype="BoolOption", func=convert_boolean), "boolean": dict(opttype="BoolOption", func=convert_boolean),
"secret": dict(opttype="PasswordOption"), "secret": dict(opttype="PasswordOption", example="xxx"),
"mail": dict(opttype="EmailOption"), "mail": dict(opttype="EmailOption", example="user@example.net"),
"unix_filename": dict(opttype="FilenameOption"), "unix_filename": dict(opttype="FilenameOption", example="/tmp/myfile.txt"),
"date": dict(opttype="DateOption"), "date": dict(opttype="DateOption", example="2000-01-01"),
"unix_user": dict(opttype="UsernameOption"), "unix_user": dict(opttype="UsernameOption", example="xxx"),
"ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}), "ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}, example="1.1.1.1"),
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}), "cidr": dict(opttype="IPOption", initkwargs={"cidr": True}, example="1.1.1.0/24"),
"netmask": dict(opttype="NetmaskOption"), "netmask": dict(opttype="NetmaskOption", example="255.255.255.0"),
"network": dict(opttype="NetworkOption"), "network": dict(opttype="NetworkOption", example="1.1.1.0"),
"network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}), "network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24"),
"broadcast": dict(opttype="BroadcastOption"), "broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"),
"netbios": dict( "netbios": dict(
opttype="DomainnameOption", opttype="DomainnameOption",
initkwargs={"type": "netbios", "warnings_only": True}, initkwargs={"type": "netbios", "warnings_only": True},
example="example"
), ),
"domainname": dict( "domainname": dict(
opttype="DomainnameOption", initkwargs={"type": "domainname", "allow_ip": False} opttype="DomainnameOption", initkwargs={"type": "domainname", "allow_ip": False},
example="example.net"
), ),
"hostname": dict( "hostname": dict(
opttype="DomainnameOption", initkwargs={"type": "hostname", "allow_ip": False} opttype="DomainnameOption", initkwargs={"type": "hostname", "allow_ip": False},
example="example"
), ),
"web_address": dict( "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}), "port": dict(opttype="PortOption", initkwargs={"allow_private": True}, example="111"),
"mac": dict(opttype="MACOption"), "mac": dict(opttype="MACOption", example="00:00:00:00:00"),
"unix_permissions": dict( "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"), "symlink": dict(opttype="SymLinkOption"),
} }
@ -107,7 +112,7 @@ class Param(BaseModel):
class AnyParam(Param): class AnyParam(Param):
type: str type: str
value: BASETYPE value: Union[BASETYPE, List[BASETYPE]]
class VariableParam(Param): class VariableParam(Param):
@ -164,7 +169,9 @@ class Calculation(BaseModel):
path: str path: str
inside_list: bool inside_list: bool
version: str version: str
namespace: str ori_path: Optional[str]=None
default_values: Any=None
namespace: Optional[str]
xmlfiles: List[str] xmlfiles: List[str]
model_config = ConfigDict(extra="forbid") model_config = ConfigDict(extra="forbid")
@ -182,12 +189,17 @@ class Calculation(BaseModel):
for param_obj in self.params: for param_obj in self.params:
param = param_obj.model_dump() param = param_obj.model_dump()
if param.get("type") == "variable": 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( 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 variable:
if not param.get("optional"): 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 continue
if not isinstance(variable, objectspace.variable): if not isinstance(variable, objectspace.variable):
raise Exception("pfff it's a family") raise Exception("pfff it's a family")
@ -196,8 +208,12 @@ class Calculation(BaseModel):
param["suffix"] = suffix param["suffix"] = suffix
if param.get("type") == "information": if param.get("type") == "information":
if param["variable"]: if param["variable"]:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( 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 variable:
msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"' msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"'
@ -219,6 +235,7 @@ class JinjaCalculation(Calculation):
jinja: StrictStr jinja: StrictStr
params: Optional[List[Param]] = None params: Optional[List[Param]] = None
return_type: BASETYPE = None return_type: BASETYPE = None
description: Optional[StrictStr] = None
def _jinja_to_function( def _jinja_to_function(
self, self,
@ -245,14 +262,20 @@ class JinjaCalculation(Calculation):
"__internal_multi": multi, "__internal_multi": multi,
}, },
} }
if self.default_values:
default["params"]['__default_value'] = self.default_values
if add_help: if add_help:
default["help"] = function + "_help" default["help"] = function + "_help"
if self.params: if self.params:
default["params"] |= self.get_params(objectspace) default["params"] |= self.get_params(objectspace)
if params: if params:
default["params"] |= 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( for sub_variable, suffix, true_path in get_jinja_variable_to_param(
self.path, path,
self.jinja, self.jinja,
objectspace, objectspace,
variable.xmlfiles, variable.xmlfiles,
@ -261,7 +284,14 @@ class JinjaCalculation(Calculation):
self.version, self.version,
self.namespace, 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] = { default["params"][true_path] = {
"type": "variable", "type": "variable",
"variable": sub_variable, "variable": sub_variable,
@ -343,8 +373,12 @@ class VariableCalculation(Calculation):
self, self,
objectspace, objectspace,
) -> dict: ) -> dict:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( 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: if not variable:
msg = f'Variable not found "{self.variable}" for attribut "{self.attribute_name}" for variable "{self.path}"' 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, "variable": variable,
"propertyerror": self.propertyerror, "propertyerror": self.propertyerror,
} }
if suffix:
param["suffix"] = suffix
params = {None: [param]} params = {None: [param]}
function = "calc_value" if self.default_values:
help_function = None params['__default_value'] = self.default_values
if self.attribute_name in PROPERTY_ATTRIBUTE: if self.attribute_name in PROPERTY_ATTRIBUTE:
function = "variable_to_property" function = "variable_to_property"
help_function = "variable_to_property" help_function = "variable_to_property"
if variable.type != "boolean": if variable.type != "boolean":
raise Exception("only boolean!") raise Exception("only boolean!")
params[None].insert(0, self.attribute_name) params[None].insert(0, self.attribute_name)
else:
function = "calc_value"
help_function = None
if suffix:
param["suffix"] = suffix
if self.allow_none: if self.allow_none:
params["allow_none"] = True params["allow_none"] = True
# current variable is a multi # current variable is a multi
@ -377,7 +414,16 @@ class VariableCalculation(Calculation):
needs_multi = True needs_multi = True
else: else:
needs_multi = self.path in objectspace.multis 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 needs_multi:
if calc_variable_is_multi: if calc_variable_is_multi:
if self.inside_list: if self.inside_list:
@ -410,20 +456,27 @@ class InformationCalculation(Calculation):
self, self,
objectspace, objectspace,
) -> dict: ) -> dict:
param = { params = {None: [{
"type": "information", "type": "information",
"information": self.information, "information": self.information,
}]
} }
if self.variable: if self.variable:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( 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: if variable is None or suffix is not None:
raise Exception("pfff") raise Exception("pfff")
param["variable"] = variable params[None][0]["variable"] = variable
if self.default_values:
params['__default_value'] = self.default_values
return { return {
"function": "calc_value", "function": "calc_value",
"params": {None: [param]}, "params": params,
} }
@ -480,14 +533,15 @@ class Family(BaseModel):
hidden: Union[bool, Calculation] = False hidden: Union[bool, Calculation] = False
disabled: Union[bool, Calculation] = False disabled: Union[bool, Calculation] = False
namespace: Optional[str] namespace: Optional[str]
version: str
xmlfiles: List[str] = [] xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True) model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
class Dynamic(Family): class Dynamic(Family):
variable: str=None
# None only for format 1.0 # None only for format 1.0
variable: str=None
dynamic: Union[List[Union[StrictStr, Calculation]], Calculation] dynamic: Union[List[Union[StrictStr, Calculation]], Calculation]
@ -510,7 +564,7 @@ class Variable(BaseModel):
mode: Optional[str] = None mode: Optional[str] = None
test: Optional[list] = None test: Optional[list] = None
path: str path: str
namespace: str namespace: Optional[str]
version: str version: str
xmlfiles: List[str] = [] xmlfiles: List[str] = []
@ -523,10 +577,12 @@ class Variable(BaseModel):
class SymLink(BaseModel): class SymLink(BaseModel):
name: str
type: Literal["symlink"] = "symlink" type: Literal["symlink"] = "symlink"
opt: Variable name: str
xmlfiles: List[str] = []
path: str path: str
opt: Variable
namespace: Optional[str]
version: str
xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid") 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 importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
from jinja2 import StrictUndefined, DictLoader from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment from jinja2.sandbox import SandboxedEnvironment
from rougail import CONVERT_OPTION from rougail.object_model import CONVERT_OPTION
from tiramisu.error import ValueWarning from tiramisu.error import ValueWarning
from .utils import normalize_family from .utils import normalize_family
global func global func
func = {'calc_value': calc_value} func = {}
dict_env = {} dict_env = {}
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined) ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
ENV.filters = func ENV.filters = func
@ -60,7 +60,14 @@ def load_functions(path):
func[function] = getattr(func_, function) 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 global ENV, CONVERT_OPTION
kw = {} kw = {}
for key, value in kwargs.items(): 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() values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
convert = CONVERT_OPTION[__internal_type].get('func', str) convert = CONVERT_OPTION[__internal_type].get('func', str)
if __internal_multi: 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) 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): def variable_to_property(prop, value):
@ -104,6 +117,7 @@ def valid_with_jinja(warnings_only=False, **kwargs):
raise ValueError(value) raise ValueError(value)
func['calc_value'] = rougail_calc_value
func['jinja_to_function'] = jinja_to_function func['jinja_to_function'] = jinja_to_function
func['jinja_to_property'] = jinja_to_property func['jinja_to_property'] = jinja_to_property
func['jinja_to_property_help'] = jinja_to_property_help func['jinja_to_property_help'] = jinja_to_property_help
@ -135,3 +149,12 @@ class ConvertDynOptionDescription(DynOptionDescription):
if "{{ suffix }}" in name: if "{{ suffix }}" in name:
return name.replace("{{ suffix }}", path_suffix) return name.replace("{{ suffix }}", path_suffix)
return name + 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, funcs_paths,
): ):
self.informations_idx = -1 self.informations_idx = -1
self.rougailconfig = objectspace.rougailconfig
self.reflector_objects = {} self.reflector_objects = {}
self.text = { self.text = {
"header": [], "header": [],
"option": [], "option": [],
} }
if self.rougailconfig["export_with_import"]: self.objectspace = objectspace
if self.rougailconfig["internal_functions"]: if self.objectspace.export_with_import:
for func in self.rougailconfig["internal_functions"]: if self.objectspace.internal_functions:
for func in self.objectspace.internal_functions:
self.text["header"].append(f"func[func] = func") self.text["header"].append(f"func[func] = func")
self.text["header"].extend( self.text["header"].extend(
[ [
@ -76,19 +76,18 @@ class TiramisuReflector:
"from tiramisu.setting import ALLOWED_LEADER_PROPERTIES", "from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
] ]
) )
if funcs_paths: if self.objectspace.export_with_import:
if self.rougailconfig["export_with_import"]:
self.text["header"].extend( self.text["header"].extend(
["from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"] ["from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"]
) )
if funcs_paths:
for funcs_path in sorted(funcs_paths, key=sorted_func_name): for funcs_path in sorted(funcs_paths, key=sorted_func_name):
if not isfile(funcs_path): if not isfile(funcs_path):
continue continue
self.text["header"].append(f"load_functions('{funcs_path}')") self.text["header"].append(f"load_functions('{funcs_path}')")
if self.rougailconfig["export_with_import"]: if self.objectspace.export_with_import:
for mode in self.rougailconfig["modes_level"]: for mode in self.objectspace.modes_level:
self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")') self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
self.objectspace = objectspace
self.make_tiramisu_objects() self.make_tiramisu_objects()
for key, value in self.objectspace.jinja.items(): for key, value in self.objectspace.jinja.items():
self.add_jinja_to_function(key, value) self.add_jinja_to_function(key, value)
@ -106,14 +105,11 @@ class TiramisuReflector:
baseelt = BaseElt() baseelt = BaseElt()
self.objectspace.reflector_names[ self.objectspace.reflector_names[
baseelt.path baseelt.path
] = f'option_0{self.rougailconfig["suffix"]}' ] = f'option_0{self.objectspace.suffix}'
basefamily = Family( basefamily = Family(
baseelt, baseelt,
self, 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(): for elt in self.objectspace.paths.get():
if elt.path in self.objectspace.families: if elt.path in self.objectspace.families:
Family( Family(
@ -125,35 +121,35 @@ class TiramisuReflector:
elt, elt,
self, self,
) )
else: # else:
path_prefixes = self.objectspace.paths.get_path_prefixes() # path_prefixes = self.objectspace.paths.get_path_prefixes()
for path_prefix in path_prefixes: # for path_prefix in path_prefixes:
space = self.objectspace.space.variables[path_prefix] # space = self.objectspace.space.variables[path_prefix]
self.set_name(space) # self.set_name(space)
baseprefix = Family( # baseprefix = Family(
space, # space,
self, # self,
) # )
basefamily.add(baseprefix) # basefamily.add(baseprefix)
for elt in self.reorder_family(space): # for elt in self.reorder_family(space):
self.populate_family( # self.populate_family(
baseprefix, # baseprefix,
elt, # elt,
) # )
if not hasattr(baseprefix.elt, "information"): # if not hasattr(baseprefix.elt, "information"):
baseprefix.elt.information = self.objectspace.information( # baseprefix.elt.information = self.objectspace.information(
baseprefix.elt.xmlfiles # baseprefix.elt.xmlfiles
) # )
for key, value in self.objectspace.paths.get_providers_path( # for key, value in self.objectspace.paths.get_providers_path(
path_prefix # path_prefix
).items(): # ).items():
setattr(baseprefix.elt.information, key, value) # setattr(baseprefix.elt.information, key, value)
for key, value in self.objectspace.paths.get_suppliers_path( # for key, value in self.objectspace.paths.get_suppliers_path(
path_prefix # path_prefix
).items(): # ).items():
setattr(baseprefix.elt.information, key, value) # setattr(baseprefix.elt.information, key, value)
baseelt.name = normalize_family(self.rougailconfig["base_option_name"]) baseelt.name = normalize_family(self.objectspace.base_option_name)
baseelt.description = self.rougailconfig["base_option_name"] baseelt.description = self.objectspace.base_option_name
self.reflector_objects[baseelt.path].get( self.reflector_objects[baseelt.path].get(
[], baseelt.description [], baseelt.description
) # pylint: disable=E1101 ) # pylint: disable=E1101
@ -292,6 +288,8 @@ class Common:
else: else:
value = param value = param
return f"ParamValue({value})" return f"ParamValue({value})"
if param["type"] == "value":
return f"ParamValue({param['value']})"
if param["type"] == "information": if param["type"] == "information":
if self.elt.multi: if self.elt.multi:
default = [] default = []
@ -428,8 +426,8 @@ class Variable(Common):
tiramisu, tiramisu,
): ):
super().__init__(elt, tiramisu) super().__init__(elt, tiramisu)
if elt.type in self.tiramisu.objectspace.rougailconfig['custom_types']: if elt.type in self.tiramisu.objectspace.custom_types:
self.object_type = self.tiramisu.objectspace.rougailconfig['custom_types'][elt.type].__name__ self.object_type = self.tiramisu.objectspace.custom_types[elt.type].__name__
else: else:
self.object_type = CONVERT_OPTION[elt.type]["opttype"] 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( keys["opt"] = self.tiramisu.reflector_objects[self.elt.opt.path].get(
self.calls, self.elt.path self.calls, self.elt.path
) )
return
if self.elt.type == "choice": if self.elt.type == "choice":
keys["values"] = self.populate_calculation(self.elt.choices, return_a_tuple=True) keys["values"] = self.populate_calculation(self.elt.choices, return_a_tuple=True)
if self.elt.path in self.objectspace.multis: if self.elt.path in self.objectspace.multis:

View file

@ -577,7 +577,7 @@ class RougailUpgrade:
): ):
if extra_dstfolder is None: if extra_dstfolder is None:
extra_dstfolder = dstfolder extra_dstfolder = dstfolder
dict_dirs = self.rougailconfig["dictionaries_dir"] dict_dirs = self.rougailconfig["main_dictionaries"]
if not isinstance(dict_dirs, list): if not isinstance(dict_dirs, list):
dict_dirs = [dict_dirs] dict_dirs = [dict_dirs]
for dict_dir in dict_dirs: for dict_dir in dict_dirs:
@ -585,7 +585,7 @@ class RougailUpgrade:
dict_dir, dict_dir,
dstfolder, dstfolder,
services_dstfolder, services_dstfolder,
self.rougailconfig["variable_namespace"], normalize_family(self.rougailconfig["main_namespace"]),
) )
for namespace, extra_dirs in self.rougailconfig["extra_dictionaries"].items(): for namespace, extra_dirs in self.rougailconfig["extra_dictionaries"].items():
extra_dstsubfolder = join(extra_dstfolder, namespace) extra_dstsubfolder = join(extra_dstfolder, namespace)
@ -596,7 +596,7 @@ class RougailUpgrade:
extra_dir, extra_dir,
extra_dstsubfolder, extra_dstsubfolder,
None, None,
namespace, normalize_family(namespace),
) )
def _load_dictionaries( 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 import DictLoader, TemplateSyntaxError
from jinja2.sandbox import SandboxedEnvironment from jinja2.sandbox import SandboxedEnvironment
from jinja2.parser import Parser 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 .i18n import _
from .error import DictConsistencyError from .error import DictConsistencyError
@ -62,15 +64,16 @@ def normalize_family(family_name: str) -> str:
"""replace space, accent, uppercase, ... by valid character""" """replace space, accent, uppercase, ... by valid character"""
if not family_name: if not family_name:
return return
family_name = family_name.lower()
family_name = family_name.replace("-", "_").replace(" ", "_").replace(".", "_") family_name = family_name.replace("-", "_").replace(" ", "_").replace(".", "_")
nfkd_form = normalize("NFKD", family_name) nfkd_form = normalize("NFKD", family_name)
family_name = "".join([c for c in nfkd_form if not combining(c)]) family_name = "".join([c for c in nfkd_form if not combining(c)])
return family_name.lower() return family_name.lower()
def load_modules(eosfunc_file) -> List[str]: def load_modules(name, module) -> List[str]:
"""list all functions in eosfunc""" """list all functions in a module"""
loader = SourceFileLoader("eosfunc", eosfunc_file) loader = SourceFileLoader(name, module)
spec = spec_from_loader(loader.name, loader) spec = spec_from_loader(loader.name, loader)
eosfunc = module_from_spec(spec) eosfunc = module_from_spec(spec)
loader.exec_module(eosfunc) loader.exec_module(eosfunc)
@ -107,6 +110,9 @@ def get_jinja_variable_to_param(
return g.node.name + "." + g.attr return g.node.name + "." + g.attr
variables = set() 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): for g in parsed_content.find_all(Getattr):
variables.add(recurse_getattr(g)) variables.add(recurse_getattr(g))
except TemplateSyntaxError as err: except TemplateSyntaxError as err:
@ -114,6 +120,8 @@ def get_jinja_variable_to_param(
raise Exception(msg) from err raise Exception(msg) from err
variables = list(variables) variables = list(variables)
variables.sort() variables.sort()
founded_variables = {}
unknown_variables = []
for variable_path in variables: for variable_path in variables:
variable, suffix = objectspace.paths.get_with_dynamic( variable, suffix = objectspace.paths.get_with_dynamic(
variable_path, variable_path,
@ -124,4 +132,14 @@ def get_jinja_variable_to_param(
xmlfiles, xmlfiles,
) )
if variable and variable.path in objectspace.variables: 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