Some further cleanup in the meta branch
* adds squashing to objects, which allows them to be squashed down to a final "view" before post_validate to avoid expensive evaluations of parent attributes
This commit is contained in:
parent
96e2be9bf8
commit
cddf1cf98e
5 changed files with 76 additions and 96 deletions
|
@ -72,6 +72,8 @@ class TaskExecutor:
|
|||
self._connection = None
|
||||
self._rslt_q = rslt_q
|
||||
|
||||
self._task.squash()
|
||||
|
||||
def run(self):
|
||||
'''
|
||||
The main executor entrypoint, where we determine if the specified
|
||||
|
|
|
@ -24,7 +24,7 @@ import itertools
|
|||
import operator
|
||||
import uuid
|
||||
|
||||
from copy import deepcopy
|
||||
from copy import copy as shallowcopy, deepcopy
|
||||
from functools import partial
|
||||
from inspect import getmembers
|
||||
|
||||
|
@ -53,8 +53,10 @@ def _generic_g(prop_name, self):
|
|||
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:
|
||||
if self._squashed:
|
||||
return self._attributes[prop_name]
|
||||
method = "_get_attr_%s" % prop_name
|
||||
return getattr(self, method)()
|
||||
except KeyError:
|
||||
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
|
||||
|
@ -62,7 +64,7 @@ def _generic_g_method(prop_name, self):
|
|||
def _generic_g_parent(prop_name, self):
|
||||
try:
|
||||
value = self._attributes[prop_name]
|
||||
if value is None and not self._finalized:
|
||||
if value is None and not self._squashed and not self._finalized:
|
||||
try:
|
||||
value = self._get_parent_attribute(prop_name)
|
||||
except AttributeError:
|
||||
|
@ -106,10 +108,13 @@ class BaseMeta(type):
|
|||
# its value from a parent object
|
||||
method = "_get_attr_%s" % attr_name
|
||||
if method in src_dict or method in dst_dict:
|
||||
#print("^ assigning generic_g_method to %s" % attr_name)
|
||||
getter = partial(_generic_g_method, attr_name)
|
||||
elif ('_get_parent_attribute' in src_dict or '_get_parent_attribute' in dst_dict) and value.inherit:
|
||||
elif '_get_parent_attribute' in dst_dict and value.inherit:
|
||||
#print("^ assigning generic_g_parent to %s" % attr_name)
|
||||
getter = partial(_generic_g_parent, attr_name)
|
||||
else:
|
||||
#print("^ assigning generic_g to %s" % attr_name)
|
||||
getter = partial(_generic_g, attr_name)
|
||||
|
||||
setter = partial(_generic_s, attr_name)
|
||||
|
@ -135,6 +140,7 @@ class BaseMeta(type):
|
|||
|
||||
# now create the attributes based on the FieldAttributes
|
||||
# available, including from parent (and grandparent) objects
|
||||
#print("creating class %s" % name)
|
||||
_create_attrs(dct, dct)
|
||||
_process_parents(parents, dct)
|
||||
|
||||
|
@ -148,7 +154,7 @@ class Base(with_metaclass(BaseMeta, object)):
|
|||
_remote_user = FieldAttribute(isa='string')
|
||||
|
||||
# variables
|
||||
_vars = FieldAttribute(isa='dict', priority=100)
|
||||
_vars = FieldAttribute(isa='dict', priority=100, inherit=False)
|
||||
|
||||
# flags and misc. settings
|
||||
_environment = FieldAttribute(isa='list')
|
||||
|
@ -173,6 +179,7 @@ class Base(with_metaclass(BaseMeta, object)):
|
|||
|
||||
# other internal params
|
||||
self._validated = False
|
||||
self._squashed = False
|
||||
self._finalized = False
|
||||
|
||||
# every object gets a random uuid:
|
||||
|
@ -297,6 +304,22 @@ class Base(with_metaclass(BaseMeta, object)):
|
|||
|
||||
self._validated = True
|
||||
|
||||
def squash(self):
|
||||
'''
|
||||
Evaluates all attributes and sets them to the evaluated version,
|
||||
so that all future accesses of attributes do not need to evaluate
|
||||
parent attributes.
|
||||
'''
|
||||
if not self._squashed:
|
||||
for name in self._valid_attrs.keys():
|
||||
getter = partial(_generic_g, name)
|
||||
setter = partial(_generic_s, name)
|
||||
deleter = partial(_generic_d, name)
|
||||
|
||||
self._attributes[name] = getattr(self, name)
|
||||
#print("squashed attr %s: %s" % (name, self._attributes[name]))
|
||||
self._squashed = True
|
||||
|
||||
def copy(self):
|
||||
'''
|
||||
Create a copy of this object and return it.
|
||||
|
@ -305,13 +328,7 @@ class Base(with_metaclass(BaseMeta, object)):
|
|||
new_me = self.__class__()
|
||||
|
||||
for name in self._valid_attrs.keys():
|
||||
attr_val = getattr(self, name)
|
||||
if isinstance(attr_val, collections.Sequence):
|
||||
setattr(new_me, name, attr_val[:])
|
||||
elif isinstance(attr_val, collections.Mapping):
|
||||
setattr(new_me, name, attr_val.copy())
|
||||
else:
|
||||
setattr(new_me, name, attr_val)
|
||||
new_me._attributes[name] = shallowcopy(self._attributes[name])
|
||||
|
||||
new_me._loader = self._loader
|
||||
new_me._variable_manager = self._variable_manager
|
||||
|
|
|
@ -102,29 +102,3 @@ class Become:
|
|||
if become_user is None:
|
||||
become_user = C.DEFAULT_BECOME_USER
|
||||
|
||||
def _get_attr_become(self):
|
||||
'''
|
||||
Override for the 'become' getattr fetcher, used from Base.
|
||||
'''
|
||||
if hasattr(self, '_get_parent_attribute'):
|
||||
return self._get_parent_attribute('become')
|
||||
else:
|
||||
return self._attributes['become']
|
||||
|
||||
def _get_attr_become_method(self):
|
||||
'''
|
||||
Override for the 'become_method' getattr fetcher, used from Base.
|
||||
'''
|
||||
if hasattr(self, '_get_parent_attribute'):
|
||||
return self._get_parent_attribute('become_method')
|
||||
else:
|
||||
return self._attributes['become_method']
|
||||
|
||||
def _get_attr_become_user(self):
|
||||
'''
|
||||
Override for the 'become_user' getattr fetcher, used from Base.
|
||||
'''
|
||||
if hasattr(self, '_get_parent_attribute'):
|
||||
return self._get_parent_attribute('become_user')
|
||||
else:
|
||||
return self._attributes['become_user']
|
||||
|
|
|
@ -278,6 +278,9 @@ class Block(Base, Become, Conditional, Taggable):
|
|||
for dep in dep_chain:
|
||||
dep.set_loader(loader)
|
||||
|
||||
def _get_attr_environment(self):
|
||||
return self._get_parent_attribute('environment', extend=True)
|
||||
|
||||
def _get_parent_attribute(self, attr, extend=False):
|
||||
'''
|
||||
Generic logic to get the attribute or parent attribute for a block value.
|
||||
|
@ -288,50 +291,50 @@ class Block(Base, Become, Conditional, Taggable):
|
|||
value = self._attributes[attr]
|
||||
|
||||
if self._parent and (value is None or extend):
|
||||
parent_value = getattr(self._parent, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, parent_value)
|
||||
else:
|
||||
value = parent_value
|
||||
if self._role and (value is None or extend) and hasattr(self._role, attr):
|
||||
parent_value = getattr(self._role, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, parent_value)
|
||||
else:
|
||||
value = parent_value
|
||||
try:
|
||||
parent_value = getattr(self._parent, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, parent_value)
|
||||
else:
|
||||
value = parent_value
|
||||
except AttributeError:
|
||||
pass
|
||||
if self._role and (value is None or extend):
|
||||
try:
|
||||
parent_value = getattr(self._role, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, parent_value)
|
||||
else:
|
||||
value = parent_value
|
||||
|
||||
dep_chain = self.get_dep_chain()
|
||||
if dep_chain and (value is None or extend):
|
||||
dep_chain.reverse()
|
||||
for dep in dep_chain:
|
||||
dep_value = getattr(dep, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, dep_value)
|
||||
else:
|
||||
value = dep_value
|
||||
dep_chain = self.get_dep_chain()
|
||||
if dep_chain and (value is None or extend):
|
||||
dep_chain.reverse()
|
||||
for dep in dep_chain:
|
||||
dep_value = getattr(dep, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, dep_value)
|
||||
else:
|
||||
value = dep_value
|
||||
|
||||
if value is not None and not extend:
|
||||
break
|
||||
if self._play and (value is None or extend) and hasattr(self._play, attr):
|
||||
parent_value = getattr(self._play, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, parent_value)
|
||||
else:
|
||||
value = parent_value
|
||||
if value is not None and not extend:
|
||||
break
|
||||
except AttributeError:
|
||||
pass
|
||||
if self._play and (value is None or extend):
|
||||
try:
|
||||
parent_value = getattr(self._play, attr, None)
|
||||
if extend:
|
||||
value = self._extend_value(value, parent_value)
|
||||
else:
|
||||
value = parent_value
|
||||
except AttributeError:
|
||||
pass
|
||||
except KeyError as e:
|
||||
pass
|
||||
|
||||
return value
|
||||
|
||||
def _get_attr_environment(self):
|
||||
return self._get_parent_attribute('environment')
|
||||
|
||||
def _get_attr_any_errors_fatal(self):
|
||||
'''
|
||||
Override for the 'tags' getattr fetcher, used from Base.
|
||||
'''
|
||||
return self._get_parent_attribute('any_errors_fatal')
|
||||
|
||||
def filter_tagged_tasks(self, play_context, all_vars):
|
||||
'''
|
||||
Creates a new block, with task lists filtered based on the tags contained
|
||||
|
|
|
@ -79,9 +79,9 @@ class Task(Base, Conditional, Taggable, Become):
|
|||
_delegate_facts = FieldAttribute(isa='bool', default=False)
|
||||
_failed_when = FieldAttribute(isa='list', default=[])
|
||||
_first_available_file = FieldAttribute(isa='list')
|
||||
_loop = FieldAttribute(isa='string', private=True)
|
||||
_loop_args = FieldAttribute(isa='list', private=True)
|
||||
_loop_control = FieldAttribute(isa='class', class_type=LoopControl)
|
||||
_loop = FieldAttribute(isa='string', private=True, inherit=False)
|
||||
_loop_args = FieldAttribute(isa='list', private=True, inherit=False)
|
||||
_loop_control = FieldAttribute(isa='class', class_type=LoopControl, inherit=False)
|
||||
_name = FieldAttribute(isa='string', default='')
|
||||
_notify = FieldAttribute(isa='list')
|
||||
_poll = FieldAttribute(isa='int')
|
||||
|
@ -401,10 +401,10 @@ class Task(Base, Conditional, Taggable, Become):
|
|||
'''
|
||||
Generic logic to get the attribute or parent attribute for a task value.
|
||||
'''
|
||||
|
||||
value = None
|
||||
try:
|
||||
value = self._attributes[attr]
|
||||
|
||||
if self._parent and (value is None or extend):
|
||||
parent_value = getattr(self._parent, attr, None)
|
||||
if extend:
|
||||
|
@ -420,23 +420,7 @@ class Task(Base, Conditional, Taggable, Become):
|
|||
'''
|
||||
Override for the 'tags' getattr fetcher, used from Base.
|
||||
'''
|
||||
environment = self._attributes['environment']
|
||||
parent_environment = self._get_parent_attribute('environment', extend=True)
|
||||
if parent_environment is not None:
|
||||
environment = self._extend_value(environment, parent_environment)
|
||||
return environment
|
||||
|
||||
def _get_attr_any_errors_fatal(self):
|
||||
'''
|
||||
Override for the 'tags' getattr fetcher, used from Base.
|
||||
'''
|
||||
return self._get_parent_attribute('any_errors_fatal')
|
||||
|
||||
def _get_attr_loop(self):
|
||||
return self._attributes['loop']
|
||||
|
||||
def _get_attr_loop_control(self):
|
||||
return self._attributes['loop_control']
|
||||
return self._get_parent_attribute('environment', extend=True)
|
||||
|
||||
def get_dep_chain(self):
|
||||
if self._parent:
|
||||
|
|
Loading…
Reference in a new issue