diff --git a/lib/ansible/playbook/attribute.py b/lib/ansible/playbook/attribute.py index b2e89c7733..ec243abcd7 100644 --- a/lib/ansible/playbook/attribute.py +++ b/lib/ansible/playbook/attribute.py @@ -21,13 +21,17 @@ __metaclass__ = type class Attribute: - def __init__(self, isa=None, private=False, default=None, required=False, listof=None): + def __init__(self, isa=None, private=False, default=None, required=False, listof=None, priority=0): self.isa = isa self.private = private self.default = default self.required = required self.listof = listof + self.priority = priority + + def __cmp__(self, other): + return cmp(other.priority, self.priority) class FieldAttribute(Attribute): pass diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py index 48f62b57df..ce0aee735d 100644 --- a/lib/ansible/playbook/base.py +++ b/lib/ansible/playbook/base.py @@ -20,6 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import itertools +import operator import uuid from functools import partial @@ -153,24 +154,18 @@ class Base: else: self._loader = DataLoader() - # FIXME: is this required anymore? This doesn't seem to do anything - # helpful, and was added in very early stages of the base class - # development. - #if isinstance(ds, string_types) or isinstance(ds, FileIO): - # ds = self._loader.load(ds) - # call the preprocess_data() function to massage the data into # something we can more easily parse, and then call the validation # function on it to ensure there are no incorrect key values ds = self.preprocess_data(ds) self._validate_attributes(ds) - # Walk all attributes in the class. - # + # Walk all attributes in the class. We sort them based on their priority + # so that certain fields can be loaded before others, if they are dependent. # FIXME: we currently don't do anything with private attributes but # may later decide to filter them out of 'ds' here. - - for name in self._get_base_attributes(): + base_attributes = self._get_base_attributes() + for name, attr in sorted(base_attributes.items(), key=operator.itemgetter(1)): # copy the value over unless a _load_field method is defined if name in ds: method = getattr(self, '_load_%s' % name, None) diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index b1f5440d74..000a280a56 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -69,15 +69,15 @@ class Play(Base, Taggable, Become): _vars_prompt = FieldAttribute(isa='list', default=[]) _vault_password = FieldAttribute(isa='string') + # Role Attributes + _roles = FieldAttribute(isa='list', default=[], priority=100) + # Block (Task) Lists Attributes _handlers = FieldAttribute(isa='list', default=[]) _pre_tasks = FieldAttribute(isa='list', default=[]) _post_tasks = FieldAttribute(isa='list', default=[]) _tasks = FieldAttribute(isa='list', default=[]) - # Role Attributes - _roles = FieldAttribute(isa='list', default=[]) - # Flag/Setting Attributes _any_errors_fatal = FieldAttribute(isa='bool', default=False) _force_handlers = FieldAttribute(isa='bool')