cachebox 6.2.1__tar.gz → 6.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cachebox-6.2.1 → cachebox-6.2.2}/Cargo.lock +1 -1
- {cachebox-6.2.1 → cachebox-6.2.2}/Cargo.toml +1 -1
- {cachebox-6.2.1 → cachebox-6.2.2}/PKG-INFO +2 -1
- {cachebox-6.2.1 → cachebox-6.2.2}/README.md +1 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/cachebox/_wrappers.py +19 -35
- {cachebox-6.2.1 → cachebox-6.2.2}/cachebox/utils.py +34 -9
- {cachebox-6.2.1 → cachebox-6.2.2}/tests/test_utils.py +121 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/.github/workflows/CI.yml +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/.github/workflows/docs.yml +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/.github/workflows/python-test.yml +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/.gitignore +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/LICENSE +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/LICENSE-THIRD-PARTY +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/build.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/cachebox/__init__.py +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/cachebox/_cachebox.py +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/cachebox/_core.pyi +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/api/impls.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/api/index.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/api/utils.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/getting-started.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/index.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/installation.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/migration.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/docs/tips.md +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/docs/mkdocs.yml +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/pyproject.toml +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/requirements-dev.txt +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/rustfmt.toml +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/alloc.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/bitmask.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/group/generic.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/group/lsx.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/group/mod.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/group/neon.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/group/sse2.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/mod.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/control/tag.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/mod.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/raw.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/scopeguard.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/hashbrown/util.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/internal/alias.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/internal/lazyheap.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/internal/linked_list.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/internal/mod.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/internal/onceinit.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/internal/pickle.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/internal/utils.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/lib.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/macro_rules.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/common.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/fifopolicy.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/lfupolicy.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/lrupolicy.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/mod.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/nopolicy.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/rrpolicy.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/traits.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/ttlpolicy.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/vttlpolicy.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/policies/wrapped.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/base.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/cache.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/fifocache.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/lfucache.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/lrucache.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/mod.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/rrcache.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/ttlcache.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/pyclasses/vttlcache.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/src/typeref.rs +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/tests/__init__.py +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/tests/conftest.py +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/tests/mixins.py +0 -0
- {cachebox-6.2.1 → cachebox-6.2.2}/tests/test_impls.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cachebox
|
|
3
|
-
Version: 6.2.
|
|
3
|
+
Version: 6.2.2
|
|
4
4
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -41,6 +41,7 @@ Project-URL: Homepage, https://github.com/awolverp/cachebox
|
|
|
41
41
|
|
|
42
42
|
[](https://github.com/awolverp/cachebox/blob/main/LICENSE)
|
|
43
43
|
[](https://pepy.tech/projects/cachebox)
|
|
44
|
+
[](https://payrequest.me/ali-pooralijan-awolverp)
|
|
44
45
|
|
|
45
46
|
</div>
|
|
46
47
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
[](https://github.com/awolverp/cachebox/blob/main/LICENSE)
|
|
12
12
|
[](https://pepy.tech/projects/cachebox)
|
|
13
|
+
[](https://payrequest.me/ali-pooralijan-awolverp)
|
|
13
14
|
|
|
14
15
|
</div>
|
|
15
16
|
|
|
@@ -18,8 +18,10 @@ class _Lock:
|
|
|
18
18
|
|
|
19
19
|
def __enter__(self) -> None:
|
|
20
20
|
self.waiters += 1
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
try:
|
|
22
|
+
self._lock.__enter__()
|
|
23
|
+
finally:
|
|
24
|
+
self.waiters -= 1
|
|
23
25
|
|
|
24
26
|
def __exit__(self, *_) -> None:
|
|
25
27
|
self._lock.__exit__(*_)
|
|
@@ -34,8 +36,10 @@ class _AsyncLock:
|
|
|
34
36
|
|
|
35
37
|
async def __aenter__(self) -> None:
|
|
36
38
|
self.waiters += 1
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
try:
|
|
40
|
+
await self._lock.__aenter__()
|
|
41
|
+
finally:
|
|
42
|
+
self.waiters -= 1
|
|
39
43
|
|
|
40
44
|
async def __aexit__(self, *_) -> None:
|
|
41
45
|
await self._lock.__aexit__(*_)
|
|
@@ -102,7 +106,7 @@ def _cached_wrapper_without_lock(
|
|
|
102
106
|
|
|
103
107
|
result = func(*args, **kwds)
|
|
104
108
|
_cache.insert(key, result)
|
|
105
|
-
|
|
109
|
+
misses += 1
|
|
106
110
|
if callback is not None:
|
|
107
111
|
callback(EVENT_MISS, key, result)
|
|
108
112
|
|
|
@@ -159,7 +163,7 @@ def _async_cached_wrapper_without_lock(
|
|
|
159
163
|
# Passing `cachebox__ignore=True` bypasses the cache and
|
|
160
164
|
# calls the function directly.
|
|
161
165
|
if kwds.pop("cachebox__ignore", False):
|
|
162
|
-
return func(*args, **kwds)
|
|
166
|
+
return await func(*args, **kwds)
|
|
163
167
|
|
|
164
168
|
_cache: BaseCacheImpl = cache(args[0]) if cache_is_fn else cache # type: ignore[arg-type]
|
|
165
169
|
key = _make_key(args, kwds)
|
|
@@ -266,17 +270,19 @@ def _cached_wrapper(
|
|
|
266
270
|
except KeyError:
|
|
267
271
|
try:
|
|
268
272
|
result = func(*args, **kwds)
|
|
269
|
-
except
|
|
273
|
+
except BaseException as exc:
|
|
270
274
|
if lock.waiters > 0:
|
|
271
275
|
pending_errors[key] = exc
|
|
276
|
+
|
|
272
277
|
raise
|
|
273
278
|
else:
|
|
274
279
|
_cache[key] = result
|
|
275
280
|
misses += 1
|
|
276
281
|
event = EVENT_MISS
|
|
277
282
|
|
|
278
|
-
|
|
279
|
-
|
|
283
|
+
finally:
|
|
284
|
+
if lock.waiters == 0:
|
|
285
|
+
locks.pop(key, None)
|
|
280
286
|
|
|
281
287
|
if callback is not None:
|
|
282
288
|
callback(event, key, result)
|
|
@@ -319,29 +325,7 @@ def _async_cached_wrapper(
|
|
|
319
325
|
hits = 0
|
|
320
326
|
misses = 0
|
|
321
327
|
|
|
322
|
-
# See _cached_wrapper
|
|
323
328
|
locks: Cache[typing.Hashable, _AsyncLock] = Cache(0)
|
|
324
|
-
|
|
325
|
-
# if lock_type is asyncio.Lock:
|
|
326
|
-
|
|
327
|
-
# async def _get_lock(key: typing.Hashable):
|
|
328
|
-
# return locks.setdefault(key, _AsyncLock(lock_type()))
|
|
329
|
-
|
|
330
|
-
# else:
|
|
331
|
-
# _lock_creation_guard = asyncio.Lock()
|
|
332
|
-
|
|
333
|
-
# async def _get_lock(key: typing.Hashable):
|
|
334
|
-
# lock = locks.get(key)
|
|
335
|
-
# if lock is not None:
|
|
336
|
-
# return lock
|
|
337
|
-
|
|
338
|
-
# async with _lock_creation_guard:
|
|
339
|
-
# lock = locks.get(key)
|
|
340
|
-
# if lock is None:
|
|
341
|
-
# locks[key] = lock = _AsyncLock(lock_type())
|
|
342
|
-
|
|
343
|
-
# return lock
|
|
344
|
-
|
|
345
329
|
pending_errors: dict[typing.Hashable, BaseException] = {}
|
|
346
330
|
|
|
347
331
|
async def _wrapped(*args, **kwds):
|
|
@@ -381,7 +365,7 @@ def _async_cached_wrapper(
|
|
|
381
365
|
except KeyError:
|
|
382
366
|
try:
|
|
383
367
|
result = await func(*args, **kwds)
|
|
384
|
-
except
|
|
368
|
+
except BaseException as exc:
|
|
385
369
|
if lock.waiters > 0:
|
|
386
370
|
pending_errors[key] = exc
|
|
387
371
|
raise
|
|
@@ -389,9 +373,9 @@ def _async_cached_wrapper(
|
|
|
389
373
|
_cache[key] = result
|
|
390
374
|
misses += 1
|
|
391
375
|
event = EVENT_MISS
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
376
|
+
finally:
|
|
377
|
+
if lock.waiters == 0:
|
|
378
|
+
locks.pop(key, None)
|
|
395
379
|
|
|
396
380
|
await _call_async_callback(callback, event, key, result)
|
|
397
381
|
|
|
@@ -73,12 +73,14 @@ def make_key(*args, **kwds) -> typing.Hashable:
|
|
|
73
73
|
if not kwds:
|
|
74
74
|
if len(args) == 1 and type(args[0]) in _FAST_TYPES:
|
|
75
75
|
return args[0]
|
|
76
|
+
|
|
76
77
|
return args
|
|
77
78
|
|
|
78
79
|
key = args + (_KWDS_MARK,)
|
|
79
80
|
for item in kwds.items():
|
|
80
81
|
key += item
|
|
81
|
-
|
|
82
|
+
|
|
83
|
+
return key
|
|
82
84
|
|
|
83
85
|
|
|
84
86
|
def make_hash_key(*args, **kwds) -> int:
|
|
@@ -155,8 +157,13 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
|
|
|
155
157
|
ignore: If ``True``, silently ignores modification attempts; if ``False``, raises
|
|
156
158
|
``TypeError`` when modification is attempted. Default is ``False``.
|
|
157
159
|
"""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
if not isinstance(cls, BaseCacheImpl):
|
|
161
|
+
raise TypeError(
|
|
162
|
+
f"expected a BaseCacheImpl instance, got {type(cls).__name__!r}"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if type(cls) is Frozen:
|
|
166
|
+
raise TypeError("cannot wrap an already-frozen cache")
|
|
160
167
|
|
|
161
168
|
self.__cache = cls
|
|
162
169
|
self.ignore = ignore
|
|
@@ -366,9 +373,16 @@ class Frozen(BaseCacheImpl[KT, VT]): # pragma: no cover
|
|
|
366
373
|
def _cast_lock(
|
|
367
374
|
iscoroutinefunction: bool,
|
|
368
375
|
lock: (
|
|
369
|
-
typing.Type[AbstractContextManager]
|
|
376
|
+
typing.Type[AbstractContextManager]
|
|
377
|
+
| typing.Type[AbstractAsyncContextManager]
|
|
378
|
+
| bool
|
|
379
|
+
| None
|
|
370
380
|
) = True,
|
|
371
|
-
) ->
|
|
381
|
+
) -> (
|
|
382
|
+
typing.Type[AbstractContextManager]
|
|
383
|
+
| typing.Type[AbstractAsyncContextManager]
|
|
384
|
+
| None
|
|
385
|
+
):
|
|
372
386
|
import _thread
|
|
373
387
|
import asyncio
|
|
374
388
|
import threading
|
|
@@ -381,12 +395,18 @@ def _cast_lock(
|
|
|
381
395
|
|
|
382
396
|
if iscoroutinefunction:
|
|
383
397
|
if not hasattr(lock, "__aenter__"):
|
|
384
|
-
raise TypeError(
|
|
398
|
+
raise TypeError(
|
|
399
|
+
"For async functions, you cannot use a regular synchronous lock."
|
|
400
|
+
)
|
|
385
401
|
|
|
386
402
|
return typing.cast(typing.Type[AbstractAsyncContextManager], lock)
|
|
387
403
|
|
|
388
404
|
# threading.Lock, threading.RLock and _thread.allocate_lock are function
|
|
389
|
-
if
|
|
405
|
+
if (
|
|
406
|
+
lock is threading.Lock
|
|
407
|
+
or lock is threading.RLock
|
|
408
|
+
or lock is _thread.allocate_lock
|
|
409
|
+
):
|
|
390
410
|
return typing.cast(typing.Type[AbstractContextManager], lock)
|
|
391
411
|
|
|
392
412
|
if not hasattr(lock, "__enter__"):
|
|
@@ -403,7 +423,10 @@ def cached(
|
|
|
403
423
|
copy_level: int = 1,
|
|
404
424
|
postprocess: _PostProcess | None = postprocess_copy_mutables,
|
|
405
425
|
lock: (
|
|
406
|
-
typing.Type[AbstractContextManager]
|
|
426
|
+
typing.Type[AbstractContextManager]
|
|
427
|
+
| typing.Type[AbstractAsyncContextManager]
|
|
428
|
+
| bool
|
|
429
|
+
| None
|
|
407
430
|
) = True,
|
|
408
431
|
) -> typing.Callable[[FT], FT]:
|
|
409
432
|
"""
|
|
@@ -480,7 +503,9 @@ def cached(
|
|
|
480
503
|
lock_type = _cast_lock(iscoroutinefunction, lock)
|
|
481
504
|
|
|
482
505
|
if not iscoroutinefunction and inspect.iscoroutinefunction(callback):
|
|
483
|
-
raise TypeError(
|
|
506
|
+
raise TypeError(
|
|
507
|
+
"For sync functions, you cannot use a asynchronous callback"
|
|
508
|
+
)
|
|
484
509
|
|
|
485
510
|
if lock_type:
|
|
486
511
|
builder = _async_cached_wrapper if iscoroutinefunction else _cached_wrapper
|
|
@@ -742,3 +742,124 @@ async def test_async_handling_pending_errors():
|
|
|
742
742
|
await calc(1, 2, 3, exception=True)
|
|
743
743
|
|
|
744
744
|
assert await calc(1, 2, 3, exception=False) == 6
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
def test_misses_should_increment_without_lock():
|
|
748
|
+
calls = {"n": 0}
|
|
749
|
+
|
|
750
|
+
@cachebox.cached(cachebox.LRUCache(0), lock=False)
|
|
751
|
+
def f(x):
|
|
752
|
+
calls["n"] += 1
|
|
753
|
+
return x * 2
|
|
754
|
+
|
|
755
|
+
assert f(1) == 2 # miss
|
|
756
|
+
assert f(1) == 2 # hit
|
|
757
|
+
assert f(2) == 4 # miss
|
|
758
|
+
|
|
759
|
+
info = cachebox.get_cached_cache_info(f)
|
|
760
|
+
print(info)
|
|
761
|
+
|
|
762
|
+
assert info.misses == 2
|
|
763
|
+
assert info.hits == 1
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
@pytest.mark.asyncio
|
|
767
|
+
async def test_ignore_path_should_return_awaited_value():
|
|
768
|
+
@cachebox.cached(cachebox.LRUCache(0), lock=False)
|
|
769
|
+
async def f(x):
|
|
770
|
+
await asyncio.sleep(0)
|
|
771
|
+
return x * 2
|
|
772
|
+
|
|
773
|
+
result = await f(
|
|
774
|
+
5,
|
|
775
|
+
cachebox__ignore=True, # type: ignore
|
|
776
|
+
)
|
|
777
|
+
assert not asyncio.iscoroutine(result)
|
|
778
|
+
assert result == 10
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
def test_locks_should_not_leak_on_exception():
|
|
782
|
+
@cachebox.cached(cachebox.LRUCache(0)) # lock پیشفرض True است
|
|
783
|
+
def f(x):
|
|
784
|
+
raise ValueError("boom")
|
|
785
|
+
|
|
786
|
+
for i in range(50):
|
|
787
|
+
with pytest.raises(ValueError):
|
|
788
|
+
f(i)
|
|
789
|
+
|
|
790
|
+
locks_cache = None
|
|
791
|
+
for cell in f.__closure__: # type: ignore
|
|
792
|
+
try:
|
|
793
|
+
val = cell.cell_contents
|
|
794
|
+
except ValueError:
|
|
795
|
+
continue
|
|
796
|
+
|
|
797
|
+
if isinstance(val, cachebox.Cache):
|
|
798
|
+
locks_cache = val
|
|
799
|
+
break
|
|
800
|
+
|
|
801
|
+
assert locks_cache is not None, "We couldn't find locks_cache"
|
|
802
|
+
print("locks length after 50 failing calls:", len(locks_cache))
|
|
803
|
+
|
|
804
|
+
assert len(locks_cache) == 0
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
@pytest.mark.asyncio
|
|
808
|
+
async def test_waiters_should_not_leak_on_cancel():
|
|
809
|
+
started = asyncio.Event()
|
|
810
|
+
release = asyncio.Event()
|
|
811
|
+
|
|
812
|
+
@cachebox.cached(cachebox.LRUCache(0))
|
|
813
|
+
async def f(x):
|
|
814
|
+
started.set()
|
|
815
|
+
await release.wait()
|
|
816
|
+
return x
|
|
817
|
+
|
|
818
|
+
first = asyncio.create_task(f(1))
|
|
819
|
+
await started.wait()
|
|
820
|
+
|
|
821
|
+
second = asyncio.create_task(f(1))
|
|
822
|
+
await asyncio.sleep(0.05)
|
|
823
|
+
|
|
824
|
+
second.cancel()
|
|
825
|
+
with pytest.raises(asyncio.CancelledError):
|
|
826
|
+
await second
|
|
827
|
+
|
|
828
|
+
release.set()
|
|
829
|
+
result = await first
|
|
830
|
+
assert result == 1
|
|
831
|
+
|
|
832
|
+
locks_cache = None
|
|
833
|
+
for cell in f.__closure__: # type: ignore
|
|
834
|
+
try:
|
|
835
|
+
val = cell.cell_contents
|
|
836
|
+
except ValueError:
|
|
837
|
+
continue
|
|
838
|
+
if isinstance(val, cachebox.Cache):
|
|
839
|
+
locks_cache = val
|
|
840
|
+
break
|
|
841
|
+
assert locks_cache is not None
|
|
842
|
+
|
|
843
|
+
print("locks length after cancel scenario:", len(locks_cache))
|
|
844
|
+
assert len(locks_cache) == 0
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
@pytest.mark.asyncio
|
|
848
|
+
async def test_cancelled_error_should_propagate_to_waiters_too():
|
|
849
|
+
gate = asyncio.Event()
|
|
850
|
+
|
|
851
|
+
@cachebox.cached(cachebox.LRUCache(0))
|
|
852
|
+
async def f(x):
|
|
853
|
+
await gate.wait()
|
|
854
|
+
raise asyncio.CancelledError()
|
|
855
|
+
|
|
856
|
+
t1 = asyncio.create_task(f(1))
|
|
857
|
+
t2 = asyncio.create_task(f(1))
|
|
858
|
+
await asyncio.sleep(0.01)
|
|
859
|
+
gate.set()
|
|
860
|
+
|
|
861
|
+
with pytest.raises(asyncio.CancelledError):
|
|
862
|
+
await t1
|
|
863
|
+
|
|
864
|
+
with pytest.raises(asyncio.CancelledError):
|
|
865
|
+
await t2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|