From 99406f3fcc3c202d52350d5133fd5fb074dfee80 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Sat, 27 Sep 2025 15:27:08 +0300 Subject: [PATCH 1/2] Document intentional discrepancies in allowlist & code comments A few type hints are deliberately not aligned with implementation signatures. Document why this is. --- rest_framework-stubs/relations.pyi | 4 +++- rest_framework-stubs/renderers.pyi | 2 ++ rest_framework-stubs/validators.pyi | 1 + scripts/stubtest/allowlist.txt | 5 +++++ scripts/stubtest/allowlist_todo.txt | 3 --- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/rest_framework-stubs/relations.pyi b/rest_framework-stubs/relations.pyi index bf95a176f..01b23566c 100644 --- a/rest_framework-stubs/relations.pyi +++ b/rest_framework-stubs/relations.pyi @@ -138,6 +138,7 @@ class SlugRelatedField(RelatedField[_MT, str, str]): slug_field: str def __init__( self, + # DISCREPANCY: signature defaults `slug_field=None`, but actually crashes when `None` is provided. slug_field: str, *, many: bool = ..., @@ -169,7 +170,8 @@ class ManyRelatedField(Field[Sequence[Any], Sequence[Any], list[Any], Any]): allow_empty: bool def __init__( self, - child_relation: RelatedField = ..., + # DISCREPANCY: signature defaults `child_relation=None`, but actually crashes when `None` is provided. + child_relation: RelatedField, *, read_only: bool = ..., write_only: bool = ..., diff --git a/rest_framework-stubs/renderers.pyi b/rest_framework-stubs/renderers.pyi index 01de43daa..c5f23cdfc 100644 --- a/rest_framework-stubs/renderers.pyi +++ b/rest_framework-stubs/renderers.pyi @@ -13,6 +13,8 @@ from rest_framework.views import APIView def zero_as_none(value: Any) -> Any | None: ... class BaseRenderer: + # DISCREPANCY: `media_type`, `format` cannot be None. + # None is a placeholder, but all subclasses must override this to `str`. media_type: str format: str charset: str | None diff --git a/rest_framework-stubs/validators.pyi b/rest_framework-stubs/validators.pyi index cf6ec952a..f4392e931 100644 --- a/rest_framework-stubs/validators.pyi +++ b/rest_framework-stubs/validators.pyi @@ -59,6 +59,7 @@ class ProhibitSurrogateCharactersValidator: def __call__(self, value: Any) -> None: ... class BaseUniqueForValidator: + # DISCREPANCY: `message` cannot be None -- None is a placeholder, but subclasses must override this to StrOrPromise message: StrOrPromise missing_message: StrOrPromise requires_context: bool diff --git a/scripts/stubtest/allowlist.txt b/scripts/stubtest/allowlist.txt index 27dca2492..79af5cd99 100644 --- a/scripts/stubtest/allowlist.txt +++ b/scripts/stubtest/allowlist.txt @@ -11,6 +11,11 @@ rest_framework.relations.SlugRelatedField.__init__ rest_framework.serializers.ManyRelatedField.__init__ rest_framework.serializers.SlugRelatedField.__init__ +# None is used as a placeholder, but not valid in actual usage +rest_framework.renderers.BaseRenderer.format +rest_framework.renderers.BaseRenderer.media_type +rest_framework.validators.BaseUniqueForValidator.message + # Migrations are omitted rest_framework.authtoken.migrations rest_framework.authtoken.migrations.0001_initial diff --git a/scripts/stubtest/allowlist_todo.txt b/scripts/stubtest/allowlist_todo.txt index f112e4c33..1b0a7f6df 100644 --- a/scripts/stubtest/allowlist_todo.txt +++ b/scripts/stubtest/allowlist_todo.txt @@ -51,8 +51,6 @@ rest_framework.parsers.BaseParser.media_type rest_framework.parsers.FileUploadParser.get_encoded_filename rest_framework.relations.ManyRelatedField.initial rest_framework.relations.ManyRelatedField.to_representation -rest_framework.renderers.BaseRenderer.format -rest_framework.renderers.BaseRenderer.media_type rest_framework.renderers.BrowsableAPIRenderer.get_extra_actions rest_framework.renderers.CoreJSONRenderer.render rest_framework.renderers._BaseOpenAPIRenderer.render @@ -99,7 +97,6 @@ rest_framework.test.APIClient.options rest_framework.test.RequestsClient.__init__ rest_framework.throttling.SimpleRateThrottle.cache rest_framework.utils.encoders.JSONEncoder.default -rest_framework.validators.BaseUniqueForValidator.message rest_framework.validators.ContextValidator rest_framework.validators.Validator rest_framework.views.APIView.metadata_class From 6c6e3558f923c10fb9082debd5aecd4ddb29f703 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Sat, 27 Sep 2025 15:42:29 +0300 Subject: [PATCH 2/2] Document also `rest_framework.fields.empty` --- rest_framework-stubs/fields.pyi | 2 ++ scripts/stubtest/allowlist.txt | 5 +++++ scripts/stubtest/allowlist_todo.txt | 2 -- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/rest_framework-stubs/fields.pyi b/rest_framework-stubs/fields.pyi index 55a2b9a1e..2858e38a4 100644 --- a/rest_framework-stubs/fields.pyi +++ b/rest_framework-stubs/fields.pyi @@ -19,6 +19,8 @@ from typing_extensions import Self class _Empty(Enum): sentinel = 0 +# DISREPANCY: `empty` hinted as enum, to work correctly in unions: +# https://github.com/typeddjango/djangorestframework-stubs/issues/42 empty: Final = _Empty.sentinel class BuiltinSignatureError(Exception): ... diff --git a/scripts/stubtest/allowlist.txt b/scripts/stubtest/allowlist.txt index 79af5cd99..29d4d4147 100644 --- a/scripts/stubtest/allowlist.txt +++ b/scripts/stubtest/allowlist.txt @@ -23,6 +23,11 @@ rest_framework.authtoken.migrations.0002_auto_20160226_1747 rest_framework.authtoken.migrations.0003_tokenproxy rest_framework.authtoken.migrations.0004_alter_tokenproxy_options +# `empty` hinted as enum, to work correctly in unions: +# https://github.com/typeddjango/djangorestframework-stubs/issues/42 +rest_framework.fields.empty +rest_framework.serializers.empty + # Mypy doesn't like default value `empty` rest_framework.fields.DateField.__init__ rest_framework.fields.DateTimeField.__init__ diff --git a/scripts/stubtest/allowlist_todo.txt b/scripts/stubtest/allowlist_todo.txt index 1b0a7f6df..eaa7133d1 100644 --- a/scripts/stubtest/allowlist_todo.txt +++ b/scripts/stubtest/allowlist_todo.txt @@ -41,7 +41,6 @@ rest_framework.fields.Option rest_framework.fields.REGEX_TYPE rest_framework.fields.SupportsToPython rest_framework.fields.TimeField.to_internal_value -rest_framework.fields.empty rest_framework.generics.BaseFilterProtocol rest_framework.generics.UsesQuerySet rest_framework.negotiation.DefaultContentNegotiation.settings @@ -89,7 +88,6 @@ rest_framework.serializers.PermissionDenied rest_framework.serializers.Throttled rest_framework.serializers.TimeField.to_internal_value rest_framework.serializers.UnsupportedMediaType -rest_framework.serializers.empty rest_framework.settings.DefaultsSettings rest_framework.settings.api_settings rest_framework.test.CoreAPIClient