Skip to content

Commit 3743454

Browse files
proboscisclaude
andcommitted
add lock to ReAwaitable
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent bbfc3d3 commit 3743454

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

returns/primitives/reawaitable.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from functools import wraps
33
from typing import NewType, ParamSpec, TypeVar, cast, final
44

5+
import anyio
6+
57
_ValueType = TypeVar('_ValueType')
68
_AwaitableT = TypeVar('_AwaitableT', bound=Awaitable)
79
_Ps = ParamSpec('_Ps')
@@ -48,10 +50,11 @@ class ReAwaitable:
4850
4951
"""
5052

51-
__slots__ = ('_cache', '_coro')
53+
__slots__ = ('_cache', '_coro', '_lock')
5254

5355
def __init__(self, coro: Awaitable[_ValueType]) -> None:
5456
"""We need just an awaitable to work with."""
57+
self._lock = anyio.Lock()
5558
self._coro = coro
5659
self._cache: _ValueType | _Sentinel = _sentinel
5760

@@ -101,9 +104,10 @@ def __repr__(self) -> str:
101104

102105
async def _awaitable(self) -> _ValueType:
103106
"""Caches the once awaited value forever."""
104-
if self._cache is _sentinel:
105-
self._cache = await self._coro
106-
return self._cache # type: ignore
107+
async with self._lock:
108+
if self._cache is _sentinel:
109+
self._cache = await self._coro
110+
return self._cache # type: ignore
107111

108112

109113
def reawaitable(
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import anyio
2+
import pytest
3+
4+
from returns.primitives.reawaitable import ReAwaitable
5+
6+
7+
async def sample_coro():
8+
await anyio.sleep(0.1)
9+
return "done"
10+
11+
@pytest.mark.anyio
12+
async def test_concurrent_awaitable():
13+
reawaitable = ReAwaitable(sample_coro())
14+
15+
async def await_reawaitable():
16+
return await reawaitable
17+
async with anyio.create_task_group() as tg:
18+
task1 = tg.start_soon(await_reawaitable)
19+
task2 = tg.start_soon(await_reawaitable)
20+

0 commit comments

Comments
 (0)