gh-106292: restore checking __dict__ in cached_property.__get__ (#106380)

* gh-106292: restore checking __dict__ in cached_property.__get__

Co-authored-by: Dong-hee Na <donghee.na92@gmail.com>
This commit is contained in:
Carl Meyer 2023-07-05 17:01:35 -06:00 committed by GitHub
parent 217f47d6e5
commit 838406b4fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 10 deletions

View file

@ -957,9 +957,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):
@ -990,6 +991,8 @@ class cached_property:
f"instance to cache {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

View file

@ -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()

View file

@ -0,0 +1,4 @@
Check for an instance-dict cached value in the :meth:`__get__` method of
:func:`functools.cached_property`. This better matches the pre-3.12 behavior
and improves compatibility for users subclassing
:func:`functools.cached_property` and adding a :meth:`__set__` method.