diff --git a/doc/README.md b/doc/README.md
index ff8a82f4..e4b748a5 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -34,3 +34,4 @@ Rougail est un bibliothèque python3 qui permet de charger des dictionnaires (fi
## Les templates
- Type creole
+FIXME ^^
diff --git a/src/rougail/annotator/condition.py b/src/rougail/annotator/condition.py
index c3f48826..89ebb2ea 100644
--- a/src/rougail/annotator/condition.py
+++ b/src/rougail/annotator/condition.py
@@ -29,7 +29,6 @@ from typing import List, Any
from ..i18n import _
from ..error import DictConsistencyError
-from ..config import RougailConfig
from .target import TargetAnnotator
from .param import ParamAnnotator
@@ -75,13 +74,13 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
for variable in self.get_variables():
if not variable.auto_freeze:
continue
- if variable.namespace != RougailConfig['variable_namespace']:
+ if variable.namespace != self.objectspace.rougailconfig['variable_namespace']:
msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}"')
raise DictConsistencyError(msg, 49, variable.xmlfiles)
new_condition = self.objectspace.condition(variable.xmlfiles)
new_condition.name = 'auto_frozen_if_not_in'
new_condition.namespace = variable.namespace
- new_condition.source = RougailConfig['auto_freeze_variable']
+ new_condition.source = self.objectspace.rougailconfig['auto_freeze_variable']
new_param = self.objectspace.param(variable.xmlfiles)
new_param.text = True
new_condition.param = [new_param]
@@ -114,12 +113,9 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
if condition.optional is False or \
self.objectspace.paths.path_is_defined(condition.source):
continue
- if hasattr(condition, 'apply_on_fallback'):
- apply_action = condition.apply_on_fallback
- else:
- apply_on_fallback = condition.name.endswith('_if_in'):
remove_conditions.append(idx)
- if apply_action:
+ if (hasattr(condition, 'apply_on_fallback') and condition.apply_on_fallback) or \
+ (not hasattr(condition, 'apply_on_fallback') and condition.name.endswith('_if_in')):
self.force_actions_to_variable(condition)
remove_conditions.sort(reverse=True)
for idx in remove_conditions:
diff --git a/src/rougail/annotator/variable.py b/src/rougail/annotator/variable.py
index a6b07c67..db432fda 100644
--- a/src/rougail/annotator/variable.py
+++ b/src/rougail/annotator/variable.py
@@ -25,6 +25,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
+from ..i18n import _
+from ..error import DictConsistencyError
from ..objspace import convert_boolean
@@ -116,6 +118,9 @@ class VariableAnnotator(Walk): # pylint: disable=R0903
if not hasattr(objectspace.space, 'variables'):
return
self.objectspace = objectspace
+ self.forbidden_name = ['services', self.objectspace.rougailconfig['variable_namespace']]
+ for extra in self.objectspace.rougailconfig['extra_dictionaries']:
+ self.forbidden_name.append(extra)
self.convert_variable()
self.convert_test()
self.convert_help()
@@ -141,6 +146,10 @@ class VariableAnnotator(Walk): # pylint: disable=R0903
variable,
variable_type: str,
) -> None:
+ if variable.namespace == self.objectspace.rougailconfig['variable_namespace'] and \
+ variable.name in self.forbidden_name:
+ msg = _(f'the name of the variable "{variable.name}" cannot be the same as the name of a namespace')
+ raise DictConsistencyError(msg, 54, variable.xmlfiles)
if variable.type != 'symlink' and not hasattr(variable, 'description'):
variable.description = variable.name
if hasattr(variable, 'value'):
diff --git a/src/rougail/convert.py b/src/rougail/convert.py
index 143bbf82..ad4f0b0d 100644
--- a/src/rougail/convert.py
+++ b/src/rougail/convert.py
@@ -58,16 +58,22 @@ from .error import DictConsistencyError
class RougailConvert:
"""Rougail object
"""
- def __init__(self) -> None:
- xmlreflector = XMLReflector()
- rougailobjspace = RougailObjSpace(xmlreflector)
+ def __init__(self,
+ rougailconfig: RougailConfig=None,
+ ) -> None:
+ if rougailconfig is None:
+ rougailconfig = RougailConfig
+ xmlreflector = XMLReflector(rougailconfig)
+ rougailobjspace = RougailObjSpace(xmlreflector,
+ rougailconfig,
+ )
self._load_dictionaries(xmlreflector,
rougailobjspace,
- RougailConfig['variable_namespace'],
- RougailConfig['dictionaries_dir'],
+ rougailconfig['variable_namespace'],
+ rougailconfig['dictionaries_dir'],
)
- for namespace, extra_dir in RougailConfig['extra_dictionaries'].items():
- if namespace in ['services', RougailConfig['variable_namespace']]:
+ for namespace, extra_dir in rougailconfig['extra_dictionaries'].items():
+ if namespace in ['services', rougailconfig['variable_namespace']]:
msg = _(f'Namespace name "{namespace}" is not allowed')
raise DictConsistencyError(msg, 21, None)
self._load_dictionaries(xmlreflector,
@@ -75,7 +81,7 @@ class RougailConvert:
namespace,
extra_dir,
)
- functions_file = RougailConfig['functions_file']
+ functions_file = rougailconfig['functions_file']
SpaceAnnotator(rougailobjspace,
functions_file,
)
diff --git a/src/rougail/objspace.py b/src/rougail/objspace.py
index b32ba34e..127bc2c5 100644
--- a/src/rougail/objspace.py
+++ b/src/rougail/objspace.py
@@ -32,7 +32,6 @@ from .xmlreflector import XMLReflector
from .utils import normalize_family
from .error import SpaceObjShallNotBeUpdated, DictConsistencyError
from .path import Path
-from .config import RougailConfig
# RougailObjSpace's elements that shall be forced to the Redefinable type
FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables')
@@ -101,9 +100,10 @@ class RougailObjSpace:
def __init__(self,
xmlreflector: XMLReflector,
+ rougailconfig: 'RougailConfig',
) -> None:
self.space = ObjSpace()
- self.paths = Path()
+ self.paths = Path(rougailconfig)
self.forced_text_elts_as_name = set(FORCED_TEXT_ELTS_AS_NAME)
self.list_conditions = {}
@@ -112,6 +112,7 @@ class RougailObjSpace:
self.has_dyn_option = False
self.make_object_space_classes(xmlreflector)
+ self.rougailconfig = rougailconfig
def make_object_space_classes(self,
xmlreflector: XMLReflector,
@@ -197,12 +198,12 @@ class RougailObjSpace:
family_names.append(child.attrib['name'])
try:
# variable objects creation
- variableobj = self.get_variableobj(xmlfile,
- child,
- space,
- namespace,
- redefine_variables,
- )
+ exists, variableobj = self.get_variableobj(xmlfile,
+ child,
+ space,
+ namespace,
+ redefine_variables,
+ )
except SpaceObjShallNotBeUpdated:
continue
self.set_text(child,
@@ -216,11 +217,12 @@ class RougailObjSpace:
variableobj,
redefine_variables,
)
- self.set_path(namespace,
- document,
- variableobj,
- space,
- )
+ if not exists:
+ self.set_path(namespace,
+ document,
+ variableobj,
+ space,
+ )
self.add_to_tree_structure(variableobj,
space,
child,
@@ -260,11 +262,12 @@ class RougailObjSpace:
if child.tag in vars(space):
# Atom instance has to be a singleton here
# we do not re-create it, we reuse it
- return getattr(space, child.tag)
- return obj(xmlfile, name)
+ return False, getattr(space, child.tag)
+ return False, obj(xmlfile, name)
+ # UnRedefinable object
if child.tag not in vars(space):
setattr(space, child.tag, [])
- return obj(xmlfile, name)
+ return False, obj(xmlfile, name)
def _get_name(self,
child,
@@ -301,12 +304,12 @@ class RougailObjSpace:
redefine = convert_boolean(subspace.get('redefine', default_redefine))
if redefine is True:
if isinstance(existed_var, self.variable): # pylint: disable=E1101
- if namespace == RougailConfig['variable_namespace']:
+ if namespace == self.rougailconfig['variable_namespace']:
redefine_variables.append(name)
else:
redefine_variables.append(space.path + '.' + name)
existed_var.xmlfiles.append(xmlfile)
- return existed_var
+ return True, existed_var
exists = convert_boolean(subspace.get('exists', True))
if exists is False:
raise SpaceObjShallNotBeUpdated()
@@ -327,7 +330,7 @@ class RougailObjSpace:
if tag not in vars(space):
setattr(space, tag, {})
obj = getattr(self, child.tag)(xmlfile, name)
- return obj
+ return False, obj
def get_existed_obj(self,
name: str,
@@ -340,7 +343,7 @@ class RougailObjSpace:
if child.tag in ['variable', 'family']:
name = normalize_family(name)
if child.tag == 'variable': # pylint: disable=E1101
- if namespace != RougailConfig['variable_namespace']:
+ if namespace != self.rougailconfig['variable_namespace']:
name = space.path + '.' + name
if not self.paths.path_is_defined(name):
return None
@@ -474,7 +477,7 @@ class RougailObjSpace:
)
elif isinstance(variableobj, self.family): # pylint: disable=E1101
family_name = normalize_family(variableobj.name)
- if namespace != RougailConfig['variable_namespace']:
+ if namespace != self.rougailconfig['variable_namespace']:
family_name = namespace + '.' + family_name
self.paths.add_family(namespace,
family_name,
diff --git a/src/rougail/path.py b/src/rougail/path.py
index 3829efee..ff1a2b78 100644
--- a/src/rougail/path.py
+++ b/src/rougail/path.py
@@ -26,7 +26,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from .i18n import _
from .error import DictConsistencyError
-from .config import RougailConfig
from .utils import normalize_family
@@ -36,11 +35,14 @@ class Path:
sample: path="creole.general.condition"
"""
- def __init__(self):
+ def __init__(self,
+ rougailconfig: 'RougailConfig',
+ ) -> None:
self.variables = {}
self.families = {}
self.full_paths_families = {}
self.full_paths_variables = {}
+ self.variable_namespace = rougailconfig['variable_namespace']
# Family
def add_family(self,
@@ -51,8 +53,10 @@ class Path:
) -> str: # pylint: disable=C0111
"""Add a new family
"""
- if namespace == RougailConfig['variable_namespace']:
+ if namespace == self.variable_namespace:
full_name = '.'.join([subpath, name])
+ if name in self.full_paths_families:
+ raise DictConsistencyError(_(f'Duplicate family name "{name}"'), 55, variableobj.xmlfiles)
self.full_paths_families[name] = full_name
else:
if '.' not in name: # pragma: no cover
@@ -93,7 +97,7 @@ class Path:
if name not in self.families:
raise DictConsistencyError(_(f'unknown option {name}'), 42, [])
dico = self.families[name]
- if current_namespace not in [RougailConfig['variable_namespace'], 'services'] and \
+ if current_namespace not in [self.variable_namespace, 'services'] and \
current_namespace != dico['namespace']:
msg = _(f'A family located in the "{dico["namespace"]}" namespace '
f'shall not be used in the "{current_namespace}" namespace')
@@ -117,7 +121,7 @@ class Path:
self.variables[new_path]['leader'] = leadership_path
self.variables[new_path]['variableobj'].path = new_path
self.variables[new_path]['family'] = leadership_path
- if namespace == RougailConfig['variable_namespace']:
+ if namespace == self.variable_namespace:
self.full_paths_variables[name] = new_path
def is_leader(self, path): # pylint: disable=C0111
@@ -141,7 +145,7 @@ class Path:
"""
if '.' not in name:
full_path = '.'.join([family, name])
- if namespace == RougailConfig['variable_namespace']:
+ if namespace == self.variable_namespace:
self.full_paths_variables[name] = full_path
else:
full_path = name
@@ -180,7 +184,7 @@ class Path:
with_suffix=True,
)
namespace = dico['variableobj'].namespace
- if namespace not in [RougailConfig['variable_namespace'], 'services'] and \
+ if namespace not in [self.variable_namespace, 'services'] and \
current_namespace != namespace:
msg = _(f'A variable located in the "{namespace}" namespace shall not be used '
f'in the "{current_namespace}" namespace')
diff --git a/src/rougail/template.py b/src/rougail/template.py
index b710563b..2cf63dcb 100644
--- a/src/rougail/template.py
+++ b/src/rougail/template.py
@@ -223,14 +223,17 @@ class RougailTemplate:
"""
def __init__(self, # pylint: disable=R0913
config: Config,
+ rougailconfig: RougailConfig=None,
) -> None:
+ if rougailconfig is None:
+ rougailconfig = RougailConfig
self.config = config
- self.destinations_dir = abspath(RougailConfig['destinations_dir'])
- self.tmp_dir = abspath(RougailConfig['tmp_dir'])
- self.templates_dir = abspath(RougailConfig['templates_dir'])
- self.patches_dir = abspath(RougailConfig['patches_dir'])
+ self.destinations_dir = abspath(rougailconfig['destinations_dir'])
+ self.tmp_dir = abspath(rougailconfig['tmp_dir'])
+ self.templates_dir = abspath(rougailconfig['templates_dir'])
+ self.patches_dir = abspath(rougailconfig['patches_dir'])
eos = {}
- functions_file = RougailConfig['functions_file']
+ functions_file = rougailconfig['functions_file']
if isfile(functions_file):
eosfunc = load_modules(functions_file)
for func in dir(eosfunc):
@@ -238,6 +241,7 @@ class RougailTemplate:
eos[func] = getattr(eosfunc, func)
self.eosfunc = eos
self.rougail_variables_dict = {}
+ self.rougailconfig = rougailconfig
def patch_template(self,
filename: str,
@@ -343,7 +347,7 @@ class RougailTemplate:
chdir(self.templates_dir)
for option in await self.config.option.list(type='all'):
namespace = await option.option.name()
- is_variable_namespace = namespace == RougailConfig['variable_namespace']
+ is_variable_namespace = namespace == self.rougailconfig['variable_namespace']
self.rougail_variables_dict[namespace] = await self.load_variables(option,
is_variable_namespace,
)
diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py
index 9198b99a..0d78bb38 100644
--- a/src/rougail/tiramisureflector.py
+++ b/src/rougail/tiramisureflector.py
@@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from json import dumps
from os.path import isfile
-from .config import RougailConfig
from .annotator import CONVERT_OPTION
from .objspace import RootRougailObject
@@ -96,10 +95,10 @@ class TiramisuReflector:
because `extra` family could use `variable_namespace` variables.
"""
if hasattr(self.objectspace.space, 'variables'):
- if RougailConfig['variable_namespace'] in self.objectspace.space.variables:
- yield self.objectspace.space.variables[RougailConfig['variable_namespace']]
+ if self.objectspace.rougailconfig['variable_namespace'] in self.objectspace.space.variables:
+ yield self.objectspace.space.variables[self.objectspace.rougailconfig['variable_namespace']]
for elt, value in self.objectspace.space.variables.items():
- if elt != RougailConfig['variable_namespace']:
+ if elt != self.objectspace.rougailconfig['variable_namespace']:
yield value
if hasattr(self.objectspace.space, 'services'):
yield self.objectspace.space.services
diff --git a/src/rougail/xmlreflector.py b/src/rougail/xmlreflector.py
index e59408b2..48bf50bb 100644
--- a/src/rougail/xmlreflector.py
+++ b/src/rougail/xmlreflector.py
@@ -32,7 +32,6 @@ from lxml.etree import DTD, parse, XMLSyntaxError # pylint: disable=E0611
from .i18n import _
from .error import DictConsistencyError
-from .config import RougailConfig
class XMLReflector:
@@ -40,14 +39,16 @@ class XMLReflector:
parsing it, validating against the Creole DTD,
writing the xml result on the disk
"""
- def __init__(self):
+ def __init__(self,
+ rougailconfig: 'RougailConfig',
+ ) -> None:
"""Loads the Creole DTD
:raises IOError: if the DTD is not found
:param dtdfilename: the full filename of the Creole DTD
"""
- dtdfilename = RougailConfig['dtdfilename']
+ dtdfilename = rougailconfig['dtdfilename']
if not isfile(dtdfilename):
raise IOError(_("no such DTD file: {}").format(dtdfilename))
with open(dtdfilename, 'r') as dtdfd:
diff --git a/tests/dictionaries/60extra_variable_name_extra/00-base.xml b/tests/dictionaries/60extra_variable_name_extra/00-base.xml
new file mode 100644
index 00000000..4eb9d373
--- /dev/null
+++ b/tests/dictionaries/60extra_variable_name_extra/00-base.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ non
+
+
+ non
+
+
+
+
+
diff --git a/tests/dictionaries/60extra_variable_name_extra/__init__.py b/tests/dictionaries/60extra_variable_name_extra/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/60extra_variable_name_extra/extra_dirs/extra/00-base.xml b/tests/dictionaries/60extra_variable_name_extra/extra_dirs/extra/00-base.xml
new file mode 100644
index 00000000..76a450e6
--- /dev/null
+++ b/tests/dictionaries/60extra_variable_name_extra/extra_dirs/extra/00-base.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/60extra_variable_name_extra/makedict/base.json b/tests/dictionaries/60extra_variable_name_extra/makedict/base.json
new file mode 100644
index 00000000..60d4d218
--- /dev/null
+++ b/tests/dictionaries/60extra_variable_name_extra/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.activer_ejabberd": "non", "extra.extra": null}
diff --git a/tests/dictionaries/60extra_variable_name_extra/tiramisu/base.py b/tests/dictionaries/60extra_variable_name_extra/tiramisu/base.py
new file mode 100644
index 00000000..dda96b9b
--- /dev/null
+++ b/tests/dictionaries/60extra_variable_name_extra/tiramisu/base.py
@@ -0,0 +1,20 @@
+from importlib.machinery import SourceFileLoader
+from importlib.util import spec_from_loader, module_from_spec
+loader = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
+spec = spec_from_loader(loader.name, loader)
+func = module_from_spec(spec)
+loader.exec_module(func)
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
+option_4 = StrOption(name="activer_ejabberd", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
+option_2 = OptionDescription(name="general", doc="général", children=[option_3, option_4], properties=frozenset({"normal"}))
+option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
+option_6 = StrOption(name="extra", doc="extra", properties=frozenset({"normal"}))
+option_5 = OptionDescription(name="extra", doc="extra", children=[option_6])
+option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_5])
diff --git a/tests/dictionaries/80family_unique/00-base.xml b/tests/dictionaries/80family_unique/00-base.xml
new file mode 100644
index 00000000..da71a435
--- /dev/null
+++ b/tests/dictionaries/80family_unique/00-base.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/80family_unique/__init__.py b/tests/dictionaries/80family_unique/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80family_unique/errno_55 b/tests/dictionaries/80family_unique/errno_55
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80variable_extra/00-base.xml b/tests/dictionaries/80variable_extra/00-base.xml
new file mode 100644
index 00000000..4f429ec0
--- /dev/null
+++ b/tests/dictionaries/80variable_extra/00-base.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/80variable_extra/__init__.py b/tests/dictionaries/80variable_extra/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80variable_extra/errno_54 b/tests/dictionaries/80variable_extra/errno_54
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80variable_extra/extra_dirs/extra/00-base.xml b/tests/dictionaries/80variable_extra/extra_dirs/extra/00-base.xml
new file mode 100644
index 00000000..dd1a7ba3
--- /dev/null
+++ b/tests/dictionaries/80variable_extra/extra_dirs/extra/00-base.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/80variable_rougail/00-base.xml b/tests/dictionaries/80variable_rougail/00-base.xml
new file mode 100644
index 00000000..2d569b61
--- /dev/null
+++ b/tests/dictionaries/80variable_rougail/00-base.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/80variable_rougail/__init__.py b/tests/dictionaries/80variable_rougail/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80variable_rougail/errno_54 b/tests/dictionaries/80variable_rougail/errno_54
new file mode 100644
index 00000000..e69de29b