@@ -66,25 +66,25 @@ def __repr__(self) -> str:
6666 return f"{ self .__class__ .__name__ } ({ self .value !r} )"
6767
6868
69- class _FutureCachedValue (Generic [R , T ]):
70- """A placeholder object to control concurrent access to a cached awaitable value.
69+ class _FutureCachedPropertyValue (Generic [R , T ]):
70+ """
71+ A placeholder object to control concurrent access to a cached awaitable value
7172
7273 When given a lock to coordinate access, only the first task to await on a
7374 cached property triggers the underlying coroutine. Once a value has been
7475 produced, all tasks are unblocked and given the same, single value.
75-
7676 """
7777
78- __slots__ = ("_get_attribute " , "_instance" , "_name" , "_lock" )
78+ __slots__ = ("_func " , "_instance" , "_name" , "_lock" )
7979
8080 def __init__ (
8181 self ,
82- get_attribute : Callable [[T ], Coroutine [ Any , Any , R ]],
82+ func : Callable [[T ], Awaitable [ R ]],
8383 instance : T ,
8484 name : str ,
8585 lock : AsyncContextManager [Any ],
8686 ):
87- self ._get_attribute = get_attribute
87+ self ._func = func
8888 self ._instance = instance
8989 self ._name = name
9090 self ._lock = lock
@@ -116,12 +116,17 @@ async def _await_impl(self) -> R:
116116 # the instance attribute is still this placeholder, and we
117117 # hold the lock. Start the getter to store the value on the
118118 # instance and return the value.
119- return await self ._get_attribute (self . _instance )
119+ return await self ._get_attribute ()
120120
121121 # another task produced a value, or the instance.__dict__ object was
122122 # deleted in the interim.
123123 return await stored
124124
125+ async def _get_attribute (self ) -> R :
126+ value = await self ._func (self ._instance )
127+ self ._instance .__dict__ [self ._name ] = AwaitableValue (value )
128+ return value
129+
125130 def __repr__ (self ) -> str :
126131 return (
127132 f"<{ type (self ).__name__ } for '{ type (self ._instance ).__name__ } ."
@@ -176,19 +181,12 @@ def __get__(
176181 # on this instance. It takes care of coordinating between different
177182 # tasks awaiting on the placeholder until the cached value has been
178183 # produced.
179- wrapper = _FutureCachedValue (
180- self ._get_attribute , instance , name , self ._asynccontextmanager_type ()
184+ wrapper = _FutureCachedPropertyValue (
185+ self .func , instance , name , self ._asynccontextmanager_type ()
181186 )
182187 cache [name ] = wrapper
183188 return wrapper
184189
185- async def _get_attribute (self , instance : T ) -> R :
186- value = await self .func (instance )
187- name = self .attrname
188- assert name is not None # enforced in __get__
189- instance .__dict__ [name ] = AwaitableValue (value )
190- return value
191-
192190
193191def cached_property (
194192 type_or_getter : Union [Type [AsyncContextManager [Any ]], Callable [[T ], Awaitable [R ]]],
0 commit comments