From 519efaf22c50e6e6ed802d6c741a5eff3bbbe8ca Mon Sep 17 00:00:00 2001 From: Sebastian Goscik Date: Thu, 4 Feb 2016 15:36:47 +0000 Subject: [PATCH] Parameter: Fixed overriding of new parameters Previously you could have `override` set to True on parameters that only existed in the current scope. Now if you try to override a parameter that doesn't exist higher up in the hiarchy you will get a ValueError. --- wlauto/core/extension.py | 25 ++++++++++++++++++------- wlauto/tests/test_extension.py | 9 ++++++++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/wlauto/core/extension.py b/wlauto/core/extension.py index 348a5b9f..679b51cc 100644 --- a/wlauto/core/extension.py +++ b/wlauto/core/extension.py @@ -41,9 +41,10 @@ class AttributeCollection(object): def values(self): return self._attrs.values() - def __init__(self, attrcls): + def __init__(self, attrcls, owner): self._attrcls = attrcls self._attrs = OrderedDict() + self.owner = owner def add(self, p): p = self._to_attrcls(p) @@ -53,6 +54,8 @@ class AttributeCollection(object): for a, v in p.__dict__.iteritems(): if v is not None: setattr(newp, a, v) + if not hasattr(newp, "_overridden"): + newp._overridden = self.owner self._attrs[p.name] = newp else: # Duplicate attribute condition is check elsewhere. @@ -107,7 +110,7 @@ class AttributeCollection(object): class AliasCollection(AttributeCollection): def __init__(self): - super(AliasCollection, self).__init__(Alias) + super(AliasCollection, self).__init__(Alias, None) def _to_attrcls(self, p): if isinstance(p, tuple) or isinstance(p, list): @@ -122,8 +125,9 @@ class AliasCollection(AttributeCollection): class ListCollection(list): - def __init__(self, attrcls): # pylint: disable=unused-argument + def __init__(self, attrcls, owner): # pylint: disable=unused-argument super(ListCollection, self).__init__() + self.owner = owner class Param(object): @@ -401,14 +405,14 @@ class ExtensionMeta(type): global_virtuals = ['initialize', 'finalize'] def __new__(mcs, clsname, bases, attrs): - mcs._propagate_attributes(bases, attrs) + mcs._propagate_attributes(bases, attrs, clsname) cls = type.__new__(mcs, clsname, bases, attrs) mcs._setup_aliases(cls) mcs._implement_virtual(cls, bases) return cls @classmethod - def _propagate_attributes(mcs, bases, attrs): + def _propagate_attributes(mcs, bases, attrs, clsname): """ For attributes specified by to_propagate, their values will be a union of that specified for cls and its bases (cls values overriding those of bases @@ -417,15 +421,22 @@ class ExtensionMeta(type): """ for prop_attr, attr_cls, attr_collector_cls in mcs.to_propagate: should_propagate = False - propagated = attr_collector_cls(attr_cls) + propagated = attr_collector_cls(attr_cls, clsname) for base in bases: if hasattr(base, prop_attr): propagated += getattr(base, prop_attr) or [] should_propagate = True if prop_attr in attrs: - propagated += attrs[prop_attr] or [] + pattrs = attrs[prop_attr] or [] + propagated += pattrs should_propagate = True if should_propagate: + for p in propagated: + override = bool(getattr(p, "override", None)) + overridden = bool(getattr(p, "_overridden", None)) + if override != overridden: + msg = "Overriding non existing parameter '{}' inside '{}'" + raise ValueError(msg.format(p.name, clsname)) attrs[prop_attr] = propagated @classmethod diff --git a/wlauto/tests/test_extension.py b/wlauto/tests/test_extension.py index dee00cc4..d19c263f 100644 --- a/wlauto/tests/test_extension.py +++ b/wlauto/tests/test_extension.py @@ -324,7 +324,14 @@ class ParametersTest(TestCase): def test_duplicate_param_override(self): class DuplicateParamExtension(MyBaseExtension): # pylint: disable=W0612 parameters = [ - Parameter('food', override=True, default='cheese'), + Parameter('base', override=True, default='buttery'), + Parameter('base', override=True, default='biscuit'), + ] + + @raises(ValueError) + def test_overriding_new_param(self): + class DuplicateParamExtension(MyBaseExtension): # pylint: disable=W0612 + parameters = [ Parameter('food', override=True, default='cheese'), ]