diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2023-07-05 23:31:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-05 23:31:54 (GMT) |
commit | 7b615a1573b8a119e8ad27915912da745756a547 (patch) | |
tree | f854d9b388f6fd0dcd1aabbd6e08bf1ec38f2c9a /Lib | |
parent | bb17e6f5de2bca85746a06d504029f90e85e3892 (diff) | |
download | cpython-7b615a1573b8a119e8ad27915912da745756a547.zip cpython-7b615a1573b8a119e8ad27915912da745756a547.tar.gz cpython-7b615a1573b8a119e8ad27915912da745756a547.tar.bz2 |
[3.12] gh-106292: restore checking __dict__ in cached_property.__get__ (GH-106380) (#106469)
gh-106292: restore checking __dict__ in cached_property.__get__ (GH-106380)
* gh-106292: restore checking __dict__ in cached_property.__get__
(cherry picked from commit 838406b4fc044c0b2f397c23275c69f16a76205b)
Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Dong-hee Na <donghee.na92@gmail.com>
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/functools.py | 23 | ||||
-rw-r--r-- | Lib/test/test_functools.py | 19 |
2 files changed, 32 insertions, 10 deletions
diff --git a/Lib/functools.py b/Lib/functools.py index 72b2103..2ae4290 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -956,9 +956,10 @@ class singledispatchmethod: ################################################################################ -### cached_property() - computed once per instance, cached as attribute +### cached_property() - property result cached as instance attribute ################################################################################ +_NOT_FOUND = object() class cached_property: def __init__(self, func): @@ -989,15 +990,17 @@ class cached_property: f"instance to cache {self.attrname!r} property." ) raise TypeError(msg) from None - val = self.func(instance) - try: - cache[self.attrname] = val - except TypeError: - msg = ( - f"The '__dict__' attribute on {type(instance).__name__!r} instance " - f"does not support item assignment for caching {self.attrname!r} property." - ) - raise TypeError(msg) from None + val = cache.get(self.attrname, _NOT_FOUND) + if val is _NOT_FOUND: + val = self.func(instance) + try: + cache[self.attrname] = val + except TypeError: + msg = ( + f"The '__dict__' attribute on {type(instance).__name__!r} instance " + f"does not support item assignment for caching {self.attrname!r} property." + ) + raise TypeError(msg) from None return val __class_getitem__ = classmethod(GenericAlias) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index d668fa4..c4eca0f 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -3037,6 +3037,25 @@ class TestCachedProperty(unittest.TestCase): def test_doc(self): self.assertEqual(CachedCostItem.cost.__doc__, "The cost of the item.") + def test_subclass_with___set__(self): + """Caching still works for a subclass defining __set__.""" + class readonly_cached_property(py_functools.cached_property): + def __set__(self, obj, value): + raise AttributeError("read only property") + + class Test: + def __init__(self, prop): + self._prop = prop + + @readonly_cached_property + def prop(self): + return self._prop + + t = Test(1) + self.assertEqual(t.prop, 1) + t._prop = 999 + self.assertEqual(t.prop, 1) + if __name__ == '__main__': unittest.main() |