summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Merickel <michael@merickel.org>2020-01-05 18:47:52 -0600
committerMichael Merickel <michael@merickel.org>2020-01-05 18:56:04 -0600
commitc5dd748a3bc06b6e7e17797863bb363a2f377a5e (patch)
tree0646e35718395b3abec0dfa8097aad385890609e
parent148cf5138638ce6b1b92b4e13fe1444df9451e34 (diff)
downloadpyramid-c5dd748a3bc06b6e7e17797863bb363a2f377a5e.tar.gz
pyramid-c5dd748a3bc06b6e7e17797863bb363a2f377a5e.tar.bz2
pyramid-c5dd748a3bc06b6e7e17797863bb363a2f377a5e.zip
allow overriding synthesized properties
-rw-r--r--src/pyramid/util.py23
-rw-r--r--tests/test_util.py30
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