From cc91706ecc94f7f1598d0da6b9b9c012e61b576d Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 26 Sep 2024 21:36:43 +0200 Subject: [PATCH 1/6] Update linting and type checker setup --- .github/workflows/test.yml | 6 +- mangum/adapter.py | 38 +++----- mangum/handlers/__init__.py | 3 +- mangum/handlers/alb.py | 24 +++--- mangum/handlers/api_gateway.py | 22 ++--- mangum/handlers/lambda_at_edge.py | 10 ++- mangum/handlers/utils.py | 22 ++--- mangum/protocols/__init__.py | 2 +- mangum/protocols/http.py | 2 +- mangum/protocols/lifespan.py | 15 ++-- mangum/types.py | 43 ++++----- pyproject.toml | 35 +++++++- pytest.ini | 5 -- scripts/README.md | 5 +- scripts/check | 9 ++ scripts/lint | 7 +- setup.cfg | 14 --- tests/conftest.py | 2 +- tests/handlers/test_alb.py | 6 +- tests/handlers/test_custom.py | 10 +-- tests/handlers/test_lambda_at_edge.py | 6 +- tests/test_adapter.py | 3 +- tests/test_http.py | 11 ++- tests/test_lifespan.py | 4 +- uv.lock | 120 ++++++-------------------- 25 files changed, 180 insertions(+), 244 deletions(-) delete mode 100644 pytest.ini create mode 100755 scripts/check delete mode 100644 setup.cfg diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e8b2a51d..4b97edcb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,12 +27,12 @@ jobs: - name: Install dependencies run: uv sync --python ${{ matrix.python-version }} --frozen + - name: Run linters + run: scripts/check + - name: Run tests run: scripts/test - - name: Run linters - run: scripts/lint - # https://github.com/marketplace/actions/alls-green#why used for branch protection checks check: if: always() diff --git a/mangum/adapter.py b/mangum/adapter.py index f5a1e8c0..0bbb10cf 100644 --- a/mangum/adapter.py +++ b/mangum/adapter.py @@ -1,32 +1,20 @@ +from __future__ import annotations + import logging -from itertools import chain from contextlib import ExitStack -from typing import List, Optional, Type +from itertools import chain +from typing import Any -from mangum.protocols import HTTPCycle, LifespanCycle -from mangum.handlers import ALB, HTTPGateway, APIGateway, LambdaAtEdge from mangum.exceptions import ConfigurationError -from mangum.types import ( - ASGI, - LifespanMode, - LambdaConfig, - LambdaEvent, - LambdaContext, - LambdaHandler, -) - +from mangum.handlers import ALB, APIGateway, HTTPGateway, LambdaAtEdge +from mangum.protocols import HTTPCycle, LifespanCycle +from mangum.types import ASGI, LambdaConfig, LambdaContext, LambdaEvent, LambdaHandler, LifespanMode logger = logging.getLogger("mangum") +HANDLERS: list[type[LambdaHandler]] = [ALB, HTTPGateway, APIGateway, LambdaAtEdge] -HANDLERS: List[Type[LambdaHandler]] = [ - ALB, - HTTPGateway, - APIGateway, - LambdaAtEdge, -] - -DEFAULT_TEXT_MIME_TYPES: List[str] = [ +DEFAULT_TEXT_MIME_TYPES: list[str] = [ "text/", "application/json", "application/javascript", @@ -42,9 +30,9 @@ def __init__( app: ASGI, lifespan: LifespanMode = "auto", api_gateway_base_path: str = "/", - custom_handlers: Optional[List[Type[LambdaHandler]]] = None, - text_mime_types: Optional[List[str]] = None, - exclude_headers: Optional[List[str]] = None, + custom_handlers: list[type[LambdaHandler]] | None = None, + text_mime_types: list[str] | None = None, + exclude_headers: list[str] | None = None, ) -> None: if lifespan not in ("auto", "on", "off"): raise ConfigurationError("Invalid argument supplied for `lifespan`. Choices are: auto|on|off") @@ -70,7 +58,7 @@ def infer(self, event: LambdaEvent, context: LambdaContext) -> LambdaHandler: "supported handler.)" ) - def __call__(self, event: LambdaEvent, context: LambdaContext) -> dict: + def __call__(self, event: LambdaEvent, context: LambdaContext) -> dict[str, Any]: handler = self.infer(event, context) with ExitStack() as stack: if self.lifespan in ("auto", "on"): diff --git a/mangum/handlers/__init__.py b/mangum/handlers/__init__.py index d92f8641..5afca3c9 100644 --- a/mangum/handlers/__init__.py +++ b/mangum/handlers/__init__.py @@ -1,6 +1,5 @@ -from mangum.handlers.api_gateway import APIGateway, HTTPGateway from mangum.handlers.alb import ALB +from mangum.handlers.api_gateway import APIGateway, HTTPGateway from mangum.handlers.lambda_at_edge import LambdaAtEdge - __all__ = ["APIGateway", "HTTPGateway", "ALB", "LambdaAtEdge"] diff --git a/mangum/handlers/alb.py b/mangum/handlers/alb.py index 880a341f..ba061a68 100644 --- a/mangum/handlers/alb.py +++ b/mangum/handlers/alb.py @@ -1,6 +1,8 @@ +from __future__ import annotations + from itertools import islice -from typing import Dict, Generator, List, Tuple -from urllib.parse import urlencode, unquote, unquote_plus +from typing import Any, Generator +from urllib.parse import unquote, unquote_plus, urlencode from mangum.handlers.utils import ( get_server_and_port, @@ -9,12 +11,12 @@ maybe_encode_body, ) from mangum.types import ( - Response, - Scope, LambdaConfig, - LambdaEvent, LambdaContext, + LambdaEvent, QueryParams, + Response, + Scope, ) @@ -37,9 +39,9 @@ def all_casings(input_string: str) -> Generator[str, None, None]: yield first.upper() + sub_casing -def case_mutated_headers(multi_value_headers: Dict[str, List[str]]) -> Dict[str, str]: +def case_mutated_headers(multi_value_headers: dict[str, list[str]]) -> dict[str, str]: """Create str/str key/value headers, with duplicate keys case mutated.""" - headers: Dict[str, str] = {} + headers: dict[str, str] = {} for key, values in multi_value_headers.items(): if len(values) > 0: casings = list(islice(all_casings(key), len(values))) @@ -68,8 +70,8 @@ def encode_query_string_for_alb(params: QueryParams) -> bytes: return query_string -def transform_headers(event: LambdaEvent) -> List[Tuple[bytes, bytes]]: - headers: List[Tuple[bytes, bytes]] = [] +def transform_headers(event: LambdaEvent) -> list[tuple[bytes, bytes]]: + headers: list[tuple[bytes, bytes]] = [] if "multiValueHeaders" in event: for k, v in event["multiValueHeaders"].items(): for inner_v in v: @@ -139,8 +141,8 @@ def scope(self) -> Scope: return scope - def __call__(self, response: Response) -> dict: - multi_value_headers: Dict[str, List[str]] = {} + def __call__(self, response: Response) -> dict[str, Any]: + multi_value_headers: dict[str, list[str]] = {} for key, value in response["headers"]: lower_key = key.decode().lower() if lower_key not in multi_value_headers: diff --git a/mangum/handlers/api_gateway.py b/mangum/handlers/api_gateway.py index 8860c504..0ecd3bd0 100644 --- a/mangum/handlers/api_gateway.py +++ b/mangum/handlers/api_gateway.py @@ -1,4 +1,6 @@ -from typing import Dict, List, Tuple +from __future__ import annotations + +from typing import Any from urllib.parse import urlencode from mangum.handlers.utils import ( @@ -10,12 +12,12 @@ strip_api_gateway_path, ) from mangum.types import ( - Response, - LambdaConfig, Headers, - LambdaEvent, + LambdaConfig, LambdaContext, + LambdaEvent, QueryParams, + Response, Scope, ) @@ -30,7 +32,7 @@ def _encode_query_string_for_apigw(event: LambdaEvent) -> bytes: return urlencode(params, doseq=True).encode() -def _handle_multi_value_headers_for_request(event: LambdaEvent) -> Dict[str, str]: +def _handle_multi_value_headers_for_request(event: LambdaEvent) -> dict[str, str]: headers = event.get("headers", {}) or {} headers = {k.lower(): v for k, v in headers.items()} if event.get("multiValueHeaders"): @@ -46,9 +48,9 @@ def _handle_multi_value_headers_for_request(event: LambdaEvent) -> Dict[str, str def _combine_headers_v2( input_headers: Headers, -) -> Tuple[Dict[str, str], List[str]]: - output_headers: Dict[str, str] = {} - cookies: List[str] = [] +) -> tuple[dict[str, str], list[str]]: + output_headers: dict[str, str] = {} + cookies: list[str] = [] for key, value in input_headers: normalized_key: str = key.decode().lower() normalized_value: str = value.decode() @@ -105,7 +107,7 @@ def scope(self) -> Scope: "aws.context": self.context, } - def __call__(self, response: Response) -> dict: + def __call__(self, response: Response) -> dict[str, Any]: finalized_headers, multi_value_headers = handle_multi_value_headers(response["headers"]) finalized_body, is_base64_encoded = handle_base64_response_body( response["body"], finalized_headers, self.config["text_mime_types"] @@ -185,7 +187,7 @@ def scope(self) -> Scope: "aws.context": self.context, } - def __call__(self, response: Response) -> dict: + def __call__(self, response: Response) -> dict[str, Any]: if self.scope["aws.event"]["version"] == "2.0": finalized_headers, cookies = _combine_headers_v2(response["headers"]) diff --git a/mangum/handlers/lambda_at_edge.py b/mangum/handlers/lambda_at_edge.py index b0ae07d1..f4e9e68b 100644 --- a/mangum/handlers/lambda_at_edge.py +++ b/mangum/handlers/lambda_at_edge.py @@ -1,4 +1,6 @@ -from typing import Dict, List +from __future__ import annotations + +from typing import Any from mangum.handlers.utils import ( handle_base64_response_body, @@ -6,7 +8,7 @@ handle_multi_value_headers, maybe_encode_body, ) -from mangum.types import Scope, Response, LambdaConfig, LambdaEvent, LambdaContext +from mangum.types import LambdaConfig, LambdaContext, LambdaEvent, Response, Scope class LambdaAtEdge: @@ -66,12 +68,12 @@ def scope(self) -> Scope: "aws.context": self.context, } - def __call__(self, response: Response) -> dict: + def __call__(self, response: Response) -> dict[str, Any]: multi_value_headers, _ = handle_multi_value_headers(response["headers"]) response_body, is_base64_encoded = handle_base64_response_body( response["body"], multi_value_headers, self.config["text_mime_types"] ) - finalized_headers: Dict[str, List[Dict[str, str]]] = { + finalized_headers: dict[str, list[dict[str, str]]] = { key.decode().lower(): [{"key": key.decode().lower(), "value": val.decode()}] for key, val in response["headers"] } diff --git a/mangum/handlers/utils.py b/mangum/handlers/utils.py index ff2f78d4..d2bdaf05 100644 --- a/mangum/handlers/utils.py +++ b/mangum/handlers/utils.py @@ -1,11 +1,13 @@ +from __future__ import annotations + import base64 -from typing import Any, Dict, List, Tuple, Union +from typing import Any from urllib.parse import unquote from mangum.types import Headers, LambdaConfig -def maybe_encode_body(body: Union[str, bytes], *, is_base64: bool) -> bytes: +def maybe_encode_body(body: str | bytes, *, is_base64: bool) -> bytes: body = body or b"" if is_base64: body = base64.b64decode(body) @@ -15,7 +17,7 @@ def maybe_encode_body(body: Union[str, bytes], *, is_base64: bool) -> bytes: return body -def get_server_and_port(headers: dict) -> Tuple[str, int]: +def get_server_and_port(headers: dict[str, Any]) -> tuple[str, int]: server_name = headers.get("host", "mangum") if ":" not in server_name: server_port = headers.get("x-forwarded-port", 80) @@ -41,9 +43,9 @@ def strip_api_gateway_path(path: str, *, api_gateway_base_path: str) -> str: def handle_multi_value_headers( response_headers: Headers, -) -> Tuple[Dict[str, str], Dict[str, List[str]]]: - headers: Dict[str, str] = {} - multi_value_headers: Dict[str, List[str]] = {} +) -> tuple[dict[str, str], dict[str, list[str]]]: + headers: dict[str, str] = {} + multi_value_headers: dict[str, list[str]] = {} for key, value in response_headers: lower_key = key.decode().lower() if lower_key in multi_value_headers: @@ -62,9 +64,9 @@ def handle_multi_value_headers( def handle_base64_response_body( body: bytes, - headers: Dict[str, str], - text_mime_types: List[str], -) -> Tuple[str, bool]: + headers: dict[str, str], + text_mime_types: list[str], +) -> tuple[str, bool]: is_base64_encoded = False output_body = "" if body != b"": @@ -83,7 +85,7 @@ def handle_base64_response_body( return output_body, is_base64_encoded -def handle_exclude_headers(headers: Dict[str, Any], config: LambdaConfig) -> Dict[str, Any]: +def handle_exclude_headers(headers: dict[str, Any], config: LambdaConfig) -> dict[str, Any]: finalized_headers = {} for header_key, header_value in headers.items(): if header_key in config["exclude_headers"]: diff --git a/mangum/protocols/__init__.py b/mangum/protocols/__init__.py index f8d83845..12571c3e 100644 --- a/mangum/protocols/__init__.py +++ b/mangum/protocols/__init__.py @@ -1,4 +1,4 @@ from .http import HTTPCycle -from .lifespan import LifespanCycleState, LifespanCycle +from .lifespan import LifespanCycle, LifespanCycleState __all__ = ["HTTPCycle", "LifespanCycleState", "LifespanCycle"] diff --git a/mangum/protocols/http.py b/mangum/protocols/http.py index fc957878..f0b50e5e 100644 --- a/mangum/protocols/http.py +++ b/mangum/protocols/http.py @@ -3,8 +3,8 @@ import logging from io import BytesIO -from mangum.types import ASGI, Message, Scope, Response from mangum.exceptions import UnexpectedMessage +from mangum.types import ASGI, Message, Response, Scope class HTTPCycleState(enum.Enum): diff --git a/mangum/protocols/lifespan.py b/mangum/protocols/lifespan.py index 6cd03aca..22ed016d 100644 --- a/mangum/protocols/lifespan.py +++ b/mangum/protocols/lifespan.py @@ -1,11 +1,12 @@ +from __future__ import annotations + import asyncio import enum import logging from types import TracebackType -from typing import Optional, Type +from mangum.exceptions import LifespanFailure, LifespanUnsupported, UnexpectedMessage from mangum.types import ASGI, LifespanMode, Message -from mangum.exceptions import LifespanUnsupported, LifespanFailure, UnexpectedMessage class LifespanCycleState(enum.Enum): @@ -21,7 +22,7 @@ class LifespanCycleState(enum.Enum): * **FAILED** - A lifespan failure has been detected, and the connection will be closed with an error. * **UNSUPPORTED** - An application attempted to send a message before receiving - the lifepan startup event. If the lifespan argument is "on", then the connection + the lifespan startup event. If the lifespan argument is "on", then the connection will be closed with an error. """ @@ -56,7 +57,7 @@ def __init__(self, app: ASGI, lifespan: LifespanMode) -> None: self.app = app self.lifespan = lifespan self.state: LifespanCycleState = LifespanCycleState.CONNECTING - self.exception: Optional[BaseException] = None + self.exception: BaseException | None = None self.loop = asyncio.get_event_loop() self.app_queue: asyncio.Queue[Message] = asyncio.Queue() self.startup_event: asyncio.Event = asyncio.Event() @@ -70,9 +71,9 @@ def __enter__(self) -> None: def __exit__( self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, ) -> None: """Runs the event loop for application shutdown.""" self.loop.run_until_complete(self.shutdown()) diff --git a/mangum/types.py b/mangum/types.py index 42b6758d..1df8c92e 100644 --- a/mangum/types.py +++ b/mangum/types.py @@ -1,18 +1,17 @@ from __future__ import annotations from typing import ( - List, - Dict, Any, - Union, - Optional, - Sequence, - MutableMapping, Awaitable, Callable, + Dict, + List, + MutableMapping, + Sequence, + Union, ) -from typing_extensions import Literal, Protocol, TypedDict, TypeAlias +from typing_extensions import Literal, Protocol, TypeAlias, TypedDict LambdaEvent = Dict[str, Any] QueryParams: TypeAlias = MutableMapping[str, Union[str, Sequence[str]]] @@ -57,8 +56,8 @@ class LambdaMobileClientContext(Protocol): """ client: LambdaMobileClient - custom: Dict[str, Any] - env: Dict[str, Any] + custom: dict[str, Any] + env: dict[str, Any] class LambdaContext(Protocol): @@ -85,8 +84,8 @@ class LambdaContext(Protocol): aws_request_id: str log_group_name: str log_stream_name: str - identity: Optional[LambdaCognitoIdentity] - client_context: Optional[LambdaMobileClientContext] + identity: LambdaCognitoIdentity | None + client_context: LambdaMobileClientContext | None def get_remaining_time_in_millis(self) -> int: """Returns the number of milliseconds left before the execution times out.""" @@ -101,8 +100,7 @@ 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"] @@ -116,25 +114,20 @@ class Response(TypedDict): class LambdaConfig(TypedDict): api_gateway_base_path: str - text_mime_types: List[str] - exclude_headers: List[str] + text_mime_types: list[str] + exclude_headers: list[str] 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[str, Any]: ... # pragma: no cover diff --git a/pyproject.toml b/pyproject.toml index 681f7f98..f858bd0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,8 +31,7 @@ dependencies = ["typing_extensions"] dev-dependencies = [ "pytest", "pytest-cov", - "black", - "flake8", + "ruff", "starlette", "quart", "hypercorn<0.15.0; python_version < '3.8'", @@ -52,5 +51,35 @@ Changelog = "https://github.com/Kludex/mangum/blob/main/CHANGELOG.md" Funding = "https://github.com/sponsors/Kludex" Source = "https://github.com/Kludex/mangum" -[tool.black] +[tool.ruff] line-length = 120 + +[tool.ruff.lint] +select = [ + "E", # https://docs.astral.sh/ruff/rules/#error-e + "F", # https://docs.astral.sh/ruff/rules/#pyflakes-f + "I", # https://docs.astral.sh/ruff/rules/#isort-i + "FA", # https://docs.astral.sh/ruff/rules/#flake8-future-annotations-fa + "UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up + "RUF100", # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf +] +ignore = ["UP031"] # https://docs.astral.sh/ruff/rules/printf-string-formatting/ + +[tool.mypy] +strict = true + +[tool.pytest.ini_options] +addopts = "-rXs --strict-config --strict-markers" +xfail_strict = true + +[tool.coverage.run] +source_pkgs = ["starlette", "tests"] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "pragma: nocover", + "if typing.TYPE_CHECKING:", + "@typing.overload", + "raise NotImplementedError", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index f861f05e..00000000 --- a/pytest.ini +++ /dev/null @@ -1,5 +0,0 @@ -[pytest] -log_cli = 1 -log_cli_level = INFO -log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s) -log_cli_date_format=%Y-%m-%d %H:%M:%S \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md index 16e31575..1742ebd2 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,7 +1,8 @@ # Development Scripts +* `scripts/setup` - Install dependencies. * `scripts/test` - Run the test suite. -* `scripts/lint` - Run the code linting. -* `scripts/publish` - Publish the latest version to PyPI. +* `scripts/lint` - Run the code format. +* `scripts/check` - Run the lint in check mode, and the type checker. Styled after GitHub's ["Scripts to Rule Them All"](https://github.com/github/scripts-to-rule-them-all). diff --git a/scripts/check b/scripts/check new file mode 100755 index 00000000..43b0805d --- /dev/null +++ b/scripts/check @@ -0,0 +1,9 @@ +#!/bin/sh -e + +set -x + +SOURCE_FILES="mangum tests" + +uvx ruff format --check --diff $SOURCE_FILES +uvx ruff check $SOURCE_FILES +uvx mypy mangum diff --git a/scripts/lint b/scripts/lint index 5cd09d38..1fd43771 100755 --- a/scripts/lint +++ b/scripts/lint @@ -2,6 +2,7 @@ set -x -uv run black mangum tests --check -uv run mypy mangum -uv run flake8 mangum tests +SOURCE_FILES="mangum tests" + +uvx ruff format $SOURCE_FILES +uvx ruff check --fix $SOURCE_FILES diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3f382070..00000000 --- a/setup.cfg +++ /dev/null @@ -1,14 +0,0 @@ -[flake8] -max-line-length = 120 -ignore = E203, W503, E704, E231 -per-file-ignores = - tests/conftest.py:E501 - tests/test_http.py:E501 - -[mypy] -disallow_untyped_defs = True -disallow_untyped_calls = True -disallow_incomplete_defs = True -disallow_untyped_decorators = True -ignore_missing_imports = True -show_error_codes = True diff --git a/tests/conftest.py b/tests/conftest.py index 082a0360..cdc8ff70 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -44,7 +44,7 @@ def mock_aws_api_gateway_event(request): "cognitoAuthenticationType": "", "cognitoAuthenticationProvider": "", "userArn": "", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48", # noqa: E501 "user": "", }, "resourcePath": "/{proxy+}", diff --git a/tests/handlers/test_alb.py b/tests/handlers/test_alb.py index 48f133a7..13c1658e 100644 --- a/tests/handlers/test_alb.py +++ b/tests/handlers/test_alb.py @@ -4,7 +4,7 @@ 2. https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html # noqa: E501 """ -from typing import Dict, List, Optional +from __future__ import annotations import pytest @@ -15,8 +15,8 @@ def get_mock_aws_alb_event( method, path, - query_parameters: Optional[Dict[str, List[str]]], - headers: Optional[Dict[str, List[str]]], + query_parameters: dict[str, list[str]] | None, + headers: dict[str, list[str]] | None, body, body_base64_encoded, multi_value_headers: bool, diff --git a/tests/handlers/test_custom.py b/tests/handlers/test_custom.py index 1e93bc16..baddac36 100644 --- a/tests/handlers/test_custom.py +++ b/tests/handlers/test_custom.py @@ -1,10 +1,4 @@ -from mangum.types import ( - Scope, - Headers, - LambdaConfig, - LambdaContext, - LambdaEvent, -) +from mangum.types import Headers, LambdaConfig, LambdaContext, LambdaEvent, Scope class CustomHandler: @@ -23,7 +17,7 @@ def body(self) -> bytes: @property def scope(self) -> Scope: - headers = {} + headers: dict[str, str] = {} return { "type": "http", "http_version": "1.1", diff --git a/tests/handlers/test_lambda_at_edge.py b/tests/handlers/test_lambda_at_edge.py index 018252ce..6c2c2388 100644 --- a/tests/handlers/test_lambda_at_edge.py +++ b/tests/handlers/test_lambda_at_edge.py @@ -26,7 +26,7 @@ def mock_lambda_at_edge_event(method, path, multi_value_query_parameters, body, "distributionDomainName": "mock-distribution.local.localhost", "distributionId": "ABC123DEF456G", "eventType": "origin-request", - "requestId": "lBEBo2N0JKYUP2JXwn_4am2xAXB2GzcL2FlwXI8G59PA8wghF2ImFQ==", # noqa: E501 + "requestId": "lBEBo2N0JKYUP2JXwn_4am2xAXB2GzcL2FlwXI8G59PA8wghF2ImFQ==", }, "request": { "clientIp": "192.168.100.1", @@ -84,7 +84,7 @@ def test_aws_cf_lambda_at_edge_scope_basic(): "distributionDomainName": "d111111abcdef8.cloudfront.net", "distributionId": "EDFDVBD6EXAMPLE", "eventType": "origin-request", - "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ==", # noqa: E501 + "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ==", }, "request": { "clientIp": "203.0.113.178", @@ -94,7 +94,7 @@ def test_aws_cf_lambda_at_edge_scope_basic(): "via": [ { "key": "Via", - "value": "2.0 2afae0d44e2540f472c0635ab62c232b.cloudfront.net (CloudFront)", # noqa: E501 + "value": "2.0 2afae0d44e2540f472c0635ab62c232b.cloudfront.net (CloudFront)", } ], "host": [{"key": "Host", "value": "example.org"}], diff --git a/tests/test_adapter.py b/tests/test_adapter.py index 05483646..faf7050b 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -6,8 +6,7 @@ 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(): diff --git a/tests/test_http.py b/tests/test_http.py index 7a70c1d0..5ec0f5e2 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -2,16 +2,15 @@ import gzip import json -import pytest - import brotli +import pytest from brotli_asgi import BrotliMiddleware - from starlette.applications import Starlette from starlette.middleware.gzip import GZipMiddleware from starlette.responses import PlainTextResponse from mangum import Mangum +from mangum.types import Receive, Scope, Send @pytest.mark.parametrize( @@ -556,7 +555,7 @@ async def app(scope, receive, send): def test_http_binary_br_response(mock_aws_api_gateway_event) -> None: body = json.dumps({"abc": "defg"}) - async def app(scope, receive, send): + async def app(scope: Scope, receive: Receive, send: Send): assert scope["type"] == "http" await send( { @@ -582,8 +581,8 @@ async def app(scope, receive, send): @pytest.mark.parametrize("mock_aws_api_gateway_event", [["GET", b"", None]], indirect=True) -def test_http_logging(mock_aws_api_gateway_event, caplog) -> None: - async def app(scope, receive, send): +def test_http_logging(mock_aws_api_gateway_event, caplog: pytest.LogCaptureFixture) -> None: + async def app(scope: Scope, receive: Receive, send: Send): assert scope["type"] == "http" await send( { diff --git a/tests/test_lifespan.py b/tests/test_lifespan.py index ac09aa4e..42cb0242 100644 --- a/tests/test_lifespan.py +++ b/tests/test_lifespan.py @@ -1,15 +1,13 @@ import logging import pytest - +from quart import Quart from starlette.applications import Starlette from starlette.responses import PlainTextResponse from mangum import Mangum from mangum.exceptions import LifespanFailure -from quart import Quart - @pytest.mark.parametrize( "mock_aws_api_gateway_event,lifespan", diff --git a/uv.lock b/uv.lock index 06bed8d3..93be29da 100644 --- a/uv.lock +++ b/uv.lock @@ -29,48 +29,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5", size = 80896 }, ] -[[package]] -name = "black" -version = "23.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typed-ast", marker = "python_full_version < '3.8' and implementation_name == 'cpython'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/36/66370f5017b100225ec4950a60caeef60201a10080da57ddb24124453fba/black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940", size = 582156 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/f4/7908f71cc71da08df1317a3619f002cbf91927fb5d3ffc7723905a2113f7/black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915", size = 1342273 }, - { url = "https://files.pythonhosted.org/packages/27/70/07aab2623cfd3789786f17e051487a41d5657258c7b1ef8f780512ffea9c/black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9", size = 2676721 }, - { url = "https://files.pythonhosted.org/packages/29/b1/b584fc863c155653963039664a592b3327b002405043b7e761b9b0212337/black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2", size = 1520336 }, - { url = "https://files.pythonhosted.org/packages/6d/b4/0f13ab7f5e364795ff82b76b0f9a4c9c50afda6f1e2feeb8b03fdd7ec57d/black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c", size = 1654611 }, - { url = "https://files.pythonhosted.org/packages/de/b4/76f152c5eb0be5471c22cd18380d31d188930377a1a57969073b89d6615d/black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c", size = 1286657 }, - { url = "https://files.pythonhosted.org/packages/d7/6f/d3832960a3b646b333b7f0d80d336a3c123012e9d9d5dba4a622b2b6181d/black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6", size = 1326112 }, - { url = "https://files.pythonhosted.org/packages/eb/a5/17b40bfd9b607b69fa726b0b3a473d14b093dcd5191ea1a1dd664eccfee3/black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b", size = 2643808 }, - { url = "https://files.pythonhosted.org/packages/69/49/7e1f0cf585b0d607aad3f971f95982cc4208fc77f92363d632d23021ee57/black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d", size = 1503287 }, - { url = "https://files.pythonhosted.org/packages/c0/53/42e312c17cfda5c8fc4b6b396a508218807a3fcbb963b318e49d3ddd11d5/black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70", size = 1638625 }, - { url = "https://files.pythonhosted.org/packages/3f/0d/81dd4194ce7057c199d4f28e4c2a885082d9d929e7a55c514b23784f7787/black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326", size = 1293585 }, - { url = "https://files.pythonhosted.org/packages/24/eb/2d2d2c27cb64cfd073896f62a952a802cd83cf943a692a2f278525b57ca9/black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b", size = 1447428 }, - { url = "https://files.pythonhosted.org/packages/49/36/15d2122f90ff1cd70f06892ebda777b650218cf84b56b5916a993dc1359a/black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2", size = 1576467 }, - { url = "https://files.pythonhosted.org/packages/ca/44/eb41edd3f558a6139f09eee052dead4a7a464e563b822ddf236f5a8ee286/black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925", size = 1226437 }, - { url = "https://files.pythonhosted.org/packages/ce/f4/2b0c6ac9e1f8584296747f66dd511898b4ebd51d6510dba118279bff53b6/black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27", size = 1331955 }, - { url = "https://files.pythonhosted.org/packages/21/14/d5a2bec5fb15f9118baab7123d344646fac0b1c6939d51c2b05259cd2d9c/black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331", size = 2658520 }, - { url = "https://files.pythonhosted.org/packages/13/0a/ed8b66c299e896780e4528eed4018f5b084da3b9ba4ee48328550567d866/black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5", size = 1509852 }, - { url = "https://files.pythonhosted.org/packages/12/4b/99c71d1cf1353edd5aff2700b8960f92e9b805c9dab72639b67dbb449d3a/black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961", size = 1641852 }, - { url = "https://files.pythonhosted.org/packages/d1/6e/5810b6992ed70403124c67e8b3f62858a32b35405177553f1a78ed6b6e31/black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8", size = 1297694 }, - { url = "https://files.pythonhosted.org/packages/13/25/cfa06788d0a936f2445af88f13604b5bcd5c9d050db618c718e6ebe66f74/black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30", size = 1341089 }, - { url = "https://files.pythonhosted.org/packages/fd/5b/fc2d7922c1a6bb49458d424b5be71d251f2d0dc97be9534e35d171bdc653/black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3", size = 2674699 }, - { url = "https://files.pythonhosted.org/packages/49/d7/f3b7da6c772800f5375aeb050a3dcf682f0bbeb41d313c9c2820d0156e4e/black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266", size = 1519946 }, - { url = "https://files.pythonhosted.org/packages/3c/d7/85f3d79f9e543402de2244c4d117793f262149e404ea0168841613c33e07/black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab", size = 1654176 }, - { url = "https://files.pythonhosted.org/packages/06/1e/273d610249f0335afb1ddb03664a03223f4826e3d1a95170a0142cb19fb4/black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb", size = 1286299 }, - { url = "https://files.pythonhosted.org/packages/ad/e7/4642b7f462381799393fbad894ba4b32db00870a797f0616c197b07129a9/black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4", size = 180965 }, -] - [[package]] name = "blinker" version = "1.5" @@ -275,21 +233,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, ] -[[package]] -name = "flake8" -version = "5.0.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "importlib-metadata", version = "4.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "mccabe" }, - { name = "pycodestyle" }, - { name = "pyflakes" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/00/9808c62b2d529cefc69ce4e4a1ea42c0f855effa55817b7327ec5b75e60a/flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db", size = 145862 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/a0/b881b63a17a59d9d07f5c0cc91a29182c8e8a9aa2bde5b3b2b16519c02f4/flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248", size = 61897 }, -] - [[package]] name = "ghp-import" version = "2.1.0" @@ -459,7 +402,7 @@ wheels = [ [[package]] name = "mangum" -version = "0.17.0" +version = "0.18.0" source = { editable = "." } dependencies = [ { name = "typing-extensions" }, @@ -467,10 +410,8 @@ dependencies = [ [package.dev-dependencies] dev = [ - { name = "black" }, { name = "brotli" }, { name = "brotli-asgi" }, - { name = "flake8" }, { name = "hypercorn", version = "0.14.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, { name = "hypercorn", version = "0.17.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, { name = "mkautodoc" }, @@ -481,6 +422,7 @@ dev = [ { name = "pytest-cov" }, { name = "quart", version = "0.18.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, { name = "quart", version = "0.18.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, + { name = "ruff" }, { name = "starlette" }, ] @@ -489,10 +431,8 @@ requires-dist = [{ name = "typing-extensions" }] [package.metadata.requires-dev] dev = [ - { name = "black" }, { name = "brotli" }, { name = "brotli-asgi" }, - { name = "flake8" }, { name = "hypercorn", marker = "python_full_version < '3.8'", specifier = "<0.15.0" }, { name = "hypercorn", marker = "python_full_version >= '3.8'", specifier = ">=0.15.0" }, { name = "mkautodoc" }, @@ -502,6 +442,7 @@ dev = [ { name = "pytest" }, { name = "pytest-cov" }, { name = "quart" }, + { name = "ruff" }, { name = "starlette" }, ] @@ -602,15 +543,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", size = 17211 }, ] -[[package]] -name = "mccabe" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350 }, -] - [[package]] name = "mergedeep" version = "1.3.4" @@ -766,9 +698,6 @@ wheels = [ name = "platformdirs" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.8'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/31/28/e40d24d2e2eb23135f8533ad33d582359c7825623b1e022f9d460def7c05/platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731", size = 19914 } wheels = [ { url = "https://files.pythonhosted.org/packages/31/16/70be3b725073035aa5fc3229321d06e22e73e3e09f6af78dcfdf16c7636c/platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b", size = 17562 }, @@ -795,24 +724,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa", size = 8946 }, ] -[[package]] -name = "pycodestyle" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/83/5bcaedba1f47200f0665ceb07bcb00e2be123192742ee0edfb66b600e5fd/pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785", size = 102127 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/e4/fc77f1039c34b3612c4867b69cbb2b8a4e569720b1f19b0637002ee03aff/pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b", size = 41493 }, -] - -[[package]] -name = "pyflakes" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/07/92/f0cb5381f752e89a598dd2850941e7f570ac3cb8ea4a344854de486db152/pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3", size = 66388 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/13/63178f59f74e53acc2165aee4b002619a3cfa7eeaeac989a9eb41edf364e/pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2", size = 66116 }, -] - [[package]] name = "pygments" version = "2.17.2" @@ -989,6 +900,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/79/ccd45c2374711b632647aad3dc27af4341c96a852049603493e33c288762/quart-0.18.4-py3-none-any.whl", hash = "sha256:578a466bcd8c58b947b384ca3517c2a2f3bfeec8f58f4ff5038d4506ffee6be7", size = 100195 }, ] +[[package]] +name = "ruff" +version = "0.6.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/f9/4ce3e765a72ab8fe0f80f48508ea38b4196daab3da14d803c21349b2d367/ruff-0.6.8.tar.gz", hash = "sha256:a5bf44b1aa0adaf6d9d20f86162b34f7c593bfedabc51239953e446aefc8ce18", size = 3084543 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/07/42ee57e8b76ca585297a663a552b4f6d6a99372ca47fdc2276ef72cc0f2f/ruff-0.6.8-py3-none-linux_armv6l.whl", hash = "sha256:77944bca110ff0a43b768f05a529fecd0706aac7bcce36d7f1eeb4cbfca5f0f2", size = 10404327 }, + { url = "https://files.pythonhosted.org/packages/eb/51/d42571ff8156d65086acb72d39aa64cb24181db53b497d0ed6293f43f07a/ruff-0.6.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27b87e1801e786cd6ede4ada3faa5e254ce774de835e6723fd94551464c56b8c", size = 10018797 }, + { url = "https://files.pythonhosted.org/packages/c1/d7/fa5514a60b03976af972b67fe345deb0335dc96b9f9a9fa4df9890472427/ruff-0.6.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd48f945da2a6334f1793d7f701725a76ba93bf3d73c36f6b21fb04d5338dcf5", size = 9691303 }, + { url = "https://files.pythonhosted.org/packages/d6/c4/d812a74976927e51d0782a47539069657ac78535779bfa4d061c4fc8d89d/ruff-0.6.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:677e03c00f37c66cea033274295a983c7c546edea5043d0c798833adf4cf4c6f", size = 10719452 }, + { url = "https://files.pythonhosted.org/packages/ec/b6/aa700c4ae6db9b3ee660e23f3c7db596e2b16a3034b797704fba33ddbc96/ruff-0.6.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f1476236b3eacfacfc0f66aa9e6cd39f2a624cb73ea99189556015f27c0bdeb", size = 10161353 }, + { url = "https://files.pythonhosted.org/packages/ea/39/0b10075ffcd52ff3a581b9b69eac53579deb230aad300ce8f9d0b58e77bc/ruff-0.6.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f5a2f17c7d32991169195d52a04c95b256378bbf0de8cb98478351eb70d526f", size = 10980630 }, + { url = "https://files.pythonhosted.org/packages/c1/af/9eb9efc98334f62652e2f9318f137b2667187851911fac3b395365a83708/ruff-0.6.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5fd0d4b7b1457c49e435ee1e437900ced9b35cb8dc5178921dfb7d98d65a08d0", size = 11768996 }, + { url = "https://files.pythonhosted.org/packages/e0/59/8b1369cf7878358952b1c0a1559b4d6b5c824c003d09b0db26d26c9d094f/ruff-0.6.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8034b19b993e9601f2ddf2c517451e17a6ab5cdb1c13fdff50c1442a7171d87", size = 11317469 }, + { url = "https://files.pythonhosted.org/packages/b9/6d/e252e9b11bbca4114c386ee41ad559d0dac13246201d77ea1223c6fea17f/ruff-0.6.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cfb227b932ba8ef6e56c9f875d987973cd5e35bc5d05f5abf045af78ad8e098", size = 12467185 }, + { url = "https://files.pythonhosted.org/packages/48/44/7caa223af7d4ea0f0b2bd34acca65a7694a58317714675a2478815ab3f45/ruff-0.6.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef0411eccfc3909269fed47c61ffebdcb84a04504bafa6b6df9b85c27e813b0", size = 10887766 }, + { url = "https://files.pythonhosted.org/packages/81/ed/394aff3a785f171869158b9d5be61eec9ffb823c3ad5d2bdf2e5f13cb029/ruff-0.6.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:007dee844738c3d2e6c24ab5bc7d43c99ba3e1943bd2d95d598582e9c1b27750", size = 10711609 }, + { url = "https://files.pythonhosted.org/packages/47/31/f31d04c842e54699eab7e3b864538fea26e6c94b71806cd10aa49f13e1c1/ruff-0.6.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ce60058d3cdd8490e5e5471ef086b3f1e90ab872b548814e35930e21d848c9ce", size = 10237621 }, + { url = "https://files.pythonhosted.org/packages/20/95/a764e84acf11d425f2f23b8b78b4fd715e9c20be4aac157c6414ca859a67/ruff-0.6.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1085c455d1b3fdb8021ad534379c60353b81ba079712bce7a900e834859182fa", size = 10558329 }, + { url = "https://files.pythonhosted.org/packages/2a/76/d4e38846ac9f6dd62dce858a54583911361b5339dcf8f84419241efac93a/ruff-0.6.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:70edf6a93b19481affd287d696d9e311388d808671bc209fb8907b46a8c3af44", size = 10954102 }, + { url = "https://files.pythonhosted.org/packages/e7/36/f18c678da6c69f8d022480f3e8ddce6e4a52e07602c1d212056fbd234f8f/ruff-0.6.8-py3-none-win32.whl", hash = "sha256:792213f7be25316f9b46b854df80a77e0da87ec66691e8f012f887b4a671ab5a", size = 8511090 }, + { url = "https://files.pythonhosted.org/packages/4c/c4/0ca7d8ffa358b109db7d7d045a1a076fd8e5d9cbeae022242d3c060931da/ruff-0.6.8-py3-none-win_amd64.whl", hash = "sha256:ec0517dc0f37cad14a5319ba7bba6e7e339d03fbf967a6d69b0907d61be7a263", size = 9350079 }, + { url = "https://files.pythonhosted.org/packages/d9/bd/a8b0c64945a92eaeeb8d0283f27a726a776a1c9d12734d990c5fc7a1278c/ruff-0.6.8-py3-none-win_arm64.whl", hash = "sha256:8d3bb2e3fbb9875172119021a13eed38849e762499e3cfde9588e4b4d70968dc", size = 8669595 }, +] + [[package]] name = "six" version = "1.16.0" From 95e2e6be133a33453e3ae84fe3bede2e66ba445a Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 26 Sep 2024 21:42:55 +0200 Subject: [PATCH 2/6] Ignore DeprecationWarnings --- pyproject.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index f858bd0c..da83b9d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,15 @@ strict = true [tool.pytest.ini_options] addopts = "-rXs --strict-config --strict-markers" xfail_strict = true +filterwarnings = [ + # Turn warnings that aren't filtered into exceptions + "error", + "ignore::DeprecationWarning:starlette", + "ignore: There is no current event loop:DeprecationWarning", + "ignore: 'pkgutil.get_loader' is deprecated.*:DeprecationWarning", + "ignore: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning", + "ignore: Attribute s is deprecated and will be removed in Python 3.14; use value instead:DeprecationWarning", +] [tool.coverage.run] source_pkgs = ["starlette", "tests"] From 567dff5d4060b6840fe01bc287856b9b7c6e59c1 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 26 Sep 2024 21:52:08 +0200 Subject: [PATCH 3/6] Update pyproject --- pyproject.toml | 4 ++++ tests/test_http.py | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index da83b9d0..865e8f30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,6 +69,10 @@ ignore = ["UP031"] # https://docs.astral.sh/ruff/rules/printf-string-formatting/ strict = true [tool.pytest.ini_options] +log_cli = true +log_cli_level = "INFO" +log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)" +log_cli_date_format = "%Y-%m-%d %H:%M:%S" addopts = "-rXs --strict-config --strict-markers" xfail_strict = true filterwarnings = [ diff --git a/tests/test_http.py b/tests/test_http.py index 5ec0f5e2..35300f0d 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import base64 import gzip import json @@ -10,7 +12,6 @@ from starlette.responses import PlainTextResponse from mangum import Mangum -from mangum.types import Receive, Scope, Send @pytest.mark.parametrize( @@ -555,7 +556,7 @@ async def app(scope, receive, send): def test_http_binary_br_response(mock_aws_api_gateway_event) -> None: body = json.dumps({"abc": "defg"}) - async def app(scope: Scope, receive: Receive, send: Send): + async def app(scope, receive, send): assert scope["type"] == "http" await send( { @@ -582,7 +583,7 @@ async def app(scope: Scope, receive: Receive, send: Send): @pytest.mark.parametrize("mock_aws_api_gateway_event", [["GET", b"", None]], indirect=True) def test_http_logging(mock_aws_api_gateway_event, caplog: pytest.LogCaptureFixture) -> None: - async def app(scope: Scope, receive: Receive, send: Send): + async def app(scope, receive, send): assert scope["type"] == "http" await send( { From 59a2192168acf16ebb8523582468ffd24fd869b3 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 26 Sep 2024 21:55:24 +0200 Subject: [PATCH 4/6] Add ignore for DeprecationWarning --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 865e8f30..3bd9209b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,6 +83,7 @@ filterwarnings = [ "ignore: 'pkgutil.get_loader' is deprecated.*:DeprecationWarning", "ignore: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning", "ignore: Attribute s is deprecated and will be removed in Python 3.14; use value instead:DeprecationWarning", + "ignore: Constant.__init__ got an unexpected keyword argument 's'. Support for arbitrary keyword arguments is deprecated and will be removed in Python 3.15.:DeprecationWarning", ] [tool.coverage.run] From 72453f76db7890f2f714730b9b52f0128c49bbca Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 26 Sep 2024 21:58:16 +0200 Subject: [PATCH 5/6] Add ignore for DeprecationWarning --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 3bd9209b..52be6268 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,6 +84,7 @@ filterwarnings = [ "ignore: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning", "ignore: Attribute s is deprecated and will be removed in Python 3.14; use value instead:DeprecationWarning", "ignore: Constant.__init__ got an unexpected keyword argument 's'. Support for arbitrary keyword arguments is deprecated and will be removed in Python 3.15.:DeprecationWarning", + "ignore: Constant.__init__ missing 1 required positional argument: 'value'. This will become an error in Python 3.15.:DeprecationWarning", ] [tool.coverage.run] From bfd0385fe574e0b0cc0457dceb925593308f4869 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 26 Sep 2024 22:00:24 +0200 Subject: [PATCH 6/6] Add ignore for DeprecationWarning --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 52be6268..72f284a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,11 +84,11 @@ filterwarnings = [ "ignore: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning", "ignore: Attribute s is deprecated and will be removed in Python 3.14; use value instead:DeprecationWarning", "ignore: Constant.__init__ got an unexpected keyword argument 's'. Support for arbitrary keyword arguments is deprecated and will be removed in Python 3.15.:DeprecationWarning", - "ignore: Constant.__init__ missing 1 required positional argument: 'value'. This will become an error in Python 3.15.:DeprecationWarning", + "ignore: Constant.__init__ missing 1 required positional argument.*:DeprecationWarning", ] [tool.coverage.run] -source_pkgs = ["starlette", "tests"] +source_pkgs = ["mangum", "tests"] [tool.coverage.report] exclude_lines = [