Skip to content

Commit

Permalink
Enforce __future__.annotations (#2483)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kludex authored Feb 29, 2024
1 parent a4cd0b5 commit bd77d7d
Show file tree
Hide file tree
Showing 28 changed files with 118 additions and 104 deletions.
11 changes: 3 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ description = "The little ASGI library that shines."
readme = "README.md"
license = "BSD-3-Clause"
requires-python = ">=3.8"
authors = [
{ name = "Tom Christie", email = "[email protected]" },
]
authors = [{ name = "Tom Christie", email = "[email protected]" }]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
Expand Down Expand Up @@ -52,7 +50,7 @@ Source = "https://github.com/encode/starlette"
path = "starlette/__init__.py"

[tool.ruff.lint]
select = ["E", "F", "I"]
select = ["E", "F", "I", "FA", "UP"]

[tool.ruff.lint.isort]
combine-as-imports = true
Expand Down Expand Up @@ -83,10 +81,7 @@ filterwarnings = [
]

[tool.coverage.run]
source_pkgs = [
"starlette",
"tests",
]
source_pkgs = ["starlette", "tests"]

[tool.coverage.report]
exclude_lines = [
Expand Down
12 changes: 6 additions & 6 deletions starlette/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def __init__(
{} if exception_handlers is None else dict(exception_handlers)
)
self.user_middleware = [] if middleware is None else list(middleware)
self.middleware_stack: typing.Optional[ASGIApp] = None
self.middleware_stack: ASGIApp | None = None

def build_middleware_stack(self) -> ASGIApp:
debug = self.debug
Expand Down Expand Up @@ -133,7 +133,7 @@ def host(self, host: str, app: ASGIApp, name: str | None = None) -> None:

def add_middleware(
self,
middleware_class: typing.Type[_MiddlewareClass[P]],
middleware_class: type[_MiddlewareClass[P]],
*args: P.args,
**kwargs: P.kwargs,
) -> None:
Expand All @@ -143,7 +143,7 @@ def add_middleware(

def add_exception_handler(
self,
exc_class_or_status_code: int | typing.Type[Exception],
exc_class_or_status_code: int | type[Exception],
handler: ExceptionHandler,
) -> None: # pragma: no cover
self.exception_handlers[exc_class_or_status_code] = handler
Expand All @@ -159,8 +159,8 @@ def add_route(
self,
path: str,
route: typing.Callable[[Request], typing.Awaitable[Response] | Response],
methods: typing.Optional[typing.List[str]] = None,
name: typing.Optional[str] = None,
methods: list[str] | None = None,
name: str | None = None,
include_in_schema: bool = True,
) -> None: # pragma: no cover
self.router.add_route(
Expand All @@ -176,7 +176,7 @@ def add_websocket_route(
self.router.add_websocket_route(path, route, name=name)

def exception_handler(
self, exc_class_or_status_code: int | typing.Type[Exception]
self, exc_class_or_status_code: int | type[Exception]
) -> typing.Callable: # type: ignore[type-arg]
warnings.warn(
"The `exception_handler` decorator is deprecated, and will be removed in version 1.0.0. " # noqa: E501
Expand Down
10 changes: 2 additions & 8 deletions starlette/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ async def async_wrapper(*args: _P.args, **kwargs: _P.kwargs) -> typing.Any:
if not has_required_scope(request, scopes_list):
if redirect is not None:
orig_request_qparam = urlencode({"next": str(request.url)})
next_url = "{redirect_path}?{orig_request}".format(
redirect_path=request.url_for(redirect),
orig_request=orig_request_qparam,
)
next_url = f"{request.url_for(redirect)}?{orig_request_qparam}"
return RedirectResponse(url=next_url, status_code=303)
raise HTTPException(status_code=status_code)
return await func(*args, **kwargs)
Expand All @@ -95,10 +92,7 @@ def sync_wrapper(*args: _P.args, **kwargs: _P.kwargs) -> typing.Any:
if not has_required_scope(request, scopes_list):
if redirect is not None:
orig_request_qparam = urlencode({"next": str(request.url)})
next_url = "{redirect_path}?{orig_request}".format(
redirect_path=request.url_for(redirect),
orig_request=orig_request_qparam,
)
next_url = f"{request.url_for(redirect)}?{orig_request_qparam}"
return RedirectResponse(url=next_url, status_code=303)
raise HTTPException(status_code=status_code)
return func(*args, **kwargs)
Expand Down
6 changes: 3 additions & 3 deletions starlette/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class EnvironError(Exception):
class Environ(typing.MutableMapping[str, str]):
def __init__(self, environ: typing.MutableMapping[str, str] = os.environ):
self._environ = environ
self._has_been_read: typing.Set[str] = set()
self._has_been_read: set[str] = set()

def __getitem__(self, key: str) -> str:
self._has_been_read.add(key)
Expand Down Expand Up @@ -60,7 +60,7 @@ def __init__(
) -> None:
self.environ = environ
self.env_prefix = env_prefix
self.file_values: typing.Dict[str, str] = {}
self.file_values: dict[str, str] = {}
if env_file is not None:
if not os.path.isfile(env_file):
warnings.warn(f"Config file '{env_file}' not found.")
Expand Down Expand Up @@ -118,7 +118,7 @@ def get(
raise KeyError(f"Config '{key}' is missing, and has no default.")

def _read_file(self, file_name: str | Path) -> dict[str, str]:
file_values: typing.Dict[str, str] = {}
file_values: dict[str, str] = {}
with open(file_name) as input_file:
for line in input_file.readlines():
line = line.strip()
Expand Down
4 changes: 3 additions & 1 deletion starlette/convertors.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import math
import typing
import uuid
Expand Down Expand Up @@ -74,7 +76,7 @@ def to_string(self, value: uuid.UUID) -> str:
return str(value)


CONVERTOR_TYPES: typing.Dict[str, Convertor[typing.Any]] = {
CONVERTOR_TYPES: dict[str, Convertor[typing.Any]] = {
"str": StringConvertor(),
"path": PathConvertor(),
"int": IntegerConvertor(),
Expand Down
12 changes: 6 additions & 6 deletions starlette/datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def replace_query_params(self, **kwargs: typing.Any) -> URL:
query = urlencode([(str(key), str(value)) for key, value in kwargs.items()])
return self.replace(query=query)

def remove_query_params(self, keys: str | typing.Sequence[str]) -> "URL":
def remove_query_params(self, keys: str | typing.Sequence[str]) -> URL:
if isinstance(keys, str):
keys = [keys]
params = MultiDict(parse_qsl(self.query, keep_blank_values=True))
Expand Down Expand Up @@ -178,7 +178,7 @@ class URLPath(str):
Used by the routing to return `url_path_for` matches.
"""

def __new__(cls, path: str, protocol: str = "", host: str = "") -> "URLPath":
def __new__(cls, path: str, protocol: str = "", host: str = "") -> URLPath:
assert protocol in ("http", "websocket", "")
return str.__new__(cls, path)

Expand Down Expand Up @@ -251,13 +251,13 @@ def __str__(self) -> str:


class ImmutableMultiDict(typing.Mapping[_KeyType, _CovariantValueType]):
_dict: typing.Dict[_KeyType, _CovariantValueType]
_dict: dict[_KeyType, _CovariantValueType]

def __init__(
self,
*args: ImmutableMultiDict[_KeyType, _CovariantValueType]
| typing.Mapping[_KeyType, _CovariantValueType]
| typing.Iterable[typing.Tuple[_KeyType, _CovariantValueType]],
| typing.Iterable[tuple[_KeyType, _CovariantValueType]],
**kwargs: typing.Any,
) -> None:
assert len(args) < 2, "Too many arguments."
Expand Down Expand Up @@ -599,7 +599,7 @@ def __setitem__(self, key: str, value: str) -> None:
set_key = key.lower().encode("latin-1")
set_value = value.encode("latin-1")

found_indexes: "typing.List[int]" = []
found_indexes: list[int] = []
for idx, (item_key, item_value) in enumerate(self._list):
if item_key == set_key:
found_indexes.append(idx)
Expand All @@ -619,7 +619,7 @@ def __delitem__(self, key: str) -> None:
"""
del_key = key.lower().encode("latin-1")

pop_indexes: "typing.List[int]" = []
pop_indexes: list[int] = []
for idx, (item_key, item_value) in enumerate(self._list):
if item_key == del_key:
pop_indexes.append(idx)
Expand Down
2 changes: 1 addition & 1 deletion starlette/formparsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async def parse(self) -> FormData:
field_name = b""
field_value = b""

items: list[tuple[str, typing.Union[str, UploadFile]]] = []
items: list[tuple[str, str | UploadFile]] = []

# Feed the parser with data from the request.
async for chunk in self.stream:
Expand Down
7 changes: 4 additions & 3 deletions starlette/middleware/authentication.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import typing

from starlette.authentication import (
Expand All @@ -16,9 +18,8 @@ def __init__(
self,
app: ASGIApp,
backend: AuthenticationBackend,
on_error: typing.Optional[
typing.Callable[[HTTPConnection, AuthenticationError], Response]
] = None,
on_error: typing.Callable[[HTTPConnection, AuthenticationError], Response]
| None = None,
) -> None:
self.app = app
self.backend = backend
Expand Down
16 changes: 8 additions & 8 deletions starlette/middleware/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import typing

import anyio
Expand Down Expand Up @@ -92,9 +94,7 @@ async def wrapped_receive(self) -> Message:


class BaseHTTPMiddleware:
def __init__(
self, app: ASGIApp, dispatch: typing.Optional[DispatchFunction] = None
) -> None:
def __init__(self, app: ASGIApp, dispatch: DispatchFunction | None = None) -> None:
self.app = app
self.dispatch_func = self.dispatch if dispatch is None else dispatch

Expand All @@ -108,7 +108,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
response_sent = anyio.Event()

async def call_next(request: Request) -> Response:
app_exc: typing.Optional[Exception] = None
app_exc: Exception | None = None
send_stream: ObjectSendStream[typing.MutableMapping[str, typing.Any]]
recv_stream: ObjectReceiveStream[typing.MutableMapping[str, typing.Any]]
send_stream, recv_stream = anyio.create_memory_object_stream()
Expand Down Expand Up @@ -203,10 +203,10 @@ def __init__(
self,
content: ContentStream,
status_code: int = 200,
headers: typing.Optional[typing.Mapping[str, str]] = None,
media_type: typing.Optional[str] = None,
background: typing.Optional[BackgroundTask] = None,
info: typing.Optional[typing.Mapping[str, typing.Any]] = None,
headers: typing.Mapping[str, str] | None = None,
media_type: str | None = None,
background: BackgroundTask | None = None,
info: typing.Mapping[str, typing.Any] | None = None,
) -> None:
self._info = info
super().__init__(content, status_code, headers, media_type, background)
Expand Down
4 changes: 3 additions & 1 deletion starlette/middleware/cors.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import functools
import re
import typing
Expand All @@ -18,7 +20,7 @@ def __init__(
allow_methods: typing.Sequence[str] = ("GET",),
allow_headers: typing.Sequence[str] = (),
allow_credentials: bool = False,
allow_origin_regex: typing.Optional[str] = None,
allow_origin_regex: str | None = None,
expose_headers: typing.Sequence[str] = (),
max_age: int = 600,
) -> None:
Expand Down
6 changes: 3 additions & 3 deletions starlette/middleware/errors.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import html
import inspect
import traceback
Expand Down Expand Up @@ -137,9 +139,7 @@ class ServerErrorMiddleware:
def __init__(
self,
app: ASGIApp,
handler: typing.Optional[
typing.Callable[[Request, Exception], typing.Any]
] = None,
handler: typing.Callable[[Request, Exception], typing.Any] | None = None,
debug: bool = False,
) -> None:
self.app = app
Expand Down
13 changes: 8 additions & 5 deletions starlette/middleware/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import typing

from starlette._exception_handler import (
Expand All @@ -16,9 +18,10 @@ class ExceptionMiddleware:
def __init__(
self,
app: ASGIApp,
handlers: typing.Optional[
typing.Mapping[typing.Any, typing.Callable[[Request, Exception], Response]]
] = None,
handlers: typing.Mapping[
typing.Any, typing.Callable[[Request, Exception], Response]
]
| None = None,
debug: bool = False,
) -> None:
self.app = app
Expand All @@ -34,7 +37,7 @@ def __init__(

def add_exception_handler(
self,
exc_class_or_status_code: typing.Union[int, typing.Type[Exception]],
exc_class_or_status_code: int | type[Exception],
handler: typing.Callable[[Request, Exception], Response],
) -> None:
if isinstance(exc_class_or_status_code, int):
Expand All @@ -53,7 +56,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
self._status_handlers,
)

conn: typing.Union[Request, WebSocket]
conn: Request | WebSocket
if scope["type"] == "http":
conn = Request(scope, receive, send)
else:
Expand Down
8 changes: 5 additions & 3 deletions starlette/middleware/sessions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import json
import typing
from base64 import b64decode, b64encode
Expand All @@ -14,13 +16,13 @@ class SessionMiddleware:
def __init__(
self,
app: ASGIApp,
secret_key: typing.Union[str, Secret],
secret_key: str | Secret,
session_cookie: str = "session",
max_age: typing.Optional[int] = 14 * 24 * 60 * 60, # 14 days, in seconds
max_age: int | None = 14 * 24 * 60 * 60, # 14 days, in seconds
path: str = "/",
same_site: typing.Literal["lax", "strict", "none"] = "lax",
https_only: bool = False,
domain: typing.Optional[str] = None,
domain: str | None = None,
) -> None:
self.app = app
self.signer = itsdangerous.TimestampSigner(str(secret_key))
Expand Down
4 changes: 3 additions & 1 deletion starlette/middleware/trustedhost.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import typing

from starlette.datastructures import URL, Headers
Expand All @@ -11,7 +13,7 @@ class TrustedHostMiddleware:
def __init__(
self,
app: ASGIApp,
allowed_hosts: typing.Optional[typing.Sequence[str]] = None,
allowed_hosts: typing.Sequence[str] | None = None,
www_redirect: bool = True,
) -> None:
if allowed_hosts is None:
Expand Down
Loading

0 comments on commit bd77d7d

Please sign in to comment.