Message398861
Here's the latest effort:
---------------------------------------------------------------
def __get__(self, instance, owner=None):
if instance is None:
return self
if self.attrname is None:
raise TypeError(
"Cannot use cached_property instance without calling __set_name__ on it.")
try:
cache = instance.__dict__
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
msg = (
f"No '__dict__' attribute on {type(instance).__name__!r} "
f"instance to cache {self.attrname!r} property."
)
raise TypeError(msg) from None
# Quickly and atomically determine which thread is reponsible
# for doing the update, so other threads can wait for that
# update to complete. If the update is already done, don't
# wait. If the updating thread is reentrant, don't wait.
key = id(self)
this_thread = get_ident()
with self.updater_lock:
val = cache.get(self.attrname, _NOT_FOUND)
if val is not _NOT_FOUND:
return val
wait = self.updater.setdefault(key, this_thread) != this_thread
# ONLY if this instance currently being updated, block and wait
# for the computed result. Other instances won't have to wait.
# If an exception occurred, stop waiting.
if wait:
with self.cv:
while cache.get(self.attrname, _NOT_FOUND) is _NOT_FOUND:
self.cv.wait()
val = cache[self.attrname]
if val is not _EXCEPTION_RAISED:
return val
# Call the underlying function to compute the value.
try:
val = self.func(instance)
except Exception:
val = _EXCEPTION_RAISED
# Attempt to store the value
try:
cache[self.attrname] = val
except TypeError:
# Note: we have no way to communicate this exception to
# threads waiting on the condition variable. However, the
# inability to store an attribute is a programming problem
# rather than a runtime problem -- this exception would
# likely occur early in testing rather than being runtime
# event triggered by specific data.
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
# Now that the value is stored, threads waiting on the condition
# variable can be awakened and the updater dictionary can be
# cleaned up.
with self.updater_lock:
self.updater.pop(key, None)
cache[self.attrname] = _EXCEPTION_RAISED
self.cv.notify_all()
if val is _EXCEPTION_RAISED:
raise
return val |
|
Date |
User |
Action |
Args |
2021-08-04 05:19:26 | rhettinger | set | recipients:
+ rhettinger, tim.peters, ncoghlan, carljm, pydanny, jab, serhiy.storchaka, ztane, graingert |
2021-08-04 05:19:26 | rhettinger | set | messageid: <1628054366.92.0.193302809619.issue43468@roundup.psfhosted.org> |
2021-08-04 05:19:26 | rhettinger | link | issue43468 messages |
2021-08-04 05:19:26 | rhettinger | create | |
|