Skip to content

Commit

Permalink
[#35] Since 3.8, CancelledError is a subclass of BaseException rather…
Browse files Browse the repository at this point in the history
… than Exception, so we need to catch it explicitly.
  • Loading branch information
zmumi committed Oct 4, 2024
1 parent 0b720c9 commit fe90d32
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 3 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
3.1.1
-----

* Since 3.8, CancelledError is a subclass of BaseException rather than Exception, so we need to catch it explicitly.

3.1.0
-----

Expand Down
4 changes: 2 additions & 2 deletions memoize/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import datetime
import functools
import logging
from asyncio import Future
from asyncio import Future, CancelledError
from typing import Optional, Callable

from memoize.configuration import CacheConfiguration, NotConfiguredCacheCalledException, \
Expand Down Expand Up @@ -116,7 +116,7 @@ async def refresh(actual_entry: Optional[CacheEntry], key: CacheKey,
logger.debug('Timeout for %s: %s', key, e)
update_statuses.mark_update_aborted(key, e)
raise CachedMethodFailedException('Refresh timed out') from e
except Exception as e:
except (Exception, CancelledError) as e:
logger.debug('Error while refreshing cache for %s: %s', key, e)
update_statuses.mark_update_aborted(key, e)
raise CachedMethodFailedException('Refresh failed to complete') from e
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def prepare_description():

setup(
name='py-memoize',
version='3.1.0',
version='3.1.1',
author='Michal Zmuda',
author_email='[email protected]',
url='https://github.com/DreamLab/memoize',
Expand Down
32 changes: 32 additions & 0 deletions tests/end2end/test_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import time
from asyncio import CancelledError
from datetime import timedelta
from unittest.mock import Mock

Expand Down Expand Up @@ -174,6 +175,37 @@ async def get_value(arg, kwarg=None):
assert context.value.__class__ == CachedMethodFailedException
assert str(context.value.__cause__) == str(ValueError('stub0'))

async def test_should_return_cancelled_exception_for_all_concurrent_callers(self):
# given
value = 0

@memoize()
async def get_value(arg, kwarg=None):
new_task = asyncio.create_task(asyncio.sleep(1))
new_task.cancel() # this will raise CancelledError
await new_task

# when
res1 = get_value('test', kwarg='args1')
res2 = get_value('test', kwarg='args1')
res3 = get_value('test', kwarg='args1')

# then
with pytest.raises(Exception) as context:
await res1
assert context.value.__class__ == CachedMethodFailedException
assert str(context.value.__cause__) == str(CancelledError())

with pytest.raises(Exception) as context:
await res2
assert context.value.__class__ == CachedMethodFailedException
assert str(context.value.__cause__) == str(CancelledError())

with pytest.raises(Exception) as context:
await res3
assert context.value.__class__ == CachedMethodFailedException
assert str(context.value.__cause__) == str(CancelledError())

async def test_should_return_timeout_for_all_concurrent_callers(self):
# given
value = 0
Expand Down

0 comments on commit fe90d32

Please sign in to comment.