Skip to content

Commit 097bd62

Browse files
committed
Replaced TypeAlias _ClassLevelWidgetT with descriptor _WidgetTypeOrInstance for Field.widget
1 parent 631b48a commit 097bd62

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

django-stubs/forms/fields.pyi

+15-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import datetime
22
from collections.abc import Collection, Iterator, Sequence
33
from decimal import Decimal
44
from re import Pattern
5-
from typing import Any, ClassVar, Protocol, TypeAlias, type_check_only
5+
from typing import Any, ClassVar, Protocol, overload, type_check_only
66
from uuid import UUID
77

88
from django.core.files import File
@@ -15,20 +15,25 @@ from django.utils.choices import CallableChoiceIterator, _ChoicesCallable, _Choi
1515
from django.utils.datastructures import _PropertyDescriptor
1616
from django.utils.functional import _StrOrPromise
1717

18-
# Problem: attribute `widget` is always of type `Widget` after field instantiation.
19-
# However, on class level it can be set to `Type[Widget]` too.
20-
# If we annotate it as `Union[Widget, Type[Widget]]`, every code that uses field
21-
# instances will not typecheck.
22-
# If we annotate it as `Widget`, any widget subclasses that do e.g.
23-
# `widget = Select` will not typecheck.
24-
# `Any` gives too much freedom, but does not create false positives.
25-
_ClassLevelWidgetT: TypeAlias = Any
18+
@type_check_only
19+
class _WidgetTypeOrInstance:
20+
def __init__(self, origin_type: type[Widget]) -> None: ...
21+
@overload
22+
def __get__(self, instance: None, owner: type[Field]) -> type[Widget] | Widget: ...
23+
@overload
24+
def __get__(self, instance: Field, owner: type[Field]) -> Widget: ...
25+
def __get__(self, instance: Field, owner: type[Field]) -> type[Widget] | Widget: ...
26+
@overload
27+
def __set__(self, instance: None, value: type[Widget]) -> None: ...
28+
@overload
29+
def __set__(self, instance: Field, value: Widget) -> None: ...
30+
def __set__(self, instance: Field, value: type[Widget] | Widget) -> None: ...
2631

2732
class Field:
2833
initial: Any
2934
label: _StrOrPromise | None
3035
required: bool
31-
widget: _ClassLevelWidgetT
36+
widget: _WidgetTypeOrInstance
3237
hidden_widget: type[Widget]
3338
default_validators: list[_ValidatorCallable]
3439
default_error_messages: ClassVar[_ErrorMessagesDict]

0 commit comments

Comments
 (0)