Drop Python 3.9 support

This commit is contained in:
François Voron
2025-10-25 08:19:03 +02:00
parent ae5ff025ef
commit fcf9a2041a
33 changed files with 224 additions and 234 deletions

View File

@ -1,7 +1,7 @@
import re
from collections.abc import Sequence
from collections.abc import Callable, Sequence
from inspect import Parameter, Signature
from typing import Any, Callable, Generic, Optional, cast
from typing import Any, Generic, cast
from fastapi import Depends, HTTPException, status
from makefun import with_signature
@ -65,9 +65,8 @@ class Authenticator(Generic[models.UP, models.ID]):
active: bool = False,
verified: bool = False,
superuser: bool = False,
get_enabled_backends: Optional[
EnabledBackendsDependency[models.UP, models.ID]
] = None,
get_enabled_backends: EnabledBackendsDependency[models.UP, models.ID]
| None = None,
):
"""
Return a dependency callable to retrieve currently authenticated user and token.
@ -111,9 +110,8 @@ class Authenticator(Generic[models.UP, models.ID]):
active: bool = False,
verified: bool = False,
superuser: bool = False,
get_enabled_backends: Optional[
EnabledBackendsDependency[models.UP, models.ID]
] = None,
get_enabled_backends: EnabledBackendsDependency[models.UP, models.ID]
| None = None,
):
"""
Return a dependency callable to retrieve currently authenticated user.
@ -161,9 +159,9 @@ class Authenticator(Generic[models.UP, models.ID]):
verified: bool = False,
superuser: bool = False,
**kwargs,
) -> tuple[Optional[models.UP], Optional[str]]:
user: Optional[models.UP] = None
token: Optional[str] = None
) -> tuple[models.UP | None, str | None]:
user: models.UP | None = None
token: str | None = None
enabled_backends: Sequence[AuthenticationBackend[models.UP, models.ID]] = (
kwargs.get("enabled_backends", self.backends)
)
@ -193,7 +191,7 @@ class Authenticator(Generic[models.UP, models.ID]):
return user, token
def _get_dependency_signature(
self, get_enabled_backends: Optional[EnabledBackendsDependency] = None
self, get_enabled_backends: EnabledBackendsDependency | None = None
) -> Signature:
"""
Generate a dynamic signature for the current_user dependency.

View File

@ -1,4 +1,4 @@
from typing import Generic, Optional, Protocol
from typing import Generic, Protocol
from fastapi_users import models
from fastapi_users.manager import BaseUserManager
@ -10,8 +10,8 @@ class StrategyDestroyNotSupportedError(Exception):
class Strategy(Protocol, Generic[models.UP, models.ID]):
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]: ... # pragma: no cover
self, token: str | None, user_manager: BaseUserManager[models.UP, models.ID]
) -> models.UP | None: ... # pragma: no cover
async def write_token(self, user: models.UP) -> str: ... # pragma: no cover

View File

@ -1,5 +1,5 @@
from datetime import datetime
from typing import Any, Generic, Optional, Protocol
from typing import Any, Generic, Protocol
from fastapi_users.authentication.strategy.db.models import AP
@ -8,8 +8,8 @@ class AccessTokenDatabase(Protocol, Generic[AP]):
"""Protocol for retrieving, creating and updating access tokens from a database."""
async def get_by_token(
self, token: str, max_age: Optional[datetime] = None
) -> Optional[AP]:
self, token: str, max_age: datetime | None = None
) -> AP | None:
"""Get a single access token by token."""
... # pragma: no cover

View File

@ -1,6 +1,6 @@
import secrets
from datetime import datetime, timedelta, timezone
from typing import Any, Generic, Optional
from typing import Any, Generic
from fastapi_users import exceptions, models
from fastapi_users.authentication.strategy.base import Strategy
@ -13,14 +13,14 @@ class DatabaseStrategy(
Strategy[models.UP, models.ID], Generic[models.UP, models.ID, AP]
):
def __init__(
self, database: AccessTokenDatabase[AP], lifetime_seconds: Optional[int] = None
self, database: AccessTokenDatabase[AP], lifetime_seconds: int | None = None
):
self.database = database
self.lifetime_seconds = lifetime_seconds
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]:
self, token: str | None, user_manager: BaseUserManager[models.UP, models.ID]
) -> models.UP | None:
if token is None:
return None

View File

@ -1,4 +1,4 @@
from typing import Generic, Optional
from typing import Generic
import jwt
@ -21,10 +21,10 @@ class JWTStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID])
def __init__(
self,
secret: SecretType,
lifetime_seconds: Optional[int],
lifetime_seconds: int | None,
token_audience: list[str] = ["fastapi-users:auth"],
algorithm: str = "HS256",
public_key: Optional[SecretType] = None,
public_key: SecretType | None = None,
):
self.secret = secret
self.lifetime_seconds = lifetime_seconds
@ -41,8 +41,8 @@ class JWTStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID])
return self.public_key or self.secret
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]:
self, token: str | None, user_manager: BaseUserManager[models.UP, models.ID]
) -> models.UP | None:
if token is None:
return None

View File

@ -1,5 +1,5 @@
import secrets
from typing import Generic, Optional
from typing import Generic
import redis.asyncio
@ -12,7 +12,7 @@ class RedisStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID
def __init__(
self,
redis: redis.asyncio.Redis,
lifetime_seconds: Optional[int] = None,
lifetime_seconds: int | None = None,
*,
key_prefix: str = "fastapi_users_token:",
):
@ -21,8 +21,8 @@ class RedisStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID
self.key_prefix = key_prefix
async def read_token(
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
) -> Optional[models.UP]:
self, token: str | None, user_manager: BaseUserManager[models.UP, models.ID]
) -> models.UP | None:
if token is None:
return None

View File

@ -1,4 +1,4 @@
from typing import Literal, Optional
from typing import Literal
from fastapi import Response, status
from fastapi.security import APIKeyCookie
@ -13,9 +13,9 @@ class CookieTransport(Transport):
def __init__(
self,
cookie_name: str = "fastapiusersauth",
cookie_max_age: Optional[int] = None,
cookie_max_age: int | None = None,
cookie_path: str = "/",
cookie_domain: Optional[str] = None,
cookie_domain: str | None = None,
cookie_secure: bool = True,
cookie_httponly: bool = True,
cookie_samesite: Literal["lax", "strict", "none"] = "lax",