From d8ae4dfbf212000e238dbdd2ed9a99dd829bdc01 Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Wed, 22 Nov 2017 14:35:58 -0600 Subject: Adding aliases for field attributes and renaming async attribute (#33141) * Adding aliases for field attributes and renaming async attribute As of Python 3.7, the use of async raises an error, whereas before the use of the reserved word was ignored. This adds an alias field for field attrs so that both async and async_val (interally) work. This allows us to be backwards-compatible with 3rd party plugins that may still reference Task.async, but for the core engine to work on Py3.7+. * Remove files fixed for 'async' usage from the python 3.7 skip list --- lib/ansible/playbook/base.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'lib/ansible/playbook/base.py') diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py index 4a27eaea6d..4beb56f55c 100644 --- a/lib/ansible/playbook/base.py +++ b/lib/ansible/playbook/base.py @@ -109,6 +109,11 @@ class BaseMeta(type): dst_dict['_valid_attrs'][attr_name] = value dst_dict['_attributes'][attr_name] = value.default + if value.alias is not None: + dst_dict[value.alias] = property(getter, setter, deleter) + dst_dict['_valid_attrs'][value.alias] = value + dst_dict['_alias_attrs'][value.alias] = attr_name + def _process_parents(parents, dst_dict): ''' Helper method which creates attributes from all parent objects @@ -124,6 +129,7 @@ class BaseMeta(type): # create some additional class attributes dct['_attributes'] = dict() dct['_valid_attrs'] = dict() + dct['_alias_attrs'] = dict() # now create the attributes based on the FieldAttributes # available, including from parent (and grandparent) objects @@ -235,12 +241,15 @@ class Base(with_metaclass(BaseMeta, object)): # so that certain fields can be loaded before others, if they are dependent. for name, attr in sorted(iteritems(self._valid_attrs), key=operator.itemgetter(1)): # copy the value over unless a _load_field method is defined + target_name = name + if name in self._alias_attrs: + target_name = self._alias_attrs[name] if name in ds: method = getattr(self, '_load_%s' % name, None) if method: - self._attributes[name] = method(name, ds[name]) + self._attributes[target_name] = method(name, ds[name]) else: - self._attributes[name] = ds[name] + self._attributes[target_name] = ds[name] # run early, non-critical validation self.validate() @@ -279,13 +288,16 @@ class Base(with_metaclass(BaseMeta, object)): # walk all fields in the object for (name, attribute) in iteritems(self._valid_attrs): + if name in self._alias_attrs: + name = self._alias_attrs[name] + # run validator only if present method = getattr(self, '_validate_%s' % name, None) if method: method(attribute, name, getattr(self, name)) else: # and make sure the attribute is of the type it should be - value = getattr(self, name) + value = self._attributes[name] if value is not None: if attribute.isa == 'string' and isinstance(value, (list, dict)): raise AnsibleParserError( @@ -314,6 +326,8 @@ class Base(with_metaclass(BaseMeta, object)): new_me = self.__class__() for name in self._valid_attrs.keys(): + if name in self._alias_attrs: + continue new_me._attributes[name] = shallowcopy(self._attributes[name]) new_me._loader = self._loader -- cgit v1.2.1