Compare commits

...

32 Commits

Author SHA1 Message Date
11294fdd61 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-14 17:21:05 +01:00
6bda645903 leadership name 2020-11-14 17:20:55 +01:00
4351662f2e Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-14 08:02:45 +01:00
a835e5a017 valid_in_network should works with CIDR 2020-11-14 08:02:38 +01:00
5a45885ed8 family and var with same name 2020-11-11 16:59:44 +01:00
3d49f2fe8c add xmlfiles in various error message 2020-11-11 16:24:06 +01:00
5bf8d69e91 Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-11-08 18:06:45 +01:00
f7db6b0289 add remove_fill attribute 2020-11-08 09:51:33 +01:00
8f01d2c1d8 can add personal function (tests file) 2020-11-08 09:43:45 +01:00
a9c74d68ff Merge branch 'develop' into dist/risotto/risotto-2.8.0/develop 2020-10-14 18:17:45 +02:00
4b21b1507f can add personal function 2020-10-14 18:17:31 +02:00
43e30bba47 support empty param 2020-10-04 20:11:00 +02:00
3040a11de9 cherry-pick 2020-10-04 17:34:48 +02:00
8cb27a79d6 doc 2020-10-04 17:28:07 +02:00
101dfefaa9 dynamic variable and calculation 2020-10-04 17:27:55 +02:00
5eba872969 add OptionInformation support 2020-10-04 17:25:42 +02:00
246ac25791 refactor valid_enum 2020-10-04 17:23:55 +02:00
48d190d39b update dependencies 2020-08-12 12:22:19 +02:00
f474edd8ae rougail => python3-rougail 2020-08-12 11:14:02 +02:00
61fc9b15e5 ajout de la dependance vers cheetah 2020-08-12 08:41:54 +02:00
79312cc8c8 Merge branch 'develop' into dist/risotto/risotto-2.7.1/develop 2020-08-12 08:37:12 +02:00
d789787d5c change Config object 2020-08-12 08:23:38 +02:00
d3670c6476 try tiramisu3 before tiramisu 2020-08-08 11:03:06 +02:00
4eb42e4290 merge flattener_dico and templates in tests 2020-08-08 08:58:35 +02:00
0da8b868ac Merge branch 'develop' into dist/risotto/risotto-2.7.1/develop 2020-08-07 17:18:01 +02:00
f07f76a4ef import de tiramisu ou tiramisu3 2020-08-07 17:17:42 +02:00
cdc4013450 extra dependencies 2020-08-05 12:17:37 +02:00
a2e8b5dad4 Merge branch 'develop' into dist/risotto/risotto-2.7.1/develop 2020-08-05 10:33:54 +02:00
f65e772b39 Merge branch 'master' into develop 2020-08-05 10:31:37 +02:00
58b3880e9b Delete changelog 2020-07-29 09:56:15 +02:00
413ab6dbb0 Add debian folder in packaging branch 2020-07-29 09:55:51 +02:00
534b5f4413 Do not include debian folder in code branch 2020-07-29 09:54:48 +02:00
1192 changed files with 4461 additions and 3308 deletions

5
debian/changelog vendored
View File

@ -1,5 +0,0 @@
rougail (0.1) unstable; urgency=low
* first version
-- Cadoles <contact@cadoles.com> Tue, 31 Mar 2020 10:40:42 +0200

6
debian/control vendored
View File

@ -2,13 +2,13 @@ Source: rougail
Section: admin
Priority: extra
Maintainer: Cadoles <contact@cadoles.com>
Build-depends: debhelper (>=11), python3-all, python3-setuptools
Build-depends: debhelper (>=11), python3-all, python3-setuptools, dh-python
Standards-Version: 3.9.4
Homepage: https://forge.cadoles.com/Infra/rougail
Package: rougail
Package: python3-rougail
Architecture: any
Pre-Depends: dpkg, python3, ${misc:Pre-Depends}
Depends: ${python:Depends}, ${misc:Depends}
Depends: ${python:Depends}, ${misc:Depends}, python3-cheetah, python3-tiramisu3
Description: configuration manager

23
doc/auto.rst Normal file
View File

@ -0,0 +1,23 @@
Valeur automatiquement modifiée
===============================
Une variable avec valeur automatiquement modifiée est une variable dont la valeur sera considéré comme modifié quand le serveur sera déployé.
Voici un variable a valeur automatiquement modifiée :
<variable name="my_variable" type="oui/non" description="My variable" auto_save="True">
Dans ce cas la valeur est fixée à la valeur actuelle.
Par exemple, si la valeur de cette variable est issue d'un calcul, la valeur ne sera plus recalculée.
Valeur en lecture seule automatique
===================================
Une variable avec valeur en lecture seule automatique est une variable dont la valeur ne sera plus modifiable par l'utilisateur quand le serveur sera déployé.
Voici un variable à valeur en lecture seule automatique :
<variable name="my_variable" type="oui/non" description="My variable" auto_freeze="True">
Dans ce cas la valeur est fixée à la valeur actuelle et elle ne sera plus modifiable par l'utilisateur.
Par exemple, si la valeur de cette variable est issue d'un calcul, la valeur ne sera plus recalculée.

285
doc/fill.rst Normal file
View File

@ -0,0 +1,285 @@
Les variables calculées
=======================
Une variable calculée est une variable donc sa valeur est le résultat d'une fonction python.
Variable avec une valeur par défaut calculée
--------------------------------------------
Créons une variable de type "oui/non" donc la valeur est retournée par la fonction "return_no" :
<variables>
<family name="family">
<variable name="my_calculated_variable" type="oui/non" description="My calculated variable"/>
</family>
</variables>
<constraints>
<fill name="return_no" target="my_calculated_variable"/>
</constraints>
Puis créons la fonction "return_no" :
def return_no():
return 'non'
Dans ce cas, la valeur par défaut est la valeur retournée par la fonction (ici "non"), elle sera calculée tant que l'utilisateur n'a pas de spécifié une valeur à cette variable.
Si l'utilisateur à définit une valeur par défaut à "my_calculated_variable" :
<variable name="my_calculated_variable" type="oui/non" description="My calculated variable">
<value>oui</value>
</variable>
Cette valeur par défaut sera complètement ignorée.
Variable avec une valeur calculée
---------------------------------
En ajoutant le paramètre "hidden" à "True" dans la variable précédente, l'utilisateur n'aura plus la possibilité de modifié la valeur. La valeur de la variable sera donc systématiquement calculée :
<variable name="my_calculated_variable" type="oui/non" description="My calculated variable" hidden="True"/>
Si une condition "hidden_if_in" est spécifié à la variable, la valeur sera modifiable par l'utilisateur si elle n'est pas cachée mais elle sera systèmatiquement calculée (même si elle a déjà était modifiée) si la variable est cachée.
Variable avec valeur calculée obligatoire
-----------------------------------------
Par défaut les variables calculées ne sont pas des varibles obligatoires.
Dans ce cas un calcul peut retourner None, mais surtout un utilisateur peut spécifier une valeur nulle à cette variable. Dans ce cas le calcul ne sera pas réalisé.
Fonction avec une valeur fixe comme paramètre positionnel
---------------------------------------------------------
Déclarons un calcul avec paramètre :
<constraints>
<fill name="return_value" target="my_calculated_variable">
<param>non</param>
</fill>
</constraints>
Créons la fonction correspondante :
def return_value(value):
return value
La variable aura donc "non" comme valeur puisque le paramètre aura la valeur fixe "non".
Paramètre nommée
----------------
Déclarons une contrainte avec un paramètre nommée :
<constraints>
<fill name="return_value" target="my_calculated_variable">
<param name="valeur">non</param>
</fill>
</constraints>
Dans ce cas la fonction return_value sera exécuté avec le paramètre nommé "valeur" dont sa valeur sera "non".
Paramètre avec un nombre
------------------------
Déclarons un calcul avec paramètre avec un nombre :
<constraints>
<fill name="return_value_with_number" target="my_calculated_variable">
<param type="number">1</param>
</fill>
</constraints>
Créons la fonction correspondante :
def return_value_with_number(value):
if value == 1:
return 'non'
return 'oui'
La variable aura donc "non" comme valeur puisque le paramètre aura la valeur fixe "1".
Paramètre dont la valeur est issue d'une autre variable
-------------------------------------------------------
Créons deux variables avec une contrainte de type variable qui contient le nom de la variable dont sa valeur sera utilisé comme paramètre :
<variables>
<family name="family">
<variable name="my_calculated_variable" type="oui/non" description="My calculated variable"/>
<variable name="my_variable" type="number" description="My variable">
<value>1</value>
</variable>
</family>
</variables>
<constraints>
<fill name="return_value_with_number" target="my_calculated_variable">
<param type="variable">my_variable</param>
</fill>
</constraints>
Si l'utilisateur laisse la valeur 1 à "my_variable", la valeur par défault de la variable "my_calculated_variable" sera "non".
Si la valeur de "my_variable" est différent de 1, la valeur par défaut de la variable "my_calculated_variable" sera "oui".
Paramètre dont la valeur est issue d'une information de la configuration
------------------------------------------------------------------------
Créons une variable et la contrainte :
<variables>
<family name="family">
<variable name="my_calculated_variable" type="string" description="My calculated variable"/>
</family>
</variables>
<constraints>
<fill name="return_value" target="my_calculated_variable">
<param type="information">server_name</param>
</fill>
</constraints>
Dans ce cas, l'information de la configuration "server_name" sera utilisé comme valeur de la variable "my_calculated_variable".
Si l'information n'existe pas, la paramètre aura la valeur "None".
Paramètre avec variable potentiellement non existante
-----------------------------------------------------
Suivant le contexte une variable peut exister ou ne pas exister.
Un paramètre de type "variable" peut être "optional" :
<variables>
<family name="family">
<variable name="my_calculated_variable" type="oui/non" description="My calculated variable"/>
</family>
</variables>
<constraints>
<fill name="return_value" target="my_calculated_variable">
<param type="variable" optional="True">unknow_variable</param>
</fill>
</constraints>
Dans ce cas la fonction "return_value" est exécuté sans paramètre.
Paramètre avec variable potentiellement désactivée
--------------------------------------------------
FIXME :
<!ATTLIST param notraisepropertyerror (True|False) "False">
Il n'y a pas spécialement de test !
Les variables suiveuses
-----------------------
FIXME :
- tests/flattener_dicos/10leadership_append/00-base.xml
- tests/flattener_dicos/10leadership_auto/00-base.xml
- tests/flattener_dicos/10leadership_autoleader/00-base.xml
- tests/flattener_dicos/10leadership_autoleader_expert/00-base.xml
Les variables dynamiques
------------------------
Paramètre avec variable dynamique
'''''''''''''''''''''''''''''''''
Il est possible de faire un calcul avec comme paramètre une variable dynamique mais pour une suffix particulier :
<variables>
<family name='family'>
<variable name='suffixes' type='string' description="Suffixes of dynamic family" multi="True">
<value>val1</value>
<value>val2</value>
</variable>
<variable name="my_calculated_variable" type="string" description="My calculated variable"/>
</family>
<family name='dyn' dynamic="suffixes">
<variable name='vardyn' type='string' description="Dynamic variable">
<value>val</value>
</variable>
</family>
</variables>
<constraints>
<fill name="return_value" target="my_calculated_variable">
<param type="variable">vardynval1</param>
</fill>
</constraints>
Dans ce cas, valeur du paramètre de la fonction "return_value" sera la valeur de la variable "vardyn" avec le suffix "val1".
Calcule d'une variable dynamique
''''''''''''''''''''''''''''''''
Il est également possible de calculer une variable dynamique à partir d'une variable standard :
<variables>
<family name='family'>
<variable name='suffixes' type='string' description="Suffixes of dynamic family" multi="True">
<value>val1</value>
<value>val2</value>
</variable>
<variable name="my_variable" type="string" description="My variable">
<value>val</value>
</variable>
</family>
<family name='dyn' dynamic="suffixes">
<variable name="my_calculated_variable_dyn_" type="string" description="My calculated variable"/>
<value>val</value>
</variable>
</family>
</variables>
<constraints>
<fill name="return_value" target="my_calculated_variable_dyn_">
<param type="variable">my_variable</param>
</fill>
</constraints>
Dans ce cas, les variables dynamiques "my_calculated_variable_dyn_" seront calculés à partir de la valeur de la variable "my_variable".
Que cela soit pour la variable "my_calculated_variable_dyn_val1" et "my_calculated_variable_dyn_val2".
Par contre, il n'est pas possible de faire un calcul pour une seule des deux variables issues de la variable dynamique.
Si c'est ce que vous cherchez à faire, il faudra prévoir un traitement particulier dans votre fonction.
Dans ce cas, il faut explicitement demander la valeur du suffix dans la fonction :
<constraints>
<fill name="return_value_suffix" target="my_calculated_variable_dyn_">
<param type="variable">my_variable</param>
<param type="suffix"/>
</fill>
</constraints>
Et ainsi faire un traitement spécifique pour ce suffix :
def return_value_suffix(value, suffix):
if suffix == 'val1':
return value
Redéfinition des calcules
-------------------------
Dans un premier dictionnaire déclarons notre variable et notre calcule :
<variables>
<family name="family">
<variable name="my_calculated_variable" type="oui/non" description="My calculated variable"/>
</family>
</variables>
<constraints>
<fill name="return_no" target="my_calculated_variable"/>
</constraints>
Dans un second dictionnaire il est possible de redéfinir le calcul :
<variables>
<family name="family">
<variable name="my_calculated_variable" redefine="True"/>
</family>
</variables>
<constraints>
<fill name="return_yes" target="my_calculated_variable"/>
</constraints>
Dans ce cas, à aucun moment la fonction "return_no" ne sera exécuté. Seul la fonction "return_yes" le sera.

13
doc/variable.rst Normal file
View File

@ -0,0 +1,13 @@
Variable
========
Variable obligatoire
--------------------
Variable dont une valeur est requise :
<variables>
<family name="family">
<variable name="my_variable" type="oui/non" description="My variable" mandatory="True"/>
</family>
</variables>

View File

@ -38,7 +38,7 @@ modes = mode_factory()
# that shall not be present in the exported (flatened) XML
ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace',
'remove_condition', 'path', 'instance_mode', 'index', 'is_in_leadership',
'level') # , '_real_container')
'level', 'remove_fill', 'xmlfiles')
ERASED_CONTAINER_ATTRIBUTES = ('id', 'container', 'group_id', 'group', 'container_group')
FORCE_CHOICE = {'oui/non': ['oui', 'non'],
@ -56,9 +56,6 @@ KEY_TYPE = {'variable': 'symlink',
'URLOption': 'web_address',
'FilenameOption': 'filename'}
TYPE_PARAM_CHECK = ('string', 'python', 'variable')
TYPE_PARAM_CONDITION = ('string', 'python', 'number', 'variable')
TYPE_PARAM_FILL = ('string', 'number', 'variable')
CONVERSION = {'number': int}
FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie'
@ -111,7 +108,7 @@ class GroupAnnotator:
self.manage_follower(namespace,
leader_family_name,
variable,
leader_name,
leadership_name,
follower_names,
leader_space,
leader_is_hidden,
@ -128,9 +125,14 @@ class GroupAnnotator:
# if variable.hidden:
# leader_is_hidden = True
else:
leader_space = self.objectspace.Leadership()
leader_space = self.objectspace.Leadership(variable.xmlfiles)
if hasattr(group, 'name'):
leadership_name = group.name
else:
leadership_name = leader_name
leader_is_hidden = self.manage_leader(leader_space,
leader_family_name,
leadership_name,
leader_name,
namespace,
variable,
@ -145,6 +147,7 @@ class GroupAnnotator:
def manage_leader(self,
leader_space: 'Leadership',
leader_family_name: str,
leadership_name: str,
leader_name: str,
namespace: str,
variable: 'Variable',
@ -155,7 +158,7 @@ class GroupAnnotator:
if variable.multi is not True:
raise DictConsistencyError(_('the variable {} in a group must be multi').format(variable.name))
leader_space.variable = []
leader_space.name = leader_name
leader_space.name = leadership_name
leader_space.hidden = variable.hidden
if variable.hidden:
leader_is_hidden = True
@ -170,9 +173,9 @@ class GroupAnnotator:
leader_space.doc = variable.description
else:
leader_space.doc = variable.name
leader_path = namespace + '.' + leader_family_name + '.' + leader_name
leadership_path = namespace + '.' + leader_family_name + '.' + leadership_name
self.objectspace.paths.add_family(namespace,
leader_path,
leadership_path,
leader_space,
)
leader_family = self.objectspace.space.variables[namespace].family[leader_family_name]
@ -236,7 +239,7 @@ class ServiceAnnotator:
families = {}
for idx, service_name in enumerate(self.objectspace.space.services.service.keys()):
service = self.objectspace.space.services.service[service_name]
new_service = self.objectspace.service()
new_service = self.objectspace.service(service.xmlfiles)
for elttype, values in vars(service).items():
if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES:
setattr(new_service, elttype, values)
@ -245,6 +248,7 @@ class ServiceAnnotator:
path = '.'.join(['services', service_name, eltname])
family = self.gen_family(eltname,
path,
service.xmlfiles,
)
if isinstance(values, dict):
values = list(values.values())
@ -261,8 +265,9 @@ class ServiceAnnotator:
def gen_family(self,
name,
path,
xmlfiles
):
family = self.objectspace.family()
family = self.objectspace.family(xmlfiles)
family.name = normalize_family(name)
family.doc = name
family.mode = None
@ -310,7 +315,10 @@ class ServiceAnnotator:
if not self.objectspace.paths.family_is_defined(subpath):
break
idx += 1
family = self.gen_family(c_name, subpath)
family = self.gen_family(c_name,
subpath,
elt.xmlfiles,
)
family.variable = []
listname = '{}list'.format(name)
activate_path = '.'.join([subpath, 'activate'])
@ -348,7 +356,7 @@ class ServiceAnnotator:
elt,
path,
):
variable = self.objectspace.variable()
variable = self.objectspace.variable(elt.xmlfiles)
variable.name = normalize_family(key)
variable.mode = None
if key == 'name':
@ -373,7 +381,7 @@ class ServiceAnnotator:
variable.multi = None
else:
variable.doc = key
val = self.objectspace.value()
val = self.objectspace.value(elt.xmlfiles)
val.type = type_
val.name = value
variable.value = [val]
@ -472,15 +480,17 @@ class VariableAnnotator:
path,
):
if variable.type in FORCE_CHOICE:
check = self.objectspace.check()
check = self.objectspace.check(variable.xmlfiles)
check.name = 'valid_enum'
check.target = path
check.namespace = namespace
param = self.objectspace.param()
param.text = str(FORCE_CHOICE[variable.type])
check.param = [param]
check.param = []
for value in FORCE_CHOICE[variable.type]:
param = self.objectspace.param(variable.xmlfiles)
param.text = value
check.param.append(param)
if not hasattr(self.objectspace.space, 'constraints'):
self.objectspace.space.constraints = self.objectspace.constraints()
self.objectspace.space.constraints = self.objectspace.constraints(variable.xmlfiles)
self.objectspace.space.constraints.namespace = namespace
if not hasattr(self.objectspace.space.constraints, 'check'):
self.objectspace.space.constraints.check = []
@ -543,14 +553,14 @@ class VariableAnnotator:
def convert_auto_freeze(self): # pylint: disable=C0111
def _convert_auto_freeze(variable, namespace):
if variable.auto_freeze:
new_condition = self.objectspace.condition()
new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_hidden_if_not_in'
new_condition.namespace = namespace
new_condition.source = FREEZE_AUTOFREEZE_VARIABLE
new_param = self.objectspace.param()
new_param = self.objectspace.param(variable.xmlfiles)
new_param.text = 'oui'
new_condition.param = [new_param]
new_target = self.objectspace.target()
new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = 'variable'
path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name
new_target.name = path
@ -584,7 +594,8 @@ class VariableAnnotator:
subpath = self.objectspace.paths.get_variable_path(separator.name,
separator.namespace,
)
raise DictConsistencyError(_('{} already has a separator').format(subpath))
xmlfiles = self.objectspace.display_xmlfiles(separator.xmlfiles)
raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}'))
option.separator = separator.text
del family.separators
@ -597,7 +608,9 @@ class ConstraintAnnotator:
if not hasattr(objectspace.space, 'constraints'):
return
self.objectspace = objectspace
self.eosfunc = imp.load_source('eosfunc', eosfunc_file)
eosfunc = imp.load_source('eosfunc', eosfunc_file)
self.functions = dir(eosfunc)
self.functions.extend(INTERNAL_FUNCTIONS)
self.valid_enums = {}
if hasattr(self.objectspace.space.constraints, 'check'):
self.check_check()
@ -619,21 +632,19 @@ class ConstraintAnnotator:
def check_check(self):
remove_indexes = []
functions = dir(self.eosfunc)
functions.extend(INTERNAL_FUNCTIONS)
for check_idx, check in enumerate(self.objectspace.space.constraints.check):
if not check.name in functions:
raise DictConsistencyError(_('cannot find check function {}').format(check.name))
if not check.name in self.functions:
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'))
if hasattr(check, 'param'):
param_option_indexes = []
for idx, param in enumerate(check.param):
if param.type not in TYPE_PARAM_CHECK:
raise DictConsistencyError(_('cannot use {} type as a param in check for {}').format(param.type, check.target))
if param.type == 'variable' and not self.objectspace.paths.path_is_defined(param.text):
if param.optional is True:
param_option_indexes.append(idx)
else:
raise DictConsistencyError(_(f'unknown param {param.text} in check'))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'))
if param.type != 'variable':
param.notraisepropertyerror = None
param_option_indexes = list(set(param_option_indexes))
@ -661,55 +672,50 @@ class ConstraintAnnotator:
remove_indexes = []
for idx, check in enumerate(self.objectspace.space.constraints.check):
if check.name == 'valid_enum':
if len(check.param) != 1:
raise DictConsistencyError(_(f'cannot set more than one param for valid_enum for variable {check.target}'))
param = check.param[0]
if check.target in self.valid_enums:
raise DictConsistencyError(_(f'valid_enum already set for {check.target}'))
if param.type not in ['string', 'python', 'number']:
raise DictConsistencyError(_(f'unknown type {param.type} for param in valid_enum for {check.target}'))
if not hasattr(check, 'param'):
raise DictConsistencyError(_(f'param is mandatory for a valid_enum of variable {check.target}'))
variable = self.objectspace.paths.get_variable_obj(check.target)
values = self.load_params_in_validenum(param,
variable.name,
variable.type,
)
self.valid_enums[check.target] = {'type': param.type,
'values': values}
values = self.load_params_in_valid_enum(check.param,
variable.name,
variable.type,
)
self._set_valid_enum(variable,
values,
variable.type,
check.target
)
remove_indexes.append(idx)
remove_indexes.sort(reverse=True)
for idx in remove_indexes:
del self.objectspace.space.constraints.check[idx]
def load_params_in_validenum(self,
param,
variable_name,
variable_type,
):
if not hasattr(param, 'text') and (param.type == 'python' or param.type == 'number'):
raise DictConsistencyError(_(f"All '{param.type}' variables shall be set in order to calculate valid_enum for variable {variable_name}"))
if variable_type == 'string' and param.type == 'number':
raise DictConsistencyError(_(f'Unconsistency valid_enum type ({param.type}), for variable {variable_name}'))
if param.type == 'python':
try:
values = eval(param.text, {'eosfunc': self.eosfunc, '__builtins__': {'range': range, 'str': str}})
except NameError:
raise DictConsistencyError(_('The function {} is unknown').format(param.text))
else:
try:
values = literal_eval(param.text)
except ValueError:
raise DictConsistencyError(_(f'Cannot load {param.text} in valid_enum'))
if not isinstance(values, list):
raise DictConsistencyError(_('Function {} shall return a list').format(param.text))
for value in values:
if variable_type == 'string' and not isinstance(value, str):
raise DictConsistencyError(_(f'Cannot load "{param.text}", "{value}" is not a string'))
if variable_type == 'number' and not isinstance(value, int):
raise DictConsistencyError(_(f'Cannot load "{param.text}", "{value}" is not a number'))
def load_params_in_valid_enum(self,
params,
variable_name,
variable_type,
):
has_variable = None
values = []
for param in params:
if param.type == 'variable':
if has_variable is not None:
raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable {variable_name}'))
has_variable = True
variable = self.objectspace.paths.get_variable_obj(param.text)
if not variable.multi:
raise DictConsistencyError(_(f'only multi "variable" parameter is allowed for valid_enum of variable {variable_name}'))
values = param.text
else:
if has_variable:
raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable {variable_name}'))
if not hasattr(param, 'text'):
if param.type == 'number':
raise DictConsistencyError(_(f'value is mandatory for valid_enum of variable {variable_name}'))
values.append(None)
else:
values.append(param.text)
return values
def check_change_warning(self):
@ -736,9 +742,6 @@ class ConstraintAnnotator:
def check_params_target(self):
for condition in self.objectspace.space.constraints.condition:
for param in condition.param:
if param.type not in TYPE_PARAM_CONDITION:
raise DictConsistencyError(_(f'cannot use {param.type} type as a param in a condition'))
if not hasattr(condition, 'target'):
raise DictConsistencyError(_('target is mandatory in condition'))
for target in condition.target:
@ -777,7 +780,7 @@ class ConstraintAnnotator:
for listvar in listvars:
variable = self.objectspace.paths.get_variable_obj(listvar)
type_ = 'variable'
new_target = self.objectspace.target()
new_target = self.objectspace.target(variable.xmlfiles)
new_target.type = type_
new_target.name = listvar
new_target.index = target.index
@ -902,7 +905,7 @@ class ConstraintAnnotator:
if hasattr(leader_or_variable, actions[0]) and getattr(leader_or_variable, actions[0]) is True:
continue
for idx, action in enumerate(actions):
prop = self.objectspace.property_()
prop = self.objectspace.property_(leader_or_variable.xmlfiles)
prop.type = 'calculation'
prop.inverse = inverse
prop.source = condition.source
@ -919,40 +922,52 @@ class ConstraintAnnotator:
variable.property.append(prop)
del self.objectspace.space.constraints.condition
def _set_valid_enum(self, variable, values, type_):
def _set_valid_enum(self, variable, values, type_, target):
# value for choice's variable is mandatory
variable.mandatory = True
# build choice
variable.choice = []
choices = []
for value in values:
if isinstance(values, str):
choice = self.objectspace.choice()
try:
choice.name = CONVERSION.get(type_, str)(value)
except:
raise DictConsistencyError(_(f'unable to change type of a valid_enum entry "{value}" is not a valid "{type_}" for "{variable.name}"'))
if choice.name == '':
choice.name = None
choices.append(choice.name)
choice.type = type_
choice.type = 'calculation'
choice.name = values
variable.choice.append(choice)
else:
self.valid_enums[target] = {'type': type_,
'values': values,
}
choices = []
for value in values:
choice = self.objectspace.choice(variable.xmlfiles)
try:
if value is not None:
choice.name = CONVERSION.get(type_, str)(value)
else:
choice.name = value
except:
raise DictConsistencyError(_(f'unable to change type of a valid_enum entry "{value}" is not a valid "{type_}" for "{variable.name}"'))
if choice.name == '':
choice.name = None
choices.append(choice.name)
choice.type = type_
variable.choice.append(choice)
# check value or set first choice value has default value
if hasattr(variable, 'value'):
for value in variable.value:
value.type = type_
try:
cvalue = CONVERSION.get(type_, str)(value.name)
except:
raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"'))
if cvalue not in choices:
raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices))
else:
new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = choices[0]
new_value.type = type_
variable.value = [new_value]
if not variable.choice:
raise DictConsistencyError(_('empty valid enum is not allowed for variable {}').format(variable.name))
# check value or set first choice value has default value
if hasattr(variable, 'value'):
for value in variable.value:
value.type = type_
try:
cvalue = CONVERSION.get(type_, str)(value.name)
except:
raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"'))
if cvalue not in choices:
raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices))
else:
new_value = self.objectspace.value()
new_value.name = values[0]
new_value.type = type_
variable.value = [new_value]
variable.type = 'choice'
def convert_check(self):
@ -972,26 +987,30 @@ class ConstraintAnnotator:
else:
raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'))
else:
check_ = self.objectspace.check()
check_ = self.objectspace.check(variable.xmlfiles)
if name == 'valid_differ':
name = 'valid_not_equal'
elif name == 'valid_network_netmask':
params_len = 1
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
elif name == 'valid_ipnetmask':
params_len = 1
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
name = 'valid_ip_netmask'
elif name == 'valid_broadcast':
params_len = 2
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
elif name == 'valid_in_network':
params_len = 2
if len(check.param) != params_len:
raise DictConsistencyError(_('{} must have {} param').format(name, params_len))
if len(check.param) not in (1, 2):
params_len = 2
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'))
check_.name = name
check_.warnings_only = check.warnings_only
if hasattr(check, 'param'):
@ -1007,7 +1026,6 @@ class ConstraintAnnotator:
indexes = list(fills.keys())
indexes.sort()
targets = []
eosfunc = dir(self.eosfunc)
for idx in indexes:
fill = fills[idx]
# test if it's redefined calculation
@ -1015,25 +1033,31 @@ class ConstraintAnnotator:
raise DictConsistencyError(_(f"A fill already exists for the target: {fill.target}"))
targets.append(fill.target)
#
if fill.name not in eosfunc:
if fill.name not in self.functions:
raise DictConsistencyError(_('cannot find fill function {}').format(fill.name))
namespace = fill.namespace
# let's replace the target by the path
fill.target = self.objectspace.paths.get_variable_path(fill.target,
namespace,
)
value = self.objectspace.value()
fill.target, suffix = self.objectspace.paths.get_variable_path(fill.target,
namespace,
with_suffix=True,
)
if suffix is not None:
raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"'))
variable = self.objectspace.paths.get_variable_obj(fill.target)
value = self.objectspace.value(variable.xmlfiles)
value.type = 'calculation'
value.name = fill.name
if hasattr(fill, 'param'):
param_to_delete = []
for fill_idx, param in enumerate(fill.param):
if param.type not in TYPE_PARAM_FILL:
raise DictConsistencyError(_(f'cannot use {param.type} type as a param in a fill/auto'))
if param.type != 'string' and not hasattr(param, 'text'):
raise DictConsistencyError(_(f"All '{param.type}' variables shall have a value in order to calculate {fill.target}"))
if param.type not in ['suffix', 'string'] and not hasattr(param, 'text'):
raise DictConsistencyError(_(f"All '{param.type}' variables must have a value in order to calculate {fill.target}"))
if param.type == 'suffix' and hasattr(param, 'text'):
raise DictConsistencyError(_(f"All '{param.type}' variables must not have a value in order to calculate {fill.target}"))
if param.type == 'string':
if not hasattr(param, 'text'):
param.text = None
if param.type == 'variable':
try:
param.text, suffix = self.objectspace.paths.get_variable_path(param.text,
@ -1053,7 +1077,6 @@ class ConstraintAnnotator:
for param_idx in param_to_delete:
fill.param.pop(param_idx)
value.param = fill.param
variable = self.objectspace.paths.get_variable_obj(fill.target)
variable.value = [value]
del self.objectspace.space.constraints.fill
@ -1061,6 +1084,7 @@ class ConstraintAnnotator:
if hasattr(self.objectspace.space.constraints, 'index'):
del self.objectspace.space.constraints.index
del self.objectspace.space.constraints.namespace
del self.objectspace.space.constraints.xmlfiles
if vars(self.objectspace.space.constraints):
raise Exception('constraints again?')
del self.objectspace.space.constraints
@ -1121,7 +1145,7 @@ class FamilyAnnotator:
# if the variable is mandatory and doesn't have any value
# then the variable's mode is set to 'basic'
if not hasattr(variable, 'value') and variable.type == 'boolean':
new_value = self.objectspace.value()
new_value = self.objectspace.value(variable.xmlfiles)
new_value.name = True
new_value.type = 'boolean'
variable.value = [new_value]
@ -1136,9 +1160,9 @@ class FamilyAnnotator:
if param.type == 'variable':
has_variable = True
break
if not has_variable:
# if one parameter is a variable, let variable choice if it's mandatory
variable.mandatory = True
#if not has_variable:
# # if one parameter is a variable, let variable choice if it's mandatory
# variable.mandatory = True
if has_value:
# if has value but without any calculation
variable.mandatory = True

View File

@ -3,17 +3,20 @@
fichier de configuration pour rougail
"""
from os.path import join, isfile, abspath, dirname
from pathlib import Path
from os.path import join, abspath, dirname
rougailroot = '/var/rougail'
patch_dir = join(rougailroot, 'patches')
manifests_dir = join(rougailroot, 'manifests')
templates_dir = join(rougailroot, 'templates')
rougailroot = '/var/rougail'
dtddir = join(dirname(abspath(__file__)), 'data')
dtdfilename = join(dtddir, 'rougail.dtd')
# chemin du répertoire source des fichiers templates
patch_dir = '/srv/rougail/patch'
variable_namespace = 'rougail'
Config = {'rougailroot': rougailroot,
'patch_dir': join(rougailroot, 'patches'),
'manifests_dir': join(rougailroot, 'manifests'),
'templates_dir': join(rougailroot, 'templates'),
'dtdfilename': join(dtddir, 'rougail.dtd'),
'dtddir': dtddir,
# chemin du répertoire source des fichiers templates
'patch_dir': '/srv/rougail/patch',
'variable_namespace': 'rougail',
}

View File

@ -45,7 +45,7 @@
<!ELEMENT services (service*)>
<!ELEMENT service ((port* | tcpwrapper* | ip* | interface* | package* | file* | digitalcertificate* | override*)*) >
<!ELEMENT service ((port* | tcpwrapper* | ip* | interface* | package* | file* | override*)*) >
<!ATTLIST service name CDATA #REQUIRED>
<!ATTLIST service manage (True|False) "True">
@ -75,14 +75,6 @@
<!ATTLIST file redefine (True|False) "False">
<!ATTLIST file templating (True|False) "True">
<!ELEMENT digitalcertificate EMPTY>
<!ATTLIST digitalcertificate name CDATA #REQUIRED >
<!ATTLIST digitalcertificate digitalcertificate_type (variable) "variable">
<!ATTLIST digitalcertificate certificate CDATA #REQUIRED >
<!ATTLIST digitalcertificate certificate_type (variable) "variable">
<!ATTLIST digitalcertificate type CDATA #REQUIRED >
<!ATTLIST digitalcertificate ca CDATA #REQUIRED >
<!ELEMENT override EMPTY>
<!ATTLIST override source CDATA #IMPLIED >
<!ATTLIST override templating (True|False) "True">
@ -110,6 +102,7 @@
<!ATTLIST variable mode (basic|normal|expert) "normal">
<!ATTLIST variable remove_check (True|False) "False">
<!ATTLIST variable remove_condition (True|False) "False">
<!ATTLIST variable remove_fill (True|False) "False">
<!ATTLIST variable test CDATA #IMPLIED>
<!ELEMENT separators (separator*)>
@ -138,10 +131,11 @@
<!ELEMENT group (follower+)>
<!ATTLIST group leader CDATA #REQUIRED>
<!ATTLIST group name CDATA #IMPLIED>
<!ATTLIST group description CDATA #IMPLIED>
<!ELEMENT param (#PCDATA)>
<!ATTLIST param type (string|variable|number|python) "string">
<!ATTLIST param type (string|number|variable|information|suffix) "string">
<!ATTLIST param name CDATA #IMPLIED>
<!ATTLIST param notraisepropertyerror (True|False) "False">
<!ATTLIST param optional (True|False) "False">

View File

@ -32,7 +32,7 @@ from .tiramisureflector import TiramisuReflector
from .utils import normalize_family
from .error import OperationError, SpaceObjShallNotBeUpdated, DictConsistencyError
from .path import Path
from .config import variable_namespace
from .config import Config
# CreoleObjSpace's elements like 'family' or 'follower', that shall be forced to the Redefinable type
FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables')
@ -59,7 +59,10 @@ CONVERT_EXPORT = {'Leadership': 'leader',
# _____________________________________________________________________________
# special types definitions for the Object Space's internal representation
class RootCreoleObject:
""
def __init__(self, xmlfiles):
if not isinstance(xmlfiles, list):
xmlfiles = [xmlfiles]
self.xmlfiles = xmlfiles
class CreoleObjSpace:
@ -92,6 +95,7 @@ class CreoleObjSpace:
self.xmlreflector = XMLReflector()
self.xmlreflector.parse_dtd(dtdfilename)
self.redefine_variables = None
self.fill_removed = None
self.check_removed = None
self.condition_removed = None
@ -153,14 +157,17 @@ class CreoleObjSpace:
"""
for xmlfile, document in self.xmlreflector.load_xml_from_folders(xmlfolders):
self.redefine_variables = []
self.fill_removed = []
self.check_removed = []
self.condition_removed = []
self.xml_parse_document(document,
self.xml_parse_document(xmlfile,
document,
self.space,
namespace,
)
def xml_parse_document(self,
xmlfile,
document,
space,
namespace,
@ -177,7 +184,7 @@ class CreoleObjSpace:
continue
if child.tag == 'family':
if child.attrib['name'] in family_names:
raise DictConsistencyError(_('Family {} is set several times').format(child.attrib['name']))
raise DictConsistencyError(_(f'Family "{child.attrib["name"]}" is set several times in "{xmlfile}"'))
family_names.append(child.attrib['name'])
if child.tag == 'variables':
child.attrib['name'] = namespace
@ -186,16 +193,18 @@ class CreoleObjSpace:
continue
# variable objects creation
try:
variableobj = self.generate_variableobj(child,
space,
namespace,
)
variableobj = self.generate_variableobj(xmlfile,
child,
space,
namespace,
)
except SpaceObjShallNotBeUpdated:
continue
self.set_text_to_obj(child,
variableobj,
)
self.set_xml_attributes_to_obj(child,
self.set_xml_attributes_to_obj(xmlfile,
child,
variableobj,
)
self.variableobj_tree_visitor(child,
@ -213,26 +222,29 @@ class CreoleObjSpace:
child,
)
if list(child) != []:
self.xml_parse_document(child,
self.xml_parse_document(xmlfile,
child,
variableobj,
namespace,
)
def generate_variableobj(self,
child,
space,
namespace,
):
xmlfile,
child,
space,
namespace,
):
"""
instanciates or creates Creole Object Subspace objects
"""
variableobj = getattr(self, child.tag)()
variableobj = getattr(self, child.tag)(xmlfile)
if isinstance(variableobj, self.Redefinable):
variableobj = self.create_or_update_redefinable_object(child.attrib,
space,
child,
namespace,
)
variableobj = self.create_or_update_redefinable_object(xmlfile,
child.attrib,
space,
child,
namespace,
)
elif isinstance(variableobj, self.Atom) and child.tag in vars(space):
# instanciates an object from the CreoleObjSpace's builtins types
# example : child.tag = constraints -> a self.Constraints() object is created
@ -246,6 +258,7 @@ class CreoleObjSpace:
return variableobj
def create_or_update_redefinable_object(self,
xmlfile,
subspace,
space,
child,
@ -279,15 +292,17 @@ class CreoleObjSpace:
name = child.text
else:
name = subspace['name']
if self.is_already_exists(name,
space,
child,
namespace,
):
existed_var = self.is_already_exists(name,
space,
child,
namespace,
)
if existed_var:
default_redefine = child.tag in FORCE_REDEFINABLES
redefine = self.convert_boolean(subspace.get('redefine', default_redefine))
exists = self.convert_boolean(subspace.get('exists', True))
if redefine is True:
existed_var.xmlfiles.append(xmlfile)
return self.translate_in_space(name,
space,
child,
@ -295,12 +310,21 @@ class CreoleObjSpace:
)
elif exists is False:
raise SpaceObjShallNotBeUpdated()
raise DictConsistencyError(_(f'Already present in another XML file, {name} cannot be re-created'))
xmlfiles = self.display_xmlfiles(existed_var.xmlfiles)
raise DictConsistencyError(_(f'"{child.tag}" named "{name}" cannot be re-created in "{xmlfile}", already defined in {xmlfiles}'))
redefine = self.convert_boolean(subspace.get('redefine', False))
exists = self.convert_boolean(subspace.get('exists', False))
if redefine is False or exists is True:
return getattr(self, child.tag)()
raise DictConsistencyError(_(f'Redefined object: {name} does not exist yet'))
return getattr(self, child.tag)(xmlfile)
raise DictConsistencyError(_(f'Redefined object in "{xmlfile}": "{name}" does not exist yet'))
def display_xmlfiles(self,
xmlfiles: list,
) -> str:
if len(xmlfiles) == 1:
return '"' + xmlfiles[0] + '"'
else:
return '"' + '", "'.join(xmlfiles[:-1]) + '"' + ' and ' + '"' + xmlfiles[-1] + '"'
def create_tree_structure(self,
space,
@ -327,16 +351,25 @@ class CreoleObjSpace:
raise OperationError(_("Creole object {} "
"has a wrong type").format(type(variableobj)))
def is_already_exists(self, name, space, child, namespace):
def is_already_exists(self,
name: str,
space: str,
child,
namespace: str,
):
if isinstance(space, self.family): # pylint: disable=E1101
if namespace != variable_namespace:
if namespace != Config['variable_namespace']:
name = space.path + '.' + name
return self.paths.path_is_defined(name)
if self.paths.path_is_defined(name):
return self.paths.get_variable_obj(name)
return
if child.tag == 'family':
norm_name = normalize_family(name)
else:
norm_name = name
return norm_name in getattr(space, child.tag, {})
children = getattr(space, child.tag, {})
if norm_name in children:
return children[norm_name]
def convert_boolean(self, value): # pylint: disable=R0201
"""Boolean coercion. The Creole XML may contain srings like `True` or `False`
@ -362,14 +395,14 @@ class CreoleObjSpace:
else:
norm_name = name
return getattr(family, variable.tag)[norm_name]
if namespace == variable_namespace:
if namespace == Config['variable_namespace']:
path = name
else:
path = family.path + '.' + name
old_family_name = self.paths.get_variable_family_name(path)
if normalize_family(family.name) == old_family_name:
return getattr(family, variable.tag)[name]
old_family = self.space.variables[variable_namespace].family[old_family_name] # pylint: disable=E1101
old_family = self.space.variables[Config['variable_namespace']].family[old_family_name] # pylint: disable=E1101
variable_obj = old_family.variable[name]
del old_family.variable[name]
if 'variable' not in vars(family):
@ -383,6 +416,18 @@ class CreoleObjSpace:
)
return variable_obj
def remove_fill(self, name): # pylint: disable=C0111
if hasattr(self.space, 'constraints') and hasattr(self.space.constraints, 'fill'):
remove_fills= []
for idx, fill in enumerate(self.space.constraints.fill): # pylint: disable=E1101
if hasattr(fill, 'target') and fill.target == name:
remove_fills.append(idx)
remove_fills = list(set(remove_fills))
remove_fills.sort(reverse=True)
for idx in remove_fills:
self.space.constraints.fill.pop(idx) # pylint: disable=E1101
def remove_check(self, name): # pylint: disable=C0111
if hasattr(self.space, 'constraints') and hasattr(self.space.constraints, 'check'):
remove_checks = []
@ -437,6 +482,7 @@ class CreoleObjSpace:
variableobj.text = text
def set_xml_attributes_to_obj(self,
xmlfile,
child,
variableobj,
):
@ -449,7 +495,8 @@ class CreoleObjSpace:
# UNREDEFINABLE concerns only 'variable' node so we can fix name
# to child.attrib['name']
name = child.attrib['name']
raise DictConsistencyError(_(f'cannot redefine attribute {attr} for variable {name}'))
xmlfiles = self.display_xmlfiles(variableobj.xmlfiles[:-1])
raise DictConsistencyError(_(f'cannot redefine attribute "{attr}" for variable "{name}" in "{xmlfile}", already defined in {xmlfiles}'))
if attr in self.booleans_attributs:
val = self.convert_boolean(val)
if not (attr == 'name' and getattr(variableobj, 'name', None) != None):
@ -468,16 +515,21 @@ class CreoleObjSpace:
self.remove_check(variableobj.name)
if child.attrib.get('remove_condition', False):
self.remove_condition(variableobj.name)
if child.attrib.get('remove_fill', False):
self.remove_fill(variableobj.name)
if child.tag == 'fill':
# if variable is a redefine in current dictionary
# XXX not working with variable not in variable and in leader/followers
variableobj.redefine = child.attrib['target'] in self.redefine_variables
if child.attrib['target'] in self.redefine_variables and child.attrib['target'] not in self.fill_removed:
self.remove_fill(child.attrib['target'])
self.fill_removed.append(child.attrib['target'])
if not hasattr(variableobj, 'index'):
variableobj.index = self.index
if child.tag == 'check' and child.attrib['target'] in self.redefine_variables and child.attrib['target'] not in self.check_removed:
self.remove_check(child.attrib['target'])
self.check_removed.append(child.attrib['target'])
if child.tag == 'condition' and child.attrib['source'] in self.redefine_variables and child.attrib['source'] not in self.check_removed:
if child.tag == 'condition' and child.attrib['source'] in self.redefine_variables and child.attrib['source'] not in self.condition_removed:
self.remove_condition(child.attrib['source'])
self.condition_removed.append(child.attrib['source'])
variableobj.namespace = namespace
@ -501,7 +553,7 @@ class CreoleObjSpace:
document.attrib.get('dynamic') != None,
variableobj)
if child.attrib.get('redefine', 'False') == 'True':
if namespace == variable_namespace:
if namespace == Config['variable_namespace']:
self.redefine_variables.append(child.attrib['name'])
else:
self.redefine_variables.append(namespace + '.' + family_name + '.' +
@ -509,7 +561,7 @@ class CreoleObjSpace:
elif child.tag == 'family':
family_name = normalize_family(child.attrib['name'])
if namespace != variable_namespace:
if namespace != Config['variable_namespace']:
family_name = namespace + '.' + family_name
self.paths.add_family(namespace,
family_name,

View File

@ -1,7 +1,7 @@
from .i18n import _
from .utils import normalize_family
from .error import OperationError, DictConsistencyError
from .config import variable_namespace
from .config import Config
class Path:
@ -13,7 +13,8 @@ class Path:
def __init__(self):
self.variables = {}
self.families = {}
self.full_paths = {}
self.full_paths_families = {}
self.full_paths_variables = {}
# Family
def add_family(self,
@ -21,9 +22,9 @@ class Path:
name: str,
variableobj: str,
) -> str: # pylint: disable=C0111
if '.' not in name and namespace == variable_namespace:
if '.' not in name and namespace == Config['variable_namespace']:
full_name = '.'.join([namespace, name])
self.full_paths[name] = full_name
self.full_paths_families[name] = full_name
else:
full_name = name
if full_name in self.families and self.families[full_name]['variableobj'] != variableobj:
@ -41,12 +42,12 @@ class Path:
check_name=False,
allow_dot=True,
)
if '.' not in name and current_namespace == variable_namespace and name in self.full_paths:
name = self.full_paths[name]
if '.' not in name and current_namespace == Config['variable_namespace'] and name in self.full_paths_families:
name = self.full_paths_families[name]
if current_namespace is None: # pragma: no cover
raise OperationError('current_namespace must not be None')
dico = self.families[name]
if dico['namespace'] != variable_namespace and current_namespace != dico['namespace']:
if dico['namespace'] != Config['variable_namespace'] and current_namespace != dico['namespace']:
raise DictConsistencyError(_('A family located in the {} namespace '
'shall not be used in the {} namespace').format(
dico['namespace'], current_namespace))
@ -55,8 +56,8 @@ class Path:
def get_family_obj(self,
name: str,
) -> 'Family': # pylint: disable=C0111
if '.' not in name and name in self.full_paths:
name = self.full_paths[name]
if '.' not in name and name in self.full_paths_families:
name = self.full_paths_families[name]
if name not in self.families:
raise DictConsistencyError(_('unknown family {}').format(name))
dico = self.families[name]
@ -65,7 +66,7 @@ class Path:
def family_is_defined(self,
name: str,
) -> str: # pylint: disable=C0111
if '.' not in name and name not in self.families and name in self.full_paths:
if '.' not in name and name not in self.families and name in self.full_paths_families:
return True
return name in self.families
@ -87,8 +88,8 @@ class Path:
False,
dico['variableobj'],
)
if namespace == variable_namespace:
self.full_paths[name] = new_path
if namespace == Config['variable_namespace']:
self.full_paths_variables[name] = new_path
else:
name = new_path
dico = self._get_variable(name)
@ -110,10 +111,10 @@ class Path:
) -> str: # pylint: disable=C0111
if '.' not in name:
full_name = '.'.join([namespace, family, name])
self.full_paths[name] = full_name
self.full_paths_variables[name] = full_name
else:
full_name = name
if namespace == variable_namespace:
if namespace == Config['variable_namespace']:
name = name.rsplit('.', 1)[1]
self.variables[full_name] = dict(name=name,
family=family,
@ -157,7 +158,7 @@ class Path:
else:
dico = self._get_variable(name)
if not allow_source:
if dico['namespace'] not in [variable_namespace, 'services'] and current_namespace != dico['namespace']:
if dico['namespace'] not in [Config['variable_namespace'], 'services'] and current_namespace != dico['namespace']:
raise DictConsistencyError(_('A variable located in the {} namespace '
'shall not be used in the {} namespace').format(
dico['namespace'], current_namespace))
@ -176,7 +177,7 @@ class Path:
def path_is_defined(self,
name: str,
) -> str: # pylint: disable=C0111
if '.' not in name and name not in self.variables and name in self.full_paths:
if '.' not in name and name not in self.variables and name in self.full_paths_variables:
return True
return name in self.variables
@ -186,17 +187,21 @@ class Path:
) -> str:
if name not in self.variables:
if name not in self.variables:
if '.' not in name and name in self.full_paths:
name = self.full_paths[name]
if '.' not in name and name in self.full_paths_variables:
name = self.full_paths_variables[name]
if name not in self.variables:
for var_name, variable in self.variables.items():
if variable['is_dynamic'] and name.startswith(var_name):
if not with_suffix:
raise Exception('This option is dynamic, should use "with_suffix" attribute')
return variable, name[len(var_name):]
if '.' not in name:
for var_name, path in self.full_paths.items():
for var_name, path in self.full_paths_variables.items():
if name.startswith(var_name):
variable = self.variables[self.full_paths[var_name]]
variable = self.variables[self.full_paths_variables[var_name]]
if variable['is_dynamic']:
if not with_suffix:
raise Exception('This option is dynamic, should use "with_suffix" attribute')
return variable, name[len(var_name):]
raise DictConsistencyError(_('unknown option {}').format(name))
if with_suffix:

View File

@ -15,10 +15,14 @@ from os.path import dirname, join, isfile
from Cheetah.Template import Template as ChtTemplate
from Cheetah.NameMapper import NotFound as CheetahNotFound
from tiramisu import Config
from tiramisu.error import PropertiesOptionError
try:
from tiramisu3 import Config
from tiramisu3.error import PropertiesOptionError
except:
from tiramisu import Config
from tiramisu.error import PropertiesOptionError
from .config import patch_dir, variable_namespace
from .config import Config
from .error import FileNotFound, TemplateError
from .i18n import _
from .utils import normalize_family
@ -290,7 +294,7 @@ class CreoleTemplateEngine:
patch_no_debug = ['-s', '-r', '-', '--backup-if-mismatch']
# patches variante + locaux
for directory in [join(patch_dir, 'variante'), patch_dir]:
for directory in [join(Config['patch_dir'], 'variante'), Config['patch_dir']]:
patch_file = join(directory, f'{filename}.patch')
if isfile(patch_file):
log.info(_("Patching template '{filename}' with '{patch_file}'"))
@ -372,7 +376,7 @@ class CreoleTemplateEngine:
"""
for option in await self.config.option.list(type='all'):
namespace = await option.option.name()
if namespace == variable_namespace:
if namespace == Config['variable_namespace']:
await self.load_eole_variables_rougail(option)
else:
families = await self.load_eole_variables(namespace,

View File

@ -1,4 +1,7 @@
from tiramisu import DynOptionDescription
try:
from tiramisu3 import DynOptionDescription
except:
from tiramisu import DynOptionDescription
from .utils import normalize_family

View File

@ -1,10 +1,7 @@
"""loader
flattened XML specific
"""
from os.path import isfile
from lxml.etree import DTD
from .config import dtdfilename, variable_namespace
from .config import Config
from .i18n import _
from .error import LoaderError
from .annotator import ERASED_ATTRIBUTES
@ -47,10 +44,16 @@ class TiramisuReflector:
funcs_path,
):
self.storage = ElementStorage()
self.storage.text = ["from tiramisu import *",
"from rougail.tiramisu import ConvertDynOptionDescription",
"import imp",
self.storage.text = ["import imp",
f"func = imp.load_source('func', '{funcs_path}')",
"for key, value in dict(locals()).items():",
" if key != ['imp', 'func']:",
" setattr(func, key, value)",
"try:",
" from tiramisu3 import *",
"except:",
" from tiramisu import *",
"from rougail.tiramisu import ConvertDynOptionDescription",
]
self.make_tiramisu_objects(xmlroot)
# parse object
@ -80,10 +83,10 @@ class TiramisuReflector:
# variable_namespace family has to be loaded before any other family
# because `extra` family could use `variable_namespace` variables.
if hasattr(xmlroot, 'variables'):
if variable_namespace in xmlroot.variables:
yield xmlroot.variables[variable_namespace]
if Config['variable_namespace'] in xmlroot.variables:
yield xmlroot.variables[Config['variable_namespace']]
for xmlelt, value in xmlroot.variables.items():
if xmlelt != variable_namespace:
if xmlelt != Config['variable_namespace']:
yield value
if hasattr(xmlroot, 'services'):
yield xmlroot.services
@ -252,7 +255,7 @@ class Common:
if not self.attrib[key]:
continue
value = "frozenset({" + self.attrib[key] + "})"
elif key in ['default', 'multi', 'suffixes', 'validators']:
elif key in ['default', 'multi', 'suffixes', 'validators', 'values']:
value = self.attrib[key]
elif isinstance(value, str) and key != 'opt' and not value.startswith('['):
value = "'" + value.replace("'", "\\\'") + "'"
@ -368,9 +371,16 @@ class Variable(Common):
elif tag == 'check':
self.attrib['validators'].append(self.calculation_value(child, ['ParamSelfOption()']))
elif tag == 'choice':
choices.append(child.name)
if child.type == 'calculation':
value = self.storage.get(child.name).get()
choices = f"Calculation(func.calc_value, Params((ParamOption({value}))))"
else:
choices.append(child.name)
if choices:
self.attrib['values'] = tuple(choices)
if isinstance(choices, list):
self.attrib['values'] = str(tuple(choices))
else:
self.attrib['values'] = choices
if self.attrib['default'] == []:
del self.attrib['default']
elif not self.attrib['multi'] and isinstance(self.attrib['default'], list):
@ -415,6 +425,10 @@ class Variable(Common):
if hasattr(param, 'suffix'):
value['suffix'] = param.suffix
return self.build_param(value)
elif param.type == 'information':
return f'ParamInformation("{param.text}", None)'
elif param.type == 'suffix':
return f'ParamSuffix()'
raise LoaderError(_('unknown param type {}').format(param.type))
def populate_value(self,

View File

@ -37,7 +37,7 @@ class XMLReflector(object):
# document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True))
document = parse(xmlfile)
if not self.dtd.validate(document):
raise DictConsistencyError(_("not a valid xml file: {}").format(xmlfile))
raise DictConsistencyError(_(f'"{xmlfile}" not a valid xml file: {self.dtd.error_log.filter_from_errors()[0]}'))
return document.getroot()
def load_xml_from_folders(self, xmlfolders):

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_2 = OptionDescription(name='tata', doc='tata', children=[])
option_2.impl_set_information("manage", True)
option_1 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'auto_freeze', 'basic', 'force_store_value', 'mandatory', Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_4, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'basic'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'auto_freeze', 'expert', 'force_store_value', 'mandatory', Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_4, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'basic', 'force_store_value', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'basic'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'expert', 'force_store_value', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'expert'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_4 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='without_type', doc='without_type', multi=False, default='non')
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((), kwargs={})), values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='Redefine description', multi=True, default=['non'], default_multi='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<variables>
<family name="general">
<variable name="general" type="oui/non" description="description">
<value>non</value>
</variable>
</family>
</variables>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

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

View File

@ -0,0 +1,14 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='general', doc='description', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif1": "non", "rougail.general.module_instancie": "non"}

View File

@ -0,0 +1,16 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='module_instancie', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'auto_freeze', 'basic', 'force_store_value', 'mandatory', Calculation(calc_value, Params(ParamValue('auto_frozen'), kwargs={'condition': ParamOption(option_5, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4, option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif1": "non"}

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'basic', 'force_store_value', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general">
<variable name="mode_conteneur_actif" type="oui/non" description="No change"/>
<variable name="mode_conteneur_actif1" type="oui/non" description="No change">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
<fill name="calc_val" target="mode_conteneur_actif">
<param type="variable">mode_conteneur_actif1</param>
</fill>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif1": "non"}

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1 @@
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif1": "non"}

View File

@ -0,0 +1,15 @@
import imp
func = imp.load_source('func', 'tests/dictionaries/../eosfunc/test.py')
for key, value in dict(locals()).items():
if key != ['imp', 'func']:
setattr(func, key, value)
try:
from tiramisu3 import *
except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default=Calculation(func.calc_val, Params((ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={})), values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='Général', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])

View File

@ -0,0 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail>
<services/>
<variables>
<family name="general" mode="basic">
<variable name="mode_conteneur_actif" type="oui/non" description="No change" mandatory="True" mode="expert"/>
<variable name="mode_conteneur_actif1" type="oui/non" description="No change">
<value>non</value>
</variable>
</family>
<separators/>
</variables>
<constraints>
<fill name="calc_val" target="mode_conteneur_actif">
<param type="variable">mode_conteneur_actif1</param>
</fill>
</constraints>
<help/>
</rougail>
<!-- vim: ts=4 sw=4 expandtab
-->

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