Skip to content

Commit 8934e2c

Browse files
committed
Merge branch 'master' into dragonfly-tests
2 parents 06564cf + f85cccb commit 8934e2c

File tree

10 files changed

+388
-321
lines changed

10 files changed

+388
-321
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,29 @@ jobs:
3434
- "valkey/valkey:8.1.3"
3535
- "redis:6.2.17"
3636
python-version: ["3.9", "3.12", "3.13", "3.14"]
37-
redis-py: ["4.6.0", "5.3.1", "6.4.0", "7.1.0"]
37+
redis-py: ["4.6.0", "5.3.1", "6.4.0", "7.2.0"]
3838
install-extras: [false]
3939
coverage: [false]
4040
exclude:
4141
- python-version: "3.9"
42-
redis-py: "7.1.0"
42+
redis-py: "7.2.0"
4343
- python-version: "3.13"
4444
redis-image: "redis:8.4.0"
45-
redis-py: "7.1.0"
45+
redis-py: "7.2.0"
4646
install-extras: false
4747
coverage: false
4848
include:
4949
- python-version: "3.13"
5050
redis-image: "redis/redis-stack-server:6.2.6-v20"
51-
redis-py: "7.1.0"
51+
redis-py: "7.2.0"
5252
install-extras: true
5353
- python-version: "3.13"
5454
redis-image: "redis/redis-stack-server:7.4.0-v3"
55-
redis-py: "7.1.0"
55+
redis-py: "7.2.0"
5656
install-extras: true
5757
- python-version: "3.13"
5858
redis-image: "redis:8.4.0"
59-
redis-py: "7.1.0"
59+
redis-py: "7.2.0"
6060
install-extras: true
6161
coverage: true
6262
permissions:

docs/about/changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ tags:
77
toc_depth: 2
88
---
99

10+
## v2.34.1
11+
12+
### 🐛 Bug Fixes
13+
14+
- Fix handling of deprecated arguments in `FakeRedis` to support redis-py 7.2.0 #457
15+
- Blocking `XREAD` with `block=0` works as expected #453
16+
1017
## v2.34.0
1118

1219
### 🚀 Features

fakeredis/_connection.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import redis
66

77
from fakeredis._fakesocket import FakeSocket
8-
from fakeredis._helpers import FakeSelector, convert_args_to_redis_init_kwargs
8+
from fakeredis._helpers import FakeSelector, convert_args_kwargs
99
from . import _msgs as msgs
1010
from ._server import FakeBaseConnectionMixin, FakeServer
1111
from ._typing import Self, lib_version, RaiseErrorTypes, VersionType, ServerType
@@ -110,7 +110,7 @@ def __init__(
110110
:param lua_modules: A set of Lua modules to load.
111111
:param client_class: The Redis client class to use, e.g., redis.Redis or valkey.Valkey.
112112
"""
113-
kwds = convert_args_to_redis_init_kwargs(client_class, *args, **kwargs)
113+
kwds = convert_args_kwargs(client_class, *args, **kwargs)
114114
kwds["server"] = server
115115
if not kwds.get("connection_pool", None):
116116
charset = kwds.get("charset", None)
@@ -154,9 +154,13 @@ def __init__(
154154
kwds.pop("version", None)
155155
kwds.pop("server_type", None)
156156
kwds.pop("lua_modules", None)
157-
if "lib_name" in kwds and "lib_version" in kwds:
157+
if "lib_name" in kwds and "lib_version" in kwds and "driver_info" not in kwds:
158158
kwds["lib_name"] = "fakeredis"
159159
kwds["lib_version"] = lib_version
160+
if "driver_info" in kwds:
161+
from redis import DriverInfo
162+
163+
kwds["driver_info"] = DriverInfo(name="fakeredis", lib_version=lib_version)
160164
super().__init__(**kwds)
161165

162166
@classmethod

fakeredis/_helpers.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from collections import defaultdict
88
from typing import Any, Set, Callable, Dict, Optional, Iterator, AnyStr, Type, MutableMapping
99

10-
import redis
11-
1210

1311
class SimpleString:
1412
def __init__(self, value: bytes) -> None:
@@ -261,21 +259,24 @@ def check_is_ready_for_command(_: Any) -> bool:
261259
return True
262260

263261

264-
def _get_args_to_warn() -> Set[str]:
265-
closure = redis.Redis.__init__.__closure__
262+
def _get_args_to_warn(method: Callable) -> Set[str]:
263+
closure = method.__closure__
266264
if closure is None:
267265
return set()
266+
res = set()
268267
for cell in closure:
269268
value = cell.cell_contents
270269
if isinstance(value, list) and len(value) > 0:
271-
return set(value)
272-
return set()
270+
res.update(value)
271+
elif callable(value):
272+
res.update(_get_args_to_warn(value))
273+
return res
273274

274275

275-
def convert_args_to_redis_init_kwargs(redis_class: Type[redis.Redis], *args: Any, **kwargs: Any) -> Dict[str, Any]:
276+
def convert_args_kwargs(klass: Type[object], *args: Any, **kwargs: Any) -> Dict[str, Any]:
276277
"""Interpret the positional and keyword arguments according to the version of redis in use"""
277-
parameters = list(inspect.signature(redis_class.__init__).parameters.values())[1:]
278-
args_to_warn = _get_args_to_warn()
278+
parameters = list(inspect.signature(klass.__init__).parameters.values())[1:]
279+
args_to_warn = _get_args_to_warn(klass.__init__)
279280
# Convert args => kwargs
280281
kwargs.update({parameters[i].name: args[i] for i in range(len(args))})
281282
kwargs.setdefault("host", uuid.uuid4().hex)

fakeredis/_server.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import time
44
import weakref
55
from collections import defaultdict
6-
from typing import Dict, Tuple, Any, List, Optional, Union
6+
from typing import Dict, Tuple, Any, List, Optional, Union, Set, Type
77

88
import redis
99

@@ -85,18 +85,32 @@ def get_server(key: str, version: VersionType, server_type: ServerType) -> "Fake
8585

8686
class FakeBaseConnectionMixin(object):
8787
def __init__(
88-
self, *args: Any, version: VersionType = (7, 0), server_type: ServerType = "redis", **kwargs: Any
88+
self,
89+
*args: Any,
90+
version: VersionType = (7, 0),
91+
server_type: ServerType = "redis",
92+
server: Optional[FakeServer] = None,
93+
client_class: Type[redis.Redis] = redis.Redis,
94+
lua_modules: Optional[Set[str]] = None,
95+
writer=None,
96+
connected: bool = True,
97+
path: Optional[str] = None,
98+
**kwargs: Any,
8999
) -> None:
100+
"""
101+
Initializes the class and sets up the required attributes and configurations for the server and client interaction.
102+
103+
"""
90104
self.client_name: Optional[str] = None
91105
self.server_key: str
92106
self._sock = None
93107
self._selector: Optional[FakeSelector] = None
94-
self._server = kwargs.pop("server", None)
95-
self._client_class = kwargs.pop("client_class", redis.Redis)
96-
self._lua_modules = kwargs.pop("lua_modules", set())
97-
self._writer = kwargs.pop("writer", None)
98-
path = kwargs.pop("path", None)
99-
connected = kwargs.pop("connected", True)
108+
self._server = server
109+
self._client_class = client_class
110+
self._lua_modules = lua_modules
111+
self._writer = writer
112+
path = path
113+
connected = connected
100114
if self._server is None:
101115
if path:
102116
self.server_key = path

fakeredis/aioredis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from . import _fakesocket
1212
from . import _helpers
1313
from . import _msgs as msgs
14-
from ._helpers import SimpleError, convert_args_to_redis_init_kwargs
14+
from ._helpers import SimpleError, convert_args_kwargs
1515
from ._server import FakeBaseConnectionMixin, VersionType, FakeServer, ServerType
1616
from ._typing import async_timeout, lib_version, Self, RaiseErrorTypes
1717

@@ -208,7 +208,7 @@ def __init__(
208208
client_class=redis_async.Redis,
209209
**kwargs: Any,
210210
) -> None:
211-
kwds = convert_args_to_redis_init_kwargs(client_class, *args, **kwargs)
211+
kwds = convert_args_kwargs(client_class, *args, **kwargs)
212212
kwds["server"] = server
213213
kwds["connected"] = kwargs.get("connected", True)
214214
if not kwds.get("connection_pool", None):

fakeredis/commands_mixins/streams_mixin.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,7 @@ def xrevrange(self, key: CommandItem, _min: StreamRangeTest, _max: StreamRangeTe
8080

8181
@command(name="XREAD", fixed=(bytes,), repeat=(bytes,), flags=msgs.FLAG_SKIP_CONVERT_TO_RESP2)
8282
def xread(self, *args: bytes) -> Optional[Dict[str, Any]]:
83-
(
84-
(
85-
count,
86-
timeout,
87-
),
88-
left_args,
89-
) = extract_args(
90-
args,
91-
(
92-
"+count",
93-
"+block",
94-
),
95-
error_on_unexpected=False,
96-
)
83+
((count, timeout), left_args) = extract_args(args, ("+count", "+block"), error_on_unexpected=False)
9784
if len(left_args) < 3 or not casematch(left_args[0], b"STREAMS") or len(left_args) % 2 != 1:
9885
raise SimpleError(msgs.SYNTAX_ERROR_MSG)
9986
left_args = left_args[1:]
@@ -370,8 +357,8 @@ def _xread(
370357
if len(stream_results) > 0:
371358
res[item.key] = stream_results
372359

373-
# On blocking read, when count is not None, and there are no results, return None (instead of an empty list)
374-
if blocking and count and len(res) == 0:
360+
# On blocking read, and there are no results, return None (instead of an empty list)
361+
if blocking and len(res) == 0:
375362
return None
376363
if self._client_info.protocol_version == 2:
377364
return [[k, v] for k, v in res.items()]

pyproject.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "fakeredis"
7-
version = "2.34.0"
7+
version = "2.34.1"
88
description = "Python implementation of redis API, can be used for testing purposes."
99
authors = [
1010
{ name = "Daniel Moran", email = "daniel@moransoftware.ca" },
@@ -37,12 +37,13 @@ classifiers = [
3737
"Programming Language :: Python :: 3.11",
3838
"Programming Language :: Python :: 3.12",
3939
"Programming Language :: Python :: 3.13",
40+
"Programming Language :: Python :: 3.14",
4041
"Topic :: Software Development :: Libraries :: Python Modules",
4142
]
4243
dependencies = [
4344
"redis>=4 ; python_version < '3.8'",
44-
"redis>=4.3 ; python_version > '3.8'",
45-
"redis<7.1.0 ; python_version < '3.10'",
45+
"redis>=4.3; python_version > '3.8'",
46+
"redis<7.2 ; python_version < '3.10'",
4647
"sortedcontainers>=2",
4748
"typing-extensions~=4.7 ; python_version < '3.11'",
4849
]
@@ -66,7 +67,7 @@ Funding = "https://github.com/sponsors/cunla"
6667

6768
[dependency-groups]
6869
dev = [
69-
"ruff>=0.14",
70+
"ruff>=0.15",
7071
"mypy>=1.15 ; python_version >= '3.10'",
7172
"pre-commit>=4.2 ; python_version >= '3.10'",
7273
]

test/test_internals/test_init_args.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,19 @@ def test_deprecated_args_show_warnings_for_retry_on_timeout(warn_mock: mock.Magi
1414
warn_mock.assert_called_once_with(
1515
"Call to '__init__' function with deprecated usage of input argument/s 'retry_on_timeout'. (TimeoutError is included by default.) -- Deprecated since version 6.0.0.",
1616
category=DeprecationWarning,
17-
stacklevel=3,
17+
stacklevel=mock.ANY,
18+
)
19+
20+
21+
@pytest.mark.fake
22+
@run_test_if_redispy_ver("gte", "7.2")
23+
@mock.patch("warnings.warn")
24+
def test_deprecated_args_show_warnings_for_lib_name(warn_mock: mock.MagicMock):
25+
fakeredis.FakeStrictRedis(host="localhost", port=6390, db=0, lib_name="SDSS")
26+
warn_mock.assert_called_once_with(
27+
"Call to '__init__' function with deprecated usage of input argument/s 'lib_name'. (Use 'driver_info' parameter instead. lib_name and lib_version will be removed in a future version.)",
28+
category=DeprecationWarning,
29+
stacklevel=mock.ANY,
1830
)
1931

2032

0 commit comments

Comments
 (0)