Skip to content

Commit 7f95bb8

Browse files
committed
Fix event loop creation for Python 3.14
- Create the event loop, because it's not created implicitly in Python 3.14. - Use threads for integration testing, to avoid an incompatibility with `pickle` and the serialiazation of Flask objects.
1 parent 29049f6 commit 7f95bb8

3 files changed

Lines changed: 17 additions & 20 deletions

File tree

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ jobs:
55
runs-on: ubuntu-latest
66
strategy:
77
matrix:
8-
python-version: ['3.9', '3.12']
8+
python-version: ['3.9', '3.14']
99
steps:
1010
- uses: actions/checkout@v4
1111
- uses: actions/setup-python@v5
@@ -20,7 +20,7 @@ jobs:
2020
- uses: actions/checkout@v4
2121
- uses: actions/setup-python@v5
2222
with:
23-
python-version: '3.12'
23+
python-version: '3.14'
2424
- run: pip install --upgrade pip uv
2525
- run: uv sync
2626
- run: uv run make check-lint

integration_tests/conftest.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,26 @@
1-
from multiprocessing import Process
1+
from threading import Thread
22

33
import pytest
44
from flask import Blueprint
5+
from werkzeug.serving import make_server
56

67
from . import server
78

89

9-
def launch_process(target, kwargs) -> Process:
10-
process = Process(target=target, kwargs=kwargs)
11-
process.start()
12-
return process
13-
14-
1510
@pytest.fixture
1611
def http_server():
1712
created_servers = {}
1813

19-
def _make_server(blueprint: Blueprint, port: int) -> Process:
14+
def _make_server(blueprint: Blueprint, port: int) -> None:
2015
app = server.create_app(blueprint=blueprint)
21-
process = launch_process(target=app.run, kwargs={"port": port})
22-
created_servers[port] = process
23-
return process
16+
srv = make_server("127.0.0.1", port, app)
17+
thread = Thread(target=srv.serve_forever)
18+
thread.daemon = True
19+
thread.start()
20+
created_servers[port] = (thread, srv)
2421

2522
yield _make_server
2623

27-
errors = []
28-
for port, process in created_servers.items():
29-
if process.exitcode is not None:
30-
errors.append(f"Server failure for port {port}")
31-
process.terminate()
32-
assert not errors
24+
for thread, srv in created_servers.values():
25+
srv.shutdown()
26+
thread.join()

src/discolinks/cli.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ def main(
199199

200200
try:
201201
with new_monitor(console=console) as monitor:
202+
# Set event loop
203+
loop = asyncio.new_event_loop()
204+
asyncio.set_event_loop(loop)
205+
202206
# Define main task (wrap in a future to make it cancellable).
203207
main_task = asyncio.ensure_future(
204208
main_async(
@@ -211,7 +215,6 @@ def main(
211215
)
212216

213217
# Cancel main task when interrupted.
214-
loop = asyncio.get_event_loop()
215218
loop.add_signal_handler(
216219
signal.SIGINT,
217220
functools.partial(main_task.cancel, msg="SIGINT"),

0 commit comments

Comments
 (0)