From 43bd3cd55952938176d7c5820f5fcabf25d36ec3 Mon Sep 17 00:00:00 2001 From: Graham Dumpleton Date: Sat, 21 Sep 2013 21:16:20 +1000 Subject: [PATCH] Raise TypeError when attempt to delete __wrapped__ on pure Python implementation and del/update __qualname__ when __wrapped__ set. --- src/wrappers.py | 23 +++++++++++++++++++++-- tests/test_object_proxy.py | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/wrappers.py b/src/wrappers.py index 171cb36..125f507 100644 --- a/src/wrappers.py +++ b/src/wrappers.py @@ -129,11 +129,25 @@ class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): return bool(self.__wrapped__) def __setattr__(self, name, value): - if name.startswith('_self_') or name == '__wrapped__': + if name.startswith('_self_'): object.__setattr__(self, name, value) + + elif name == '__wrapped__': + object.__setattr__(self, name, value) + try: + object.__delattr__(self, '__qualname__') + except AttributeError: + pass + object.__setattr__(self, name, value) + try: + object.__setattr__(self, '__qualname__', value.__qualname__) + except AttributeError: + pass + elif name == '__qualname__': setattr(self.__wrapped__, name, value) object.__setattr__(self, name, value) + else: setattr(self.__wrapped__, name, value) @@ -141,11 +155,16 @@ class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): return getattr(self.__wrapped__, name) def __delattr__(self, name): - if name.startswith('_self_') or name == '__wrapped__': + if name.startswith('_self_'): object.__delattr__(self, name) + + elif name == '__wrapped__': + raise TypeError('__wrapped__ must be an object') + elif name == '__qualname__': object.__delattr__(self, name) delattr(self.__wrapped__, name) + else: delattr(self.__wrapped__, name) diff --git a/tests/test_object_proxy.py b/tests/test_object_proxy.py index 11809d5..ca4c900 100644 --- a/tests/test_object_proxy.py +++ b/tests/test_object_proxy.py @@ -51,14 +51,46 @@ class TestAttributeAccess(unittest.TestCase): return args, kwargs function2 = wrapt.ObjectProxy(function1) + self.assertEqual(function2, function1) self.assertEqual(function2.__wrapped__, function1) + self.assertEqual(function2.__name__, function1.__name__) + + if six.PY3: + self.assertEqual(function2.__qualname__, function1.__qualname__) function2.__wrapped__ = None - self.assertEqual(function2.__wrapped__, None) - self.assertFalse(hasattr(function1, '__wrapped__')) + self.assertEqual(function2, None) + self.assertEqual(function2.__wrapped__, None) + self.assertFalse(hasattr(function2, '__name__')) + + if six.PY3: + self.assertFalse(hasattr(function2, '__qualname__')) + + def function3(*args, **kwargs): + return args, kwargs + + function2.__wrapped__ = function3 + + self.assertEqual(function2, function3) + self.assertEqual(function2.__wrapped__, function3) + self.assertEqual(function2.__name__, function3.__name__) + + if six.PY3: + self.assertEqual(function2.__qualname__, function3.__qualname__) + + def test_delete_wrapped(self): + def function1(*args, **kwargs): + return args, kwargs + function2 = wrapt.ObjectProxy(function1) + + def run(*args): + del function2.__wrapped__ + + self.assertRaises(TypeError, run, ()) + def test_proxy_attribute(self): def function1(*args, **kwargs): return args, kwargs