Skip to content

Commit dadd366

Browse files
authored
Merge branch 'master' into yard1/health_check_fix
2 parents 6cfe412 + 20c4475 commit dadd366

File tree

13 files changed

+46
-21
lines changed

13 files changed

+46
-21
lines changed

.github/actions/run-tests/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ runs:
3838
echo "::group::Installing dependencies"
3939
pip install -r dev_requirements.txt
4040
pip uninstall -y redis # uninstall Redis package installed via redis-entraid
41-
pip install -e . # install the working copy
41+
pip install -e .[jwt] # install the working copy
4242
if [ "${{inputs.parser-backend}}" == "hiredis" ]; then
4343
pip install "hiredis${{inputs.hiredis-version}}"
4444
echo "PARSER_BACKEND=$(echo "${{inputs.parser-backend}}_${{inputs.hiredis-version}}" | sed 's/[^a-zA-Z0-9]/_/g')" >> $GITHUB_ENV

.github/workflows/spellcheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- name: Checkout
99
uses: actions/checkout@v4
1010
- name: Check Spelling
11-
uses: rojopolis/spellcheck-github-actions@0.38.0
11+
uses: rojopolis/spellcheck-github-actions@0.47.0
1212
with:
1313
config_path: .github/spellcheck-settings.yml
1414
task_name: Markdown

CONTRIBUTING.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ Here's how to get started with your code contribution:
3232

3333
1. Create your own fork of redis-py
3434
2. Do the changes in your fork
35-
3.
36-
*Create a virtualenv and install the development dependencies from the dev_requirements.txt file:*
37-
38-
a. python -m venv .venv
39-
b. source .venv/bin/activate
40-
c. pip install -r dev_requirements.txt
41-
c. pip install -e .
35+
3. Create a virtualenv and install the development dependencies from the dev_requirements.txt file:
36+
```
37+
python -m venv .venv
38+
source .venv/bin/activate
39+
pip install -r dev_requirements.txt
40+
pip install -e .[jwt]
41+
```
4242
4343
4. If you need a development environment, run `invoke devenv`. Note: this relies on docker-compose to build environments, and assumes that you have a version supporting [docker profiles](https://docs.docker.com/compose/profiles/).
4444
5. While developing, make sure the tests pass by running `invoke tests`

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ classifiers = [
3737
]
3838
dependencies = [
3939
'async-timeout>=4.0.3; python_full_version<"3.11.3"',
40-
"PyJWT~=2.9.0",
4140
]
4241

4342
[project.optional-dependencies]
@@ -49,6 +48,9 @@ ocsp = [
4948
"pyopenssl==20.0.1",
5049
"requests>=2.31.0",
5150
]
51+
jwt = [
52+
"PyJWT~=2.9.0",
53+
]
5254

5355
[project.urls]
5456
Changes = "https://github.com/redis/redis-py/releases"

redis/asyncio/lock.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,10 @@ def release(self) -> Awaitable[None]:
249249
"""Releases the already acquired lock"""
250250
expected_token = self.local.token
251251
if expected_token is None:
252-
raise LockError("Cannot release an unlocked lock")
252+
raise LockError(
253+
"Cannot release a lock that's not owned or is already unlocked.",
254+
lock_name=self.name,
255+
)
253256
self.local.token = None
254257
return self.do_release(expected_token)
255258

redis/asyncio/sentinel.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ def __init__(
198198
sentinels,
199199
min_other_sentinels=0,
200200
sentinel_kwargs=None,
201+
force_master_ip=None,
201202
**connection_kwargs,
202203
):
203204
# if sentinel_kwargs isn't defined, use the socket_* options from
@@ -214,6 +215,7 @@ def __init__(
214215
]
215216
self.min_other_sentinels = min_other_sentinels
216217
self.connection_kwargs = connection_kwargs
218+
self._force_master_ip = force_master_ip
217219

218220
async def execute_command(self, *args, **kwargs):
219221
"""
@@ -277,7 +279,13 @@ async def discover_master(self, service_name: str):
277279
sentinel,
278280
self.sentinels[0],
279281
)
280-
return state["ip"], state["port"]
282+
283+
ip = (
284+
self._force_master_ip
285+
if self._force_master_ip is not None
286+
else state["ip"]
287+
)
288+
return ip, state["port"]
281289

282290
error_info = ""
283291
if len(collected_errors) > 0:

redis/auth/token.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from abc import ABC, abstractmethod
22
from datetime import datetime, timezone
33

4-
import jwt
54
from redis.auth.err import InvalidTokenSchemaErr
65

76

@@ -81,6 +80,12 @@ class JWToken(TokenInterface):
8180
REQUIRED_FIELDS = {"exp"}
8281

8382
def __init__(self, token: str):
83+
try:
84+
import jwt
85+
except ImportError as ie:
86+
raise ImportError(
87+
f"The PyJWT library is required for {self.__class__.__name__}.",
88+
) from ie
8489
self._value = token
8590
self._decoded = jwt.decode(
8691
self._value,

redis/cluster.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2122,7 +2122,7 @@ def send_cluster_commands(
21222122
raise_on_error=raise_on_error,
21232123
allow_redirections=allow_redirections,
21242124
)
2125-
except (ClusterDownError, ConnectionError) as e:
2125+
except RedisCluster.ERRORS_ALLOW_RETRY as e:
21262126
if retry_attempts > 0:
21272127
# Try again with the new cluster setup. All other errors
21282128
# should be raised.

redis/commands/core.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import warnings
66
from typing import (
77
TYPE_CHECKING,
8+
Any,
89
AsyncIterator,
910
Awaitable,
1011
Callable,
@@ -6397,12 +6398,12 @@ def function_list(
63976398
return self.execute_command("FUNCTION LIST", *args)
63986399

63996400
def _fcall(
6400-
self, command: str, function, numkeys: int, *keys_and_args: Optional[List]
6401+
self, command: str, function, numkeys: int, *keys_and_args: Any
64016402
) -> Union[Awaitable[str], str]:
64026403
return self.execute_command(command, function, numkeys, *keys_and_args)
64036404

64046405
def fcall(
6405-
self, function, numkeys: int, *keys_and_args: Optional[List]
6406+
self, function, numkeys: int, *keys_and_args: Any
64066407
) -> Union[Awaitable[str], str]:
64076408
"""
64086409
Invoke a function.
@@ -6412,7 +6413,7 @@ def fcall(
64126413
return self._fcall("FCALL", function, numkeys, *keys_and_args)
64136414

64146415
def fcall_ro(
6415-
self, function, numkeys: int, *keys_and_args: Optional[List]
6416+
self, function, numkeys: int, *keys_and_args: Any
64166417
) -> Union[Awaitable[str], str]:
64176418
"""
64186419
This is a read-only variant of the FCALL command that cannot

redis/lock.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,10 @@ def release(self) -> None:
251251
"""
252252
expected_token = self.local.token
253253
if expected_token is None:
254-
raise LockError("Cannot release an unlocked lock", lock_name=self.name)
254+
raise LockError(
255+
"Cannot release a lock that's not owned or is already unlocked.",
256+
lock_name=self.name,
257+
)
255258
self.local.token = None
256259
self.do_release(expected_token)
257260

0 commit comments

Comments
 (0)