Skip to content

Commit

Permalink
Fill remaining missing hints & disallow partial hints (#480)
Browse files Browse the repository at this point in the history
Disallow untyped/incomplete function definitions (`disallow_untyped_defs = true`, `disallow_incomplete_defs = true`)

Using `_typeshed.Incomplete` instead of `Any` as the placeholder type.
  • Loading branch information
intgr authored Oct 5, 2023
1 parent adf6975 commit 326bcc8
Show file tree
Hide file tree
Showing 35 changed files with 176 additions and 113 deletions.
22 changes: 19 additions & 3 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ warn_unused_ignores = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unreachable = true
# TODO: enable disallow_*_defs later
disallow_untyped_defs = false
disallow_incomplete_defs = false
disallow_untyped_defs = true
disallow_incomplete_defs = true
disable_error_code = empty-body
# TODO: update our test error messages to match new mypy output
show_error_codes = false
Expand All @@ -25,5 +24,22 @@ plugins =
[mypy.plugins.django-stubs]
django_settings_module = scripts.drf_tests_settings

# Suppress errors from site-packages due to https://github.com/typeddjango/pytest-mypy-plugins/issues/134
[mypy-uritemplate.*]
warn_unreachable = false

[mypy-yaml.*]
disallow_untyped_defs = false
disallow_incomplete_defs = false

[mypy-urllib3.*]
disallow_untyped_defs = false
disallow_incomplete_defs = false

[mypy-requests.*]
disallow_untyped_defs = false
disallow_incomplete_defs = false

[mypy-markdown.*]
disallow_untyped_defs = false
disallow_incomplete_defs = false
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ select = [

[tool.ruff.isort]
split-on-trailing-comma = false
extra-standard-library = ["_typeshed"]

[build-system]
requires = ["setuptools<64", "wheel"]
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ from typing import Any

from django.contrib.auth.base_user import AbstractBaseUser
from django.core.management.base import BaseCommand
from rest_framework.authtoken.models import Token

UserModel: AbstractBaseUser

class Command(BaseCommand):
help: str
def create_user_token(self, username: str, reset_token: bool): ...
def create_user_token(self, username: str, reset_token: bool) -> Token: ...
def add_arguments(self, parser: Any) -> None: ...
def handle(self, *args: Any, **options: Any) -> None: ...
3 changes: 2 additions & 1 deletion rest_framework-stubs/authtoken/models.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Any

from django.db import models
from typing_extensions import Self

class Token(models.Model):
key: models.CharField
Expand All @@ -11,4 +12,4 @@ class Token(models.Model):

class TokenProxy(Token):
@property
def pk(self) -> Any: ...
def pk(self: Self) -> Any: ...
4 changes: 2 additions & 2 deletions rest_framework-stubs/compat.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ except ImportError:
pygments = None
try:
import markdown
def apply_markdown(text: str): ...
def apply_markdown(text: str) -> str: ...

except ImportError:
apply_markdown = None # type: ignore
Expand All @@ -45,7 +45,7 @@ if markdown is not None and pygments is not None:
class CodeBlockPreprocessor(Preprocessor):
pattern: Any
formatter: Any
def run(self, lines: Any): ...
def run(self, lines: list[str]) -> list[str]: ...

def pygments_css(style: Any) -> str | None: ...
def pygments_highlight(text: str, lang: str, style: Any) -> Any: ...
Expand Down
6 changes: 3 additions & 3 deletions rest_framework-stubs/exceptions.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ from django.http import HttpRequest, JsonResponse
from django_stubs_ext import StrOrPromise
from rest_framework.renderers import BaseRenderer
from rest_framework.request import Request
from typing_extensions import TypeAlias, TypedDict
from typing_extensions import Self, TypeAlias, TypedDict

class ErrorDetail(str):
code: str | None
def __new__(cls, string: str, code: str | None = ...): ...
def __new__(cls, string: str, code: str | None = ...) -> Self: ...

_Detail: TypeAlias = ErrorDetail | list[_Detail] | dict[str, _Detail]
# NB! _APIExceptionInput doesn't technically handle Sequence/Mapping, but only list/tuple/dict.
Expand Down Expand Up @@ -68,7 +68,7 @@ class UnsupportedMediaType(APIException):
class Throttled(APIException):
extra_detail_singular: str
extra_detail_plural: str
def __init__(self, wait: float | None = ..., detail: _APIExceptionInput = ..., code: str | None = ...): ...
def __init__(self, wait: float | None = ..., detail: _APIExceptionInput = ..., code: str | None = ...) -> None: ...

def server_error(request: HttpRequest | Request, *args: Any, **kwargs: Any) -> JsonResponse: ...
def bad_request(request: HttpRequest | Request, exception: Exception, *args: Any, **kwargs: Any) -> JsonResponse: ...
5 changes: 3 additions & 2 deletions rest_framework-stubs/fields.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import datetime
import uuid
from _typeshed import Incomplete
from collections.abc import Callable, Generator, Iterable, Mapping, MutableMapping, Sequence
from decimal import Decimal
from enum import Enum
Expand All @@ -26,11 +27,11 @@ class CreateOnlyDefault:
requires_context: bool
default: Any
def __init__(self, default: Any) -> None: ...
def __call__(self, serializer_field: Field): ...
def __call__(self, serializer_field: Field) -> Incomplete: ...

class CurrentUserDefault:
requires_context: bool
def __call__(self, serializer_field: Field): ...
def __call__(self, serializer_field: Field) -> Incomplete: ...

class SkipField(Exception): ...

Expand Down
17 changes: 11 additions & 6 deletions rest_framework-stubs/filters.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections.abc import Iterable, Mapping, Sequence
from typing import Any, TypeVar

Expand All @@ -10,18 +11,18 @@ _MT = TypeVar("_MT", bound=Model)
class BaseFilterBackend:
def filter_queryset(self, request: Request, queryset: QuerySet[_MT], view: APIView) -> QuerySet[_MT]: ...
def get_schema_fields(self, view: APIView) -> list[Any]: ...
def get_schema_operation_parameters(self, view: APIView): ...
def get_schema_operation_parameters(self, view: APIView) -> list[dict[str, Incomplete]]: ...

class SearchFilter(BaseFilterBackend):
search_param: str
template: str
lookup_prefixes: dict[str, str]
search_title: str
search_description: str
def get_search_fields(self, view: APIView, request: Request): ...
def get_search_fields(self, view: APIView, request: Request) -> Incomplete: ...
def get_search_terms(self, request: Request) -> list[str]: ...
def construct_search(self, field_name: str) -> str: ...
def must_call_distinct(self, queryset: QuerySet, search_fields) -> bool: ...
def must_call_distinct(self, queryset: QuerySet, search_fields: Incomplete) -> bool: ...
def to_html(self, request: Request, queryset: QuerySet, view: APIView) -> str: ...

class OrderingFilter(BaseFilterBackend):
Expand All @@ -33,9 +34,13 @@ class OrderingFilter(BaseFilterBackend):
def get_ordering(self, request: Request, queryset: QuerySet, view: APIView) -> Sequence[str] | None: ...
def get_default_ordering(self, view: APIView) -> Sequence[str] | None: ...
def get_default_valid_fields(
self, queryset: QuerySet, view, context: Mapping[str, Any] = ...
self, queryset: QuerySet, view: APIView, context: Mapping[str, Any] = ...
) -> list[tuple[str, str]]: ...
def get_valid_fields(self, queryset: QuerySet, view, context: Mapping[str, Any] = ...) -> list[tuple[str, str]]: ...
def remove_invalid_fields(self, queryset: QuerySet, fields: Iterable[str], view, request: Request) -> list[str]: ...
def get_valid_fields(
self, queryset: QuerySet, view: APIView, context: Mapping[str, Any] = ...
) -> list[tuple[str, str]]: ...
def remove_invalid_fields(
self, queryset: QuerySet, fields: Iterable[str], view: APIView, request: Request
) -> list[str]: ...
def get_template_context(self, request: Request, queryset: QuerySet, view: APIView) -> dict[str, Any]: ...
def to_html(self, request: Request, queryset: QuerySet, view: APIView) -> str: ...
3 changes: 2 additions & 1 deletion rest_framework-stubs/generics.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections.abc import Sequence
from typing import Any, Protocol, TypeVar

Expand Down Expand Up @@ -27,7 +28,7 @@ class BaseFilterProtocol(Protocol[_MT_inv]):
self, request: Request, queryset: QuerySet[_MT_inv], view: views.APIView
) -> QuerySet[_MT_inv]: ...
def get_schema_fields(self, view: views.APIView) -> list[Any]: ...
def get_schema_operation_parameters(self, view: views.APIView): ...
def get_schema_operation_parameters(self, view: views.APIView) -> Incomplete: ...

class GenericAPIView(views.APIView, UsesQuerySet[_MT_co]):
queryset: QuerySet[_MT_co] | Manager[_MT_co] | None
Expand Down
7 changes: 4 additions & 3 deletions rest_framework-stubs/management/commands/generateschema.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from typing import Any

from django.core.management.base import BaseCommand
Expand All @@ -7,8 +8,8 @@ COREAPI_MODE: str

class Command(BaseCommand):
help: str
def get_mode(self): ...
def get_mode(self) -> Incomplete: ...
def add_arguments(self, parser: Any) -> None: ...
def handle(self, *args: Any, **options: Any) -> None: ...
def get_renderer(self, format: str): ...
def get_generator_class(self): ...
def get_renderer(self, format: str) -> Incomplete: ...
def get_generator_class(self) -> Incomplete: ...
5 changes: 4 additions & 1 deletion rest_framework-stubs/negotiation.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections.abc import Iterable

from rest_framework.parsers import BaseParser
Expand All @@ -7,7 +8,9 @@ from rest_framework.settings import api_settings

class BaseContentNegotiation:
def select_parser(self, request: Request, parsers: Iterable[BaseParser]) -> BaseParser | None: ...
def select_renderer(self, request: Request, renderers: Iterable[BaseRenderer], format_suffix: str | None = ...): ...
def select_renderer(
self, request: Request, renderers: Iterable[BaseRenderer], format_suffix: str | None = ...
) -> Incomplete: ...

class DefaultContentNegotiation(BaseContentNegotiation):
settings = api_settings
Expand Down
10 changes: 6 additions & 4 deletions rest_framework-stubs/pagination.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ _MT = TypeVar("_MT", bound=Model)

class BasePagination:
display_page_controls: bool
def get_paginated_response_schema(self, schema: Any): ...
def get_paginated_response_schema(self, schema: dict[str, Any]) -> dict[str, Any]: ...
def get_paginated_response(self, data: Any) -> Response: ...
def get_results(self, data: dict[str, Any]) -> Any: ...
def get_schema_fields(self, view: APIView) -> list: ...
def get_schema_operation_parameters(self, view: APIView) -> list: ...
def paginate_queryset(self, queryset: QuerySet, request: Request, view: APIView | None = ...): ...
def get_schema_fields(self, view: APIView) -> list[Any]: ...
def get_schema_operation_parameters(self, view: APIView) -> list[Any]: ...
def paginate_queryset(
self, queryset: QuerySet[_MT], request: Request, view: APIView | None = ...
) -> list[_MT] | None: ...
def to_html(self) -> str: ...

class PageNumberPagination(BasePagination):
Expand Down
9 changes: 5 additions & 4 deletions rest_framework-stubs/permissions.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections.abc import Sequence
from typing import Any, Protocol # noqa: Y037 # https://github.com/python/mypy/issues/12392

Expand Down Expand Up @@ -25,17 +26,17 @@ class OperationHolderMixin:
class SingleOperandHolder(OperationHolderMixin):
operator_class: _SupportsHasPermission
op1_class: _PermissionClass
def __init__(self, operator_class: _SupportsHasPermission, op1_class: _PermissionClass): ...
def __call__(self, *args, **kwargs) -> _SupportsHasPermission: ...
def __init__(self, operator_class: _SupportsHasPermission, op1_class: _PermissionClass) -> None: ...
def __call__(self, *args: Incomplete, **kwargs: Incomplete) -> _SupportsHasPermission: ...

class OperandHolder(OperationHolderMixin):
operator_class: _SupportsHasPermission
op1_class: _PermissionClass
op2_class: _PermissionClass
def __init__(
self, operator_class: _SupportsHasPermission, op1_class: _PermissionClass, op2_class: _PermissionClass
): ...
def __call__(self, *args, **kwargs) -> _SupportsHasPermission: ...
) -> None: ...
def __call__(self, *args: Incomplete, **kwargs: Incomplete) -> _SupportsHasPermission: ...

class AND(_SupportsHasPermission):
def __init__(self, op1: _SupportsHasPermission, op2: _SupportsHasPermission) -> None: ...
Expand Down
2 changes: 1 addition & 1 deletion rest_framework-stubs/relations.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ObjectTypeError(TypeError): ...

class Hyperlink(str):
def __new__(cls, url: str, obj: Any) -> Self: ...
def __getnewargs__(self): ...
def __getnewargs__(self) -> tuple[str, str]: ... # type: ignore[override]
@property
def name(self) -> str: ...
is_hyperlink: bool
Expand Down
20 changes: 13 additions & 7 deletions rest_framework-stubs/renderers.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections.abc import Iterable, Mapping, Sequence
from json import JSONEncoder
from typing import Any
Expand Down Expand Up @@ -31,7 +32,7 @@ class TemplateHTMLRenderer(BaseRenderer):
template_name: str | None
exception_template_names: Sequence[str]
def resolve_template(self, template_names: Iterable[str]) -> Any: ...
def get_template_context(self, data: Any, renderer_context: Mapping[str, Any]): ...
def get_template_context(self, data: Any, renderer_context: Mapping[str, Any]) -> Incomplete: ...
def get_template_names(self, response: Response, view: APIView) -> list[str]: ...
def get_exception_template(self, response: Response) -> Any: ...

Expand All @@ -42,7 +43,7 @@ class HTMLFormRenderer(BaseRenderer):
base_template: str

default_style: ClassLookupDict
def render_field(self, field, parent_style: Mapping[str, Any]) -> str: ...
def render_field(self, field: Incomplete, parent_style: Mapping[str, Any]) -> str: ...

class BrowsableAPIRenderer(BaseRenderer):
"""
Expand All @@ -59,7 +60,12 @@ class BrowsableAPIRenderer(BaseRenderer):
) -> str: ...
def show_form_for_method(self, view: APIView, method: str, request: Request, obj: Any) -> bool: ...
def _get_serializer(
self, serializer_class: type[BaseSerializer], view_instance: APIView, request: Request, *args, **kwargs
self,
serializer_class: type[BaseSerializer],
view_instance: APIView,
request: Request,
*args: Incomplete,
**kwargs: Incomplete
) -> BaseSerializer: ...
def get_rendered_html_form(self, data: Any, view: APIView, method: str, request: Request) -> Any: ...
def render_form_for_serializer(self, serializer: BaseSerializer) -> Any: ...
Expand Down Expand Up @@ -96,11 +102,11 @@ class _BaseOpenAPIRenderer:
charset: Any
format: str
def __init__(self) -> None: ...
def render(self, data: Any, media_type: Any | None = ..., renderer_context: Any | None = ...): ...
def render(self, data: Any, media_type: Any | None = ..., renderer_context: Any | None = ...) -> Incomplete: ...
def get_schema(self, instance: Any) -> dict[str, Any]: ...
def get_parameters(self, link) -> dict[str, Any]: ...
def get_operation(self, link, name, tag) -> dict[str, Any]: ...
def get_paths(self, document) -> dict[str, Any]: ...
def get_parameters(self, link: Incomplete) -> dict[str, Any]: ...
def get_operation(self, link: Incomplete, name: Incomplete, tag: Incomplete) -> dict[str, Any]: ...
def get_paths(self, document: Incomplete) -> dict[str, Any]: ...
def get_structure(self, data: Any) -> dict[str, Any]: ...

class JSONOpenAPIRenderer(_BaseOpenAPIRenderer): ...
Expand Down
5 changes: 3 additions & 2 deletions rest_framework-stubs/request.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections.abc import Iterator, Sequence
from contextlib import AbstractContextManager, contextmanager
from types import TracebackType
Expand All @@ -17,7 +18,7 @@ from rest_framework.views import APIView
def is_form_media_type(media_type: str) -> bool: ...

class override_method(AbstractContextManager[Request]):
def __init__(self, view: APIView, request: Request, method: str): ...
def __init__(self, view: APIView, request: Request, method: str) -> None: ...
def __enter__(self) -> Request: ...
def __exit__(
self,
Expand Down Expand Up @@ -79,5 +80,5 @@ class Request(HttpRequest):
@property
def POST(self) -> _ImmutableQueryDict: ... # type: ignore[override]
@property
def FILES(self): ...
def FILES(self) -> Incomplete: ... # type: ignore[override]
def force_plaintext_errors(self, value: Any) -> None: ...
3 changes: 2 additions & 1 deletion rest_framework-stubs/schemas/coreapi.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections import Counter
from collections.abc import Iterable, Sequence
from typing import Any
Expand Down Expand Up @@ -43,7 +44,7 @@ class SchemaGenerator(BaseSchemaGenerator):
def get_keys(self, subpath: Any, method: Any, view: APIView) -> list[str]: ...
def determine_path_prefix(self, paths: list[str]) -> str: ...

def field_to_schema(field: Field): ...
def field_to_schema(field: Field) -> Incomplete: ...

class AutoSchema(ViewInspector):
def __init__(self, manual_fields: list[coreapi.Field] | None = ...) -> None: ...
Expand Down
5 changes: 3 additions & 2 deletions rest_framework-stubs/schemas/inspectors.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from _typeshed import Incomplete
from collections.abc import Mapping
from re import Pattern
from typing import Any
Expand All @@ -6,10 +7,10 @@ class ViewInspector:
header_regex: Pattern
instance_schemas: Mapping[str, Any]
def __init__(self) -> None: ...
def __get__(self, instance: Any, owner: Any): ...
def __get__(self, instance: Any, owner: Any) -> Incomplete: ...
def __set__(self, instance: Any, other: Any) -> None: ...
@property
def view(self): ...
def view(self) -> Incomplete: ...
@view.setter
def view(self, value: Any) -> None: ...
def get_description(self, path: Any, method: Any) -> str: ...
Expand Down
Loading

0 comments on commit 326bcc8

Please sign in to comment.