Merge branch 'develop' into new-global-classes
diff --git a/README-extentions.rst b/README-extentions.rst
index 61364a4..a18a37a 100644
--- a/README-extentions.rst
+++ b/README-extentions.rst
@@ -208,6 +208,28 @@
group_errors: True
+Use global classes
+------------------
+
+Allows specify regexp pattern for "global class".
+
+Normally, classes are loaded when first seen. Thus they are not evaluated later when hit 2nd time. Only way to override
+parameters they load is by another class.
+
+Global classes, recognized by regexp pattern, are always loaded when hit and thus their content might be
+understood as enforced, globally available and not to be overridden by other class, even deeper in hierarchy.
+
+To avoid pitfalls do not over-engineer your solution. By default global class regexp pattern is not set.
+
+
+Global class regexp setup:
+
+.. code-block:: yaml
+
+ #/etc/reclass/reclass-config.yml
+ global_class_regexp = ['.*global']
+
+
Use references in class names
-----------------------------
diff --git a/reclass/core.py b/reclass/core.py
index d3d6187..a90b9be 100644
--- a/reclass/core.py
+++ b/reclass/core.py
@@ -40,6 +40,8 @@
self._input_data = input_data
if self._settings.ignore_class_notfound:
self._cnf_r = re.compile('|'.join([x for x in self._settings.ignore_class_notfound_regexp]))
+ self._gcl_r = re.compile('|'.join([x for x in self._settings.global_class_regexp]))
+
@staticmethod
def _get_timestamp():
@@ -100,6 +102,10 @@
return Entity(self._settings, parameters=p, name='input data')
def _recurse_entity(self, entity, merge_base=None, context=None, seen=None, nodename=None, environment=None):
+
+ # values/parser in order to interpolate references in classes
+ _parser = Parser()
+
if seen is None:
seen = {}
@@ -113,6 +119,10 @@
context = Entity(self._settings, name='empty (@{0})'.format(nodename))
for klass in entity.classes.as_list():
+
+ #if merge_base is not None:
+ # klass=str(_parser.parse(klass, self._settings).render(merge_base.parameters.as_dict(), {}))
+
if klass.count('$') > 0:
try:
klass = str(self._parser.parse(klass, self._settings).render(merge_base.parameters.as_dict(), {}))
@@ -121,8 +131,8 @@
klass = str(self._parser.parse(klass, self._settings).render(context.parameters.as_dict(), {}))
except ResolveError as e:
raise ClassNameResolveError(klass, nodename, entity.uri)
-
- if klass not in seen:
+ # class not seen or class on a list of global classes (always (re)loaded)
+ if klass not in seen or self._gcl_r.match(klass):
try:
class_entity = self._storage.get_class(klass, environment, self._settings)
except ClassNotFound as e:
diff --git a/reclass/datatypes/parameters.py b/reclass/datatypes/parameters.py
index e58a1b1..bedad88 100644
--- a/reclass/datatypes/parameters.py
+++ b/reclass/datatypes/parameters.py
@@ -130,13 +130,18 @@
else:
values = ValueList(Value(cur, self._settings, self._uri), self._settings)
- if isinstance(new, Value):
+
+ value_list = isinstance(new, ValueList) or isinstance(cur, ValueList)
+
+ if not value_list and (new.contents() is None or new.contents() == cur.contents()):
+ return cur
+ elif isinstance(new, Value):
values.append(new)
elif isinstance(new, ValueList):
values.extend(new)
else:
values.append(Value(new, self._settings, self._uri, parse_string=self._parse_strings))
-
+
return values
def _merge_dict(self, cur, new, path):
@@ -188,7 +193,8 @@
"""
- if cur is None:
+
+ if cur is None or str(cur) == 'None':
return new
elif isinstance(new, dict) and isinstance(cur, dict):
return self._merge_dict(cur, new, path)
diff --git a/reclass/defaults.py b/reclass/defaults.py
index 5dbd94b..19592c6 100644
--- a/reclass/defaults.py
+++ b/reclass/defaults.py
@@ -28,6 +28,9 @@
OPT_IGNORE_CLASS_NOTFOUND_REGEXP = ['.*']
OPT_IGNORE_CLASS_NOTFOUND_WARNING = True
+
+OPT_GLOBAL_CLASS_REGEXP = []
+
OPT_IGNORE_OVERWRITTEN_MISSING_REFERENCES = True
OPT_ALLOW_SCALAR_OVER_DICT = False
diff --git a/reclass/settings.py b/reclass/settings.py
index 6e35dd2..af6c76d 100644
--- a/reclass/settings.py
+++ b/reclass/settings.py
@@ -42,6 +42,11 @@
self.ref_parser = reclass.values.parser_funcs.get_ref_parser(self.escape_character, self.reference_sentinels, self.export_sentinels)
self.simple_ref_parser = reclass.values.parser_funcs.get_simple_ref_parser(self.escape_character, self.reference_sentinels, self.export_sentinels)
+ self.global_class_regexp = options.get('global_class_regexp', OPT_GLOBAL_CLASS_REGEXP)
+ if isinstance(self.global_class_regexp, basestring):
+ self.global_class_regexp = [ self.global_class_regexp ]
+
+
def __eq__(self, other):
return isinstance(other, type(self)) \
and self.allow_scalar_over_dict == other.allow_scalar_over_dict \
@@ -60,7 +65,8 @@
and self.reference_sentinels == other.reference_sentinels \
and self.ignore_class_notfound == other.ignore_class_notfound \
and self.ignore_class_notfound_regexp == other.ignore_class_notfound_regexp \
- and self.ignore_class_notfound_warning == other.ignore_class_notfound_warning
+ and self.ignore_class_notfound_warning == other.ignore_class_notfound_warning \
+ and self.global_class_regexp == other.global_class_regexp
def __copy__(self):
cls = self.__class__