Skip to content

chore: Update redis-py<7 & python >= 3.9 #500

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
19 changes: 9 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: set up python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.12'

- run: pip install -r requirements/linting.txt -r requirements/pyproject.txt pre-commit

Expand All @@ -35,7 +35,7 @@ jobs:
- name: set up python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.12'

- run: pip install -r requirements/docs.txt -r requirements/pyproject.txt
- run: pip install .
Expand All @@ -54,16 +54,15 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu]
python: ['3.8', '3.9', '3.10', '3.11', '3.12']
redis: ['5']
python: ['3.9', '3.10', '3.11', '3.12', '3.13']
redis: ['8.0']
include:
- python: '3.11'
redis: '6'
- python: '3.12'
redis: '7.2'
os: 'ubuntu'
- python: '3.11'
redis: '7'
- python: '3.12'
redis: '7.4'
os: 'ubuntu'

env:
PYTHON: ${{ matrix.python }}
OS: ${{ matrix.os }}
Expand Down Expand Up @@ -124,7 +123,7 @@ jobs:
- name: set up python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.12'

- name: install
run: pip install -U build
Expand Down
6 changes: 6 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
History
-------

v0.26.4 (2025-XX-XX)
....................

* Extend support for redis-py 6.x - Add python 3.13 support - Remove python 3.8 by @nsteinmetz in #500


v0.26.3 (2025-01-06)
....................

Expand Down
26 changes: 12 additions & 14 deletions arq/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dataclasses import dataclass
from datetime import datetime, timedelta
from operator import attrgetter
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple, Union, cast
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
from urllib.parse import parse_qs, urlparse
from uuid import uuid4

Expand All @@ -28,7 +28,7 @@ class RedisSettings:
Used by :func:`arq.connections.create_pool` and :class:`arq.worker.Worker`.
"""

host: Union[str, List[Tuple[str, int]]] = 'localhost'
host: Union[str, list[tuple[str, int]]] = 'localhost'
port: int = 6379
unix_socket_path: Optional[str] = None
database: int = 0
Expand All @@ -49,8 +49,7 @@ class RedisSettings:
sentinel: bool = False
sentinel_master: str = 'mymaster'

retry_on_timeout: bool = False
retry_on_error: Optional[List[Exception]] = None
retry_on_error: Optional[list[Exception]] = None
retry: Optional[Retry] = None

@classmethod
Expand Down Expand Up @@ -101,7 +100,7 @@ class ArqRedis(BaseRedis):

def __init__(
self,
pool_or_conn: Optional[ConnectionPool] = None,
pool_or_conn: Optional[ConnectionPool] = None, # type: ignore[type-arg]
job_serializer: Optional[Serializer] = None,
job_deserializer: Optional[Deserializer] = None,
default_queue_name: str = default_queue_name,
Expand Down Expand Up @@ -189,7 +188,7 @@ async def _get_job_result(self, key: bytes) -> JobResult:
r.job_id = job_id
return r

async def all_job_results(self) -> List[JobResult]:
async def all_job_results(self) -> list[JobResult]:
"""
Get results for all jobs in redis.
"""
Expand All @@ -207,7 +206,7 @@ async def _get_job_def(self, job_id: bytes, score: int) -> JobDef:
jd.job_id = job_id.decode()
return jd

async def queued_jobs(self, *, queue_name: Optional[str] = None) -> List[JobDef]:
async def queued_jobs(self, *, queue_name: Optional[str] = None) -> list[JobDef]:
"""
Get information about queued, mostly useful when testing.
"""
Expand All @@ -216,6 +215,9 @@ async def queued_jobs(self, *, queue_name: Optional[str] = None) -> List[JobDef]
jobs = await self.zrange(queue_name, withscores=True, start=0, end=-1)
return await asyncio.gather(*[self._get_job_def(job_id, int(score)) for job_id, score in jobs])

async def aclose(self) -> None:
await super().aclose() # type: ignore[misc]


async def create_pool(
settings_: Optional[RedisSettings] = None,
Expand All @@ -241,12 +243,12 @@ async def create_pool(
def pool_factory(*args: Any, **kwargs: Any) -> ArqRedis:
client = Sentinel( # type: ignore[misc]
*args,
sentinels=settings.host,
sentinels=settings.host, # type: ignore[arg-type]
ssl=settings.ssl,
**kwargs,
)
redis = client.master_for(settings.sentinel_master, redis_class=ArqRedis)
return cast(ArqRedis, redis)
return redis

else:
pool_factory = functools.partial(
Expand All @@ -263,7 +265,6 @@ def pool_factory(*args: Any, **kwargs: Any) -> ArqRedis:
ssl_ca_data=settings.ssl_ca_data,
ssl_check_hostname=settings.ssl_check_hostname,
retry=settings.retry,
retry_on_timeout=settings.retry_on_timeout,
retry_on_error=settings.retry_on_error,
max_connections=settings.max_connections,
)
Expand Down Expand Up @@ -312,8 +313,5 @@ async def log_redis_info(redis: 'Redis[bytes]', log_func: Callable[[str], Any])
clients_connected = info_clients.get('connected_clients', '?')

log_func(
f'redis_version={redis_version} '
f'mem_usage={mem_usage} '
f'clients_connected={clients_connected} '
f'db_keys={key_count}'
f'redis_version={redis_version} mem_usage={mem_usage} clients_connected={clients_connected} db_keys={key_count}'
)
20 changes: 10 additions & 10 deletions arq/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Any, Callable, Dict, Optional, Tuple
from typing import Any, Callable, Optional

from redis.asyncio import Redis

Expand All @@ -14,8 +14,8 @@

logger = logging.getLogger('arq.jobs')

Serializer = Callable[[Dict[str, Any]], bytes]
Deserializer = Callable[[bytes], Dict[str, Any]]
Serializer = Callable[[dict[str, Any]], bytes]
Deserializer = Callable[[bytes], dict[str, Any]]


class ResultNotFound(RuntimeError):
Expand All @@ -42,8 +42,8 @@ class JobStatus(str, Enum):
@dataclass
class JobDef:
function: str
args: Tuple[Any, ...]
kwargs: Dict[str, Any]
args: tuple[Any, ...]
kwargs: dict[str, Any]
job_try: int
enqueue_time: datetime
score: Optional[int]
Expand Down Expand Up @@ -210,8 +210,8 @@ class DeserializationError(SerializationError):

def serialize_job(
function_name: str,
args: Tuple[Any, ...],
kwargs: Dict[str, Any],
args: tuple[Any, ...],
kwargs: dict[str, Any],
job_try: Optional[int],
enqueue_time_ms: int,
*,
Expand All @@ -228,8 +228,8 @@ def serialize_job(

def serialize_result(
function: str,
args: Tuple[Any, ...],
kwargs: Dict[str, Any],
args: tuple[Any, ...],
kwargs: dict[str, Any],
job_try: int,
enqueue_time_ms: int,
success: bool,
Expand Down Expand Up @@ -291,7 +291,7 @@ def deserialize_job(r: bytes, *, deserializer: Optional[Deserializer] = None) ->

def deserialize_job_raw(
r: bytes, *, deserializer: Optional[Deserializer] = None
) -> Tuple[str, Tuple[Any, ...], Dict[str, Any], int, int]:
) -> tuple[str, tuple[Any, ...], dict[str, Any], int, int]:
if deserializer is None:
deserializer = pickle.loads
try:
Expand Down
4 changes: 2 additions & 2 deletions arq/logs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Any, Dict
from typing import Any


def default_log_config(verbose: bool) -> Dict[str, Any]:
def default_log_config(verbose: bool) -> dict[str, Any]:
"""
Setup default config. for dictConfig.

Expand Down
11 changes: 6 additions & 5 deletions arq/typing.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections.abc import Sequence
from datetime import timedelta
from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Protocol, Sequence, Set, Type, Union
from typing import TYPE_CHECKING, Any, Literal, Optional, Protocol, Union

__all__ = (
'OptionType',
Expand All @@ -16,7 +17,7 @@
from .cron import CronJob
from .worker import Function

OptionType = Union[None, Set[int], int]
OptionType = Union[None, set[int], int]
WEEKDAYS = 'mon', 'tues', 'wed', 'thurs', 'fri', 'sat', 'sun'
WeekdayOptionType = Union[OptionType, Literal['mon', 'tues', 'wed', 'thurs', 'fri', 'sat', 'sun']]
SecondsTimedelta = Union[int, float, timedelta]
Expand All @@ -25,14 +26,14 @@
class WorkerCoroutine(Protocol):
__qualname__: str

async def __call__(self, ctx: Dict[Any, Any], *args: Any, **kwargs: Any) -> Any: # pragma: no cover
async def __call__(self, ctx: dict[Any, Any], *args: Any, **kwargs: Any) -> Any: # pragma: no cover
pass


class StartupShutdown(Protocol):
__qualname__: str

async def __call__(self, ctx: Dict[Any, Any]) -> Any: # pragma: no cover
async def __call__(self, ctx: dict[Any, Any]) -> Any: # pragma: no cover
pass


Expand All @@ -44,4 +45,4 @@ class WorkerSettingsBase(Protocol):
# and many more...


WorkerSettingsType = Union[Dict[str, Any], Type[WorkerSettingsBase]]
WorkerSettingsType = Union[dict[str, Any], type[WorkerSettingsBase]]
5 changes: 3 additions & 2 deletions arq/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import asyncio
import logging
import os
from collections.abc import AsyncGenerator, Sequence
from datetime import datetime, timedelta, timezone
from functools import lru_cache
from time import time
from typing import TYPE_CHECKING, Any, AsyncGenerator, Dict, Optional, Sequence, overload
from typing import TYPE_CHECKING, Any, Optional, overload

from .constants import timezone_env_vars

Expand Down Expand Up @@ -121,7 +122,7 @@ def truncate(s: str, length: int = DEFAULT_CURTAIL) -> str:
return s


def args_to_string(args: Sequence[Any], kwargs: Dict[str, Any]) -> str:
def args_to_string(args: Sequence[Any], kwargs: dict[str, Any]) -> str:
arguments = ''
if args:
arguments = ', '.join(map(repr, args))
Expand Down
2 changes: 1 addition & 1 deletion arq/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Version here is used for the package version via the `[tool.hatch.version]` section of `pyproject.toml`.
VERSION = '0.26.3'
VERSION = '0.26.4'
Loading