WIP: Expand the developer documentation #27
4094 changed files with 17737 additions and 26467 deletions
|
@ -394,6 +394,24 @@ Copy a variable in another:
|
||||||
type: variable
|
type: variable
|
||||||
variable: _.my_variable
|
variable: _.my_variable
|
||||||
|
|
||||||
|
Copy the default value from a variable, means copy type, params and multi attribute too if not define in second variable.
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
---
|
||||||
|
version: 1.1
|
||||||
|
my_variable:
|
||||||
|
multi: true
|
||||||
|
type: domainname
|
||||||
|
params:
|
||||||
|
allow_ip: true
|
||||||
|
my_calculated_variable:
|
||||||
|
default:
|
||||||
|
type: variable
|
||||||
|
variable: _.var1
|
||||||
|
|
||||||
|
Here my_calculated_variable is a domainname variable with parameter allow_ip=True and multi to true.
|
||||||
|
|
||||||
Copy one variable to another if the source has no `property` problem:
|
Copy one variable to another if the source has no `property` problem:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
|
@ -28,19 +28,27 @@ 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 tiramisu import Config
|
from tiramisu import Config
|
||||||
from copy import copy
|
from tiramisu.error import PropertiesOptionError
|
||||||
|
from warnings import warn
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from .convert import RougailConvert
|
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) -> 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.impl_get_information("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 }}', str(subconfig.suffixes[-1]))
|
||||||
|
path = kls.impl_getpath()
|
||||||
|
if "{{ suffix }}" in path:
|
||||||
|
path = path.replace('{{ suffix }}', normalize_family(str(subconfig.suffixes[-1])))
|
||||||
|
return f"{path}{comment}"
|
||||||
|
|
||||||
|
|
||||||
class Rougail:
|
class Rougail:
|
||||||
|
@ -61,9 +69,10 @@ class Rougail:
|
||||||
path_prefix: str,
|
path_prefix: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add a prefix"""
|
"""Add a prefix"""
|
||||||
|
self.converted.load_config()
|
||||||
self.converted.parse_directories(path_prefix)
|
self.converted.parse_directories(path_prefix)
|
||||||
|
|
||||||
def get_config(self):
|
def run(self):
|
||||||
"""Get Tiramisu Config"""
|
"""Get Tiramisu Config"""
|
||||||
if not self.config:
|
if not self.config:
|
||||||
tiram_obj = self.converted.save(self.rougailconfig["tiramisu_cache"])
|
tiram_obj = self.converted.save(self.rougailconfig["tiramisu_cache"])
|
||||||
|
@ -77,5 +86,47 @@ class Rougail:
|
||||||
self.config.property.read_write()
|
self.config.property.read_write()
|
||||||
return self.config
|
return self.config
|
||||||
|
|
||||||
|
def get_config(self):
|
||||||
|
warn("get_config is deprecated, use run instead", DeprecationWarning, stacklevel=2)
|
||||||
|
return self.run()
|
||||||
|
|
||||||
__ALL__ = ("Rougail", "RougailConfig", "RougailUpgrade")
|
def user_datas(self,
|
||||||
|
user_datas: List[dict]):
|
||||||
|
values = {}
|
||||||
|
errors = []
|
||||||
|
warnings = []
|
||||||
|
for datas in user_datas:
|
||||||
|
for name, data in datas.get('values', {}).items():
|
||||||
|
values.setdefault(name, {}).update(data)
|
||||||
|
errors.extend(datas.get('errors', []))
|
||||||
|
warnings.extend(datas.get('warnings', []))
|
||||||
|
while values:
|
||||||
|
value_is_set = False
|
||||||
|
for option in self.config:
|
||||||
|
if option.path() in values and option.index() in values[option.path()]:
|
||||||
|
try:
|
||||||
|
option.value.set(values[option.path()])
|
||||||
|
value_is_set = True
|
||||||
|
values.pop(option.path())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if not value_is_set:
|
||||||
|
break
|
||||||
|
for path, data in values.items():
|
||||||
|
for index, value in data.items():
|
||||||
|
try:
|
||||||
|
print('attention', path, value)
|
||||||
|
self.config.option(path).value.set(value)
|
||||||
|
print('pfff')
|
||||||
|
except AttributeError as err:
|
||||||
|
errors.append(str(err))
|
||||||
|
except ValueError as err:
|
||||||
|
errors.append(str(err).replace('"', "'"))
|
||||||
|
except PropertiesOptionError as err:
|
||||||
|
# warnings.append(f'"{err}" but is defined in "{self.filename}"')
|
||||||
|
warnings.append(str(err))
|
||||||
|
return {'errors': errors,
|
||||||
|
'warnings': warnings,
|
||||||
|
}
|
||||||
|
|
||||||
|
__all__ = ("Rougail", "RougailConfig", "RougailUpgrade")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -30,7 +30,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from rougail.i18n import _
|
from rougail.i18n import _
|
||||||
from rougail.error import DictConsistencyError
|
from rougail.error import DictConsistencyError
|
||||||
from rougail.utils import get_realpath
|
|
||||||
from rougail.annotator.variable import Walk
|
from rougail.annotator.variable import Walk
|
||||||
from rougail.object_model import VariableCalculation
|
from rougail.object_model import VariableCalculation
|
||||||
|
|
||||||
|
@ -65,14 +64,17 @@ 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()
|
||||||
self.change_modes()
|
if self.objectspace.modes_level:
|
||||||
|
self.modes = {
|
||||||
|
name: Mode(idx)
|
||||||
|
for idx, name in enumerate(self.objectspace.modes_level)
|
||||||
|
}
|
||||||
|
self.default_variable_mode = self.objectspace.default_variable_mode
|
||||||
|
self.default_family_mode = self.objectspace.default_family_mode
|
||||||
|
self.change_modes()
|
||||||
self.convert_help()
|
self.convert_help()
|
||||||
|
|
||||||
def check_leadership(self) -> None:
|
def check_leadership(self) -> None:
|
||||||
|
@ -93,7 +95,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 +121,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 +143,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 +205,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 +218,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}"'
|
||||||
|
@ -231,20 +243,17 @@ class Annotator(Walk):
|
||||||
leader: "self.objectspace.variable",
|
leader: "self.objectspace.variable",
|
||||||
follower: "self.objectspace.variable",
|
follower: "self.objectspace.variable",
|
||||||
) -> None:
|
) -> None:
|
||||||
if follower.auto_save is True:
|
|
||||||
msg = _(f'leader/followers "{follower.name}" could not be auto_save')
|
|
||||||
raise DictConsistencyError(msg, 29, follower.xmlfiles)
|
|
||||||
if leader == follower:
|
if leader == follower:
|
||||||
# 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 +275,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 +286,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 +308,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 +321,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():
|
||||||
|
|
|
@ -112,37 +112,37 @@ 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)
|
||||||
if not variable.auto_save:
|
if not variable.auto_save:
|
||||||
# if auto_save, save calculated value
|
# if auto_save, save calculated value
|
||||||
self.objectspace.properties.add(path, "force_default_on_freeze", True)
|
self.objectspace.properties.add(path, "force_default_on_freeze", True)
|
||||||
if variable.mandatory and variable.multi:
|
if not variable.empty and self.objectspace.multis.get(variable.path, False):
|
||||||
# a multi could not have "None" has value
|
# a multi could not have "None" has value
|
||||||
# to permit it, just add mandatory="False"
|
# to permit it, just add empty="false"
|
||||||
self.objectspace.properties.add(path, "notempty", True)
|
self.objectspace.properties.add(path, "notempty", True)
|
||||||
if variable.unique:
|
if variable.unique:
|
||||||
self.objectspace.properties.add(path, "unique", True)
|
self.objectspace.properties.add(path, "unique", True)
|
||||||
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,
|
||||||
|
|
|
@ -55,6 +55,8 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
for variable in self.get_variables():
|
for variable in self.get_variables():
|
||||||
if variable.type == "symlink":
|
if variable.type == "symlink":
|
||||||
continue
|
continue
|
||||||
|
if variable.version != '1.0' and variable.type == 'port':
|
||||||
|
self._convert_port(variable)
|
||||||
self._convert_value(variable)
|
self._convert_value(variable)
|
||||||
|
|
||||||
def _convert_value(
|
def _convert_value(
|
||||||
|
@ -98,6 +100,14 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
self.objectspace.default_multi[variable.path] = variable.default
|
self.objectspace.default_multi[variable.path] = variable.default
|
||||||
variable.default = None
|
variable.default = None
|
||||||
|
|
||||||
|
def _convert_port(self, variable) -> None:
|
||||||
|
if variable.multi is False and isinstance(variable.default, int):
|
||||||
|
variable.default = str(variable.default)
|
||||||
|
elif variable.multi is True and isinstance(variable.default, list):
|
||||||
|
for idx, value in enumerate(variable.default):
|
||||||
|
if isinstance(value, int):
|
||||||
|
variable.default[idx] = str(value)
|
||||||
|
|
||||||
def valid_choices(self) -> None:
|
def valid_choices(self) -> None:
|
||||||
"""A variable with type "Choice" that is not mandatory must has "nil" value"""
|
"""A variable with type "Choice" that is not mandatory must has "nil" value"""
|
||||||
for variable in self.get_variables():
|
for variable in self.get_variables():
|
||||||
|
@ -108,7 +118,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:
|
||||||
|
|
|
@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
from rougail.i18n import _
|
from rougail.i18n import _
|
||||||
from rougail.error import DictConsistencyError
|
from rougail.error import DictConsistencyError
|
||||||
from rougail.object_model import Calculation
|
from rougail.object_model import Calculation, VariableCalculation
|
||||||
from tiramisu.error import display_list
|
from tiramisu.error import display_list
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,30 +65,41 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
if not objectspace.paths:
|
if not objectspace.paths:
|
||||||
return
|
return
|
||||||
self.objectspace = objectspace
|
self.objectspace = objectspace
|
||||||
self.forbidden_name = [
|
if self.objectspace.main_namespace:
|
||||||
"services",
|
self.forbidden_name = [
|
||||||
self.objectspace.rougailconfig["variable_namespace"],
|
self.objectspace.main_namespace
|
||||||
]
|
]
|
||||||
for extra in self.objectspace.rougailconfig["extra_dictionaries"]:
|
for extra in self.objectspace.extra_dictionaries:
|
||||||
self.forbidden_name.append(extra)
|
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()
|
||||||
self.convert_test()
|
self.convert_test()
|
||||||
|
self.convert_examples()
|
||||||
self.convert_help()
|
self.convert_help()
|
||||||
self.verify_choices()
|
self.verify_choices()
|
||||||
|
|
||||||
def convert_variable(self):
|
def convert_variable(self):
|
||||||
"""convert variable"""
|
"""convert variable"""
|
||||||
|
for variable in self.get_variables():
|
||||||
|
if variable.version != "1.0":
|
||||||
|
if variable.type == "symlink":
|
||||||
|
continue
|
||||||
|
self._convert_variable_inference(variable)
|
||||||
for variable in self.get_variables():
|
for variable in self.get_variables():
|
||||||
if variable.type == "symlink":
|
if variable.type == "symlink":
|
||||||
continue
|
continue
|
||||||
if variable.version != "1.0":
|
if variable.version != "1.0":
|
||||||
self._convert_variable_inference(variable)
|
self._default_variable_copy_informations(variable)
|
||||||
if variable.multi is None:
|
if variable.multi is None:
|
||||||
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(
|
||||||
|
@ -100,6 +111,8 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
# choice type inference from the `choices` attribute
|
# choice type inference from the `choices` attribute
|
||||||
if variable.choices is not None:
|
if variable.choices is not None:
|
||||||
variable.type = "choice"
|
variable.type = "choice"
|
||||||
|
elif variable.regexp is not None:
|
||||||
|
variable.type = "regexp"
|
||||||
elif variable.default not in [None, []]:
|
elif variable.default not in [None, []]:
|
||||||
if isinstance(variable.default, list):
|
if isinstance(variable.default, list):
|
||||||
tested_value = variable.default[0]
|
tested_value = variable.default[0]
|
||||||
|
@ -107,12 +120,37 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
tested_value = variable.default
|
tested_value = variable.default
|
||||||
variable.type = self.basic_types.get(type(tested_value), None)
|
variable.type = self.basic_types.get(type(tested_value), None)
|
||||||
# variable has no multi attribute
|
# variable has no multi attribute
|
||||||
if variable.multi is None:
|
if variable.multi is None and not (variable.type is None and isinstance(variable.default, VariableCalculation)):
|
||||||
if variable.path in self.objectspace.leaders:
|
if variable.path in self.objectspace.leaders:
|
||||||
variable.multi = True
|
variable.multi = True
|
||||||
else:
|
else:
|
||||||
variable.multi = isinstance(variable.default, list)
|
variable.multi = isinstance(variable.default, list)
|
||||||
|
|
||||||
|
def _default_variable_copy_informations(
|
||||||
|
self,
|
||||||
|
variable,
|
||||||
|
) -> None:
|
||||||
|
# if a variable has a variable as default value, that means the type/params or multi should has same value
|
||||||
|
if variable.type is not None or not isinstance(variable.default, VariableCalculation):
|
||||||
|
return
|
||||||
|
# copy type and params
|
||||||
|
calculated_variable_path = variable.default.variable
|
||||||
|
calculated_variable, suffix = self.objectspace.paths.get_with_dynamic(
|
||||||
|
calculated_variable_path, variable.default.path_prefix, variable.path, variable.version, variable.namespace, variable.xmlfiles
|
||||||
|
)
|
||||||
|
if calculated_variable is None:
|
||||||
|
return
|
||||||
|
variable.type = calculated_variable.type
|
||||||
|
if variable.params is None and calculated_variable.params is not None:
|
||||||
|
variable.params = calculated_variable.params
|
||||||
|
# copy multi attribut
|
||||||
|
if variable.multi is None:
|
||||||
|
calculated_path = calculated_variable.path
|
||||||
|
if calculated_path in self.objectspace.leaders and variable.path in self.objectspace.followers and calculated_path.rsplit('.')[0] == variable.path.rsplit('.')[0]:
|
||||||
|
variable.multi = False
|
||||||
|
else:
|
||||||
|
variable.multi = calculated_variable.multi
|
||||||
|
|
||||||
def _convert_variable(
|
def _convert_variable(
|
||||||
self,
|
self,
|
||||||
variable: dict,
|
variable: dict,
|
||||||
|
@ -129,8 +167,7 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
self.objectspace.multis[variable.path] = True
|
self.objectspace.multis[variable.path] = True
|
||||||
if variable.path in self.objectspace.leaders:
|
if variable.path in self.objectspace.leaders:
|
||||||
if not self.objectspace.multis.get(variable.path, False):
|
if not self.objectspace.multis.get(variable.path, False):
|
||||||
msg = _(f'the variable "{variable.path}" in a leadership must be multi')
|
variable.multi = self.objectspace.multis[variable.path] = True
|
||||||
raise DictConsistencyError(msg, 32, variable.xmlfiles)
|
|
||||||
family = self.objectspace.paths[variable.path.rsplit(".", 1)[0]]
|
family = self.objectspace.paths[variable.path.rsplit(".", 1)[0]]
|
||||||
if variable.hidden:
|
if variable.hidden:
|
||||||
family.hidden = variable.hidden
|
family.hidden = variable.hidden
|
||||||
|
@ -138,19 +175,34 @@ class Annotator(Walk): # pylint: disable=R0903
|
||||||
variable.hidden = family.hidden
|
variable.hidden = family.hidden
|
||||||
variable.hidden = None
|
variable.hidden = None
|
||||||
if variable.choices is not None and variable.type != 'choice':
|
if variable.choices is not None and variable.type != 'choice':
|
||||||
msg = _(f'the variable "{variable.path}" has choice attribut but has not the "choice" type')
|
msg = _(f'the variable "{variable.path}" has choices attribut but has not the "choice" type')
|
||||||
raise DictConsistencyError(msg, 11, variable.xmlfiles)
|
raise DictConsistencyError(msg, 11, variable.xmlfiles)
|
||||||
|
if variable.regexp is not None and variable.type != 'regexp':
|
||||||
|
msg = _(f'the variable "{variable.path}" has regexp attribut but has not the "regexp" type')
|
||||||
|
raise DictConsistencyError(msg, 37, variable.xmlfiles)
|
||||||
|
|
||||||
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
|
|
||||||
continue
|
continue
|
||||||
self.objectspace.informations.add(
|
self.objectspace.informations.add(
|
||||||
variable.path, "test", tuple(variable.test)
|
variable.path, "test", tuple(variable.test)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def convert_examples(self):
|
||||||
|
"""Convert variable tests value"""
|
||||||
|
for variable in self.get_variables():
|
||||||
|
if variable.type == "symlink":
|
||||||
|
continue
|
||||||
|
if variable.examples is None:
|
||||||
|
continue
|
||||||
|
self.objectspace.informations.add(
|
||||||
|
variable.path, "examples", tuple(variable.examples)
|
||||||
|
)
|
||||||
|
|
||||||
def convert_help(self):
|
def convert_help(self):
|
||||||
"""Convert variable help"""
|
"""Convert variable help"""
|
||||||
for variable in self.get_variables():
|
for variable in self.get_variables():
|
||||||
|
@ -161,7 +213,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
|
||||||
|
|
|
@ -28,52 +28,427 @@ 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",
|
extra_vars: dict
|
||||||
"default_files_group": "root",
|
):
|
||||||
"default_files_included": "no",
|
self.backward_compatibility = backward_compatibility
|
||||||
"default_overrides_engine": "jinja",
|
self.root = root
|
||||||
"default_service_names_engine": "none",
|
self.config = Config(
|
||||||
"default_certificate_domain": "rougail.server_name",
|
self.root,
|
||||||
"base_option_name": "baseoption",
|
)
|
||||||
"export_with_import": True,
|
self.config.property.read_only()
|
||||||
"force_convert_dyn_option_description": False,
|
self.extra_vars = extra_vars
|
||||||
"suffix": "",
|
self.not_in_tiramisu = NOT_IN_TIRAMISU | extra_vars
|
||||||
"tiramisu_cache": None,
|
for variable, default_value in self.not_in_tiramisu.items():
|
||||||
"custom_types": {},
|
if not isinstance(default_value, str):
|
||||||
}
|
default_value = default_value.copy()
|
||||||
|
setattr(self, variable, default_value)
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
rougailconfig = _RougailConfig(self.backward_compatibility, self.root, self.extra_vars)
|
||||||
|
rougailconfig.config.value.importation(self.config.value.exportation())
|
||||||
|
rougailconfig.config.property.importation(self.config.property.exportation())
|
||||||
|
rougailconfig.config.property.read_only()
|
||||||
|
for variable in self.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 self.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.reset()
|
||||||
|
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 self.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 = None
|
||||||
|
followers = []
|
||||||
|
for opt, value in option.value.get().items():
|
||||||
|
if opt.issymlinkoption():
|
||||||
|
continue
|
||||||
|
if leader is None:
|
||||||
|
leader = value
|
||||||
|
else:
|
||||||
|
followers.append(value)
|
||||||
|
return dict(zip(leader, followers))
|
||||||
|
|
||||||
|
def parse(self, config) -> str:
|
||||||
|
for option in config:
|
||||||
|
if option.isoptiondescription():
|
||||||
|
yield from self.parse(option)
|
||||||
|
elif not option.issymlinkoption():
|
||||||
|
yield f'{option.path()}: {option.value.get()}'
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
self.config.property.read_write()
|
||||||
|
try:
|
||||||
|
values = "\n".join(self.parse(self.config))
|
||||||
|
except Exception as err:
|
||||||
|
values = str(err)
|
||||||
|
self.config.property.read_only()
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
class FakeRougailConvert(RougailConvert):
|
||||||
|
def __init__(self,
|
||||||
|
add_extra_options: bool,
|
||||||
|
) -> None:
|
||||||
|
self.add_extra_options = add_extra_options
|
||||||
|
super().__init__({})
|
||||||
|
|
||||||
|
def load_config(self) -> None:
|
||||||
|
self.sort_dictionaries_all = False
|
||||||
|
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']
|
||||||
|
self.add_extra_options = self.add_extra_options
|
||||||
|
|
||||||
|
|
||||||
|
def get_rougail_config(*,
|
||||||
|
backward_compatibility: bool=True,
|
||||||
|
add_extra_options: bool=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
|
||||||
|
|
||||||
|
sort_dictionaries_all:
|
||||||
|
description: Sort dictionaries from differents directories
|
||||||
|
negative_description: Sort dictionaries directory by directory
|
||||||
|
default: false
|
||||||
|
|
||||||
|
main_namespace:
|
||||||
|
description: Main namespace name
|
||||||
|
default: MAIN_MAMESPACE_DEFAULT
|
||||||
|
alternative_name: s
|
||||||
|
mandatory: false
|
||||||
|
|
||||||
|
extra_dictionaries:
|
||||||
|
description: Extra namespaces
|
||||||
|
type: leadership
|
||||||
|
disabled:
|
||||||
|
variable: main_namespace
|
||||||
|
when: null
|
||||||
|
|
||||||
|
names:
|
||||||
|
description: 'Extra namespace name'
|
||||||
|
alternative_name: xn
|
||||||
|
multi: true
|
||||||
|
mandatory: false
|
||||||
|
|
||||||
|
directories:
|
||||||
|
description: Directories where extra dictionary files are placed
|
||||||
|
alternative_name: xd
|
||||||
|
type: unix_filename
|
||||||
|
params:
|
||||||
|
allow_relative: true
|
||||||
|
test_existence: true
|
||||||
|
types:
|
||||||
|
- directory
|
||||||
|
multi: true
|
||||||
|
|
||||||
|
upgrade:
|
||||||
|
description: Update dictionaries to newest Rougail format version
|
||||||
|
negative_description: Do not update dictionaries to newest Rougail format version
|
||||||
|
default: false
|
||||||
|
|
||||||
|
upgrade_options:
|
||||||
|
description: Update informations
|
||||||
|
disabled:
|
||||||
|
variable: upgrade
|
||||||
|
when: false
|
||||||
|
|
||||||
|
main_dictionaries:
|
||||||
|
description: 'Directories where dictionary files will be placed'
|
||||||
|
default:
|
||||||
|
variable: __.main_dictionaries
|
||||||
|
|
||||||
|
extra_dictionary:
|
||||||
|
description: 'Directories where extra files will be placed'
|
||||||
|
type: unix_filename
|
||||||
|
params:
|
||||||
|
allow_relative: true
|
||||||
|
test_existence: true
|
||||||
|
types:
|
||||||
|
- directory
|
||||||
|
disabled:
|
||||||
|
variable: __.main_namespace
|
||||||
|
when: null
|
||||||
|
|
||||||
|
functions_files:
|
||||||
|
description: File with functions
|
||||||
|
alternative_name: c
|
||||||
|
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
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
description: Name of Rougail plugins
|
||||||
|
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 = {'structural': [],
|
||||||
|
'output': [],
|
||||||
|
'user data': [],
|
||||||
|
}
|
||||||
|
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
|
||||||
|
disabled:
|
||||||
|
variable: upgrade"""
|
||||||
|
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 == 'structural':
|
||||||
|
rougail_process += " commandline: false"
|
||||||
|
elif 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
|
||||||
|
mandatory: false
|
||||||
|
multi: true
|
||||||
|
""".format(NAME=normalize_family(process),
|
||||||
|
)
|
||||||
|
rougail_options += rougail_process
|
||||||
|
convert = FakeRougailConvert(add_extra_options)
|
||||||
|
convert._init()
|
||||||
|
convert.namespace = None
|
||||||
|
convert.parse_root_file(
|
||||||
|
'rougail.config',
|
||||||
|
'',
|
||||||
|
'1.1',
|
||||||
|
YAML().load(rougail_options),
|
||||||
|
)
|
||||||
|
extra_vars = {}
|
||||||
|
for process in processes:
|
||||||
|
for obj in processes[process]:
|
||||||
|
if 'extra_vars' in obj:
|
||||||
|
extra_vars |= obj['extra_vars']
|
||||||
|
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(None)
|
||||||
|
optiondescription = {}
|
||||||
|
exec(tiram_obj, {}, optiondescription) # pylint: disable=W0122
|
||||||
|
return _RougailConfig(backward_compatibility,
|
||||||
|
optiondescription["option_0"],
|
||||||
|
extra_vars=extra_vars,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
RougailConfig = get_rougail_config()
|
||||||
|
|
|
@ -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
|
||||||
|
@ -54,7 +58,9 @@ from .error import DictConsistencyError
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .object_model import CONVERT_OPTION # Choice,
|
from .object_model import CONVERT_OPTION # Choice,
|
||||||
from .object_model import (
|
from .object_model import (
|
||||||
|
PROPERTY_ATTRIBUTE,
|
||||||
CALCULATION_TYPES,
|
CALCULATION_TYPES,
|
||||||
|
CALCULATION_PROPERTY_TYPES,
|
||||||
PARAM_TYPES,
|
PARAM_TYPES,
|
||||||
AnyParam,
|
AnyParam,
|
||||||
Calculation,
|
Calculation,
|
||||||
|
@ -65,7 +71,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 +104,7 @@ class Property:
|
||||||
|
|
||||||
|
|
||||||
class Paths:
|
class Paths:
|
||||||
_regexp_relative = compile(r"^_*\.(.*)$")
|
regexp_relative = compile(r"^_*\.(.*)$")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -105,6 +112,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 +133,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 +155,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 +178,11 @@ class Paths:
|
||||||
new_path = name
|
new_path = name
|
||||||
continue
|
continue
|
||||||
for dynamic_path in self._dynamics:
|
for dynamic_path in self._dynamics:
|
||||||
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
|
if '.' in dynamic_path:
|
||||||
|
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 +215,11 @@ class Paths:
|
||||||
new_path = name
|
new_path = name
|
||||||
continue
|
continue
|
||||||
for dynamic_path in self._dynamics:
|
for dynamic_path in self._dynamics:
|
||||||
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
|
if '.' in dynamic_path:
|
||||||
|
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,7 +230,10 @@ 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])
|
||||||
new_path += "." + name_dynamic
|
if new_path is None:
|
||||||
|
new_path = name_dynamic
|
||||||
|
else:
|
||||||
|
new_path += "." + name_dynamic
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if new_path:
|
if new_path:
|
||||||
|
@ -274,7 +304,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 +316,9 @@ 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.rougailconfig = rougailconfig
|
||||||
|
self.paths = Paths(self.main_namespace)
|
||||||
self.families = []
|
self.families = []
|
||||||
self.variables = []
|
self.variables = []
|
||||||
self.parents = {".": []}
|
self.parents = {".": []}
|
||||||
|
@ -297,13 +329,9 @@ 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.extend(self.rougailconfig["custom_types"])
|
|
||||||
#
|
#
|
||||||
self.family = Family
|
self.convert_options = list(CONVERT_OPTION)
|
||||||
self.dynamic = Dynamic
|
self.convert_options.extend(self.custom_types)
|
||||||
self.choice = Variable # Choice
|
|
||||||
#
|
#
|
||||||
self.exclude_imports = []
|
self.exclude_imports = []
|
||||||
self.informations = Informations()
|
self.informations = Informations()
|
||||||
|
@ -314,13 +342,49 @@ 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.add_extra_options = rougailconfig["structural_commandline.add_extra_options"]
|
||||||
|
self.plugins = []
|
||||||
|
|
||||||
|
def _init(self):
|
||||||
if self.is_init:
|
if self.is_init:
|
||||||
return
|
return
|
||||||
self.variable = Variable
|
variable = Variable
|
||||||
|
family = Family
|
||||||
|
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' in module.__all__:
|
||||||
|
variable = type(variable.__name__ + '_' + plugin, (variable, module.Variable), {})
|
||||||
|
if 'Family' in module.__all__:
|
||||||
|
family = type(family.__name__ + '_' + plugin, (family, module.Family), {})
|
||||||
|
self.variable = variable
|
||||||
|
self.family = family
|
||||||
|
self.dynamic = type(Dynamic.__name__, (Dynamic, family), {})
|
||||||
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
|
|
||||||
self.family_types = hint["type"].__args__ # pylint: disable=W0201
|
self.family_types = hint["type"].__args__ # pylint: disable=W0201
|
||||||
self.family_attrs = frozenset( # pylint: disable=W0201
|
self.family_attrs = frozenset( # pylint: disable=W0201
|
||||||
set(hint) - {"name", "path", "xmlfiles"} | {"redefine"}
|
set(hint) - {"name", "path", "xmlfiles"} | {"redefine"}
|
||||||
|
@ -330,16 +394,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 +441,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,7 +494,10 @@ 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])
|
||||||
path = f"{subpath}.{name}"
|
if not subpath:
|
||||||
|
path = name
|
||||||
|
else:
|
||||||
|
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)}"'
|
||||||
raise DictConsistencyError(msg, 17, [filename])
|
raise DictConsistencyError(msg, 17, [filename])
|
||||||
|
@ -493,8 +558,18 @@ 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,
|
||||||
self.paths[path].model_copy(update=obj),
|
self.paths[path].model_copy(update=obj),
|
||||||
|
@ -515,17 +590,29 @@ class ParserVariable:
|
||||||
extra_attrs = set(family_obj) - self.family_attrs
|
extra_attrs = set(family_obj) - self.family_attrs
|
||||||
if extra_attrs:
|
if extra_attrs:
|
||||||
raise Exception(f"extra attrs ... {extra_attrs}")
|
raise Exception(f"extra attrs ... {extra_attrs}")
|
||||||
if self.get_family_or_variable_type(family_obj) == "dynamic":
|
obj_type = self.get_family_or_variable_type(family_obj)
|
||||||
|
if obj_type is None:
|
||||||
|
# auto set type
|
||||||
|
if '_dynamic' in family_obj:
|
||||||
|
dynamic = family_obj['_dynamic']
|
||||||
|
elif 'dynamic' in family_obj:
|
||||||
|
dynamic = family_obj['dynamic']
|
||||||
|
else:
|
||||||
|
dynamic = None
|
||||||
|
if isinstance(dynamic, (list, dict)):
|
||||||
|
family_obj['type'] = obj_type = 'dynamic'
|
||||||
|
if obj_type == "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 }}'
|
||||||
msg = f'dynamic family name must have "{{{{ suffix }}}}" in his name for "{path}"'
|
else:
|
||||||
raise DictConsistencyError(msg, 13, [filename])
|
msg = f'dynamic family name must have "{{{{ suffix }}}}" in his name for "{path}"'
|
||||||
if version != "1.0" and not family_obj and comment:
|
raise DictConsistencyError(msg, 13, [filename])
|
||||||
family_obj["description"] = comment
|
if version != '1.0' and not family_obj and comment:
|
||||||
|
family_obj['description'] = comment
|
||||||
self.add_family(
|
self.add_family(
|
||||||
path,
|
path,
|
||||||
name,
|
name,
|
||||||
|
@ -580,8 +667,8 @@ class ParserVariable:
|
||||||
):
|
):
|
||||||
# it's a dict, so a new variables!
|
# it's a dict, so a new variables!
|
||||||
continue
|
continue
|
||||||
# FIXME should be remove with 1.0 format
|
# 'variable' for compatibility to format 1.0
|
||||||
if key == "variable" and obj.get("type") != "dynamic":
|
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 +686,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 +713,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 +775,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 +816,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 +841,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 +942,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 +957,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 +975,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]
|
||||||
parent = path.rsplit(".", 1)[0]
|
if '.' in path:
|
||||||
|
parent = path.rsplit(".", 1)[0]
|
||||||
|
else:
|
||||||
|
parent = '.'
|
||||||
self.parents[parent].remove(path)
|
self.parents[parent].remove(path)
|
||||||
|
|
||||||
###############################################################################################
|
###############################################################################################
|
||||||
|
@ -890,7 +993,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
|
||||||
|
@ -907,11 +1010,16 @@ class ParserVariable:
|
||||||
calculations = calculations[0]
|
calculations = calculations[0]
|
||||||
else:
|
else:
|
||||||
calculations = calculations[1]
|
calculations = calculations[1]
|
||||||
return (
|
if not isinstance(value, dict) or attribute not in calculations:
|
||||||
attribute in calculations
|
return False
|
||||||
and isinstance(value, dict)
|
if 'type' in value:
|
||||||
and value.get("type") in CALCULATION_TYPES
|
return value['type'] in CALCULATION_TYPES
|
||||||
)
|
# auto set type
|
||||||
|
typ = set(CALCULATION_TYPES) & set(value)
|
||||||
|
if len(typ) == 1:
|
||||||
|
value['type'] = list(typ)[0]
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def set_calculation(
|
def set_calculation(
|
||||||
self,
|
self,
|
||||||
|
@ -944,6 +1052,11 @@ class ParserVariable:
|
||||||
raise Exception("params must be a dict")
|
raise Exception("params must be a dict")
|
||||||
params = []
|
params = []
|
||||||
for key, val in calculation_object["params"].items():
|
for key, val in calculation_object["params"].items():
|
||||||
|
if isinstance(val, dict) and "type" not in val:
|
||||||
|
# auto set type
|
||||||
|
param_typ = set(CALCULATION_TYPES) & set(val)
|
||||||
|
if len(param_typ) == 1:
|
||||||
|
val['type'] = list(param_typ)[0]
|
||||||
if not isinstance(val, dict) or "type" not in val:
|
if not isinstance(val, dict) or "type" not in val:
|
||||||
param_typ = "any"
|
param_typ = "any"
|
||||||
val = {
|
val = {
|
||||||
|
@ -976,7 +1089,10 @@ class ParserVariable:
|
||||||
if typ == "suffix" and not family_is_dynamic:
|
if typ == "suffix" and not family_is_dynamic:
|
||||||
msg = f'suffix calculation for "{attribute}" in "{path}" cannot be set none dynamic family'
|
msg = f'suffix calculation for "{attribute}" in "{path}" cannot be set none dynamic family'
|
||||||
raise DictConsistencyError(msg, 53, xmlfiles)
|
raise DictConsistencyError(msg, 53, xmlfiles)
|
||||||
calc = CALCULATION_TYPES[typ](**calculation_object)
|
if attribute in PROPERTY_ATTRIBUTE:
|
||||||
|
calc = CALCULATION_PROPERTY_TYPES[typ](**calculation_object)
|
||||||
|
else:
|
||||||
|
calc = CALCULATION_TYPES[typ](**calculation_object)
|
||||||
if index is None:
|
if index is None:
|
||||||
obj[attribute] = calc
|
obj[attribute] = calc
|
||||||
else:
|
else:
|
||||||
|
@ -1025,7 +1141,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 +1155,54 @@ class RougailConvert(ParserVariable):
|
||||||
"",
|
"",
|
||||||
False,
|
False,
|
||||||
None,
|
None,
|
||||||
None,
|
'',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
root_parent = "."
|
root_parent = "."
|
||||||
directory_dict = chain(
|
if self.main_namespace:
|
||||||
(
|
directory_dict = chain(
|
||||||
(
|
(
|
||||||
self.rougailconfig["variable_namespace"],
|
(
|
||||||
self.rougailconfig["dictionaries_dir"],
|
self.main_namespace,
|
||||||
|
self.main_dictionaries,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
self.extra_dictionaries.items(),
|
||||||
self.rougailconfig["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 == ".":
|
||||||
|
namespace_path = self.namespace
|
||||||
|
else:
|
||||||
|
namespace_path = f"{root_parent}.{self.namespace}"
|
||||||
|
if namespace_path in self.parents:
|
||||||
|
raise Exception("pfff")
|
||||||
|
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 == ".":
|
if root_parent == ".":
|
||||||
namespace_path = self.namespace
|
namespace_path = ''
|
||||||
else:
|
else:
|
||||||
namespace_path = f"{root_parent}.{self.namespace}"
|
namespace_path = f"{root_parent}"
|
||||||
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 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 +1235,20 @@ class RougailConvert(ParserVariable):
|
||||||
objects,
|
objects,
|
||||||
filename,
|
filename,
|
||||||
)
|
)
|
||||||
self.parse_family(
|
if objects is None:
|
||||||
filename,
|
return
|
||||||
self.namespace,
|
self.parse_root_file(filename,
|
||||||
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 +1273,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(
|
||||||
|
@ -1142,6 +1291,8 @@ class RougailConvert(ParserVariable):
|
||||||
filename: str,
|
filename: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""version is mandatory in YAML file"""
|
"""version is mandatory in YAML file"""
|
||||||
|
if obj is None:
|
||||||
|
obj = {}
|
||||||
for name in ["_version", "version"]:
|
for name in ["_version", "version"]:
|
||||||
if name not in obj:
|
if name not in obj:
|
||||||
continue
|
continue
|
||||||
|
@ -1149,7 +1300,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 +1327,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,11 +1340,12 @@ 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"
|
||||||
if filename:
|
if filename:
|
||||||
with open(filename, "w", encoding="utf-8") as tiramisu:
|
with open(filename, "w", encoding="utf-8") as tiramisu:
|
||||||
tiramisu.write(output)
|
tiramisu.write(output)
|
||||||
# print(output)
|
#print(output)
|
||||||
return output
|
return output
|
||||||
|
|
|
@ -79,3 +79,8 @@ class UpgradeError(Exception):
|
||||||
class NotFoundError(Exception):
|
class NotFoundError(Exception):
|
||||||
"not found error"
|
"not found error"
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
## ---- specific exceptions ----
|
||||||
|
|
||||||
|
class VariableCalculationDependencyError(Exception):
|
||||||
|
pass
|
||||||
|
|
|
@ -29,8 +29,9 @@ from pydantic import (
|
||||||
StrictStr,
|
StrictStr,
|
||||||
ConfigDict,
|
ConfigDict,
|
||||||
)
|
)
|
||||||
|
from tiramisu import undefined
|
||||||
from .utils import get_jinja_variable_to_param, get_realpath
|
from .utils import get_jinja_variable_to_param, get_realpath
|
||||||
from .error import DictConsistencyError
|
from .error import DictConsistencyError, VariableCalculationDependencyError
|
||||||
|
|
||||||
BASETYPE = Union[StrictBool, StrictInt, StrictFloat, StrictStr, None]
|
BASETYPE = Union[StrictBool, StrictInt, StrictFloat, StrictStr, None]
|
||||||
PROPERTY_ATTRIBUTE = ["frozen", "hidden", "disabled", "mandatory"]
|
PROPERTY_ATTRIBUTE = ["frozen", "hidden", "disabled", "mandatory"]
|
||||||
|
@ -45,46 +46,63 @@ def convert_boolean(value: str) -> bool:
|
||||||
return True
|
return True
|
||||||
elif value == "false":
|
elif value == "false":
|
||||||
return False
|
return False
|
||||||
elif value in ['', None]:
|
elif value in ["", None]:
|
||||||
return None
|
return None
|
||||||
raise Exception(f'unknown boolean value "{value}"')
|
raise Exception(f'unknown boolean value "{value}"')
|
||||||
|
|
||||||
|
|
||||||
CONVERT_OPTION = {
|
CONVERT_OPTION = {
|
||||||
"string": dict(opttype="StrOption"),
|
"string": dict(opttype="StrOption", example="example"),
|
||||||
"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="secrets"),
|
||||||
"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="username"),
|
||||||
"ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}),
|
"ip": dict(
|
||||||
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}),
|
opttype="IPOption", initkwargs={"allow_reserved": True}, example="1.1.1.1"
|
||||||
"netmask": dict(opttype="NetmaskOption"),
|
),
|
||||||
"network": dict(opttype="NetworkOption"),
|
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}, example="1.1.1.0/24"),
|
||||||
"network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}),
|
"netmask": dict(opttype="NetmaskOption", example="255.255.255.0"),
|
||||||
"broadcast": dict(opttype="BroadcastOption"),
|
"network": dict(opttype="NetworkOption", example="1.1.1.0"),
|
||||||
|
"network_cidr": dict(
|
||||||
|
opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24"
|
||||||
|
),
|
||||||
|
"broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"),
|
||||||
"netbios": dict(
|
"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(
|
||||||
"mac": dict(opttype="MACOption"),
|
opttype="PortOption", initkwargs={"allow_private": True}, example="111"
|
||||||
|
),
|
||||||
|
"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="a_choice"),
|
||||||
|
"regexp": dict(opttype="RegexpOption"),
|
||||||
#
|
#
|
||||||
"symlink": dict(opttype="SymLinkOption"),
|
"symlink": dict(opttype="SymLinkOption"),
|
||||||
}
|
}
|
||||||
|
@ -94,26 +112,28 @@ class Param(BaseModel):
|
||||||
key: str
|
key: str
|
||||||
model_config = ConfigDict(extra="forbid")
|
model_config = ConfigDict(extra="forbid")
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
path,
|
self,
|
||||||
attribute,
|
path,
|
||||||
family_is_dynamic,
|
attribute,
|
||||||
is_follower,
|
family_is_dynamic,
|
||||||
xmlfiles,
|
is_follower,
|
||||||
**kwargs,
|
xmlfiles,
|
||||||
) -> None:
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AnyParam(Param):
|
class AnyParam(Param):
|
||||||
type: str
|
type: str
|
||||||
value: BASETYPE
|
value: Union[BASETYPE, List[BASETYPE]]
|
||||||
|
|
||||||
|
|
||||||
class VariableParam(Param):
|
class VariableParam(Param):
|
||||||
type: str
|
type: str
|
||||||
variable: str
|
variable: str
|
||||||
propertyerror: bool = True
|
propertyerror: bool = True
|
||||||
|
whole: bool = False
|
||||||
optional: bool = False
|
optional: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,12 +141,13 @@ class SuffixParam(Param):
|
||||||
type: str
|
type: str
|
||||||
suffix: Optional[int] = None
|
suffix: Optional[int] = None
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
**kwargs,
|
self,
|
||||||
) -> None:
|
**kwargs,
|
||||||
if not kwargs['family_is_dynamic']:
|
) -> None:
|
||||||
|
if not kwargs["family_is_dynamic"]:
|
||||||
msg = f'suffix parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family'
|
msg = f'suffix parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family'
|
||||||
raise DictConsistencyError(msg, 10, kwargs['xmlfiles'])
|
raise DictConsistencyError(msg, 10, kwargs["xmlfiles"])
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,17 +160,17 @@ class InformationParam(Param):
|
||||||
class IndexParam(Param):
|
class IndexParam(Param):
|
||||||
type: str
|
type: str
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
**kwargs,
|
self,
|
||||||
) -> None:
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
if not kwargs["is_follower"]:
|
if not kwargs["is_follower"]:
|
||||||
msg = f'the variable "{kwargs["path"]}" is not a follower, so cannot have index type for param in "{kwargs["attribute"]}"'
|
msg = f'the variable "{kwargs["path"]}" is not a follower, so cannot have index type for param in "{kwargs["attribute"]}"'
|
||||||
raise DictConsistencyError(msg, 25, kwargs['xmlfiles'])
|
raise DictConsistencyError(msg, 25, kwargs["xmlfiles"])
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PARAM_TYPES = {
|
PARAM_TYPES = {
|
||||||
"any": AnyParam,
|
"any": AnyParam,
|
||||||
"variable": VariableParam,
|
"variable": VariableParam,
|
||||||
|
@ -164,7 +185,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 +205,22 @@ 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 +229,17 @@ 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}"'
|
||||||
|
@ -214,11 +256,20 @@ class Calculation(BaseModel):
|
||||||
|
|
||||||
class JinjaCalculation(Calculation):
|
class JinjaCalculation(Calculation):
|
||||||
attribute_name: Literal[
|
attribute_name: Literal[
|
||||||
"frozen", "hidden", "mandatory", "disabled", "default", "validators", "choices", "dynamic"
|
"frozen",
|
||||||
|
"hidden",
|
||||||
|
"mandatory",
|
||||||
|
"empty",
|
||||||
|
"disabled",
|
||||||
|
"default",
|
||||||
|
"validators",
|
||||||
|
"choices",
|
||||||
|
"dynamic",
|
||||||
]
|
]
|
||||||
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,
|
||||||
|
@ -243,16 +294,25 @@ class JinjaCalculation(Calculation):
|
||||||
"__internal_jinja": jinja_path,
|
"__internal_jinja": jinja_path,
|
||||||
"__internal_type": return_type,
|
"__internal_type": return_type,
|
||||||
"__internal_multi": multi,
|
"__internal_multi": multi,
|
||||||
|
"__internal_files": self.xmlfiles,
|
||||||
|
"__internal_attribute": self.attribute_name,
|
||||||
|
"__internal_variable": self.path,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
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 +321,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,
|
||||||
|
@ -309,7 +376,7 @@ class JinjaCalculation(Calculation):
|
||||||
False,
|
False,
|
||||||
objectspace,
|
objectspace,
|
||||||
add_help=True,
|
add_help=True,
|
||||||
params={None: [self.attribute_name]},
|
params={None: [self.attribute_name], "when": True, "inverse": False},
|
||||||
)
|
)
|
||||||
elif self.attribute_name == "choices":
|
elif self.attribute_name == "choices":
|
||||||
return_type = self.return_type
|
return_type = self.return_type
|
||||||
|
@ -331,27 +398,42 @@ class JinjaCalculation(Calculation):
|
||||||
raise Exception("hu?")
|
raise Exception("hu?")
|
||||||
|
|
||||||
|
|
||||||
class VariableCalculation(Calculation):
|
class _VariableCalculation(Calculation):
|
||||||
attribute_name: Literal[
|
|
||||||
"frozen", "hidden", "mandatory", "disabled", "default", "choices", "dynamic"
|
|
||||||
]
|
|
||||||
variable: StrictStr
|
variable: StrictStr
|
||||||
propertyerror: bool = True
|
propertyerror: bool = True
|
||||||
allow_none: bool = False
|
allow_none: bool = False
|
||||||
|
|
||||||
def to_function(
|
def get_variable(self,
|
||||||
|
objectspace,
|
||||||
|
) -> "Variable":
|
||||||
|
if self.ori_path is None:
|
||||||
|
path = self.path
|
||||||
|
else:
|
||||||
|
path = self.ori_path
|
||||||
|
variable, suffix = objectspace.paths.get_with_dynamic(
|
||||||
|
self.variable,
|
||||||
|
self.path_prefix,
|
||||||
|
path,
|
||||||
|
self.version,
|
||||||
|
self.namespace,
|
||||||
|
self.xmlfiles,
|
||||||
|
)
|
||||||
|
if variable and not isinstance(variable, objectspace.variable):
|
||||||
|
# FIXME remove the pfff
|
||||||
|
raise Exception("pfff it's a family")
|
||||||
|
return variable, suffix
|
||||||
|
|
||||||
|
def get_params(
|
||||||
self,
|
self,
|
||||||
objectspace,
|
objectspace,
|
||||||
) -> dict:
|
variable: "Variable",
|
||||||
variable, suffix = objectspace.paths.get_with_dynamic(
|
suffix: Optional[str],
|
||||||
self.variable, self.path_prefix, self.path, self.version, self.namespace, self.xmlfiles
|
*,
|
||||||
)
|
needs_multi: Optional[bool] = None,
|
||||||
|
):
|
||||||
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}"'
|
||||||
raise DictConsistencyError(msg, 88, self.xmlfiles)
|
raise DictConsistencyError(msg, 88, self.xmlfiles)
|
||||||
if not isinstance(variable, objectspace.variable):
|
|
||||||
# FIXME remove the pfff
|
|
||||||
raise Exception("pfff it's a family")
|
|
||||||
param = {
|
param = {
|
||||||
"type": "variable",
|
"type": "variable",
|
||||||
"variable": variable,
|
"variable": variable,
|
||||||
|
@ -360,24 +442,31 @@ class VariableCalculation(Calculation):
|
||||||
if suffix:
|
if suffix:
|
||||||
param["suffix"] = 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:
|
|
||||||
function = "variable_to_property"
|
|
||||||
help_function = "variable_to_property"
|
|
||||||
if variable.type != "boolean":
|
|
||||||
raise Exception("only boolean!")
|
|
||||||
params[None].insert(0, self.attribute_name)
|
|
||||||
if self.allow_none:
|
if self.allow_none:
|
||||||
params["allow_none"] = True
|
params["allow_none"] = True
|
||||||
# current variable is a multi
|
if needs_multi is None:
|
||||||
if self.attribute_name in PROPERTY_ATTRIBUTE:
|
if self.attribute_name != "default":
|
||||||
needs_multi = False
|
needs_multi = True
|
||||||
elif self.attribute_name != "default":
|
else:
|
||||||
needs_multi = True
|
needs_multi = self.path in objectspace.multis
|
||||||
else:
|
calc_variable_is_multi = variable.path in objectspace.multis
|
||||||
needs_multi = self.path in objectspace.multis
|
if not calc_variable_is_multi:
|
||||||
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))
|
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
|
||||||
|
elif suffix and '{{ suffix }}' in suffix:
|
||||||
|
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:
|
||||||
|
@ -390,15 +479,82 @@ class VariableCalculation(Calculation):
|
||||||
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list'
|
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list'
|
||||||
raise DictConsistencyError(msg, 23, self.xmlfiles)
|
raise DictConsistencyError(msg, 23, self.xmlfiles)
|
||||||
elif calc_variable_is_multi:
|
elif calc_variable_is_multi:
|
||||||
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi'
|
if variable.multi or variable.path.rsplit('.', 1)[0] != self.path.rsplit('.', 1)[0]:
|
||||||
raise DictConsistencyError(msg, 21, self.xmlfiles)
|
# it's not a follower or not in same leadership
|
||||||
ret = {
|
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi'
|
||||||
"function": function,
|
raise DictConsistencyError(msg, 21, self.xmlfiles)
|
||||||
|
else:
|
||||||
|
params[None][0]['index'] = {'index': {'type': 'index'}}
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
class VariableCalculation(_VariableCalculation):
|
||||||
|
attribute_name: Literal["default", "choices", "dynamic"]
|
||||||
|
optional: bool = False
|
||||||
|
|
||||||
|
def to_function(
|
||||||
|
self,
|
||||||
|
objectspace,
|
||||||
|
) -> dict:
|
||||||
|
if self.attribute_name != "default" and self.optional:
|
||||||
|
msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"'
|
||||||
|
raise DictConsistencyError(msg, 33, self.xmlfiles)
|
||||||
|
variable, suffix = self.get_variable(objectspace)
|
||||||
|
if not variable and self.optional:
|
||||||
|
raise VariableCalculationDependencyError()
|
||||||
|
params = self.get_params(objectspace,
|
||||||
|
variable,
|
||||||
|
suffix,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"function": "calc_value",
|
||||||
"params": params,
|
"params": params,
|
||||||
}
|
}
|
||||||
if help_function:
|
|
||||||
ret["help"] = help_function
|
|
||||||
return ret
|
class VariablePropertyCalculation(_VariableCalculation):
|
||||||
|
attribute_name: Literal[*PROPERTY_ATTRIBUTE]
|
||||||
|
when: Any = undefined
|
||||||
|
when_not: Any = undefined
|
||||||
|
|
||||||
|
def to_function(
|
||||||
|
self,
|
||||||
|
objectspace,
|
||||||
|
) -> dict:
|
||||||
|
variable, suffix = self.get_variable(objectspace)
|
||||||
|
params = self.get_params(objectspace,
|
||||||
|
variable,
|
||||||
|
suffix,
|
||||||
|
needs_multi=False,)
|
||||||
|
variable = params[None][0]["variable"]
|
||||||
|
if self.when is not undefined:
|
||||||
|
if self.version == "1.0":
|
||||||
|
msg = f'when is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"'
|
||||||
|
raise DictConsistencyError(msg, 103, variable.xmlfiles)
|
||||||
|
if self.when_not is not undefined:
|
||||||
|
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
|
||||||
|
raise DictConsistencyError(msg, 31, variable.xmlfiles)
|
||||||
|
when = self.when
|
||||||
|
inverse = False
|
||||||
|
elif self.when_not is not undefined:
|
||||||
|
if self.version == "1.0":
|
||||||
|
msg = f'when_not is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"'
|
||||||
|
raise DictConsistencyError(msg, 104, variable.xmlfiles)
|
||||||
|
when = self.when_not
|
||||||
|
inverse = True
|
||||||
|
else:
|
||||||
|
if variable.type != "boolean":
|
||||||
|
raise Exception("only boolean!")
|
||||||
|
when = True
|
||||||
|
inverse = False
|
||||||
|
params[None].insert(0, self.attribute_name)
|
||||||
|
params["when"] = when
|
||||||
|
params["inverse"] = inverse
|
||||||
|
return {
|
||||||
|
"function": "variable_to_property",
|
||||||
|
"params": params,
|
||||||
|
"help": "variable_to_property",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class InformationCalculation(Calculation):
|
class InformationCalculation(Calculation):
|
||||||
|
@ -410,37 +566,96 @@ class InformationCalculation(Calculation):
|
||||||
self,
|
self,
|
||||||
objectspace,
|
objectspace,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
param = {
|
params = {
|
||||||
"type": "information",
|
None: [
|
||||||
"information": self.information,
|
{
|
||||||
|
"type": "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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SuffixCalculation(Calculation):
|
class _SuffixCalculation(Calculation):
|
||||||
attribute_name: Literal["default", "choice", "dynamic"]
|
|
||||||
suffix: Optional[int] = None
|
suffix: Optional[int] = None
|
||||||
|
|
||||||
|
def get_suffix(self) -> dict:
|
||||||
|
suffix = {"type": "suffix"}
|
||||||
|
if self.suffix is not None:
|
||||||
|
suffix["suffix"] = self.suffix
|
||||||
|
return suffix
|
||||||
|
|
||||||
|
|
||||||
|
class SuffixCalculation(_SuffixCalculation):
|
||||||
|
attribute_name: Literal["default", "choice", "dynamic"]
|
||||||
|
|
||||||
def to_function(
|
def to_function(
|
||||||
self,
|
self,
|
||||||
objectspace,
|
objectspace,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
suffix = {"type": "suffix"}
|
suffix = {"type": "suffix"}
|
||||||
if self.suffix is not None:
|
if self.suffix is not None:
|
||||||
suffix['suffix'] = self.suffix
|
suffix["suffix"] = self.suffix
|
||||||
return {
|
return {
|
||||||
"function": "calc_value",
|
"function": "calc_value",
|
||||||
"params": {None: [suffix]},
|
"params": {None: [self.get_suffix()]},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SuffixPropertyCalculation(_SuffixCalculation):
|
||||||
|
attribute_name: Literal[*PROPERTY_ATTRIBUTE]
|
||||||
|
when: Any = undefined
|
||||||
|
when_not: Any = undefined
|
||||||
|
|
||||||
|
def to_function(
|
||||||
|
self,
|
||||||
|
objectspace,
|
||||||
|
) -> dict:
|
||||||
|
if self.version == "1.0":
|
||||||
|
msg = f'when is not allowed in format version 1.0 for attribute "{self.attribute_name}"'
|
||||||
|
raise DictConsistencyError(msg, 105, variable.xmlfiles)
|
||||||
|
if self.when is not undefined:
|
||||||
|
if self.when_not is not undefined:
|
||||||
|
msg = f'the suffix has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
|
||||||
|
raise DictConsistencyError(msg, 35, variable.xmlfiles)
|
||||||
|
when = self.when
|
||||||
|
inverse = False
|
||||||
|
elif self.when_not is not undefined:
|
||||||
|
when = self.when_not
|
||||||
|
inverse = True
|
||||||
|
else:
|
||||||
|
msg = f'the suffix has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
|
||||||
|
raise DictConsistencyError
|
||||||
|
params = {None: [self.attribute_name, self.get_suffix()],
|
||||||
|
"when": when,
|
||||||
|
"inverse": inverse,
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"function": "variable_to_property",
|
||||||
|
"params": params,
|
||||||
|
"help": "variable_to_property",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -467,6 +682,13 @@ CALCULATION_TYPES = {
|
||||||
"suffix": SuffixCalculation,
|
"suffix": SuffixCalculation,
|
||||||
"index": IndexCalculation,
|
"index": IndexCalculation,
|
||||||
}
|
}
|
||||||
|
CALCULATION_PROPERTY_TYPES = {
|
||||||
|
"jinja": JinjaCalculation,
|
||||||
|
"variable": VariablePropertyCalculation,
|
||||||
|
"information": InformationCalculation,
|
||||||
|
"suffix": SuffixPropertyCalculation,
|
||||||
|
"index": IndexCalculation,
|
||||||
|
}
|
||||||
BASETYPE_CALC = Union[StrictBool, StrictInt, StrictFloat, StrictStr, Calculation, None]
|
BASETYPE_CALC = Union[StrictBool, StrictInt, StrictFloat, StrictStr, Calculation, None]
|
||||||
|
|
||||||
|
|
||||||
|
@ -480,14 +702,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]
|
||||||
|
|
||||||
|
|
||||||
|
@ -498,6 +721,7 @@ class Variable(BaseModel):
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
default: Union[List[BASETYPE_CALC], BASETYPE_CALC] = None
|
default: Union[List[BASETYPE_CALC], BASETYPE_CALC] = None
|
||||||
choices: Optional[Union[List[BASETYPE_CALC], Calculation]] = None
|
choices: Optional[Union[List[BASETYPE_CALC], Calculation]] = None
|
||||||
|
regexp: Optional[str] = None
|
||||||
params: Optional[List[Param]] = None
|
params: Optional[List[Param]] = None
|
||||||
validators: Optional[List[Calculation]] = None
|
validators: Optional[List[Calculation]] = None
|
||||||
multi: Optional[bool] = None
|
multi: Optional[bool] = None
|
||||||
|
@ -506,27 +730,28 @@ class Variable(BaseModel):
|
||||||
hidden: Union[bool, Calculation] = False
|
hidden: Union[bool, Calculation] = False
|
||||||
disabled: Union[bool, Calculation] = False
|
disabled: Union[bool, Calculation] = False
|
||||||
mandatory: Union[None, bool, Calculation] = True
|
mandatory: Union[None, bool, Calculation] = True
|
||||||
|
empty: Union[None, bool, Calculation] = True
|
||||||
auto_save: bool = False
|
auto_save: bool = False
|
||||||
mode: Optional[str] = None
|
mode: Optional[str] = None
|
||||||
test: Optional[list] = None
|
test: Optional[list] = None
|
||||||
|
examples: Optional[list] = None
|
||||||
path: str
|
path: str
|
||||||
namespace: str
|
namespace: Optional[str]
|
||||||
version: str
|
version: str
|
||||||
|
path_prefix: Optional[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 Choice(Variable):
|
|
||||||
# type: Literal["choice"] = "choice"
|
|
||||||
# choices: Union[List[BASETYPE_CALC], Calculation]
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
path_prefix: Optional[str]
|
||||||
|
xmlfiles: List[str] = []
|
||||||
|
|
||||||
model_config = ConfigDict(extra="forbid")
|
model_config = ConfigDict(extra="forbid")
|
||||||
|
|
89
src/rougail/structural_commandline/annotator.py
Normal file
89
src/rougail/structural_commandline/annotator.py
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
"""Annotate to add specify attribute for tiramisu-cmdline
|
||||||
|
|
||||||
|
Silique (https://www.silique.fr)
|
||||||
|
Copyright (C) 2024
|
||||||
|
|
||||||
|
distribued with GPL-2 or later license
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
"""
|
||||||
|
from rougail.annotator.variable import Walk
|
||||||
|
from rougail.utils import _
|
||||||
|
from rougail.error import DictConsistencyError
|
||||||
|
|
||||||
|
class Annotator(Walk):
|
||||||
|
"""Annotate value"""
|
||||||
|
level = 80
|
||||||
|
|
||||||
|
def __init__(self, objectspace, *args) -> None:
|
||||||
|
if not objectspace.paths:
|
||||||
|
return
|
||||||
|
self.alternative_names = {}
|
||||||
|
self.objectspace = objectspace
|
||||||
|
not_for_commandlines = []
|
||||||
|
for family in self.get_families():
|
||||||
|
if family.commandline:
|
||||||
|
continue
|
||||||
|
self.not_for_commandline(family)
|
||||||
|
not_for_commandlines.append(family.path + '.')
|
||||||
|
for variable in self.get_variables():
|
||||||
|
if variable.type == 'symlink':
|
||||||
|
continue
|
||||||
|
variable_path = variable.path
|
||||||
|
for family_path in not_for_commandlines:
|
||||||
|
if variable_path.startswith(family_path):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if not variable.commandline:
|
||||||
|
self.not_for_commandline(variable)
|
||||||
|
else:
|
||||||
|
self.manage_alternative_name(variable)
|
||||||
|
self.manage_negative_description(variable)
|
||||||
|
|
||||||
|
def not_for_commandline(self, variable) -> None:
|
||||||
|
self.objectspace.properties.add(variable.path, 'not_for_commandline', True)
|
||||||
|
|
||||||
|
def manage_alternative_name(self, variable) -> None:
|
||||||
|
if not variable.alternative_name:
|
||||||
|
return
|
||||||
|
alternative_name = variable.alternative_name
|
||||||
|
variable_path = variable.path
|
||||||
|
all_letters = ''
|
||||||
|
for letter in alternative_name:
|
||||||
|
all_letters += letter
|
||||||
|
if all_letters == 'h':
|
||||||
|
msg = _(f'alternative_name "{alternative_name}" conflict with "--help"')
|
||||||
|
raise DictConsistencyError(msg, 202, variable.xmlfiles)
|
||||||
|
if all_letters in self.alternative_names:
|
||||||
|
msg = _(f'conflict alternative_name "{alternative_name}": "{variable_path}" and "{self.alternative_names[all_letters]}"')
|
||||||
|
raise DictConsistencyError(msg, 202, variable.xmlfiles)
|
||||||
|
|
||||||
|
self.alternative_names[alternative_name] = variable_path
|
||||||
|
if '.' not in variable_path:
|
||||||
|
path = alternative_name
|
||||||
|
else:
|
||||||
|
path = variable_path.rsplit('.', 1)[0] + '.' + alternative_name
|
||||||
|
self.objectspace.add_variable(alternative_name, {'type': 'symlink', 'path': path, 'opt': variable}, variable.xmlfiles, False, False, variable.version)
|
||||||
|
|
||||||
|
def manage_negative_description(self, variable) -> None:
|
||||||
|
if not variable.negative_description:
|
||||||
|
if variable.type == 'boolean' and not self.objectspace.add_extra_options:
|
||||||
|
raise DictConsistencyError(_(f'negative_description is mandatory for boolean variable, but "{variable.path}" hasn\'t'), 200, variable.xmlfiles)
|
||||||
|
return
|
||||||
|
if variable.type != 'boolean':
|
||||||
|
raise DictConsistencyError(_(f'negative_description is only available for boolean variable, but "{variable.path}" is "{variable.type}"'), 201, variable.xmlfiles)
|
||||||
|
self.objectspace.informations.add(
|
||||||
|
variable.path, "negative_description", variable.negative_description
|
||||||
|
)
|
42
src/rougail/structural_commandline/config.py
Normal file
42
src/rougail/structural_commandline/config.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
"""
|
||||||
|
Config file for Rougail-structural_commandline
|
||||||
|
|
||||||
|
Silique (https://www.silique.fr)
|
||||||
|
Copyright (C) 2024
|
||||||
|
|
||||||
|
distribued with GPL-2 or later license
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
"""
|
||||||
|
def get_rougail_config(*,
|
||||||
|
backward_compatibility=True,
|
||||||
|
) -> dict:
|
||||||
|
options = """
|
||||||
|
structural_commandline:
|
||||||
|
description: Configuration rougail-structural_commandline
|
||||||
|
commandline: false
|
||||||
|
add_extra_options:
|
||||||
|
description: Add extra options to tiramisu-cmdline-parser
|
||||||
|
default: true
|
||||||
|
"""
|
||||||
|
return {'name': 'exporter',
|
||||||
|
'process': 'structural',
|
||||||
|
'options': options,
|
||||||
|
'level': 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ('get_rougail_config')
|
||||||
|
|
36
src/rougail/structural_commandline/object_model.py
Normal file
36
src/rougail/structural_commandline/object_model.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
"""Annotate to add specify attribute for tiramisu-cmdline
|
||||||
|
|
||||||
|
Silique (https://www.silique.fr)
|
||||||
|
Copyright (C) 2024
|
||||||
|
|
||||||
|
distribued with GPL-2 or later license
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
"""
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Variable(BaseModel):
|
||||||
|
alternative_name: Optional[str]=None
|
||||||
|
commandline: bool=True
|
||||||
|
negative_description: Optional[str]=None
|
||||||
|
|
||||||
|
|
||||||
|
class Family(BaseModel):
|
||||||
|
commandline: bool=True
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ('Variable', 'Family')
|
|
@ -35,16 +35,16 @@ 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 rougail.error import display_xmlfiles
|
||||||
|
from tiramisu.error import ValueWarning, ConfigError
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
|
|
||||||
|
|
||||||
global func
|
global func
|
||||||
func = {'calc_value': calc_value}
|
|
||||||
dict_env = {}
|
dict_env = {}
|
||||||
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
|
||||||
ENV.filters = func
|
func = ENV.filters
|
||||||
ENV.compile_templates('jinja_caches', zip=None)
|
ENV.compile_templates('jinja_caches', zip=None)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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_variable, __internal_attribute, __internal_jinja, __internal_type, __internal_multi, __internal_files, __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():
|
||||||
|
@ -71,22 +78,40 @@ def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwa
|
||||||
c_kw = c_kw.setdefault(subkey, {})
|
c_kw = c_kw.setdefault(subkey, {})
|
||||||
c_kw[var] = value
|
c_kw[var] = value
|
||||||
else:
|
else:
|
||||||
|
if key in kw:
|
||||||
|
raise ConfigError(f'internal error, multi key for "{key}" in jinja_to_function')
|
||||||
kw[key] = value
|
kw[key] = value
|
||||||
values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
|
try:
|
||||||
|
values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
|
||||||
|
except Exception as err:
|
||||||
|
raise ConfigError(f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}') from err
|
||||||
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('\n') if val != ""]
|
||||||
values = convert(values)
|
if not values and __default_value is not None:
|
||||||
return values if values != '' and values != 'None' else None
|
return __default_value
|
||||||
|
return values
|
||||||
|
try:
|
||||||
|
values = convert(values)
|
||||||
|
except Exception as err:
|
||||||
|
raise ConfigError(f'cannot converting "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}') from err
|
||||||
|
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, when, inverse):
|
||||||
return prop if value else None
|
if inverse:
|
||||||
|
is_match = value != when
|
||||||
|
else:
|
||||||
|
is_match = value == when
|
||||||
|
return prop if is_match else None
|
||||||
|
|
||||||
|
|
||||||
def jinja_to_property(prop, **kwargs):
|
def jinja_to_property(prop, when, inverse, **kwargs):
|
||||||
value = func['jinja_to_function'](**kwargs)
|
value = func['jinja_to_function'](**kwargs)
|
||||||
return func['variable_to_property'](prop, value is not None)
|
return func['variable_to_property'](prop, value is not None, when, inverse)
|
||||||
|
|
||||||
|
|
||||||
def jinja_to_property_help(prop, **kwargs):
|
def jinja_to_property_help(prop, **kwargs):
|
||||||
|
@ -104,6 +129,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 +161,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
|
||||||
|
|
|
@ -33,7 +33,7 @@ from json import dumps
|
||||||
from os.path import isfile, basename
|
from os.path import isfile, basename
|
||||||
|
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .error import DictConsistencyError
|
from .error import DictConsistencyError, VariableCalculationDependencyError
|
||||||
from .utils import normalize_family
|
from .utils import normalize_family
|
||||||
from .object_model import Calculation, CONVERT_OPTION
|
from .object_model import Calculation, CONVERT_OPTION
|
||||||
|
|
||||||
|
@ -60,35 +60,37 @@ 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(
|
||||||
[
|
[
|
||||||
"from tiramisu import *",
|
"from tiramisu import *",
|
||||||
"from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
|
"from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
|
||||||
|
"from re import compile as re_compile",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
if self.objectspace.export_with_import:
|
||||||
|
self.text["header"].extend(
|
||||||
|
[
|
||||||
|
"from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if funcs_paths:
|
if funcs_paths:
|
||||||
if self.rougailconfig["export_with_import"]:
|
|
||||||
self.text["header"].extend(
|
|
||||||
["from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"]
|
|
||||||
)
|
|
||||||
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,54 +108,51 @@ 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():
|
for elt in self.objectspace.paths.get():
|
||||||
if 1:
|
if elt.path in self.objectspace.families:
|
||||||
# for elt in self.reorder_family(self.objectspace.space):
|
Family(
|
||||||
for elt in self.objectspace.paths.get():
|
elt,
|
||||||
if elt.path in self.objectspace.families:
|
|
||||||
Family(
|
|
||||||
elt,
|
|
||||||
self,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
Variable(
|
|
||||||
elt,
|
|
||||||
self,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
path_prefixes = self.objectspace.paths.get_path_prefixes()
|
|
||||||
for path_prefix in path_prefixes:
|
|
||||||
space = self.objectspace.space.variables[path_prefix]
|
|
||||||
self.set_name(space)
|
|
||||||
baseprefix = Family(
|
|
||||||
space,
|
|
||||||
self,
|
self,
|
||||||
)
|
)
|
||||||
basefamily.add(baseprefix)
|
else:
|
||||||
for elt in self.reorder_family(space):
|
Variable(
|
||||||
self.populate_family(
|
elt,
|
||||||
baseprefix,
|
self,
|
||||||
elt,
|
)
|
||||||
)
|
# else:
|
||||||
if not hasattr(baseprefix.elt, "information"):
|
# path_prefixes = self.objectspace.paths.get_path_prefixes()
|
||||||
baseprefix.elt.information = self.objectspace.information(
|
# for path_prefix in path_prefixes:
|
||||||
baseprefix.elt.xmlfiles
|
# space = self.objectspace.space.variables[path_prefix]
|
||||||
)
|
# self.set_name(space)
|
||||||
for key, value in self.objectspace.paths.get_providers_path(
|
# baseprefix = Family(
|
||||||
path_prefix
|
# space,
|
||||||
).items():
|
# self,
|
||||||
setattr(baseprefix.elt.information, key, value)
|
# )
|
||||||
for key, value in self.objectspace.paths.get_suppliers_path(
|
# basefamily.add(baseprefix)
|
||||||
path_prefix
|
# for elt in self.reorder_family(space):
|
||||||
).items():
|
# self.populate_family(
|
||||||
setattr(baseprefix.elt.information, key, value)
|
# baseprefix,
|
||||||
baseelt.name = normalize_family(self.rougailconfig["base_option_name"])
|
# elt,
|
||||||
baseelt.description = self.rougailconfig["base_option_name"]
|
# )
|
||||||
|
# if not hasattr(baseprefix.elt, "information"):
|
||||||
|
# baseprefix.elt.information = self.objectspace.information(
|
||||||
|
# baseprefix.elt.xmlfiles
|
||||||
|
# )
|
||||||
|
# for key, value in self.objectspace.paths.get_providers_path(
|
||||||
|
# path_prefix
|
||||||
|
# ).items():
|
||||||
|
# setattr(baseprefix.elt.information, key, value)
|
||||||
|
# for key, value in self.objectspace.paths.get_suppliers_path(
|
||||||
|
# path_prefix
|
||||||
|
# ).items():
|
||||||
|
# setattr(baseprefix.elt.information, key, value)
|
||||||
|
baseelt.name = normalize_family(self.objectspace.base_option_name)
|
||||||
|
baseelt.description = self.objectspace.base_option_name
|
||||||
self.reflector_objects[baseelt.path].get(
|
self.reflector_objects[baseelt.path].get(
|
||||||
[], baseelt.description
|
[], baseelt.description
|
||||||
) # pylint: disable=E1101
|
) # pylint: disable=E1101
|
||||||
|
@ -205,7 +204,9 @@ class Common:
|
||||||
self.populate_attrib()
|
self.populate_attrib()
|
||||||
if self.informations:
|
if self.informations:
|
||||||
for information in self.informations:
|
for information in self.informations:
|
||||||
self.tiramisu.text['option'].append(f'{information}.set_option({self.option_name})')
|
self.tiramisu.text["option"].append(
|
||||||
|
f"{information}.set_option({self.option_name})"
|
||||||
|
)
|
||||||
return self.option_name
|
return self.option_name
|
||||||
|
|
||||||
def populate_attrib(self):
|
def populate_attrib(self):
|
||||||
|
@ -279,7 +280,7 @@ class Common:
|
||||||
informations = self.objectspace.informations.get(self.elt.path)
|
informations = self.objectspace.informations.get(self.elt.path)
|
||||||
if not informations:
|
if not informations:
|
||||||
return
|
return
|
||||||
keys['informations'] = informations
|
keys["informations"] = informations
|
||||||
|
|
||||||
def populate_param(
|
def populate_param(
|
||||||
self,
|
self,
|
||||||
|
@ -292,7 +293,10 @@ 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":
|
||||||
|
# default? really?
|
||||||
if self.elt.multi:
|
if self.elt.multi:
|
||||||
default = []
|
default = []
|
||||||
else:
|
else:
|
||||||
|
@ -301,14 +305,20 @@ class Common:
|
||||||
if param["variable"].path == self.elt.path:
|
if param["variable"].path == self.elt.path:
|
||||||
return f'ParamSelfInformation("{param["information"]}", {default})'
|
return f'ParamSelfInformation("{param["information"]}", {default})'
|
||||||
information_variable_path = param["variable"].path
|
information_variable_path = param["variable"].path
|
||||||
information_variable = self.tiramisu.reflector_objects[information_variable_path]
|
information_variable = self.tiramisu.reflector_objects[
|
||||||
|
information_variable_path
|
||||||
|
]
|
||||||
if information_variable_path not in self.calls:
|
if information_variable_path not in self.calls:
|
||||||
option_name = information_variable.get(self.calls, self.elt.path)
|
option_name = information_variable.get(self.calls, self.elt.path)
|
||||||
return f'ParamInformation("{param["information"]}", {default}, option={option_name})'
|
return f'ParamInformation("{param["information"]}", {default}, option={option_name})'
|
||||||
else:
|
else:
|
||||||
information = f'ParamInformation("{param["information"]}", {default})'
|
information = (
|
||||||
|
f'ParamInformation("{param["information"]}", {default})'
|
||||||
|
)
|
||||||
information_name = self.tiramisu.get_information_name()
|
information_name = self.tiramisu.get_information_name()
|
||||||
self.tiramisu.text["option"].append(f'{information_name} = {information}')
|
self.tiramisu.text["option"].append(
|
||||||
|
f"{information_name} = {information}"
|
||||||
|
)
|
||||||
information_variable.informations.append(information_name)
|
information_variable.informations.append(information_name)
|
||||||
return information_name
|
return information_name
|
||||||
return f'ParamInformation("{param["information"]}", {default})'
|
return f'ParamInformation("{param["information"]}", {default})'
|
||||||
|
@ -324,6 +334,7 @@ class Common:
|
||||||
param.get("propertyerror", True),
|
param.get("propertyerror", True),
|
||||||
param.get("suffix"),
|
param.get("suffix"),
|
||||||
param.get("dynamic"),
|
param.get("dynamic"),
|
||||||
|
param.get('whole', False),
|
||||||
)
|
)
|
||||||
if param["type"] == "any":
|
if param["type"] == "any":
|
||||||
if isinstance(param["value"], str):
|
if isinstance(param["value"], str):
|
||||||
|
@ -335,21 +346,25 @@ class Common:
|
||||||
|
|
||||||
def build_option_param(
|
def build_option_param(
|
||||||
self,
|
self,
|
||||||
param,
|
variable,
|
||||||
propertyerror,
|
propertyerror,
|
||||||
suffix: Optional[str],
|
suffix: Optional[str],
|
||||||
dynamic,
|
dynamic,
|
||||||
|
whole: bool,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""build variable parameters"""
|
"""build variable parameters"""
|
||||||
if param.path == self.elt.path:
|
if variable.path == self.elt.path:
|
||||||
return "ParamSelfOption(whole=False)"
|
return f"ParamSelfOption(whole={whole})"
|
||||||
option_name = self.tiramisu.reflector_objects[param.path].get(
|
if whole:
|
||||||
|
msg = f'variable param "{variable.path}" has whole attribute but it\'s not allowed for external variable'
|
||||||
|
raise DictConsistencyError(msg, 34, self.elt.xmlfiles)
|
||||||
|
option_name = self.tiramisu.reflector_objects[variable.path].get(
|
||||||
self.calls, self.elt.path
|
self.calls, self.elt.path
|
||||||
)
|
)
|
||||||
params = [f"{option_name}"]
|
params = [f"{option_name}"]
|
||||||
if suffix is not None:
|
if suffix is not None:
|
||||||
param_type = "ParamDynOption"
|
param_type = "ParamDynOption"
|
||||||
params.append(str(suffix))
|
params.append(self.convert_str(suffix))
|
||||||
else:
|
else:
|
||||||
param_type = "ParamOption"
|
param_type = "ParamOption"
|
||||||
if not propertyerror:
|
if not propertyerror:
|
||||||
|
@ -387,10 +402,11 @@ class Common:
|
||||||
ret = ret + ")"
|
ret = ret + ")"
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def populate_calculation(self,
|
def populate_calculation(
|
||||||
datas: Union[Calculation, str, list],
|
self,
|
||||||
return_a_tuple: bool=False,
|
datas: Union[Calculation, str, list],
|
||||||
) -> str:
|
return_a_tuple: bool = False,
|
||||||
|
) -> str:
|
||||||
if isinstance(datas, str):
|
if isinstance(datas, str):
|
||||||
return self.convert_str(datas)
|
return self.convert_str(datas)
|
||||||
if isinstance(datas, Calculation):
|
if isinstance(datas, Calculation):
|
||||||
|
@ -400,15 +416,18 @@ class Common:
|
||||||
params = []
|
params = []
|
||||||
for idx, data in enumerate(datas):
|
for idx, data in enumerate(datas):
|
||||||
if isinstance(data, Calculation):
|
if isinstance(data, Calculation):
|
||||||
params.append(self.calculation_value(data))
|
try:
|
||||||
|
params.append(self.calculation_value(data))
|
||||||
|
except VariableCalculationDependencyError:
|
||||||
|
pass
|
||||||
elif isinstance(data, str):
|
elif isinstance(data, str):
|
||||||
params.append(self.convert_str(data))
|
params.append(self.convert_str(data))
|
||||||
else:
|
else:
|
||||||
params.append(str(data))
|
params.append(str(data))
|
||||||
if return_a_tuple:
|
if return_a_tuple:
|
||||||
ret = '('
|
ret = "("
|
||||||
else:
|
else:
|
||||||
ret = '['
|
ret = "["
|
||||||
ret += ", ".join(params)
|
ret += ", ".join(params)
|
||||||
if return_a_tuple:
|
if return_a_tuple:
|
||||||
if len(params) <= 1:
|
if len(params) <= 1:
|
||||||
|
@ -428,8 +447,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,19 +460,37 @@ 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.type == 'regexp':
|
||||||
|
self.object_type = 'Regexp_' + self.option_name
|
||||||
|
self.tiramisu.text['header'].append(f'''class {self.object_type}(RegexpOption):
|
||||||
|
__slots__ = tuple()
|
||||||
|
_type = 'value'
|
||||||
|
{self.object_type}._regexp = re_compile(r"{self.elt.regexp}")
|
||||||
|
''')
|
||||||
if self.elt.path in self.objectspace.multis:
|
if self.elt.path in self.objectspace.multis:
|
||||||
keys["multi"] = self.objectspace.multis[self.elt.path]
|
keys["multi"] = self.objectspace.multis[self.elt.path]
|
||||||
if not hasattr(self.elt, "default"):
|
|
||||||
print('FIXME CA EXISTE!!!')
|
|
||||||
if hasattr(self.elt, "default") and self.elt.default is not None:
|
if hasattr(self.elt, "default") and self.elt.default is not None:
|
||||||
keys["default"] = self.populate_calculation(self.elt.default)
|
try:
|
||||||
|
keys["default"] = self.populate_calculation(self.elt.default)
|
||||||
|
except VariableCalculationDependencyError:
|
||||||
|
pass
|
||||||
if self.elt.path in self.objectspace.default_multi:
|
if self.elt.path in self.objectspace.default_multi:
|
||||||
keys["default_multi"] = self.populate_calculation(self.objectspace.default_multi[self.elt.path])
|
try:
|
||||||
|
keys["default_multi"] = self.populate_calculation(
|
||||||
|
self.objectspace.default_multi[self.elt.path]
|
||||||
|
)
|
||||||
|
except VariableCalculationDependencyError:
|
||||||
|
pass
|
||||||
if self.elt.validators:
|
if self.elt.validators:
|
||||||
keys["validators"] = self.populate_calculation(self.elt.validators)
|
keys["validators"] = self.populate_calculation(self.elt.validators)
|
||||||
for key, value in CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items():
|
for key, value in (
|
||||||
|
CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items()
|
||||||
|
):
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = self.convert_str(value)
|
value = self.convert_str(value)
|
||||||
keys[key] = value
|
keys[key] = value
|
||||||
|
|
21
src/rougail/update/__init__.py
Normal file
21
src/rougail/update/__init__.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
"""
|
||||||
|
Silique (https://www.silique.fr)
|
||||||
|
Copyright (C) 2024
|
||||||
|
|
||||||
|
distribued with GPL-2 or later license
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
"""
|
||||||
|
from .update import RougailUpgrade
|
|
@ -1,4 +1,4 @@
|
||||||
"""Update Rougail XML file to new version
|
"""Update Rougail structure file to new version
|
||||||
|
|
||||||
Cadoles (http://www.cadoles.com)
|
Cadoles (http://www.cadoles.com)
|
||||||
Copyright (C) 2021
|
Copyright (C) 2021
|
||||||
|
@ -23,7 +23,7 @@ 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 import listdir, makedirs
|
from os import listdir
|
||||||
from os.path import basename, isdir, isfile, join
|
from os.path import basename, isdir, isfile, join
|
||||||
from typing import Any, List, Optional, Tuple
|
from typing import Any, List, Optional, Tuple
|
||||||
|
|
||||||
|
@ -35,15 +35,14 @@ except ModuleNotFoundError as err:
|
||||||
|
|
||||||
# from ast import parse as ast_parse
|
# from ast import parse as ast_parse
|
||||||
from json import dumps
|
from json import dumps
|
||||||
|
from ruamel.yaml import YAML
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ruamel.yaml import YAML
|
from ..config import RougailConfig
|
||||||
|
from ..error import UpgradeError
|
||||||
from .config import RougailConfig
|
from ..i18n import _
|
||||||
from .error import UpgradeError
|
from ..object_model import CONVERT_OPTION
|
||||||
from .i18n import _
|
from ..utils import normalize_family
|
||||||
from .object_model import CONVERT_OPTION
|
|
||||||
from .utils import normalize_family
|
|
||||||
|
|
||||||
VERSIONS = ["0.10", "1.0", "1.1"]
|
VERSIONS = ["0.10", "1.0", "1.1"]
|
||||||
|
|
||||||
|
@ -64,7 +63,7 @@ class upgrade_010_to_10:
|
||||||
xmlsrc: str,
|
xmlsrc: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.xmlsrc = xmlsrc
|
self.xmlsrc = xmlsrc
|
||||||
self.paths = {"family": {}, "variable": {}}
|
self.paths = {"family": {}, "variable": {}, 'dynamic': {}}
|
||||||
self.lists = {
|
self.lists = {
|
||||||
"service": {},
|
"service": {},
|
||||||
"ip": {},
|
"ip": {},
|
||||||
|
@ -72,7 +71,7 @@ class upgrade_010_to_10:
|
||||||
"file": {},
|
"file": {},
|
||||||
}
|
}
|
||||||
self.flatten_paths = {"family": {}, "variable": {}}
|
self.flatten_paths = {"family": {}, "variable": {}}
|
||||||
self.variables = self.parse_variables(dico, namespace)
|
self.variables = self.parse_variables(dico, namespace, namespace, root=True)
|
||||||
self.parse_variables_with_path()
|
self.parse_variables_with_path()
|
||||||
self.parse_services(dico)
|
self.parse_services(dico)
|
||||||
self.parse_constraints(dico)
|
self.parse_constraints(dico)
|
||||||
|
@ -81,13 +80,20 @@ class upgrade_010_to_10:
|
||||||
self,
|
self,
|
||||||
family: dict,
|
family: dict,
|
||||||
sub_path: str,
|
sub_path: str,
|
||||||
|
true_sub_path: str,
|
||||||
|
*,
|
||||||
|
root: bool=False,
|
||||||
|
is_dynamic: bool=False,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
new_families = {}
|
new_families = {}
|
||||||
|
if root:
|
||||||
|
new_families['version'] = None
|
||||||
if "variables" in family:
|
if "variables" in family:
|
||||||
for subelt in family["variables"]:
|
for subelt in family["variables"]:
|
||||||
for typ, obj in subelt.items():
|
for typ, obj in subelt.items():
|
||||||
for subobj in obj:
|
for subobj in obj:
|
||||||
getattr(self, f"convert_{typ}")(subobj, new_families, sub_path)
|
local_is_dynamic = is_dynamic or subobj.get('dynamic') is not None
|
||||||
|
getattr(self, f"convert_{typ}")(subobj, new_families, sub_path, true_sub_path, local_is_dynamic)
|
||||||
family.pop("variables")
|
family.pop("variables")
|
||||||
return new_families
|
return new_families
|
||||||
|
|
||||||
|
@ -96,9 +102,17 @@ class upgrade_010_to_10:
|
||||||
family: dict,
|
family: dict,
|
||||||
new_families: dict,
|
new_families: dict,
|
||||||
sub_path: str,
|
sub_path: str,
|
||||||
|
true_sub_path: str,
|
||||||
|
is_dynamic: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
# name is the key, do not let it in values
|
# name is the key, do not let it in values
|
||||||
name = family.pop("name")
|
name = family.pop("name")
|
||||||
|
if true_sub_path:
|
||||||
|
true_sub_path = true_sub_path + "." + name
|
||||||
|
else:
|
||||||
|
true_sub_path = name
|
||||||
|
if is_dynamic:
|
||||||
|
name += '{{ suffix }}'
|
||||||
if sub_path:
|
if sub_path:
|
||||||
sub_path = sub_path + "." + name
|
sub_path = sub_path + "." + name
|
||||||
else:
|
else:
|
||||||
|
@ -112,7 +126,7 @@ class upgrade_010_to_10:
|
||||||
if typ == "dynamic":
|
if typ == "dynamic":
|
||||||
family["variable"] = self.get_variable_path(value)
|
family["variable"] = self.get_variable_path(value)
|
||||||
# add sub families and sub variables
|
# add sub families and sub variables
|
||||||
sub_families = self.parse_variables(family, sub_path)
|
sub_families = self.parse_variables(family, sub_path, true_sub_path, is_dynamic=is_dynamic)
|
||||||
for sub_name, sub_family in sub_families.copy().items():
|
for sub_name, sub_family in sub_families.copy().items():
|
||||||
if sub_name not in family:
|
if sub_name not in family:
|
||||||
continue
|
continue
|
||||||
|
@ -128,12 +142,23 @@ class upgrade_010_to_10:
|
||||||
variable: dict,
|
variable: dict,
|
||||||
new_families: dict,
|
new_families: dict,
|
||||||
sub_path: str,
|
sub_path: str,
|
||||||
|
true_sub_path: str,
|
||||||
|
is_dynamic: bool,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
name = variable.pop("name")
|
name = variable.pop("name")
|
||||||
|
if is_dynamic:
|
||||||
|
if true_sub_path:
|
||||||
|
true_sub_path = true_sub_path + "." + name
|
||||||
|
else:
|
||||||
|
true_sub_path = name
|
||||||
|
self.flatten_paths["variable"][name] = true_sub_path
|
||||||
|
name += '{{ suffix }}'
|
||||||
if sub_path:
|
if sub_path:
|
||||||
sub_path = sub_path + "." + name
|
sub_path = sub_path + "." + name
|
||||||
else:
|
else:
|
||||||
sub_path = name
|
sub_path = name
|
||||||
|
if is_dynamic:
|
||||||
|
self.paths['dynamic'][true_sub_path] = sub_path
|
||||||
new_families[name] = variable
|
new_families[name] = variable
|
||||||
self.flatten_paths["variable"][name] = sub_path
|
self.flatten_paths["variable"][name] = sub_path
|
||||||
self.paths["variable"][sub_path] = variable
|
self.paths["variable"][sub_path] = variable
|
||||||
|
@ -173,24 +198,32 @@ class upgrade_010_to_10:
|
||||||
)(test)
|
)(test)
|
||||||
)
|
)
|
||||||
variable["test"] = tests
|
variable["test"] = tests
|
||||||
|
if variable.get('mandatory', False):
|
||||||
|
del variable["mandatory"]
|
||||||
|
CONVERT_TYPE = {'filename': 'unix_filename',
|
||||||
|
'password': 'secret',
|
||||||
|
}
|
||||||
|
if variable.get('type') in CONVERT_TYPE:
|
||||||
|
variable['type'] = CONVERT_TYPE[variable['type']]
|
||||||
|
|
||||||
def parse_variables_with_path(self):
|
def parse_variables_with_path(self):
|
||||||
for variable in self.paths["variable"].values():
|
for variable in self.paths["variable"].values():
|
||||||
|
multi = variable.get('multi', False)
|
||||||
if "value" in variable:
|
if "value" in variable:
|
||||||
default = variable.pop("value")
|
default = variable.pop("value")
|
||||||
if default is not None:
|
if default is not None:
|
||||||
if not variable.get("multi", False) and len(default) == 1:
|
if not multi and len(default) == 1:
|
||||||
variable["default"] = self.get_value(default[0])
|
variable["default"] = self.get_value(default[0], multi)
|
||||||
else:
|
else:
|
||||||
variable["default"] = [
|
variable["default"] = [
|
||||||
self.get_value(value) for value in default
|
self.get_value(value, multi) for value in default
|
||||||
]
|
]
|
||||||
if "choice" in variable:
|
if "choice" in variable:
|
||||||
if not variable["choice"]:
|
if not variable["choice"]:
|
||||||
variable["choices"] = variable.pop("choice")
|
variable["choices"] = variable.pop("choice")
|
||||||
else:
|
else:
|
||||||
variable["choices"] = [
|
variable["choices"] = [
|
||||||
self.get_value(choice) for choice in variable.pop("choice")
|
self.get_value(choice, multi) for choice in variable.pop("choice")
|
||||||
]
|
]
|
||||||
|
|
||||||
def parse_services(
|
def parse_services(
|
||||||
|
@ -306,15 +339,32 @@ class upgrade_010_to_10:
|
||||||
apply_on_fallback = False
|
apply_on_fallback = False
|
||||||
source = self.get_variable_path(condition["source"])
|
source = self.get_variable_path(condition["source"])
|
||||||
if not source:
|
if not source:
|
||||||
source = f'__{condition["source"]}'
|
source = condition["source"]
|
||||||
name = condition.pop("name")
|
name = condition.pop("name")
|
||||||
prop = name.split("_", 1)[0]
|
prop = name.split("_", 1)[0]
|
||||||
|
multi = False
|
||||||
|
for target in condition["target"]:
|
||||||
|
typ = target.get("type", "variable")
|
||||||
|
if typ == "variable":
|
||||||
|
variable_path = self.get_variable_path(target["text"])
|
||||||
|
if variable_path is None:
|
||||||
|
continue
|
||||||
|
variable = self.paths["variable"][variable_path]
|
||||||
|
if variable.get('multi', False):
|
||||||
|
multi = True
|
||||||
if apply_on_fallback:
|
if apply_on_fallback:
|
||||||
condition_value = True
|
condition_value = True
|
||||||
else:
|
else:
|
||||||
|
if "{{ suffix }}" in source:
|
||||||
|
force_param = {'__var': source}
|
||||||
|
source = '__var'
|
||||||
|
else:
|
||||||
|
force_param = None
|
||||||
condition_value = self.params_condition_to_jinja(
|
condition_value = self.params_condition_to_jinja(
|
||||||
prop, source, condition["param"], name.endswith("if_in")
|
prop, source, condition["param"], name.endswith("if_in"), multi
|
||||||
)
|
)
|
||||||
|
if force_param:
|
||||||
|
condition_value.setdefault('params', {}).update(force_param)
|
||||||
for target in condition["target"]:
|
for target in condition["target"]:
|
||||||
typ = target.get("type", "variable")
|
typ = target.get("type", "variable")
|
||||||
if typ == "variable":
|
if typ == "variable":
|
||||||
|
@ -367,7 +417,7 @@ class upgrade_010_to_10:
|
||||||
check["param"] = [
|
check["param"] = [
|
||||||
{"text": variable_path, "type": "variable"}
|
{"text": variable_path, "type": "variable"}
|
||||||
] + check.get("param", [])
|
] + check.get("param", [])
|
||||||
check_value = self.convert_param_function(check)
|
check_value = self.convert_param_function(check, variable.get('multi', False))
|
||||||
variable.setdefault("validators", []).append(check_value)
|
variable.setdefault("validators", []).append(check_value)
|
||||||
|
|
||||||
def parse_fill(
|
def parse_fill(
|
||||||
|
@ -377,17 +427,22 @@ class upgrade_010_to_10:
|
||||||
for target in fill.pop("target"):
|
for target in fill.pop("target"):
|
||||||
params = []
|
params = []
|
||||||
variable_path = self.get_variable_path(target["text"])
|
variable_path = self.get_variable_path(target["text"])
|
||||||
if variable_path is None:
|
if variable_path in self.paths["dynamic"]:
|
||||||
continue
|
variable_path = self.paths["dynamic"][variable_path]
|
||||||
variable = self.paths["variable"][variable_path]
|
if variable_path in self.paths["variable"]:
|
||||||
if fill.get("type") == "jinja":
|
variable = self.paths["variable"][variable_path]
|
||||||
fill_value = {
|
if fill.get("type") == "jinja":
|
||||||
"type": "jinja",
|
fill_value = {
|
||||||
"jinja": fill["name"],
|
"type": "jinja",
|
||||||
}
|
"jinja": fill["name"],
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
fill_value = self.convert_param_function(fill, variable.get('multi', False))
|
||||||
|
variable["default"] = fill_value
|
||||||
|
if variable.get('mandatory') is False:
|
||||||
|
del variable['mandatory']
|
||||||
else:
|
else:
|
||||||
fill_value = self.convert_param_function(fill)
|
raise Exception(f'cannot set fill to unknown variable "{variable_path}"')
|
||||||
variable["default"] = fill_value
|
|
||||||
|
|
||||||
def params_condition_to_jinja(
|
def params_condition_to_jinja(
|
||||||
self,
|
self,
|
||||||
|
@ -395,6 +450,7 @@ class upgrade_010_to_10:
|
||||||
path: str,
|
path: str,
|
||||||
params: List[dict],
|
params: List[dict],
|
||||||
if_in: bool,
|
if_in: bool,
|
||||||
|
multi: bool,
|
||||||
) -> str:
|
) -> str:
|
||||||
new_params = {}
|
new_params = {}
|
||||||
jinja = "{% if "
|
jinja = "{% if "
|
||||||
|
@ -402,7 +458,7 @@ class upgrade_010_to_10:
|
||||||
if idx:
|
if idx:
|
||||||
jinja += " or "
|
jinja += " or "
|
||||||
|
|
||||||
new_param, value = self.get_jinja_param_and_value(param)
|
new_param, value = self.get_jinja_param_and_value(param, multi)
|
||||||
if value:
|
if value:
|
||||||
jinja += path + " == " + value
|
jinja += path + " == " + value
|
||||||
if new_param:
|
if new_param:
|
||||||
|
@ -422,10 +478,11 @@ class upgrade_010_to_10:
|
||||||
def get_value(
|
def get_value(
|
||||||
self,
|
self,
|
||||||
param: dict,
|
param: dict,
|
||||||
|
multi: bool,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
typ = param.get("type", "string")
|
typ = param.get("type", "string")
|
||||||
if typ == "string":
|
if typ == "string":
|
||||||
value = param["text"]
|
value = param.get("text")
|
||||||
elif typ == "number":
|
elif typ == "number":
|
||||||
value = int(param["text"])
|
value = int(param["text"])
|
||||||
elif typ == "nil":
|
elif typ == "nil":
|
||||||
|
@ -447,7 +504,7 @@ class upgrade_010_to_10:
|
||||||
if "propertyerror" in param:
|
if "propertyerror" in param:
|
||||||
value["propertyerror"] = param["propertyerror"]
|
value["propertyerror"] = param["propertyerror"]
|
||||||
elif typ == "function":
|
elif typ == "function":
|
||||||
value = self.convert_param_function(param)
|
value = self.convert_param_function(param, multi)
|
||||||
elif typ == "information":
|
elif typ == "information":
|
||||||
value = {
|
value = {
|
||||||
"type": "information",
|
"type": "information",
|
||||||
|
@ -465,10 +522,11 @@ class upgrade_010_to_10:
|
||||||
def get_jinja_param_and_value(
|
def get_jinja_param_and_value(
|
||||||
self,
|
self,
|
||||||
param,
|
param,
|
||||||
|
multi: bool,
|
||||||
) -> Tuple[list, Any]:
|
) -> Tuple[list, Any]:
|
||||||
new_param = None
|
new_param = None
|
||||||
typ = param.get("type", "string")
|
typ = param.get("type", "string")
|
||||||
value = self.get_value(param)
|
value = self.get_value(param, multi)
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
if typ == "information":
|
if typ == "information":
|
||||||
key = normalize_family(value["information"])
|
key = normalize_family(value["information"])
|
||||||
|
@ -476,17 +534,25 @@ class upgrade_010_to_10:
|
||||||
attr_name = f'{value["variable"]}.{key}'
|
attr_name = f'{value["variable"]}.{key}'
|
||||||
else:
|
else:
|
||||||
attr_name = key
|
attr_name = key
|
||||||
attr_name = f"__information.{attr_name}"
|
attr_name = f"__information_{attr_name}"
|
||||||
new_param = {attr_name: value}
|
new_param = {attr_name: value}
|
||||||
value = attr_name
|
value = attr_name
|
||||||
elif typ in ["index", "suffix"]:
|
elif typ in ["index", "suffix"]:
|
||||||
attr_name = f"__{typ}"
|
if 'name' in value:
|
||||||
new_param = {attr_name: value}
|
attr_name = value['name']
|
||||||
|
else:
|
||||||
|
attr_name = f"__{typ}"
|
||||||
|
new_param = {attr_name: {"type": typ}}
|
||||||
value = attr_name
|
value = attr_name
|
||||||
elif "propertyerror" in param or "optional" in param:
|
elif "propertyerror" in param or "optional" in param:
|
||||||
attr_name = value["variable"]
|
attr_name = value["variable"]
|
||||||
new_param = {attr_name: value}
|
new_param = {attr_name: value}
|
||||||
value = value[typ]
|
value = value[typ]
|
||||||
|
elif "{{ suffix }}" in value[typ]:
|
||||||
|
path = value[typ]
|
||||||
|
attr_name = path.split('.')[-1][:-12] # remove {{ suffix }}
|
||||||
|
new_param = {attr_name: value}
|
||||||
|
value = attr_name
|
||||||
else:
|
else:
|
||||||
value = value[typ]
|
value = value[typ]
|
||||||
if not value:
|
if not value:
|
||||||
|
@ -498,22 +564,35 @@ class upgrade_010_to_10:
|
||||||
def convert_param_function(
|
def convert_param_function(
|
||||||
self,
|
self,
|
||||||
param: dict,
|
param: dict,
|
||||||
|
multi: bool,
|
||||||
) -> str:
|
) -> str:
|
||||||
text = param["name"]
|
text = param["name"]
|
||||||
params = {}
|
params = {}
|
||||||
|
# multi = False
|
||||||
if "param" in param and param["param"]:
|
if "param" in param and param["param"]:
|
||||||
|
if text == 'calc_value' and len(param["param"]) == 1 and isinstance(param["param"][0], dict) and param["param"][0].get('type') == 'variable' and param["param"][0].get("text"):
|
||||||
|
value = param["param"][0]["text"]
|
||||||
|
path = self.get_variable_path(value)
|
||||||
|
if not path:
|
||||||
|
path = value
|
||||||
|
ret = {"type": "variable", "variable": path}
|
||||||
|
if 'optional' in param["param"][0]:
|
||||||
|
ret['optional'] = param["param"][0]["optional"]
|
||||||
|
return ret
|
||||||
first, *others = param["param"]
|
first, *others = param["param"]
|
||||||
new_param, first = self.get_jinja_param_and_value(first)
|
new_param, first = self.get_jinja_param_and_value(first, multi)
|
||||||
text = f"{first} | {text}"
|
text = f"{first} | {text}"
|
||||||
if new_param:
|
if new_param:
|
||||||
params |= new_param
|
params |= new_param
|
||||||
if others:
|
if others:
|
||||||
values = []
|
values = []
|
||||||
for param in others:
|
for param in others:
|
||||||
new_param, value = self.get_jinja_param_and_value(param)
|
new_param, value = self.get_jinja_param_and_value(param, multi)
|
||||||
if new_param:
|
if new_param:
|
||||||
params |= new_param
|
params |= new_param
|
||||||
if "name" in param:
|
if "name" in param:
|
||||||
|
if param["name"] == "multi" and value == "true":
|
||||||
|
multi = True
|
||||||
values.append(f'{param["name"]}={value}')
|
values.append(f'{param["name"]}={value}')
|
||||||
else:
|
else:
|
||||||
values.append(value)
|
values.append(value)
|
||||||
|
@ -522,7 +601,12 @@ class upgrade_010_to_10:
|
||||||
text += ")"
|
text += ")"
|
||||||
else:
|
else:
|
||||||
text += "()"
|
text += "()"
|
||||||
text = "{{ " + text + " }}"
|
if not multi:
|
||||||
|
text = "{{ " + text + " }}"
|
||||||
|
else:
|
||||||
|
text = """{% for __variable in """ + text + """ %}
|
||||||
|
{{ __variable }}
|
||||||
|
{% endfor %}"""
|
||||||
ret = {"type": "jinja", "jinja": text}
|
ret = {"type": "jinja", "jinja": text}
|
||||||
if params:
|
if params:
|
||||||
ret["params"] = params
|
ret["params"] = params
|
||||||
|
@ -537,8 +621,10 @@ class upgrade_010_to_10:
|
||||||
and path in self.flatten_paths["variable"]
|
and path in self.flatten_paths["variable"]
|
||||||
):
|
):
|
||||||
path = self.flatten_paths["variable"][path]
|
path = self.flatten_paths["variable"][path]
|
||||||
|
if path in self.paths["dynamic"]:
|
||||||
|
path = self.paths["dynamic"][path]
|
||||||
if path not in self.paths["variable"]:
|
if path not in self.paths["variable"]:
|
||||||
return
|
return path
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def get_family_path(
|
def get_family_path(
|
||||||
|
@ -570,43 +656,38 @@ class RougailUpgrade:
|
||||||
rougailconfig = RougailConfig
|
rougailconfig = RougailConfig
|
||||||
self.rougailconfig = rougailconfig
|
self.rougailconfig = rougailconfig
|
||||||
|
|
||||||
def load_dictionaries(
|
def run(
|
||||||
self,
|
self,
|
||||||
dstfolder: str,
|
|
||||||
services_dstfolder: Optional[str] = None,
|
|
||||||
extra_dstfolder: Optional[str] = None,
|
|
||||||
):
|
):
|
||||||
if extra_dstfolder is None:
|
for dict_dir, dest_dir in zip(self.rougailconfig["main_dictionaries"], self.rougailconfig["upgrade_options.main_dictionaries"]):
|
||||||
extra_dstfolder = dstfolder
|
|
||||||
dict_dirs = self.rougailconfig["dictionaries_dir"]
|
|
||||||
if not isinstance(dict_dirs, list):
|
|
||||||
dict_dirs = [dict_dirs]
|
|
||||||
for dict_dir in dict_dirs:
|
|
||||||
self._load_dictionaries(
|
self._load_dictionaries(
|
||||||
dict_dir,
|
dict_dir,
|
||||||
dstfolder,
|
dest_dir,
|
||||||
services_dstfolder,
|
normalize_family(self.rougailconfig["main_namespace"]),
|
||||||
self.rougailconfig["variable_namespace"],
|
|
||||||
)
|
)
|
||||||
for namespace, extra_dirs in self.rougailconfig["extra_dictionaries"].items():
|
if self.rougailconfig['main_namespace']:
|
||||||
extra_dstsubfolder = join(extra_dstfolder, namespace)
|
if self.rougailconfig["extra_dictionaries"]:
|
||||||
if not isdir(extra_dstsubfolder):
|
dst_extra_dir = self.rougailconfig["upgrade_options.extra_dictionary"]
|
||||||
makedirs(extra_dstsubfolder)
|
for namespace, extra_dirs in self.rougailconfig["extra_dictionaries"].items():
|
||||||
for extra_dir in extra_dirs:
|
extra_dstsubfolder = Path(dst_extra_dir) / namespace
|
||||||
self._load_dictionaries(
|
if not extra_dstsubfolder.is_dir():
|
||||||
extra_dir,
|
extra_dstsubfolder.mkdir()
|
||||||
extra_dstsubfolder,
|
for extra_dir in extra_dirs:
|
||||||
None,
|
self._load_dictionaries(
|
||||||
namespace,
|
str(extra_dir),
|
||||||
)
|
str(extra_dstsubfolder),
|
||||||
|
normalize_family(namespace),
|
||||||
|
)
|
||||||
|
|
||||||
def _load_dictionaries(
|
def _load_dictionaries(
|
||||||
self,
|
self,
|
||||||
srcfolder: str,
|
srcfolder: str,
|
||||||
dstfolder: str,
|
dstfolder: Optional[str],
|
||||||
services_dstfolder: Optional[str],
|
|
||||||
namespace: str,
|
namespace: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if dstfolder is None:
|
||||||
|
dstfolder = srcfolder
|
||||||
|
Path(dstfolder).mkdir(parents=True, exist_ok=True)
|
||||||
filenames = [
|
filenames = [
|
||||||
filename
|
filename
|
||||||
for filename in listdir(srcfolder)
|
for filename in listdir(srcfolder)
|
||||||
|
@ -615,18 +696,8 @@ class RougailUpgrade:
|
||||||
filenames.sort()
|
filenames.sort()
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
xmlsrc = Path(srcfolder) / Path(filename)
|
xmlsrc = Path(srcfolder) / Path(filename)
|
||||||
ymlfile = filename[:-3] + "yml"
|
|
||||||
xmldst = Path(dstfolder) / Path(ymlfile)
|
ymldst = Path(dstfolder) / (Path(filename).stem + '.yml')
|
||||||
if xmldst.is_file():
|
|
||||||
raise Exception(
|
|
||||||
f'cannot update "{xmlsrc}" destination file "{xmldst}" already exists'
|
|
||||||
)
|
|
||||||
if services_dstfolder:
|
|
||||||
ymldst_services = Path(services_dstfolder) / ymlfile
|
|
||||||
if ymldst_services.is_file():
|
|
||||||
raise Exception(
|
|
||||||
f'cannot update "{xmlsrc}" destination file "{ymldst_services}" already exists'
|
|
||||||
)
|
|
||||||
if filename.endswith(".xml"):
|
if filename.endswith(".xml"):
|
||||||
if parse is None:
|
if parse is None:
|
||||||
raise Exception("XML module is not installed")
|
raise Exception("XML module is not installed")
|
||||||
|
@ -641,7 +712,7 @@ class RougailUpgrade:
|
||||||
)
|
)
|
||||||
ext = "xml"
|
ext = "xml"
|
||||||
else:
|
else:
|
||||||
with xmlsrc.open() as xml_fh:
|
with xmlsrc.open() as file_fh:
|
||||||
root = YAML(typ="safe").load(file_fh)
|
root = YAML(typ="safe").load(file_fh)
|
||||||
search_function_name = get_function_name(str(root["version"]))
|
search_function_name = get_function_name(str(root["version"]))
|
||||||
ext = "yml"
|
ext = "yml"
|
||||||
|
@ -661,24 +732,23 @@ class RougailUpgrade:
|
||||||
root_services = root_services_
|
root_services = root_services_
|
||||||
if function_version == search_function_name:
|
if function_version == search_function_name:
|
||||||
function_found = True
|
function_found = True
|
||||||
if root:
|
if root != {'version': None}:
|
||||||
root["version"] = version
|
root["version"] = float(version)
|
||||||
xmldst.parent.mkdir(parents=True, exist_ok=True)
|
with ymldst.open("w") as ymlfh:
|
||||||
with xmldst.open("w") as ymlfh:
|
|
||||||
yaml = YAML()
|
yaml = YAML()
|
||||||
yaml.dump(
|
yaml.dump(
|
||||||
root,
|
root,
|
||||||
xmldst,
|
|
||||||
)
|
|
||||||
if root_services and services_dstfolder:
|
|
||||||
root_services["version"] = version
|
|
||||||
ymldst_services.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
with ymldst_services.open("w") as ymlfh:
|
|
||||||
yaml = YAML()
|
|
||||||
yaml.dump(
|
|
||||||
root_services,
|
|
||||||
ymlfh,
|
ymlfh,
|
||||||
)
|
)
|
||||||
|
# if root_services and services_dstfolder:
|
||||||
|
# root_services["version"] = version
|
||||||
|
# ymldst_services.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
# with ymldst_services.open("w") as ymlfh:
|
||||||
|
# yaml = YAML()
|
||||||
|
# yaml.dump(
|
||||||
|
# root_services,
|
||||||
|
# ymlfh,
|
||||||
|
# )
|
||||||
|
|
||||||
def _attribut_to_bool(self, variable):
|
def _attribut_to_bool(self, variable):
|
||||||
for prop in [
|
for prop in [
|
||||||
|
@ -834,23 +904,47 @@ class RougailUpgrade:
|
||||||
return dico
|
return dico
|
||||||
|
|
||||||
def _update_1_1(self, root):
|
def _update_1_1(self, root):
|
||||||
if not isinstance(root, dict):
|
new_root = {}
|
||||||
return
|
update_root = False
|
||||||
# migrate dynamic family
|
|
||||||
if (
|
|
||||||
("variable" in root and isinstance(root["variable"], str))
|
|
||||||
or ("_variable" in root and isinstance(root["_variable"], str))
|
|
||||||
) and (
|
|
||||||
("_type" in root and root["_type"] == "dynamic")
|
|
||||||
or ("type" in root and root["type"] == "dynamic")
|
|
||||||
):
|
|
||||||
root["dynamic"] = {
|
|
||||||
"type": "variable",
|
|
||||||
"variable": root.pop("variable"),
|
|
||||||
"propertyerror": False,
|
|
||||||
}
|
|
||||||
for key, value in root.items():
|
for key, value in root.items():
|
||||||
|
new_root[key] = value
|
||||||
|
if not isinstance(value, dict):
|
||||||
|
continue
|
||||||
|
# migrate dynamic family
|
||||||
|
if (
|
||||||
|
("variable" in value and isinstance(value["variable"], str))
|
||||||
|
or ("_variable" in value and isinstance(value["_variable"], str))
|
||||||
|
) and (
|
||||||
|
("_type" in value and value["_type"] == "dynamic")
|
||||||
|
or ("type" in value and value["type"] == "dynamic")
|
||||||
|
):
|
||||||
|
value["dynamic"] = {
|
||||||
|
"type": "variable",
|
||||||
|
"variable": value.pop("variable"),
|
||||||
|
"propertyerror": False,
|
||||||
|
}
|
||||||
|
if '{{ suffix }}' not in key:
|
||||||
|
new_root[key + '{{ suffix }}'] = new_root.pop(key)
|
||||||
|
update_root = True
|
||||||
self._update_1_1(value)
|
self._update_1_1(value)
|
||||||
|
for typ, obj in {'boolean': bool,
|
||||||
|
'number': int,
|
||||||
|
'string': str,
|
||||||
|
'float': float,
|
||||||
|
}.items():
|
||||||
|
if value.get('type') == typ:
|
||||||
|
default = value.get('default')
|
||||||
|
if default is None or default == []:
|
||||||
|
continue
|
||||||
|
if isinstance(default, obj):
|
||||||
|
del value['type']
|
||||||
|
elif isinstance(default, list) and isinstance(default[0], obj):
|
||||||
|
del value['type']
|
||||||
|
if value.get('multi') and isinstance(value.get('default'), list):
|
||||||
|
del value['multi']
|
||||||
|
if update_root:
|
||||||
|
root.clear()
|
||||||
|
root.update(new_root)
|
||||||
|
|
||||||
def update_1_1(
|
def update_1_1(
|
||||||
self,
|
self,
|
||||||
|
@ -878,7 +972,7 @@ class RougailUpgrade:
|
||||||
objects = root.find(typ)
|
objects = root.find(typ)
|
||||||
if objects is None:
|
if objects is None:
|
||||||
objects = []
|
objects = []
|
||||||
new_objects = self._xml_to_yaml(objects, typ, variables, "")
|
new_objects = self._xml_to_yaml(objects, typ, variables, namespace)
|
||||||
if new_objects[typ]:
|
if new_objects[typ]:
|
||||||
new_root.update(new_objects)
|
new_root.update(new_objects)
|
||||||
else:
|
else:
|
||||||
|
@ -928,7 +1022,6 @@ class RougailUpgrade:
|
||||||
if not has_value:
|
if not has_value:
|
||||||
value = SubElement(variable, "value")
|
value = SubElement(variable, "value")
|
||||||
value.text = choices[0]
|
value.text = choices[0]
|
||||||
variable.attrib["mandatory"] = "True"
|
|
||||||
|
|
||||||
# convert group to leadership
|
# convert group to leadership
|
||||||
groups = []
|
groups = []
|
|
@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
from unicodedata import normalize, combining
|
from unicodedata import normalize, combining
|
||||||
import re
|
import re
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
from importlib.machinery import SourceFileLoader
|
from importlib.machinery import SourceFileLoader
|
||||||
from importlib.util import spec_from_loader, module_from_spec
|
from importlib.util import spec_from_loader, module_from_spec
|
||||||
|
@ -37,7 +38,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 +65,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,13 +111,18 @@ 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:
|
||||||
msg = _(f'error in jinja "{jinja_text}": {err}')
|
msg = _(f'error in jinja "{jinja_text}" for the variable "{ current_path }": {err}')
|
||||||
raise Exception(msg) from err
|
raise DictConsistencyError(msg, 39, xmlfiles) from err
|
||||||
variables = list(variables)
|
variables = list(variables)
|
||||||
variables.sort()
|
variables.sort(reverse=True)
|
||||||
|
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 +133,36 @@ 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:
|
||||||
|
sub_family = variable_path + '.'
|
||||||
|
for founded_variable in chain(founded_variables, unknown_variables):
|
||||||
|
if founded_variable.startswith(sub_family):
|
||||||
|
break
|
||||||
|
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:
|
||||||
|
root_path = None
|
||||||
|
vpath = variable_path
|
||||||
|
while '.' in vpath:
|
||||||
|
vpath = vpath.rsplit('.', 1)[0]
|
||||||
|
variable, suffix = objectspace.paths.get_with_dynamic(
|
||||||
|
vpath,
|
||||||
|
path_prefix,
|
||||||
|
current_path,
|
||||||
|
version,
|
||||||
|
namespace,
|
||||||
|
xmlfiles,
|
||||||
|
)
|
||||||
|
if variable and variable.path in objectspace.families:
|
||||||
|
root_path = vpath
|
||||||
|
break
|
||||||
|
if root_path:
|
||||||
|
yield {}, None, root_path
|
||||||
|
for variable_path, data in founded_variables.items():
|
||||||
|
yield data[1], data[0], variable_path
|
||||||
|
|
9
tests/dictionaries/00_0empty/tiramisu/base.py
Normal file
9
tests/dictionaries/00_0empty/tiramisu/base.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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=[])
|
11
tests/dictionaries/00_0empty/tiramisu/multi.py
Normal file
11
tests/dictionaries/00_0empty/tiramisu/multi.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("standard")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("advanced")
|
||||||
|
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"}))
|
||||||
|
optiondescription_2 = OptionDescription(name="2", doc="2", children=[], properties=frozenset({"advanced"}))
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_2])
|
9
tests/dictionaries/00_0empty/tiramisu/no_namespace.py
Normal file
9
tests/dictionaries/00_0empty/tiramisu/no_namespace.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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=[])
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
_version: '1.1'
|
||||||
|
version: # a variable
|
11
tests/dictionaries/00_0version_underscore/tiramisu/base.py
Normal file
11
tests/dictionaries/00_0version_underscore/tiramisu/base.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
15
tests/dictionaries/00_0version_underscore/tiramisu/multi.py
Normal file
15
tests/dictionaries/00_0version_underscore/tiramisu/multi.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
|
@ -0,0 +1,10 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
3
tests/dictionaries/00_1empty_variable/makedict/base.json
Normal file
3
tests/dictionaries/00_1empty_variable/makedict/base.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"rougail.empty": null
|
||||||
|
}
|
11
tests/dictionaries/00_1empty_variable/tiramisu/base.py
Normal file
11
tests/dictionaries/00_1empty_variable/tiramisu/base.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
15
tests/dictionaries/00_1empty_variable/tiramisu/multi.py
Normal file
15
tests/dictionaries/00_1empty_variable/tiramisu/multi.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
|
@ -0,0 +1,10 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
version: 1.1
|
||||||
|
var1: "no" # a first variable
|
||||||
|
var2:
|
||||||
|
description: a second variable
|
||||||
|
multi: true
|
||||||
|
default:
|
||||||
|
jinja: |
|
||||||
|
{{ _.var1 }}
|
||||||
|
description: the value of var1
|
13
tests/dictionaries/00_2default_calculated/tiramisu/base.py
Normal file
13
tests/dictionaries/00_2default_calculated/tiramisu/base.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var2"), '_.var1': ParamOption(option_2)})), properties=frozenset({"mandatory", "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])
|
19
tests/dictionaries/00_2default_calculated/tiramisu/multi.py
Normal file
19
tests/dictionaries/00_2default_calculated/tiramisu/multi.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("1.rougail.var2"), '_.var1': ParamOption(option_3)})), properties=frozenset({"mandatory", "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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("2.rougail.var2"), '_.var1': ParamOption(option_7)})), properties=frozenset({"mandatory", "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])
|
|
@ -0,0 +1,12 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var2"), '_.var1': ParamOption(option_1)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
version: 1.1
|
||||||
|
var1: # a first variable
|
||||||
|
- 'no'
|
||||||
|
- 'yes'
|
||||||
|
- maybe
|
||||||
|
var2:
|
||||||
|
description: a second variable
|
||||||
|
multi: true
|
||||||
|
default:
|
||||||
|
jinja: |
|
||||||
|
{% for val in _.var1 %}
|
||||||
|
{{ val }}
|
||||||
|
{% endfor %}
|
||||||
|
description: the value of _.var1
|
|
@ -0,0 +1,13 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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", "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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var2"), '_.var1': ParamOption(option_2)})), properties=frozenset({"mandatory", "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])
|
|
@ -0,0 +1,19 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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", "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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("1.rougail.var2"), '_.var1': ParamOption(option_3)})), properties=frozenset({"mandatory", "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", "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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("2.rougail.var2"), '_.var1': ParamOption(option_7)})), properties=frozenset({"mandatory", "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])
|
|
@ -0,0 +1,12 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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", "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), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var2"), '_.var1': ParamOption(option_1)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
version: 1.1
|
||||||
|
var1:
|
||||||
|
description: a first variable
|
||||||
|
multi: true
|
||||||
|
type: domainname
|
||||||
|
params:
|
||||||
|
allow_ip: true
|
||||||
|
var2:
|
||||||
|
description: a second variable
|
||||||
|
default:
|
||||||
|
type: variable
|
||||||
|
variable: _.var1
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": []
|
||||||
|
},
|
||||||
|
"rougail.var2": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": []
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": [],
|
||||||
|
"rougail.var2": []
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": []
|
||||||
|
},
|
||||||
|
"rougail.var2": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": []
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
["rougail.var1", "rougail.var2"]
|
|
@ -0,0 +1,12 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("standard")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("advanced")
|
||||||
|
option_2 = DomainnameOption(name="var1", doc="a first variable", multi=True, type="domainname", allow_ip=True, properties=frozenset({"basic", "mandatory"}), informations={'type': 'domainname'})
|
||||||
|
option_3 = DomainnameOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_2)))), type="domainname", allow_ip=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'domainname'})
|
||||||
|
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])
|
|
@ -0,0 +1,17 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("standard")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("advanced")
|
||||||
|
option_3 = DomainnameOption(name="var1", doc="a first variable", multi=True, type="domainname", allow_ip=True, properties=frozenset({"basic", "mandatory"}), informations={'type': 'domainname'})
|
||||||
|
option_4 = DomainnameOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_3)))), type="domainname", allow_ip=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'domainname'})
|
||||||
|
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 = DomainnameOption(name="var1", doc="a first variable", multi=True, type="domainname", allow_ip=True, properties=frozenset({"basic", "mandatory"}), informations={'type': 'domainname'})
|
||||||
|
option_8 = DomainnameOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_7)))), type="domainname", allow_ip=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'domainname'})
|
||||||
|
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])
|
|
@ -0,0 +1,11 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('tests/dictionaries/../eosfunc/test.py')
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("basic")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("standard")
|
||||||
|
ALLOWED_LEADER_PROPERTIES.add("advanced")
|
||||||
|
option_1 = DomainnameOption(name="var1", doc="a first variable", multi=True, type="domainname", allow_ip=True, properties=frozenset({"basic", "mandatory"}), informations={'type': 'domainname'})
|
||||||
|
option_2 = DomainnameOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_1)))), type="domainname", allow_ip=True, properties=frozenset({"mandatory", "standard"}), informations={'type': 'domainname'})
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
version: '1.0'
|
||||||
|
var1:
|
||||||
|
description: a variable
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
var2:
|
||||||
|
description: a variable
|
10
tests/dictionaries/00_4load_subfolder/makedict/after.json
Normal file
10
tests/dictionaries/00_4load_subfolder/makedict/after.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"rougail.var2": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
}
|
4
tests/dictionaries/00_4load_subfolder/makedict/base.json
Normal file
4
tests/dictionaries/00_4load_subfolder/makedict/base.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": null,
|
||||||
|
"rougail.var2": null
|
||||||
|
}
|
10
tests/dictionaries/00_4load_subfolder/makedict/before.json
Normal file
10
tests/dictionaries/00_4load_subfolder/makedict/before.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"rougail.var2": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
["rougail.var1", "rougail.var2"]
|
12
tests/dictionaries/00_4load_subfolder/tiramisu/base.py
Normal file
12
tests/dictionaries/00_4load_subfolder/tiramisu/base.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
17
tests/dictionaries/00_4load_subfolder/tiramisu/multi.py
Normal file
17
tests/dictionaries/00_4load_subfolder/tiramisu/multi.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
|
@ -0,0 +1,11 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
version: '1.0'
|
||||||
|
without_type:
|
||||||
|
description: a variable
|
||||||
|
default: non
|
6
tests/dictionaries/00_5load_notype/makedict/after.json
Normal file
6
tests/dictionaries/00_5load_notype/makedict/after.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"rougail.without_type": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "non"
|
||||||
|
}
|
||||||
|
}
|
3
tests/dictionaries/00_5load_notype/makedict/base.json
Normal file
3
tests/dictionaries/00_5load_notype/makedict/base.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"rougail.without_type": "non"
|
||||||
|
}
|
6
tests/dictionaries/00_5load_notype/makedict/before.json
Normal file
6
tests/dictionaries/00_5load_notype/makedict/before.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"rougail.without_type": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "non"
|
||||||
|
}
|
||||||
|
}
|
11
tests/dictionaries/00_5load_notype/tiramisu/base.py
Normal file
11
tests/dictionaries/00_5load_notype/tiramisu/base.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
15
tests/dictionaries/00_5load_notype/tiramisu/multi.py
Normal file
15
tests/dictionaries/00_5load_notype/tiramisu/multi.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
10
tests/dictionaries/00_5load_notype/tiramisu/no_namespace.py
Normal file
10
tests/dictionaries/00_5load_notype/tiramisu/no_namespace.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
|
@ -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
|
26
tests/dictionaries/00_6boolean/makedict/after.json
Normal file
26
tests/dictionaries/00_6boolean/makedict/after.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
8
tests/dictionaries/00_6boolean/makedict/base.json
Normal file
8
tests/dictionaries/00_6boolean/makedict/base.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"rougail.var1": true,
|
||||||
|
"rougail.var2": true,
|
||||||
|
"rougail.var3": true,
|
||||||
|
"rougail.var4": false,
|
||||||
|
"rougail.var5": false,
|
||||||
|
"rougail.var6": false
|
||||||
|
}
|
26
tests/dictionaries/00_6boolean/makedict/before.json
Normal file
26
tests/dictionaries/00_6boolean/makedict/before.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
16
tests/dictionaries/00_6boolean/tiramisu/base.py
Normal file
16
tests/dictionaries/00_6boolean/tiramisu/base.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
25
tests/dictionaries/00_6boolean/tiramisu/multi.py
Normal file
25
tests/dictionaries/00_6boolean/tiramisu/multi.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
15
tests/dictionaries/00_6boolean/tiramisu/no_namespace.py
Normal file
15
tests/dictionaries/00_6boolean/tiramisu/no_namespace.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from tiramisu import *
|
||||||
|
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
|
||||||
|
from re import compile as re_compile
|
||||||
|
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
|
||||||
|
load_functions('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])
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue