From cd2cb178aeb799efe4aba36f93d48c95f6da3b61 Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Mon, 12 Oct 2015 17:05:22 -0400 Subject: [PATCH] Totally rework the way UnsafeProxy does things --- lib/ansible/vars/__init__.py | 7 +- lib/ansible/vars/unsafe_proxy.py | 115 +++++-------------------------- 2 files changed, 20 insertions(+), 102 deletions(-) diff --git a/lib/ansible/vars/__init__.py b/lib/ansible/vars/__init__.py index fd9bcb73847..c37f2963881 100644 --- a/lib/ansible/vars/__init__.py +++ b/lib/ansible/vars/__init__.py @@ -44,7 +44,7 @@ from ansible.utils.debug import debug from ansible.utils.listify import listify_lookup_plugin_terms from ansible.utils.vars import combine_vars from ansible.vars.hostvars import HostVars -from ansible.vars.unsafe_proxy import UnsafeProxy +from ansible.vars.unsafe_proxy import wrap_var VARIABLE_CACHE = dict() HOSTVARS_CACHE = dict() @@ -243,10 +243,7 @@ class VariableManager: # finally, the facts caches for this host, if it exists try: - host_facts = self._fact_cache.get(host.name, dict()) - for k in host_facts.keys(): - if host_facts[k] is not None and not isinstance(host_facts[k], UnsafeProxy): - host_facts[k] = UnsafeProxy(host_facts[k]) + host_facts = wrap_var(self._fact_cache.get(host.name, dict())) all_vars = combine_vars(all_vars, host_facts) except KeyError: pass diff --git a/lib/ansible/vars/unsafe_proxy.py b/lib/ansible/vars/unsafe_proxy.py index 04d5a5dcc82..9d39af565b0 100644 --- a/lib/ansible/vars/unsafe_proxy.py +++ b/lib/ansible/vars/unsafe_proxy.py @@ -50,116 +50,37 @@ # http://code.activestate.com/recipes/496741-object-proxying/ # Author: Tomer Filiba -__all__ = ['UnsafeProxy', 'wrap_var'] +__all__ = ['UnsafeProxy', 'AnsibleUnsafe', 'wrap_var'] -class UnsafeProxy(object): - __slots__ = ["_obj", "__weakref__"] - def __init__(self, obj): - object.__setattr__(self, "_obj", obj) - - # - # proxying (special cases) - # - def __getattribute__(self, name): - if name == '_obj': - return object.__getattribute__(self, "_obj") - elif name == '__reduce_ex__': - return object.__getattribute__(self, "__reduce_ex__") - elif name == '__UNSAFE__': - return True - else: - return getattr(object.__getattribute__(self, "_obj"), name) +import __builtin__ - def __eq__(self, obj): - ''' - special handling for == due to the fact that int objects do - not define it, so trying to guess whether we should or should - not override object.__eq__ with the wrapped classes version - causes problems - ''' - return object.__getattribute__(self, "_obj") == obj +class AnsibleUnsafe(object): + __UNSAFE__ = True - def __delattr__(self, name): - delattr(object.__getattribute__(self, "_obj"), name) - def __setattr__(self, name, value): - setattr(object.__getattribute__(self, "_obj"), name, value) - - def __nonzero__(self): - return bool(object.__getattribute__(self, "_obj")) - def __str__(self): - #import epdb; epdb.st() - return str(object.__getattribute__(self, "_obj")) - def __unicode__(self): - #import epdb; epdb.st() - return unicode(object.__getattribute__(self, "_obj")) - def __repr__(self): - return repr(object.__getattribute__(self, "_obj")) +class AnsibleUnsafeStr(str, AnsibleUnsafe): + pass - def __reduce_ex__(self, protocol): - return (UnsafeProxy, (self._obj,)) +class AnsibleUnsafeUnicode(unicode, AnsibleUnsafe): + pass - # - # factories - # - _special_names = [ - '__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__', - '__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__', - '__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__', - '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__', - '__idiv__', '__idivmod__', '__ifloordiv__', '__ilshift__', '__imod__', - '__imul__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__', - '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', - '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', - '__neg__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', - '__rdiv__', '__rdivmod__', '__repr__', '__reversed__', '__rfloordiv__', - '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', - '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setitem__', - '__setslice__', '__sub__', '__truediv__', '__xor__', 'next', - ] - - @classmethod - def _create_class_proxy(cls, theclass): - """creates a proxy for the given class""" - - def make_method(name): - def method(self, *args, **kw): - return getattr(object.__getattribute__(self, "_obj"), name)(*args, **kw) - return method - - namespace = {} - for name in cls._special_names: - if hasattr(theclass, name) and not hasattr(cls, name): - namespace[name] = make_method(name) - return type("%s(%s)" % (cls.__name__, theclass.__name__), (cls,), namespace) - +class UnsafeProxy(object): def __new__(cls, obj, *args, **kwargs): - """ - creates an proxy instance referencing `obj`. (obj, *args, **kwargs) are - passed to this class' __init__, so deriving classes can define an - __init__ method of their own. - note: _class_proxy_cache is unique per deriving class (each deriving - class must hold its own cache) - """ - try: - cache = cls.__dict__["_class_proxy_cache"] - except KeyError: - cls._class_proxy_cache = cache = {} - try: - theclass = cache[obj.__class__] - except KeyError: - cache[obj.__class__] = theclass = cls._create_class_proxy(obj.__class__) - ins = object.__new__(theclass) - return ins + if obj.__class__ == unicode: + return AnsibleUnsafeUnicode(obj) + elif obj.__class__ == str: + return AnsibleUnsafeStr(obj) + else: + return obj def _wrap_dict(v): for k in v.keys(): - if v[k] is not None and not isinstance(v[k], UnsafeProxy): + if v[k] is not None: v[k] = wrap_var(v[k]) return v def _wrap_list(v): for idx, item in enumerate(v): - if item is not None and not isinstance(item, UnsafeProxy): + if item is not None: v[idx] = wrap_var(item) return v @@ -169,7 +90,7 @@ def wrap_var(v): elif isinstance(v, list): v = _wrap_list(v) else: - if v is not None and not isinstance(v, UnsafeProxy): + if v is not None and not isinstance(v, AnsibleUnsafe): v = UnsafeProxy(v) return v