Skip to content

Commit f1e9dbd

Browse files
committed
fix(async): make wrapper clear methods await-safe for coroutine-decorated functions
clear_cache/clear_being_calculated on async-decorated wrappers previously returned None, so await func.clear_cache() raised TypeError. Return an immediate awaitable for coroutine wrappers while preserving existing sync usage, and add a regression test covering both sync and awaited calls.
1 parent be4dd10 commit f1e9dbd

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

src/cachier/core.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@
3535
ZERO_TIMEDELTA = timedelta(seconds=0)
3636

3737

38+
class _ImmediateAwaitable:
39+
"""Lightweight awaitable that yields an immediate value."""
40+
41+
def __init__(self, value: Any = None) -> None:
42+
self._value = value
43+
44+
def __await__(self):
45+
if False:
46+
yield None
47+
return self._value
48+
49+
3850
def _max_workers():
3951
return int(os.environ.get(MAX_WORKERS_ENVAR_NAME, DEFAULT_MAX_WORKERS))
4052

@@ -593,10 +605,16 @@ def func_wrapper(*args, **kwargs):
593605
def _clear_cache():
594606
"""Clear the cache."""
595607
core.clear_cache()
608+
if is_coroutine:
609+
return _ImmediateAwaitable()
610+
return None
596611

597612
def _clear_being_calculated():
598613
"""Mark all entries in this cache as not being calculated."""
599614
core.clear_being_calculated()
615+
if is_coroutine:
616+
return _ImmediateAwaitable()
617+
return None
600618

601619
async def _aclear_cache():
602620
"""Clear the cache asynchronously."""

tests/test_async_core.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,27 @@ def sync_func(x):
358358
await sync_func.aclear_cache()
359359

360360

361+
@pytest.mark.memory
362+
@pytest.mark.asyncio
363+
class TestAsyncWrapperMaintenanceMethods:
364+
"""Tests for clear helpers exposed on async wrappers."""
365+
366+
async def test_clear_methods_are_await_safe(self):
367+
"""Async wrappers support both sync and awaited clear_cache usage."""
368+
369+
@cachier(backend="memory")
370+
async def async_func(x):
371+
return x
372+
373+
# Legacy sync usage should keep working.
374+
async_func.clear_cache()
375+
async_func.clear_being_calculated()
376+
377+
# Awaiting these methods should also work.
378+
await async_func.clear_cache()
379+
await async_func.clear_being_calculated()
380+
381+
361382
# =============================================================================
362383
# Argument Handling Tests
363384
# =============================================================================

0 commit comments

Comments
 (0)