Skip to content

Commit 5c72521

Browse files
authored
Add support for Python 3.14 (#522)
1 parent fda407c commit 5c72521

File tree

5 files changed

+18
-7
lines changed

5 files changed

+18
-7
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
fail-fast: false
5858
matrix:
5959
os: [ubuntu]
60-
python: ['3.9', '3.10', '3.11', '3.12', '3.13']
60+
python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
6161
redis: ['5']
6262
include:
6363
- python: '3.11'

arq/cron.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import asyncio
21
import dataclasses
2+
import inspect
33
from dataclasses import dataclass
44
from datetime import datetime, timedelta
55
from typing import Optional, Union
@@ -175,7 +175,7 @@ def cron(
175175
else:
176176
coroutine_ = coroutine
177177

178-
if not asyncio.iscoroutinefunction(coroutine_):
178+
if not inspect.iscoroutinefunction(coroutine_):
179179
raise RuntimeError(f'{coroutine_} is not a coroutine function')
180180
timeout = to_seconds(timeout)
181181
keep_result = to_seconds(keep_result)

arq/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def to_seconds(td: Optional['SecondsTimedelta']) -> Optional[float]:
9999

100100

101101
async def poll(step: float = 0.5) -> AsyncGenerator[float, None]:
102-
loop = asyncio.get_event_loop()
102+
loop = asyncio.get_running_loop()
103103
start = loop.time()
104104
while True:
105105
before = loop.time()

arq/worker.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def func(
8686
else:
8787
coroutine_ = coroutine
8888

89-
if not asyncio.iscoroutinefunction(coroutine_):
89+
if not inspect.iscoroutinefunction(coroutine_):
9090
raise RuntimeError(f'{coroutine_} is not a coroutine function')
9191
timeout = to_seconds(timeout)
9292
keep_result = to_seconds(keep_result)
@@ -267,7 +267,11 @@ def __init__(
267267
# self.job_tasks holds references the actual jobs running
268268
self.job_tasks: dict[str, asyncio.Task[Any]] = {}
269269
self.main_task: Optional[asyncio.Task[None]] = None
270-
self.loop = asyncio.get_event_loop()
270+
try:
271+
self.loop = asyncio.get_event_loop()
272+
except RuntimeError:
273+
self.loop = asyncio.new_event_loop()
274+
asyncio.set_event_loop(self.loop)
271275
self.ctx = ctx or {}
272276
max_timeout = max(f.timeout_s or self.job_timeout_s for f in self.functions.values())
273277
self.in_progress_timeout_s = (max_timeout or 0) + 10

pyproject.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ classifiers = [
2929
'Programming Language :: Python :: 3.11',
3030
'Programming Language :: Python :: 3.12',
3131
'Programming Language :: Python :: 3.13',
32+
'Programming Language :: Python :: 3.14',
3233
'Topic :: Internet',
3334
'Topic :: Software Development :: Libraries :: Python Modules',
3435
'Topic :: System :: Clustering',
@@ -90,7 +91,13 @@ required-version = '>=0.8.4'
9091

9192
[tool.pytest.ini_options]
9293
testpaths = 'tests'
93-
filterwarnings = ['error']
94+
filterwarnings = [
95+
'error',
96+
# Emitted by pytest-asyncio, necessary until we update it:
97+
'''ignore:'asyncio.iscoroutinefunction' is deprecated:DeprecationWarning''',
98+
'''ignore:'asyncio.get_event_loop_policy' is deprecated:DeprecationWarning''',
99+
'''ignore:'asyncio.set_event_loop_policy' is deprecated:DeprecationWarning''',
100+
]
94101
asyncio_mode = 'auto'
95102
timeout = 10
96103

0 commit comments

Comments
 (0)