Skip to content
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

Support Python 3.13 #327

Merged
merged 12 commits into from
Sep 20, 2024
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4

Expand All @@ -25,7 +25,7 @@ jobs:
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --frozen
run: uv sync --python ${{ matrix.python-version }} --frozen
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zanieb I don't know if this is a bug, but I had to add this because on 3.13 it was not creating a venv with 3.13, but with 3.10. FYI


- name: Run tests
run: scripts/test
Expand Down
29 changes: 16 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ Hello. Contributions to this project are highly encouraged and appreciated. This

## Contents

- [Creating a pull request](#creating-a-pull-request)
* [Setting up the repository](#setting-up-the-repository)
- [Developing the project locally](#developing-the-project-locally)
* [Setup](#setup)
* [Test](#test)
+ [Coverage requirements](#coverage-requirements)
* [Lint](#lint)
+ [Code style and formatting](#code-style-and-formatting)
+ [Static type checking](#static-type-checking)
- [Using the issue tracker](#using-the-issue-tracker)
* [Technical support](#technical-support)
* [Feature requests](#feature-requests)
- [Contributing to Mangum](#contributing-to-mangum)
- [Contents](#contents)
- [Creating a pull request](#creating-a-pull-request)
- [Setting up the repository](#setting-up-the-repository)
- [Developing the project locally](#developing-the-project-locally)
- [Setup](#setup)
- [Test](#test)
- [Coverage requirements](#coverage-requirements)
- [Lint](#lint)
- [Code style and formatting](#code-style-and-formatting)
- [Static type checking](#static-type-checking)
- [Using the issue tracker](#using-the-issue-tracker)
- [Technical support](#technical-support)
- [Feature requests](#feature-requests)
- [Thank you](#thank-you)

## Creating a pull request

Expand Down Expand Up @@ -65,7 +68,7 @@ python -m venv venv
pip install -r requirements.txt
```

This environment is used to run the tests for Python versions 3.7, 3.8, 3.9, and 3.10.
This environment is used to run the tests for Python versions 3.8, 3.9, 3.10, 3.11, 3.12 and 3.13.

### Test

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Mangum is an adapter for running [ASGI](https://asgi.readthedocs.io/en/latest/)

- Event handlers for API Gateway [HTTP](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) and [REST](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html) APIs, [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html), [Function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html), and [CloudFront Lambda@Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html).

- Compatibility with ASGI application frameworks, such as [Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), [Quart](https://pgjones.gitlab.io/quart/) and [Django](https://www.djangoproject.com/).
- Compatibility with ASGI application frameworks, such as [Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), [Quart](https://pgjones.gitlab.io/quart/) and [Django](https://www.djangoproject.com/).

- Support for binary media types and payload compression in API Gateway using GZip or Brotli.

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Mangum is an adapter for running [ASGI](https://asgi.readthedocs.io/en/latest/)

- Event handlers for API Gateway [HTTP](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) and [REST](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html) APIs, [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html), [Function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html), and [CloudFront Lambda@Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html).

- Compatibility with ASGI application frameworks, such as [Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), [Quart](https://pgjones.gitlab.io/quart/) and [Django](https://www.djangoproject.com/).
- Compatibility with ASGI application frameworks, such as [Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), [Quart](https://pgjones.gitlab.io/quart/) and [Django](https://www.djangoproject.com/).

- Support for binary media types and payload compression in API Gateway using GZip or Brotli.

Expand Down
1 change: 0 additions & 1 deletion mangum/handlers/alb.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ def body(self) -> bytes:

@property
def scope(self) -> Scope:

headers = transform_headers(self.event)
list_headers = [list(x) for x in headers]
# Unique headers. If there are duplicates, it will use the last defined.
Expand Down
1 change: 0 additions & 1 deletion mangum/protocols/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ async def send(self, message: Message) -> None:
self.headers = message.get("headers", [])
self.state = HTTPCycleState.RESPONSE
elif self.state is HTTPCycleState.RESPONSE and message["type"] == "http.response.body":

body = message.get("body", b"")
more_body = message.get("more_body", False)
self.buffer.write(body)
Expand Down
2 changes: 0 additions & 2 deletions mangum/protocols/lifespan.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,12 @@ async def run(self) -> None:
async def receive(self) -> Message:
"""Awaited by the application to receive ASGI `lifespan` events."""
if self.state is LifespanCycleState.CONNECTING:

# Connection established. The next event returned by the queue will be
# `lifespan.startup` to inform the application that the connection is
# ready to receive lfiespan messages.
self.state = LifespanCycleState.STARTUP

elif self.state is LifespanCycleState.STARTUP:

# Connection shutting down. The next event returned by the queue will be
# `lifespan.shutdown` to inform the application that the connection is now
# closing so that it may perform cleanup.
Expand Down
18 changes: 12 additions & 6 deletions mangum/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ def get_remaining_time_in_millis(self) -> int:


class ASGI(Protocol):
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: ... # pragma: no cover
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
... # pragma: no cover


LifespanMode: TypeAlias = Literal["auto", "on", "off"]
Expand All @@ -120,15 +121,20 @@ class LambdaConfig(TypedDict):


class LambdaHandler(Protocol):
def __init__(self, *args: Any) -> None: ... # pragma: no cover
def __init__(self, *args: Any) -> None:
... # pragma: no cover

@classmethod
def infer(cls, event: LambdaEvent, context: LambdaContext, config: LambdaConfig) -> bool: ... # pragma: no cover
def infer(cls, event: LambdaEvent, context: LambdaContext, config: LambdaConfig) -> bool:
... # pragma: no cover

@property
def body(self) -> bytes: ... # pragma: no cover
def body(self) -> bytes:
... # pragma: no cover

@property
def scope(self) -> Scope: ... # pragma: no cover
def scope(self) -> Scope:
... # pragma: no cover

def __call__(self, response: Response) -> dict: ... # pragma: no cover
def __call__(self, response: Response) -> dict:
... # pragma: no cover
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ authors = [
]
description = "AWS Lambda support for ASGI applications"
readme = "README.md"
requires-python = ">=3.8"
requires-python = ">=3.7"
classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
Expand All @@ -20,6 +20,9 @@ classifiers = [
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP",
]
dependencies = ["typing_extensions"]
Expand All @@ -33,6 +36,8 @@ dev-dependencies = [
"flake8",
"starlette",
"quart",
"hypercorn<0.15.0; python_version < '3.8'",
"hypercorn>=0.15.0; python_version >= '3.8'",
"mypy",
"brotli",
"brotli-asgi",
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[flake8]
max-line-length = 120
ignore = E203, W503, E704
ignore = E203, W503, E704, E231
per-file-ignores =
tests/conftest.py:E501
tests/test_http.py:E501
Expand Down
3 changes: 2 additions & 1 deletion tests/test_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from mangum.types import Receive, Scope, Send


async def app(scope: Scope, receive: Receive, send: Send): ...
async def app(scope: Scope, receive: Receive, send: Send):
...


def test_default_settings():
Expand Down
Loading