Skip to content

[5.0] Update core.cache.backends, add RedisCache and related classes #1948

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions django-stubs/core/cache/backends/base.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections.abc import Callable, Iterable, Iterator
from re import Pattern
from typing import Any

from django.core.exceptions import ImproperlyConfigured
Expand Down Expand Up @@ -66,4 +67,6 @@ class BaseCache:
def close(self, **kwargs: Any) -> None: ...
async def aclose(self, **kwargs: Any) -> None: ...

memcached_error_chars_re: Pattern[str]

def memcache_key_warnings(key: str) -> Iterator[str]: ...
55 changes: 55 additions & 0 deletions django-stubs/core/cache/backends/redis.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from collections.abc import Mapping
from datetime import timedelta
from typing import Any, Callable, Iterable, Protocol, SupportsInt, overload, type_check_only

from _typeshed import ReadableBuffer
from django.core.cache.backends.base import BaseCache
from redis._parsers import BaseParser
from redis.client import Redis
from redis.connection import ConnectionPool
from typing_extensions import TypeAlias

@type_check_only
class _RedisCacheClientSerializer(Protocol):
def dumps(self, obj: Any) -> bytes: ...
@overload
def loads(self, data: SupportsInt) -> int: ...
@overload
def loads(self, data: ReadableBuffer) -> Any: ...
Comment on lines +15 to +18
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to define a more simple signature

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by "more simple"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just worried it might be painful to implement such a protocol if RedisCacheClient.serializer is explicitly specified, but this isn't that big of a concern

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most users would just opt to subclass the existing RedisSerializer concrete class.


class RedisSerializer:
def __init__(self, protocol: int | None = None) -> None: ...
def dumps(self, obj: Any) -> bytes: ...
@overload
def loads(self, data: SupportsInt) -> int: ...
@overload
def loads(self, data: ReadableBuffer) -> Any: ...

# Taken from https://github.com/redis/redis-py/blob/6b8978/redis/typing.py
_Key: TypeAlias = str | bytes | memoryview
_Expiry: TypeAlias = int | timedelta

class RedisCacheClient:
def __init__(
self,
servers: list[str],
serializer: str | Callable[[], _RedisCacheClientSerializer] | _RedisCacheClientSerializer | None = None,
pool_class: str | type[ConnectionPool] | None = None,
parser_class: str | type[BaseParser] | None = None,
**options: Any,
) -> None: ...
def get_client(self, key: _Key | None = None, *, write: bool = False) -> Redis: ...
def add(self, key: _Key, value: Any, timeout: _Expiry | None) -> bool: ...
def get(self, key: _Key, default: Any) -> Any: ...
def set(self, key: _Key, value: Any, timeout: _Expiry | None) -> None: ...
def touch(self, key: _Key, timeout: _Expiry) -> bool: ...
def delete(self, key: _Key) -> bool: ...
def get_many(self, keys: Iterable[_Key]) -> dict[_Key, Any]: ...
def has_key(self, key: _Key) -> bool: ...
def incr(self, key: _Key, delta: int) -> Any: ...
def set_many(self, data: Mapping[_Key, Any], timeout: _Expiry) -> None: ...
def delete_many(self, keys: Iterable[_Key]) -> None: ...
def clear(self) -> bool: ...

class RedisCache(BaseCache):
def __init__(self, server: str | list[str], params: dict[str, Any]) -> None: ...
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ psycopg2-binary
Django==4.2.7; python_version < '3.10'
Django==5.0.3; python_version >= '3.10'
-e ./ext
-e .[compatible-mypy]
-e .[redis,compatible-mypy]

# Overrides:
mypy==1.9.0
1 change: 1 addition & 0 deletions scripts/stubtest/allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ django.contrib.gis.geometry.json_regex
django.contrib.gis.geometry.wkt_regex
django.contrib.gis.geos.hex_regex
django.contrib.gis.geos.wkt_regex
django.core.cache.backends.base.memcached_error_chars_re
django.core.validators.EmailValidator.domain_regex
django.core.validators.EmailValidator.literal_regex
django.core.validators.EmailValidator.user_regex
Expand Down
2 changes: 0 additions & 2 deletions scripts/stubtest/allowlist_todo_django50.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ django.contrib.sites.migrations.0001_initial
django.contrib.sites.migrations.0002_alter_domain_unique
django.contrib.staticfiles.checks.E005
django.contrib.staticfiles.checks.check_storages
django.core.cache.backends.base.memcached_error_chars_re
django.core.cache.backends.redis
django.core.files.File.open
django.core.files.base.File.open
django.core.handlers.asgi.ASGIHandler.get_script_prefix
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def find_stub_files(name: str) -> List[str]:
# Keep compatible-mypy major.minor version pinned to what we use in CI (requirements.txt)
extras_require = {
"compatible-mypy": ["mypy~=1.9.0"],
"redis": ["redis"],
}

setup(
Expand Down