Skip to content

Commit 9f5c852

Browse files
committed
Revert "Support Python 3.14 (#354)"
This reverts commit 2e3ba33.
1 parent 033d165 commit 9f5c852

File tree

16 files changed

+566
-1310
lines changed

16 files changed

+566
-1310
lines changed

.coveragerc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[run]
2+
source =
3+
mangum
4+
omit =
5+
tests/*

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- name: Install uv
2323
uses: astral-sh/setup-uv@v2
2424
with:
25-
version: "0.9.18"
25+
version: "0.4.12"
2626
enable-cache: true
2727

2828
- name: Set up Python

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
14+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
1515
steps:
1616
- uses: actions/checkout@v4
1717

1818
- name: Install uv
1919
uses: astral-sh/setup-uv@v2
2020
with:
21-
version: "0.9.18"
21+
version: "0.4.12"
2222
enable-cache: true
2323

2424
- name: Set up Python ${{ matrix.python-version }}

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Install uv
1717
uses: astral-sh/setup-uv@v2
1818
with:
19-
version: "0.9.18"
19+
version: "0.4.12"
2020
enable-cache: true
2121

2222
- name: Set up Python

mangum/_compat.py

Lines changed: 0 additions & 91 deletions
This file was deleted.

mangum/adapter.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from __future__ import annotations
22

33
import logging
4+
from contextlib import ExitStack
45
from itertools import chain
56
from typing import Any
67

7-
from mangum._compat import asyncio_run
88
from mangum.exceptions import ConfigurationError
99
from mangum.handlers import ALB, APIGateway, HTTPGateway, LambdaAtEdge
1010
from mangum.protocols import HTTPCycle, LifespanCycle
@@ -59,20 +59,17 @@ def infer(self, event: LambdaEvent, context: LambdaContext) -> LambdaHandler:
5959
)
6060

6161
def __call__(self, event: LambdaEvent, context: LambdaContext) -> dict[str, Any]:
62-
async def handle_request() -> dict[str, Any]:
63-
handler = self.infer(event, context)
64-
scope = handler.scope
65-
62+
handler = self.infer(event, context)
63+
scope = handler.scope
64+
with ExitStack() as stack:
6665
if self.lifespan in ("auto", "on"):
6766
lifespan_cycle = LifespanCycle(self.app, self.lifespan)
68-
async with lifespan_cycle:
69-
scope.update({"state": lifespan_cycle.lifespan_state.copy()})
70-
http_cycle = HTTPCycle(scope, handler.body)
71-
http_response = await http_cycle(self.app)
72-
return handler(http_response)
73-
else:
74-
http_cycle = HTTPCycle(scope, handler.body)
75-
http_response = await http_cycle(self.app)
76-
return handler(http_response)
67+
stack.enter_context(lifespan_cycle)
68+
scope.update({"state": lifespan_cycle.lifespan_state.copy()})
69+
70+
http_cycle = HTTPCycle(scope, handler.body)
71+
http_response = http_cycle(self.app)
72+
73+
return handler(http_response)
7774

78-
return asyncio_run(handle_request())
75+
assert False, "unreachable" # pragma: no cover

mangum/protocols/http.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,25 @@ def __init__(self, scope: Scope, body: bytes) -> None:
3333
self.state = HTTPCycleState.REQUEST
3434
self.logger = logging.getLogger("mangum.http")
3535
self.app_queue: asyncio.Queue[Message] = asyncio.Queue()
36-
self.app_queue.put_nowait({"type": "http.request", "body": body, "more_body": False})
36+
self.app_queue.put_nowait(
37+
{
38+
"type": "http.request",
39+
"body": body,
40+
"more_body": False,
41+
}
42+
)
3743

38-
async def __call__(self, app: ASGI) -> Response:
39-
await self.run(app)
40-
return {"status": self.status, "headers": self.headers, "body": self.body}
44+
def __call__(self, app: ASGI) -> Response:
45+
asgi_instance = self.run(app)
46+
loop = asyncio.get_event_loop()
47+
asgi_task = loop.create_task(asgi_instance)
48+
loop.run_until_complete(asgi_task)
49+
50+
return {
51+
"status": self.status,
52+
"headers": self.headers,
53+
"body": self.body,
54+
}
4155

4256
async def run(self, app: ASGI) -> None:
4357
try:

mangum/protocols/lifespan.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,26 +59,26 @@ def __init__(self, app: ASGI, lifespan: LifespanMode) -> None:
5959
self.lifespan = lifespan
6060
self.state: LifespanCycleState = LifespanCycleState.CONNECTING
6161
self.exception: BaseException | None = None
62+
self.loop = asyncio.get_event_loop()
6263
self.app_queue: asyncio.Queue[Message] = asyncio.Queue()
6364
self.startup_event: asyncio.Event = asyncio.Event()
6465
self.shutdown_event: asyncio.Event = asyncio.Event()
6566
self.logger = logging.getLogger("mangum.lifespan")
6667
self.lifespan_state: dict[str, Any] = {}
6768

68-
async def __aenter__(self) -> LifespanCycle:
69+
def __enter__(self) -> None:
6970
"""Runs the event loop for application startup."""
70-
asyncio.create_task(self.run())
71-
await self.startup()
72-
return self
71+
self.loop.create_task(self.run())
72+
self.loop.run_until_complete(self.startup())
7373

74-
async def __aexit__(
74+
def __exit__(
7575
self,
7676
exc_type: type[BaseException] | None,
7777
exc_value: BaseException | None,
7878
traceback: TracebackType | None,
7979
) -> None:
8080
"""Runs the event loop for application shutdown."""
81-
await self.shutdown()
81+
self.loop.run_until_complete(self.shutdown())
8282

8383
async def run(self) -> None:
8484
"""Calls the application with the `lifespan` connection scope."""

pyproject.toml

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,17 @@ classifiers = [
2121
"Programming Language :: Python :: 3.11",
2222
"Programming Language :: Python :: 3.12",
2323
"Programming Language :: Python :: 3.13",
24-
"Programming Language :: Python :: 3.14",
2524
"Topic :: Internet :: WWW/HTTP",
2625
]
2726
dependencies = ["typing_extensions"]
2827

29-
[tool.uv]
30-
default-groups = ["dev"]
31-
3228
[dependency-groups]
3329
dev = [
34-
"pytest>=8.0.0",
35-
"coverage",
30+
"pytest",
31+
"pytest-cov",
3632
"ruff",
3733
"starlette",
38-
"quart>=0.20.0",
34+
"quart",
3935
"hypercorn>=0.15.0",
4036
"mypy",
4137
"brotli",
@@ -70,6 +66,10 @@ ignore = ["UP031"] # https://docs.astral.sh/ruff/rules/printf-string-formatting/
7066
strict = true
7167

7268
[tool.pytest.ini_options]
69+
log_cli = true
70+
log_cli_level = "INFO"
71+
log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
72+
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
7373
addopts = "-rXs --strict-config --strict-markers"
7474
xfail_strict = true
7575
filterwarnings = [
@@ -86,12 +86,8 @@ filterwarnings = [
8686

8787
[tool.coverage.run]
8888
source_pkgs = ["mangum", "tests"]
89-
omit = ["mangum/_compat.py"]
9089

9190
[tool.coverage.report]
92-
fail_under = 100
93-
skip_covered = true
94-
show_missing = true
9591
exclude_lines = [
9692
"pragma: no cover",
9793
"pragma: nocover",

scripts/test

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@
22

33
set -x # print executed commands to the terminal
44

5-
uv run coverage run -m pytest "${@}"
6-
uv run coverage report
5+
uv run pytest --ignore venv --cov=mangum --cov=tests --cov-fail-under=100 --cov-report=term-missing "${@}"

0 commit comments

Comments
 (0)