diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3e4daa8..d09af185 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: - '4.2' - '5.0' - '5.1' + - '5.2' redis-version: - 'latest' @@ -38,7 +39,7 @@ jobs: python-version: '3.9' # latest Django with pre-release redis - - django-version: '5.1' + - django-version: '5.2' redis-version: 'master' python-version: '3.12' diff --git a/changelog.d/824.misc b/changelog.d/824.misc new file mode 100644 index 00000000..4a6180c1 --- /dev/null +++ b/changelog.d/824.misc @@ -0,0 +1,2 @@ +Confirm support for Django 5.2. +Fix shadowing builtin Python exceptions. diff --git a/django_redis/client/default.py b/django_redis/client/default.py index 940e1a0e..de8f5b2a 100644 --- a/django_redis/client/default.py +++ b/django_redis/client/default.py @@ -21,14 +21,21 @@ from django.core.exceptions import ImproperlyConfigured from django.utils.module_loading import import_string from redis import Redis -from redis.exceptions import ConnectionError, ResponseError, TimeoutError +from redis.exceptions import ConnectionError as RedisConnectionError +from redis.exceptions import ResponseError +from redis.exceptions import TimeoutError as RedisTimeoutError from redis.typing import AbsExpiryT, EncodableT, ExpiryT, KeyT, PatternT from django_redis import pool from django_redis.exceptions import CompressorError, ConnectionInterrupted from django_redis.util import CacheKey -_main_exceptions = (TimeoutError, ResponseError, ConnectionError, socket.timeout) +_main_exceptions = ( + RedisConnectionError, + RedisTimeoutError, + ResponseError, + socket.timeout, +) special_re = re.compile("([*?[])") @@ -1001,7 +1008,7 @@ def sscan( cursor, result = client.sscan( key, - match=cast(PatternT, self.encode(match)) if match else None, + match=cast("PatternT", self.encode(match)) if match else None, count=count, ) return {self.decode(value) for value in result} @@ -1024,7 +1031,7 @@ def sscan_iter( key = self.make_key(key, version=version) for value in client.sscan_iter( key, - match=cast(PatternT, self.encode(match)) if match else None, + match=cast("PatternT", self.encode(match)) if match else None, count=count, ): yield self.decode(value) diff --git a/django_redis/client/herd.py b/django_redis/client/herd.py index c5c6d7d8..e812e2e1 100644 --- a/django_redis/client/herd.py +++ b/django_redis/client/herd.py @@ -4,12 +4,19 @@ from collections import OrderedDict from django.conf import settings -from redis.exceptions import ConnectionError, ResponseError, TimeoutError +from redis.exceptions import ConnectionError as RedisConnectionError +from redis.exceptions import ResponseError +from redis.exceptions import TimeoutError as RedisTimeoutError from django_redis.client.default import DEFAULT_TIMEOUT, DefaultClient from django_redis.exceptions import ConnectionInterrupted -_main_exceptions = (ConnectionError, ResponseError, TimeoutError, socket.timeout) +_main_exceptions = ( + RedisConnectionError, + RedisTimeoutError, + ResponseError, + socket.timeout, +) class Marker: diff --git a/django_redis/client/sharded.py b/django_redis/client/sharded.py index 5e2eec90..941a8a40 100644 --- a/django_redis/client/sharded.py +++ b/django_redis/client/sharded.py @@ -4,7 +4,7 @@ from typing import Any, Iterator, List, Optional, Set, Union from redis import Redis -from redis.exceptions import ConnectionError +from redis.exceptions import ConnectionError as RedisConnectionError from redis.typing import KeyT from django_redis.client.default import DEFAULT_TIMEOUT, DefaultClient @@ -130,7 +130,7 @@ def has_key(self, key, version=None, client=None): key = self.make_key(key, version=version) try: return client.exists(key) == 1 - except ConnectionError as e: + except RedisConnectionError as e: raise ConnectionInterrupted(connection=client) from e def delete(self, key, version=None, client=None): @@ -256,7 +256,7 @@ def incr_version(self, key, delta=1, version=None, client=None): try: ttl = self.ttl(old_key, version=version, client=client) - except ConnectionError as e: + except RedisConnectionError as e: raise ConnectionInterrupted(connection=client) from e if value is None: @@ -296,7 +296,7 @@ def keys(self, search, version=None): try: for connection in self._serverdict.values(): keys.extend(connection.keys(pattern)) - except ConnectionError as e: + except RedisConnectionError as e: # FIXME: technically all clients should be passed as `connection`. client = self.get_server(pattern) raise ConnectionInterrupted(connection=client) from e diff --git a/setup.cfg b/setup.cfg index 98dbf56a..f7acd774 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,6 +15,7 @@ classifiers = Framework :: Django :: 4.2 Framework :: Django :: 5.0 Framework :: Django :: 5.1 + Framework :: Django :: 5.2 Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: OS Independent @@ -59,10 +60,10 @@ envlist = mypy # tests against released versions py{38,39}-dj{42}-redislatest - py{310,311,312}-dj{42,50,51}-redislatest + py{310,311,312}-dj{42,50,51,52}-redislatest # tests against unreleased versions - py311-dj51-redismaster - py311-djmain-redis{latest,master} + py312-dj52-redismaster + py312-djmain-redis{latest,master} [gh-actions] python = @@ -77,6 +78,7 @@ DJANGO = 4.2: dj42 5.0: dj50 5.1: dj51 + 5.2: dj52 main: djmain REDIS = latest: redislatest @@ -91,6 +93,7 @@ deps = dj42: Django>=4.2,<5.0 dj50: Django>=5.0,<5.1 dj51: Django>=5.1,<5.2 + dj52: Django>=5.2,<6.0 djmain: https://github.com/django/django/archive/main.tar.gz msgpack>=0.6.0 pytest diff --git a/tests/test_backend.py b/tests/test_backend.py index 193d6b23..65d97fed 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -300,7 +300,7 @@ def test_delete_many_generator(self, cache: RedisCache): assert bool(res) is False def test_delete_many_empty_generator(self, cache: RedisCache): - res = cache.delete_many(key for key in cast(List[str], [])) + res = cache.delete_many(key for key in cast("List[str]", [])) assert bool(res) is False def test_incr(self, cache: RedisCache): @@ -749,7 +749,7 @@ def test_primary_replica_switching(self, cache: RedisCache): if isinstance(cache.client, ShardClient): pytest.skip("ShardClient doesn't support get_client") - cache = cast(RedisCache, caches["sample"]) + cache = cast("RedisCache", caches["sample"]) client = cache.client client._server = ["foo", "bar"] client._clients = ["Foo", "Bar"] @@ -761,7 +761,7 @@ def test_primary_replica_switching_with_index(self, cache: RedisCache): if isinstance(cache.client, ShardClient): pytest.skip("ShardClient doesn't support get_client") - cache = cast(RedisCache, caches["sample"]) + cache = cast("RedisCache", caches["sample"]) client = cache.client client._server = ["foo", "bar"] client._clients = ["Foo", "Bar"] diff --git a/tests/test_cache_options.py b/tests/test_cache_options.py index 6f16376b..31461eef 100644 --- a/tests/test_cache_options.py +++ b/tests/test_cache_options.py @@ -4,7 +4,7 @@ import pytest from django.core.cache import caches from pytest import LogCaptureFixture -from redis.exceptions import ConnectionError +from redis.exceptions import ConnectionError as RedisConnectionError from django_redis.cache import RedisCache from django_redis.client import ShardClient @@ -26,7 +26,7 @@ def ignore_exceptions_cache(settings) -> RedisCache: settings.CACHES = caches_setting settings.DJANGO_REDIS_IGNORE_EXCEPTIONS = True settings.DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True - return cast(RedisCache, caches["doesnotexist"]) + return cast("RedisCache", caches["doesnotexist"]) def test_get_django_omit_exceptions_many_returns_default_arg( @@ -58,7 +58,7 @@ def test_get_django_omit_exceptions_priority_1(settings): caches_setting["doesnotexist"]["OPTIONS"]["IGNORE_EXCEPTIONS"] = True settings.CACHES = caches_setting settings.DJANGO_REDIS_IGNORE_EXCEPTIONS = False - cache = cast(RedisCache, caches["doesnotexist"]) + cache = cast("RedisCache", caches["doesnotexist"]) assert cache._ignore_exceptions is True assert cache.get("key") is None @@ -68,9 +68,9 @@ def test_get_django_omit_exceptions_priority_2(settings): caches_setting["doesnotexist"]["OPTIONS"]["IGNORE_EXCEPTIONS"] = False settings.CACHES = caches_setting settings.DJANGO_REDIS_IGNORE_EXCEPTIONS = True - cache = cast(RedisCache, caches["doesnotexist"]) + cache = cast("RedisCache", caches["doesnotexist"]) assert cache._ignore_exceptions is False - with pytest.raises(ConnectionError): + with pytest.raises(RedisConnectionError): cache.get("key") @@ -84,7 +84,7 @@ def key_prefix_cache(cache: RedisCache, settings) -> Iterable[RedisCache]: @pytest.fixture def with_prefix_cache() -> Iterable[RedisCache]: - with_prefix = cast(RedisCache, caches["with_prefix"]) + with_prefix = cast("RedisCache", caches["with_prefix"]) yield with_prefix with_prefix.clear()