diff --git a/stubs/Authlib/@tests/django_settings.py b/stubs/Authlib/@tests/django_settings.py new file mode 100644 index 000000000000..507540459e03 --- /dev/null +++ b/stubs/Authlib/@tests/django_settings.py @@ -0,0 +1,12 @@ +SECRET_KEY = "1" + +INSTALLED_APPS = ( + "django.contrib.contenttypes", + "django.contrib.sites", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.admin.apps.SimpleAdminConfig", + "django.contrib.staticfiles", + "django.contrib.auth", + "authlib", +) diff --git a/stubs/Authlib/@tests/stubtest_allowlist.txt b/stubs/Authlib/@tests/stubtest_allowlist.txt index 98002c5bac78..1cad504d5e7e 100644 --- a/stubs/Authlib/@tests/stubtest_allowlist.txt +++ b/stubs/Authlib/@tests/stubtest_allowlist.txt @@ -42,8 +42,5 @@ authlib.oidc.core.grants.implicit.OpenIDImplicitGrant.validate_consent_request # Exclude integrations dirs # Failed to import, getting ModuleNotFoundError for third-party libs: -authlib.integrations.django_client.* -authlib.integrations.django_oauth1.* -authlib.integrations.django_oauth2.* authlib.integrations.sqla_oauth2.* authlib.integrations.starlette_client.* diff --git a/stubs/Authlib/METADATA.toml b/stubs/Authlib/METADATA.toml index d4984a274e2d..83f1b0023ace 100644 --- a/stubs/Authlib/METADATA.toml +++ b/stubs/Authlib/METADATA.toml @@ -2,4 +2,8 @@ version = "1.8.0" upstream-repository = "https://github.com/authlib/authlib" dependencies = ["cryptography"] # Requires a version of flask with a `py.typed` file -optional-dependencies = ["requests", "httpx2", "Flask>=2.0.0"] +optional-dependencies = ["requests", "httpx2", "Flask>=2.0.0", "django-stubs"] + +[tool.stubtest] +mypy-plugins = ["mypy_django_plugin.main"] +mypy-plugins-config = {"django-stubs" = {"django_settings_module" = "@tests.django_settings"}} diff --git a/stubs/Authlib/authlib/integrations/django_client/apps.pyi b/stubs/Authlib/authlib/integrations/django_client/apps.pyi index 1325168c1fc4..73b21ef3a103 100644 --- a/stubs/Authlib/authlib/integrations/django_client/apps.pyi +++ b/stubs/Authlib/authlib/integrations/django_client/apps.pyi @@ -1,24 +1,23 @@ from _typeshed import Incomplete -from typing import TypeAlias + +from django.http import HttpRequest, HttpResponseRedirect from ..base_client import BaseApp, OAuth1Mixin, OAuth2Mixin, OpenIDMixin from ..requests_client import OAuth1Session, OAuth2Session -_HttpResponseRedirect: TypeAlias = Incomplete # actual type is django.http.response.HttpResponseRedirect - class DjangoAppMixin: - def save_authorize_data(self, request, **kwargs) -> None: ... - def authorize_redirect(self, request, redirect_uri=None, **kwargs): ... + def save_authorize_data(self, request: HttpRequest, **kwargs) -> None: ... + def authorize_redirect(self, request: HttpRequest, redirect_uri=None, **kwargs) -> HttpResponseRedirect: ... class DjangoOAuth1App(DjangoAppMixin, OAuth1Mixin, BaseApp): client_cls = OAuth1Session - def authorize_access_token(self, request, **kwargs): ... + def authorize_access_token(self, request: HttpRequest, **kwargs): ... class DjangoOAuth2App(DjangoAppMixin, OAuth2Mixin, OpenIDMixin, BaseApp): client_cls = OAuth2Session def logout_redirect( self, - request, + request: HttpRequest, post_logout_redirect_uri=None, id_token_hint=None, *, @@ -26,6 +25,6 @@ class DjangoOAuth2App(DjangoAppMixin, OAuth2Mixin, OpenIDMixin, BaseApp): client_id=None, logout_hint=None, ui_locales=None, - ) -> _HttpResponseRedirect: ... - def validate_logout_response(self, request): ... - def authorize_access_token(self, request, **kwargs): ... + ) -> HttpResponseRedirect: ... + def validate_logout_response(self, request: HttpRequest): ... + def authorize_access_token(self, request: HttpRequest, **kwargs) -> dict[Incomplete, Incomplete]: ... diff --git a/stubs/Authlib/authlib/integrations/django_client/integration.pyi b/stubs/Authlib/authlib/integrations/django_client/integration.pyi index 91469e1953da..2c373bcaed33 100644 --- a/stubs/Authlib/authlib/integrations/django_client/integration.pyi +++ b/stubs/Authlib/authlib/integrations/django_client/integration.pyi @@ -1,9 +1,8 @@ -from _typeshed import Incomplete +from django.dispatch import Signal from ..base_client import FrameworkIntegration -# actual type is django.dispatch.Signal -token_update: Incomplete +token_update: Signal class DjangoIntegration(FrameworkIntegration): def update_token(self, token, refresh_token=None, access_token=None) -> None: ... diff --git a/stubs/Authlib/authlib/integrations/django_oauth1/authorization_server.pyi b/stubs/Authlib/authlib/integrations/django_oauth1/authorization_server.pyi index 2d4b0bacaca5..7b8bac2aecd2 100644 --- a/stubs/Authlib/authlib/integrations/django_oauth1/authorization_server.pyi +++ b/stubs/Authlib/authlib/integrations/django_oauth1/authorization_server.pyi @@ -2,6 +2,7 @@ import logging from _typeshed import Incomplete from authlib.oauth1 import AuthorizationServer as _AuthorizationServer, OAuth1Request, TemporaryCredential +from django.http import HttpResponse log: logging.Logger @@ -16,7 +17,7 @@ class BaseServer(_AuthorizationServer): def create_token_credential(self, request): ... def check_authorization_request(self, request) -> OAuth1Request: ... def create_oauth1_request(self, request) -> OAuth1Request: ... - def handle_response(self, status_code, payload, headers): ... + def handle_response(self, status_code, payload, headers) -> HttpResponse: ... class CacheAuthorizationServer(BaseServer): def __init__(self, client_model, token_model, token_generator=None) -> None: ... diff --git a/stubs/Authlib/authlib/integrations/django_oauth1/nonce.pyi b/stubs/Authlib/authlib/integrations/django_oauth1/nonce.pyi index b4d93191444c..19cfe5b2e926 100644 --- a/stubs/Authlib/authlib/integrations/django_oauth1/nonce.pyi +++ b/stubs/Authlib/authlib/integrations/django_oauth1/nonce.pyi @@ -1 +1 @@ -def exists_nonce_in_cache(nonce, request, timeout) -> bool: ... +def exists_nonce_in_cache(nonce, request, timeout: int | float | None) -> bool: ... diff --git a/stubs/Authlib/authlib/integrations/django_oauth2/authorization_server.pyi b/stubs/Authlib/authlib/integrations/django_oauth2/authorization_server.pyi index cecb3d9ae968..c85f197288ba 100644 --- a/stubs/Authlib/authlib/integrations/django_oauth2/authorization_server.pyi +++ b/stubs/Authlib/authlib/integrations/django_oauth2/authorization_server.pyi @@ -1,7 +1,10 @@ -from _typeshed import Incomplete +from _typeshed import Incomplete, SupportsKeysAndGetItem, Unused +from collections.abc import Callable +from typing import Literal, ParamSpec, TypeVar, overload from authlib.oauth2 import AuthorizationServer as _AuthorizationServer from authlib.oauth2.rfc6750 import BearerTokenGenerator +from django.http import HttpResponse from .requests import DjangoJsonRequest, DjangoOAuth2Request @@ -16,9 +19,20 @@ class AuthorizationServer(_AuthorizationServer): def save_token(self, token, request): ... def create_oauth2_request(self, request) -> DjangoOAuth2Request: ... def create_json_request(self, request) -> DjangoJsonRequest: ... - def handle_response(self, status_code, payload, headers): ... + def handle_response(self, status_code, payload, headers) -> HttpResponse: ... def send_signal(self, name, *args, **kwargs) -> None: ... def create_bearer_token_generator(self) -> BearerTokenGenerator: ... -def create_token_generator(token_generator_conf, length: int = 42): ... -def create_token_expires_in_generator(expires_in_conf=None): ... +_P = ParamSpec("_P") +_R = TypeVar("_R") + +@overload +def create_token_generator(token_generator_conf: Callable[_P, _R], length: Unused = 42) -> Callable[_P, _R]: ... +@overload +def create_token_generator(token_generator_conf: str, length: Unused = 42): ... +@overload +def create_token_generator(token_generator_conf: Literal[True], length: int = 42) -> Callable[..., str]: ... + +def create_token_expires_in_generator( + expires_in_conf: SupportsKeysAndGetItem[str, int] | None = None, +) -> Callable[[Incomplete, str], int]: ... diff --git a/stubs/Authlib/authlib/integrations/django_oauth2/endpoints.pyi b/stubs/Authlib/authlib/integrations/django_oauth2/endpoints.pyi index 9eb7a277a46b..86bc750addb3 100644 --- a/stubs/Authlib/authlib/integrations/django_oauth2/endpoints.pyi +++ b/stubs/Authlib/authlib/integrations/django_oauth2/endpoints.pyi @@ -1,5 +1,7 @@ +from typing import Literal + from authlib.oauth2.rfc7009 import RevocationEndpoint as _RevocationEndpoint class RevocationEndpoint(_RevocationEndpoint): - def query_token(self, token, token_type_hint): ... + def query_token(self, token, token_type_hint: Literal["access_token", "refresh_token"] | None): ... def revoke_token(self, token, request) -> None: ... diff --git a/stubs/Authlib/authlib/integrations/django_oauth2/requests.pyi b/stubs/Authlib/authlib/integrations/django_oauth2/requests.pyi index 05006392b374..e6ad84e91c33 100644 --- a/stubs/Authlib/authlib/integrations/django_oauth2/requests.pyi +++ b/stubs/Authlib/authlib/integrations/django_oauth2/requests.pyi @@ -1,20 +1,29 @@ +from collections import defaultdict + from authlib.oauth2.rfc6749 import JsonPayload, JsonRequest, OAuth2Payload, OAuth2Request +from django.http import HttpRequest +from django.http.request import _ImmutableQueryDict class DjangoOAuth2Payload(OAuth2Payload): - def __init__(self, request) -> None: ... + def __init__(self, request: HttpRequest) -> None: ... + @property + def data(self) -> dict[str, str]: ... + @property + def datalist(self) -> defaultdict[str, list[str]]: ... class DjangoOAuth2Request(OAuth2Request): payload: DjangoOAuth2Payload - def __init__(self, request) -> None: ... + def __init__(self, request: HttpRequest) -> None: ... @property - def args(self): ... + def args(self) -> _ImmutableQueryDict: ... @property - def form(self): ... + def form(self) -> _ImmutableQueryDict: ... class DjangoJsonPayload(JsonPayload): - def __init__(self, request) -> None: ... + def __init__(self, request: HttpRequest) -> None: ... + @property def data(self): ... class DjangoJsonRequest(JsonRequest): payload: DjangoJsonPayload - def __init__(self, request) -> None: ... + def __init__(self, request: HttpRequest) -> None: ... diff --git a/stubs/Authlib/authlib/integrations/django_oauth2/resource_protector.pyi b/stubs/Authlib/authlib/integrations/django_oauth2/resource_protector.pyi index 1538f368ca44..9fa642d3b9da 100644 --- a/stubs/Authlib/authlib/integrations/django_oauth2/resource_protector.pyi +++ b/stubs/Authlib/authlib/integrations/django_oauth2/resource_protector.pyi @@ -2,14 +2,15 @@ from _typeshed import Incomplete from authlib.oauth2 import ResourceProtector as _ResourceProtector from authlib.oauth2.rfc6750 import BearerTokenValidator as _BearerTokenValidator +from django.http import HttpRequest, JsonResponse class ResourceProtector(_ResourceProtector): - def acquire_token(self, request, scopes=None, **kwargs): ... - def __call__(self, scopes=None, optional=False, **kwargs): ... + def acquire_token(self, request: HttpRequest, scopes=None, **kwargs): ... + def __call__(self, scopes=None, optional: bool = False, **kwargs): ... class BearerTokenValidator(_BearerTokenValidator): token_model: Incomplete def __init__(self, token_model, realm=None, **extra_attributes): ... def authenticate_token(self, token_string): ... -def return_error_response(error): ... +def return_error_response(error) -> JsonResponse: ... diff --git a/stubs/Authlib/authlib/integrations/django_oauth2/signals.pyi b/stubs/Authlib/authlib/integrations/django_oauth2/signals.pyi index c5e48ddef194..f0e9b1968428 100644 --- a/stubs/Authlib/authlib/integrations/django_oauth2/signals.pyi +++ b/stubs/Authlib/authlib/integrations/django_oauth2/signals.pyi @@ -1,6 +1,5 @@ -from _typeshed import Incomplete +from django.dispatch import Signal -# actual types is django.dispatch.Signal -client_authenticated: Incomplete -token_revoked: Incomplete -token_authenticated: Incomplete +client_authenticated: Signal +token_revoked: Signal +token_authenticated: Signal diff --git a/stubs/Authlib/authlib/integrations/flask_oauth2/requests.pyi b/stubs/Authlib/authlib/integrations/flask_oauth2/requests.pyi index 3a8c03d05cfe..cc199f454951 100644 --- a/stubs/Authlib/authlib/integrations/flask_oauth2/requests.pyi +++ b/stubs/Authlib/authlib/integrations/flask_oauth2/requests.pyi @@ -16,7 +16,7 @@ class FlaskOAuth2Request(OAuth2Request): payload: FlaskOAuth2Payload def __init__(self, request: Request) -> None: ... @property - def args(self) -> MultiDict[str, str]: ... # type: ignore[override] + def args(self) -> MultiDict[str, str]: ... @property def form(self) -> ImmutableMultiDict[str, str]: ... diff --git a/stubs/Authlib/authlib/oauth2/rfc6749/requests.pyi b/stubs/Authlib/authlib/oauth2/rfc6749/requests.pyi index 37cafb6b54c9..aacba53016b8 100644 --- a/stubs/Authlib/authlib/oauth2/rfc6749/requests.pyi +++ b/stubs/Authlib/authlib/oauth2/rfc6749/requests.pyi @@ -49,7 +49,7 @@ class OAuth2Request(OAuth2Payload): def __init__(self, method: str, uri: str, body, headers: Mapping[str, str] | None = None) -> None: ... @property - def args(self) -> dict[str, str | None]: ... + def args(self) -> dict[str, str]: ... @property def form(self) -> dict[str, str]: ... @property