From c5dd748a3bc06b6e7e17797863bb363a2f377a5e Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 5 Jan 2020 18:47:52 -0600 Subject: allow overriding synthesized properties --- src/pyramid/util.py | 23 ++++++++++++++++++++++- tests/test_util.py | 30 ++++++++++++++++-------------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/pyramid/util.py b/src/pyramid/util.py index e552b37de..ca644dcce 100644 --- a/src/pyramid/util.py +++ b/src/pyramid/util.py @@ -73,6 +73,27 @@ def as_sorted_tuple(val): return val +class SettableProperty(object): + def __init__(self, wrapped, name): + self.wrapped = wrapped + self.name = name + functools.update_wrapper(self, wrapped) + + def __get__(self, obj, type=None): + if obj is None: # pragma: no cover + return self + value = obj.__dict__.get(self.name, _marker) + if value is _marker: + value = self.wrapped(obj) + return value + + def __set__(self, obj, value): + obj.__dict__[self.name] = value + + def __delete__(self, obj): + del obj.__dict__[self.name] + + class InstancePropertyHelper(object): """A helper object for assigning properties and descriptors to instances. It is not normally possible to do this because descriptors must be @@ -113,7 +134,7 @@ class InstancePropertyHelper(object): fn = pyramid.decorator.reify(fn) elif not is_property: - fn = property(fn) + fn = SettableProperty(fn, name) return name, fn diff --git a/tests/test_util.py b/tests/test_util.py index 293036c10..1553d8e60 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -103,25 +103,26 @@ class Test_InstancePropertyHelper(unittest.TestCase): ) def test_override_property(self): - def worker(obj): # pragma: no cover + def worker(obj): pass foo = Dummy() helper = self._getTargetClass() helper.set_property(foo, worker, name='x') - - def doit(): - foo.x = 1 - - self.assertRaises(AttributeError, doit) + self.assertIsNone(foo.x) + foo.x = 1 + self.assertEqual(foo.x, 1) + del foo.x + self.assertIsNone(foo.x) def test_override_reify(self): - def worker(obj): # pragma: no cover + def worker(obj): pass foo = Dummy() helper = self._getTargetClass() helper.set_property(foo, worker, name='x', reify=True) + self.assertIsNone(foo.x) foo.x = 1 self.assertEqual(1, foo.x) foo.x = 2 @@ -301,23 +302,24 @@ class Test_InstancePropertyMixin(unittest.TestCase): ) def test_override_property(self): - def worker(obj): # pragma: no cover + def worker(obj): pass foo = self._makeOne() foo.set_property(worker, name='x') - - def doit(): - foo.x = 1 - - self.assertRaises(AttributeError, doit) + self.assertIsNone(foo.x) + foo.x = 1 + self.assertEqual(foo.x, 1) + del foo.x + self.assertIsNone(foo.x) def test_override_reify(self): - def worker(obj): # pragma: no cover + def worker(obj): pass foo = self._makeOne() foo.set_property(worker, name='x', reify=True) + self.assertIsNone(foo.x) foo.x = 1 self.assertEqual(1, foo.x) foo.x = 2 -- cgit v1.2.3