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
This commit is contained in:
James Cammarata 2017-11-22 14:35:58 -06:00 committed by Matt Clay
commit d8ae4dfbf2
14 changed files with 43 additions and 36 deletions

View file

@ -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