summaryrefslogtreecommitdiff
path: root/lib/ansible/playbook/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/playbook/base.py')
-rw-r--r--lib/ansible/playbook/base.py72
1 files changed, 55 insertions, 17 deletions
diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py
index e35cd904e7..2447a72824 100644
--- a/lib/ansible/playbook/base.py
+++ b/lib/ansible/playbook/base.py
@@ -47,19 +47,28 @@ except ImportError:
def _generic_g(prop_name, self):
+ try:
+ return self._attributes[prop_name]
+ except KeyError:
+ raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
+
+def _generic_g_method(prop_name, self):
method = "_get_attr_%s" % prop_name
try:
- value = getattr(self, method)()
- except AttributeError:
- try:
- value = self._attributes[prop_name]
- if value is None and not self._finalized:
- try:
- value = self._get_parent_attribute(prop_name)
- except AttributeError:
- pass
- except KeyError:
- raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
+ return getattr(self, method)()
+ except KeyError:
+ raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
+
+def _generic_g_parent(prop_name, self):
+ try:
+ value = self._attributes[prop_name]
+ if value is None and not self._finalized:
+ try:
+ value = self._get_parent_attribute(prop_name)
+ except AttributeError:
+ pass
+ except KeyError:
+ raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
return value
@@ -71,8 +80,19 @@ def _generic_d(prop_name, self):
class BaseMeta(type):
+ """
+ Metaclass for the Base object, which is used to construct the class
+ attributes based on the FieldAttributes available.
+ """
+
def __new__(cls, name, parents, dct):
def _create_attrs(src_dict, dst_dict):
+ '''
+ Helper method which creates the attributes based on those in the
+ source dictionary of attributes. This also populates the other
+ attributes used to keep track of these attributes and via the
+ getter/setter/deleter methods.
+ '''
keys = list(src_dict.keys())
for attr_name in keys:
value = src_dict[attr_name]
@@ -80,8 +100,19 @@ class BaseMeta(type):
if attr_name.startswith('_'):
attr_name = attr_name[1:]
- getter = partial(_generic_g, attr_name)
- setter = partial(_generic_s, attr_name)
+ # here we selectively assign the getter based on a few
+ # things, such as whether we have a _get_attr_<name>
+ # method, or if the attribute is marked as not inheriting
+ # its value from a parent object
+ method = "_get_attr_%s" % attr_name
+ if method in src_dict or method in dst_dict:
+ getter = partial(_generic_g_method, attr_name)
+ elif ('_get_parent_attribute' in src_dict or '_get_parent_attribute' in dst_dict) and value.inherit:
+ getter = partial(_generic_g_parent, attr_name)
+ else:
+ getter = partial(_generic_g, attr_name)
+
+ setter = partial(_generic_s, attr_name)
deleter = partial(_generic_d, attr_name)
dst_dict[attr_name] = property(getter, setter, deleter)
@@ -89,14 +120,21 @@ class BaseMeta(type):
dst_dict['_attributes'][attr_name] = value.default
def _process_parents(parents, dst_dict):
+ '''
+ Helper method which creates attributes from all parent objects
+ recursively on through grandparent objects
+ '''
for parent in parents:
if hasattr(parent, '__dict__'):
_create_attrs(parent.__dict__, dst_dict)
_process_parents(parent.__bases__, dst_dict)
+ # create some additional class attributes
dct['_attributes'] = dict()
dct['_valid_attrs'] = dict()
+ # now create the attributes based on the FieldAttributes
+ # available, including from parent (and grandparent) objects
_create_attrs(dct, dct)
_process_parents(parents, dct)
@@ -140,10 +178,10 @@ class Base(with_metaclass(BaseMeta, object)):
# every object gets a random uuid:
self._uuid = uuid.uuid4()
- # initialize the default field attribute values
- #self._attributes = dict()
- #for (name, attr) in iteritems(self._valid_attrs):
- # self._attributes[name] = attr.default
+ # we create a copy of the attributes here due to the fact that
+ # it was intialized as a class param in the meta class, so we
+ # need a unique object here (all members contained within are
+ # unique already).
self._attributes = self._attributes.copy()
# and init vars, avoid using defaults in field declaration as it lives across plays