diff --git a/pyproject.toml b/pyproject.toml index 2fd7fb48..b1271db8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ path = "starlette/__init__.py" [tool.ruff.lint] select = ["E", "F", "I", "FA", "UP"] +ignore = ["UP031"] [tool.ruff.lint.isort] combine-as-imports = true @@ -78,6 +79,8 @@ filterwarnings = [ "ignore: The `allow_redirects` argument is deprecated. Use `follow_redirects` instead.:DeprecationWarning", "ignore: 'cgi' is deprecated and slated for removal in Python 3.13:DeprecationWarning", "ignore: You seem to already have a custom sys.excepthook handler installed. I'll skip installing Trio's custom handler, but this means MultiErrors will not show full tracebacks.:RuntimeWarning", + # TODO: This warning appeared when we bumped anyio to 4.4.0. + "ignore: Unclosed .MemoryObject(Send|Receive)Stream.:ResourceWarning", ] [tool.coverage.run] diff --git a/requirements.txt b/requirements.txt index e828ffeb..2e2e4f9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,25 +2,25 @@ -e .[full] # TODO: We need to delete the following line when fixing the test suite for anyio 4.4.0. -anyio==4.3.0 +anyio==4.4.0 # Testing -coverage==7.4.3 -importlib-metadata==7.0.1 -mypy==1.8.0 -ruff==0.1.15 -typing_extensions==4.10.0 +coverage==7.5.4 +importlib-metadata==8.0.0 +mypy==1.10.1 +ruff==0.5.0 +typing_extensions==4.12.2 types-contextvars==2.4.7.3 -types-PyYAML==6.0.12.12 +types-PyYAML==6.0.12.20240311 types-dataclasses==0.6.6 -pytest==8.0.2 -trio==0.24.0 +pytest==8.2.2 +trio==0.25.1 # Documentation -mkdocs==1.5.3 -mkdocs-material==9.5.12 +mkdocs==1.6.0 +mkdocs-material==9.5.27 mkautodoc==0.2.0 # Packaging -build==1.1.1 -twine==5.0.0 +build==1.2.1 +twine==5.1.1 diff --git a/scripts/lint b/scripts/lint index 586aedfc..19dbc7db 100755 --- a/scripts/lint +++ b/scripts/lint @@ -9,4 +9,4 @@ export SOURCE_FILES="starlette tests" set -x ${PREFIX}ruff format $SOURCE_FILES -${PREFIX}ruff --fix $SOURCE_FILES +${PREFIX}ruff check --fix $SOURCE_FILES diff --git a/starlette/_utils.py b/starlette/_utils.py index 42777c58..b6970542 100644 --- a/starlette/_utils.py +++ b/starlette/_utils.py @@ -26,13 +26,11 @@ AwaitableCallable = typing.Callable[..., typing.Awaitable[T]] @typing.overload -def is_async_callable(obj: AwaitableCallable[T]) -> TypeGuard[AwaitableCallable[T]]: - ... +def is_async_callable(obj: AwaitableCallable[T]) -> TypeGuard[AwaitableCallable[T]]: ... @typing.overload -def is_async_callable(obj: typing.Any) -> TypeGuard[AwaitableCallable[typing.Any]]: - ... +def is_async_callable(obj: typing.Any) -> TypeGuard[AwaitableCallable[typing.Any]]: ... def is_async_callable(obj: typing.Any) -> typing.Any: @@ -49,13 +47,11 @@ T_co = typing.TypeVar("T_co", covariant=True) class AwaitableOrContextManager( typing.Awaitable[T_co], typing.AsyncContextManager[T_co], typing.Protocol[T_co] -): - ... +): ... class SupportsAsyncClose(typing.Protocol): - async def close(self) -> None: - ... # pragma: no cover + async def close(self) -> None: ... # pragma: no cover SupportsAsyncCloseType = typing.TypeVar( diff --git a/starlette/config.py b/starlette/config.py index 5b9813be..4c3dfe5b 100644 --- a/starlette/config.py +++ b/starlette/config.py @@ -68,16 +68,13 @@ class Config: self.file_values = self._read_file(env_file) @typing.overload - def __call__(self, key: str, *, default: None) -> str | None: - ... + def __call__(self, key: str, *, default: None) -> str | None: ... @typing.overload - def __call__(self, key: str, cast: type[T], default: T = ...) -> T: - ... + def __call__(self, key: str, cast: type[T], default: T = ...) -> T: ... @typing.overload - def __call__(self, key: str, cast: type[str] = ..., default: str = ...) -> str: - ... + def __call__(self, key: str, cast: type[str] = ..., default: str = ...) -> str: ... @typing.overload def __call__( @@ -85,12 +82,12 @@ class Config: key: str, cast: typing.Callable[[typing.Any], T] = ..., default: typing.Any = ..., - ) -> T: - ... + ) -> T: ... @typing.overload - def __call__(self, key: str, cast: type[str] = ..., default: T = ...) -> T | str: - ... + def __call__( + self, key: str, cast: type[str] = ..., default: T = ... + ) -> T | str: ... def __call__( self, diff --git a/starlette/middleware/__init__.py b/starlette/middleware/__init__.py index 3d0342dc..d9e64f57 100644 --- a/starlette/middleware/__init__.py +++ b/starlette/middleware/__init__.py @@ -14,11 +14,13 @@ P = ParamSpec("P") class _MiddlewareClass(Protocol[P]): - def __init__(self, app: ASGIApp, *args: P.args, **kwargs: P.kwargs) -> None: - ... # pragma: no cover + def __init__( + self, app: ASGIApp, *args: P.args, **kwargs: P.kwargs + ) -> None: ... # pragma: no cover - 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 class Middleware: diff --git a/starlette/responses.py b/starlette/responses.py index 1f41c23d..4f15404c 100644 --- a/starlette/responses.py +++ b/starlette/responses.py @@ -299,12 +299,10 @@ class FileResponse(Response): if self.filename is not None: content_disposition_filename = quote(self.filename) if content_disposition_filename != self.filename: - content_disposition = "{}; filename*=utf-8''{}".format( - content_disposition_type, content_disposition_filename - ) + content_disposition = f"{content_disposition_type}; filename*=utf-8''{content_disposition_filename}" # noqa: E501 else: - content_disposition = '{}; filename="{}"'.format( - content_disposition_type, self.filename + content_disposition = ( + f'{content_disposition_type}; filename="{self.filename}"' ) self.headers.setdefault("content-disposition", content_disposition) self.stat_result = stat_result diff --git a/starlette/status.py b/starlette/status.py index 2cd5db57..93ae7a17 100644 --- a/starlette/status.py +++ b/starlette/status.py @@ -5,6 +5,7 @@ https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml And RFC 2324 - https://tools.ietf.org/html/rfc2324 """ + from __future__ import annotations import warnings diff --git a/starlette/templating.py b/starlette/templating.py index 8e1737f6..aae2cbe2 100644 --- a/starlette/templating.py +++ b/starlette/templating.py @@ -71,8 +71,7 @@ class Jinja2Templates: context_processors: list[typing.Callable[[Request], dict[str, typing.Any]]] | None = None, **env_options: typing.Any, - ) -> None: - ... + ) -> None: ... @typing.overload def __init__( @@ -81,8 +80,7 @@ class Jinja2Templates: env: jinja2.Environment, context_processors: list[typing.Callable[[Request], dict[str, typing.Any]]] | None = None, - ) -> None: - ... + ) -> None: ... def __init__( self, @@ -150,8 +148,7 @@ class Jinja2Templates: headers: typing.Mapping[str, str] | None = None, media_type: str | None = None, background: BackgroundTask | None = None, - ) -> _TemplateResponse: - ... + ) -> _TemplateResponse: ... @typing.overload def TemplateResponse( diff --git a/tests/test__utils.py b/tests/test__utils.py index 06fece58..2ecf4748 100644 --- a/tests/test__utils.py +++ b/tests/test__utils.py @@ -5,22 +5,18 @@ from starlette._utils import is_async_callable def test_async_func() -> None: - async def async_func() -> None: - ... # pragma: no cover + async def async_func() -> None: ... # pragma: no cover - def func() -> None: - ... # pragma: no cover + def func() -> None: ... # pragma: no cover assert is_async_callable(async_func) assert not is_async_callable(func) def test_async_partial() -> None: - async def async_func(a: Any, b: Any) -> None: - ... # pragma: no cover + async def async_func(a: Any, b: Any) -> None: ... # pragma: no cover - def func(a: Any, b: Any) -> None: - ... # pragma: no cover + def func(a: Any, b: Any) -> None: ... # pragma: no cover partial = functools.partial(async_func, 1) assert is_async_callable(partial) @@ -31,12 +27,10 @@ def test_async_partial() -> None: def test_async_method() -> None: class Async: - async def method(self) -> None: - ... # pragma: no cover + async def method(self) -> None: ... # pragma: no cover class Sync: - def method(self) -> None: - ... # pragma: no cover + def method(self) -> None: ... # pragma: no cover assert is_async_callable(Async().method) assert not is_async_callable(Sync().method) @@ -44,12 +38,10 @@ def test_async_method() -> None: def test_async_object_call() -> None: class Async: - async def __call__(self) -> None: - ... # pragma: no cover + async def __call__(self) -> None: ... # pragma: no cover class Sync: - def __call__(self) -> None: - ... # pragma: no cover + def __call__(self) -> None: ... # pragma: no cover assert is_async_callable(Async()) assert not is_async_callable(Sync()) @@ -61,16 +53,14 @@ def test_async_partial_object_call() -> None: self, a: Any, b: Any, - ) -> None: - ... # pragma: no cover + ) -> None: ... # pragma: no cover class Sync: def __call__( self, a: Any, b: Any, - ) -> None: - ... # pragma: no cover + ) -> None: ... # pragma: no cover partial = functools.partial(Async(), 1) assert is_async_callable(partial) @@ -83,8 +73,7 @@ def test_async_nested_partial() -> None: async def async_func( a: Any, b: Any, - ) -> None: - ... # pragma: no cover + ) -> None: ... # pragma: no cover partial = functools.partial(async_func, b=2) nested_partial = functools.partial(partial, a=1) diff --git a/tests/test_applications.py b/tests/test_applications.py index 5b6c9d54..af3cdda6 100644 --- a/tests/test_applications.py +++ b/tests/test_applications.py @@ -463,8 +463,7 @@ def test_decorator_deprecations() -> None: async def middleware( request: Request, call_next: RequestResponseEndpoint - ) -> None: - ... # pragma: no cover + ) -> None: ... # pragma: no cover app.middleware("http")(middleware) assert len(record) == 1 @@ -494,8 +493,7 @@ def test_decorator_deprecations() -> None: ) ) as record: - async def startup() -> None: - ... # pragma: no cover + async def startup() -> None: ... # pragma: no cover app.on_event("startup")(startup) assert len(record) == 1 diff --git a/tests/test_responses.py b/tests/test_responses.py index c134cbda..f05529dd 100644 --- a/tests/test_responses.py +++ b/tests/test_responses.py @@ -510,17 +510,17 @@ def test_streaming_response_known_size(test_client_factory: TestClientFactory) - def test_response_memoryview(test_client_factory: TestClientFactory) -> None: - app = Response(content=memoryview(b"\xC0")) + app = Response(content=memoryview(b"\xc0")) client: TestClient = test_client_factory(app) response = client.get("/") - assert response.content == b"\xC0" + assert response.content == b"\xc0" def test_streaming_response_memoryview(test_client_factory: TestClientFactory) -> None: - app = StreamingResponse(content=iter([memoryview(b"\xC0"), memoryview(b"\xF5")])) + app = StreamingResponse(content=iter([memoryview(b"\xc0"), memoryview(b"\xf5")])) client: TestClient = test_client_factory(app) response = client.get("/") - assert response.content == b"\xC0\xF5" + assert response.content == b"\xc0\xf5" @pytest.mark.anyio diff --git a/tests/test_routing.py b/tests/test_routing.py index b75fc47f..03c31c67 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -909,19 +909,15 @@ def test_duplicated_param_names() -> None: class Endpoint: - async def my_method(self, request: Request) -> None: - ... # pragma: no cover + async def my_method(self, request: Request) -> None: ... # pragma: no cover @classmethod - async def my_classmethod(cls, request: Request) -> None: - ... # pragma: no cover + async def my_classmethod(cls, request: Request) -> None: ... # pragma: no cover @staticmethod - async def my_staticmethod(request: Request) -> None: - ... # pragma: no cover + async def my_staticmethod(request: Request) -> None: ... # pragma: no cover - def __call__(self, request: Request) -> None: - ... # pragma: no cover + def __call__(self, request: Request) -> None: ... # pragma: no cover @pytest.mark.parametrize( @@ -1254,8 +1250,7 @@ def test_decorator_deprecations() -> None: with pytest.deprecated_call(): - async def startup() -> None: - ... # pragma: nocover + async def startup() -> None: ... # pragma: nocover router.on_event("startup")(startup) diff --git a/tests/test_websockets.py b/tests/test_websockets.py index 854c2691..95ffbdbe 100644 --- a/tests/test_websockets.py +++ b/tests/test_websockets.py @@ -492,8 +492,7 @@ def test_websocket_scope_interface() -> None: async def mock_receive() -> Message: # type: ignore ... # pragma: no cover - async def mock_send(message: Message) -> None: - ... # pragma: no cover + async def mock_send(message: Message) -> None: ... # pragma: no cover websocket = WebSocket( {"type": "websocket", "path": "/abc/", "headers": []},