From 9a41aa63ba22e599aa8f355eed6cb60c90f896c6 Mon Sep 17 00:00:00 2001 From: PIG208 <39874143+PIG208@users.noreply.github.com> Date: Mon, 19 Sep 2022 10:01:44 -0400 Subject: [PATCH] Broaden type annotation for verbose_name(_plural) to accept lazystr. (#1139) * Broaden type annotation for verbose_name(_plural) to accept lazystr. Fixes #1137. Signed-off-by: Zixuan James Li * Broaden type annotation for help_text to accept lazystr. Signed-off-by: Zixuan James Li * Broaden type annotation for ValidationError to accept lazystr. Signed-off-by: Zixuan James Li * Broaden type annotation for label to accept lazystr. Signed-off-by: Zixuan James Li * Add StrPromise and StrOrPromise aliases to django_stubs_ext. We make StrPromise and StrOrPromise available via django_stubs_ext so that conditional imports with TYPE_CHECKING is not required. These aliases fall back to Promise or Union[str, Promise] when not TYPE_CHECKING. Signed-off-by: Zixuan James Li Signed-off-by: Zixuan James Li --- django-stubs/apps/config.pyi | 3 +- django-stubs/contrib/admin/options.pyi | 5 +- django-stubs/contrib/admin/sites.pyi | 4 +- django-stubs/contrib/admin/widgets.pyi | 9 ++- django-stubs/contrib/gis/db/models/fields.pyi | 9 ++- .../contrib/postgres/fields/array.pyi | 3 +- django-stubs/core/cache/backends/db.pyi | 5 +- django-stubs/core/exceptions.pyi | 3 +- django-stubs/db/models/fields/__init__.pyi | 48 +++++------ django-stubs/db/models/fields/files.pyi | 7 +- django-stubs/db/models/fields/json.pyi | 3 +- django-stubs/db/models/fields/related.pyi | 17 ++-- django-stubs/db/models/options.pyi | 5 +- django-stubs/forms/boundfield.pyi | 5 +- django-stubs/forms/fields.pyi | 81 ++++++++++--------- django-stubs/forms/models.pyi | 17 ++-- django-stubs/utils/functional.pyi | 1 + django_stubs_ext/django_stubs_ext/__init__.py | 11 ++- django_stubs_ext/django_stubs_ext/aliases.py | 6 ++ 19 files changed, 138 insertions(+), 104 deletions(-) diff --git a/django-stubs/apps/config.pyi b/django-stubs/apps/config.pyi index 21696a9..bc23d0f 100644 --- a/django-stubs/apps/config.pyi +++ b/django-stubs/apps/config.pyi @@ -3,6 +3,7 @@ from typing import Dict, Iterator, Optional, Type from django.apps.registry import Apps from django.db.models.base import Model +from django.utils.functional import _StrOrPromise MODELS_MODULE_NAME: str @@ -11,7 +12,7 @@ class AppConfig: module: Optional[types.ModuleType] = ... apps: Optional[Apps] = ... label: str = ... - verbose_name: str = ... + verbose_name: _StrOrPromise = ... path: str = ... models_module: Optional[str] = ... models: Dict[str, Type[Model]] = ... diff --git a/django-stubs/contrib/admin/options.pyi b/django-stubs/contrib/admin/options.pyi index b3ccd41..9cc1a38 100644 --- a/django-stubs/contrib/admin/options.pyi +++ b/django-stubs/contrib/admin/options.pyi @@ -41,6 +41,7 @@ from django.http.response import HttpResponse, HttpResponseRedirect, JsonRespons from django.template.response import _TemplateForResponseT from django.urls.resolvers import URLPattern from django.utils.datastructures import _ListOrTuple +from django.utils.functional import _StrOrPromise from django.utils.safestring import SafeString from typing_extensions import Literal, TypedDict @@ -296,8 +297,8 @@ class InlineModelAdmin(Generic[_ChildModelT, _ParentModelT], BaseModelAdmin[_Chi min_num: Optional[int] = ... max_num: Optional[int] = ... template: str = ... - verbose_name: Optional[str] = ... - verbose_name_plural: Optional[str] = ... + verbose_name: Optional[_StrOrPromise] = ... + verbose_name_plural: Optional[_StrOrPromise] = ... can_delete: bool = ... show_change_link: bool = ... classes: Optional[Sequence[str]] = ... diff --git a/django-stubs/contrib/admin/sites.pyi b/django-stubs/contrib/admin/sites.pyi index 0cd0970..e5f7688 100644 --- a/django-stubs/contrib/admin/sites.pyi +++ b/django-stubs/contrib/admin/sites.pyi @@ -11,7 +11,7 @@ from django.http.request import HttpRequest from django.http.response import HttpResponse from django.template.response import TemplateResponse from django.urls import URLPattern, URLResolver -from django.utils.functional import LazyObject +from django.utils.functional import LazyObject, _StrOrPromise if sys.version_info >= (3, 9): from weakref import WeakSet @@ -77,7 +77,7 @@ class AdminSite: def i18n_javascript(self, request: HttpRequest, extra_context: Optional[Dict[str, Any]] = ...) -> HttpResponse: ... def logout(self, request: HttpRequest, extra_context: Optional[Dict[str, Any]] = ...) -> TemplateResponse: ... def login(self, request: HttpRequest, extra_context: Optional[Dict[str, Any]] = ...) -> HttpResponse: ... - def _build_app_dict(self, request: HttpRequest, label: Optional[str] = ...) -> Dict[str, Any]: ... + def _build_app_dict(self, request: HttpRequest, label: Optional[_StrOrPromise] = ...) -> Dict[str, Any]: ... def get_app_list(self, request: HttpRequest) -> List[Any]: ... def index(self, request: HttpRequest, extra_context: Optional[Dict[str, Any]] = ...) -> TemplateResponse: ... def app_index( diff --git a/django-stubs/contrib/admin/widgets.pyi b/django-stubs/contrib/admin/widgets.pyi index 24716a8..45f044d 100644 --- a/django-stubs/contrib/admin/widgets.pyi +++ b/django-stubs/contrib/admin/widgets.pyi @@ -7,12 +7,17 @@ from django.db.models.fields import _FieldChoices from django.db.models.fields.reverse_related import ForeignObjectRel, ManyToManyRel, ManyToOneRel from django.forms.models import ModelChoiceIterator from django.forms.widgets import Media, _OptAttrs +from django.utils.functional import _StrOrPromise class FilteredSelectMultiple(forms.SelectMultiple): - verbose_name: str = ... + verbose_name: _StrOrPromise = ... is_stacked: bool = ... def __init__( - self, verbose_name: str, is_stacked: bool, attrs: Optional[_OptAttrs] = ..., choices: _FieldChoices = ... + self, + verbose_name: _StrOrPromise, + is_stacked: bool, + attrs: Optional[_OptAttrs] = ..., + choices: _FieldChoices = ..., ) -> None: ... class AdminDateWidget(forms.DateInput): diff --git a/django-stubs/contrib/gis/db/models/fields.pyi b/django-stubs/contrib/gis/db/models/fields.pyi index 64a2812..2927b82 100644 --- a/django-stubs/contrib/gis/db/models/fields.pyi +++ b/django-stubs/contrib/gis/db/models/fields.pyi @@ -2,6 +2,7 @@ from typing import Any, Iterable, NamedTuple, Optional, Tuple, TypeVar, Union from django.core.validators import _ValidatorCallable from django.db.models.fields import Field, _ErrorMessagesT, _FieldChoices +from django.utils.functional import _StrOrPromise # __set__ value type _ST = TypeVar("_ST") @@ -19,7 +20,7 @@ def get_srid_info(srid: int, connection: Any) -> SRIDCacheEntry: ... class BaseSpatialField(Field[_ST, _GT]): def __init__( self, - verbose_name: Optional[Union[str, bytes]] = ..., + verbose_name: Optional[Union[_StrOrPromise, bytes]] = ..., srid: int = ..., spatial_index: bool = ..., *, @@ -38,7 +39,7 @@ class BaseSpatialField(Field[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[_ValidatorCallable] = ..., @@ -65,7 +66,7 @@ class GeometryField(BaseSpatialField): geography: Any = ... def __init__( self, - verbose_name: Optional[Union[str, bytes]] = ..., + verbose_name: Optional[Union[_StrOrPromise, bytes]] = ..., dim: int = ..., geography: bool = ..., *, @@ -88,7 +89,7 @@ class GeometryField(BaseSpatialField): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[_ValidatorCallable] = ..., diff --git a/django-stubs/contrib/postgres/fields/array.pyi b/django-stubs/contrib/postgres/fields/array.pyi index 9b6b72b..604d6aa 100644 --- a/django-stubs/contrib/postgres/fields/array.pyi +++ b/django-stubs/contrib/postgres/fields/array.pyi @@ -5,6 +5,7 @@ from django.db.models import Field, Transform from django.db.models.expressions import Combinable from django.db.models.fields import _ErrorMessagesT, _FieldChoices from django.db.models.fields.mixins import CheckFieldDefaultMixin +from django.utils.functional import _StrOrPromise # __set__ value type _ST = TypeVar("_ST") @@ -42,7 +43,7 @@ class ArrayField(CheckFieldDefaultMixin, Field[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[_ValidatorCallable] = ..., diff --git a/django-stubs/core/cache/backends/db.pyi b/django-stubs/core/cache/backends/db.pyi index 82fb34a..e82bf50 100644 --- a/django-stubs/core/cache/backends/db.pyi +++ b/django-stubs/core/cache/backends/db.pyi @@ -1,13 +1,14 @@ from typing import Any, Dict from django.core.cache.backends.base import BaseCache +from django.utils.functional import _StrOrPromise class Options: db_table: str = ... app_label: str = ... model_name: str = ... - verbose_name: str = ... - verbose_name_plural: str = ... + verbose_name: _StrOrPromise = ... + verbose_name_plural: _StrOrPromise = ... object_name: str = ... abstract: bool = ... managed: bool = ... diff --git a/django-stubs/core/exceptions.pyi b/django-stubs/core/exceptions.pyi index 43211be..9b0810e 100644 --- a/django-stubs/core/exceptions.pyi +++ b/django-stubs/core/exceptions.pyi @@ -1,5 +1,6 @@ from typing import Any, Dict, Iterator, List, Optional, Tuple, Union +from django.utils.functional import _StrPromise from typing_extensions import Literal class FieldDoesNotExist(Exception): ... @@ -35,7 +36,7 @@ class ValidationError(Exception): def __init__( self, # Accepts arbitrarily nested data structure, mypy doesn't allow describing it accurately. - message: Union[str, ValidationError, Dict[str, Any], List[Any]], + message: Union[str, _StrPromise, ValidationError, Dict[str, Any], List[Any]], code: Optional[str] = ..., params: Optional[Dict[str, Any]] = ..., ) -> None: ... diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index 7be7510..283a4d4 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -30,7 +30,7 @@ from django.db.models.query_utils import Q, RegisterLookupMixin from django.forms import Field as FormField from django.forms import Widget from django.utils.datastructures import DictWrapper -from django.utils.functional import _Getter +from django.utils.functional import _Getter, _StrOrPromise from typing_extensions import Protocol class Empty: ... @@ -120,7 +120,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]): _pyi_lookup_exact_type: Any widget: Widget - help_text: str + help_text: _StrOrPromise attname: str auto_created: bool primary_key: bool @@ -134,7 +134,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]): max_length: Optional[int] model: Type[Model] name: str - verbose_name: str + verbose_name: _StrOrPromise description: Union[str, _Getter[str]] blank: bool null: bool @@ -158,7 +158,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]): non_db_attrs: Tuple[str, ...] def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., primary_key: bool = ..., max_length: Optional[int] = ..., @@ -174,7 +174,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., auto_created: bool = ..., @@ -260,7 +260,7 @@ class DecimalField(Field[_ST, _GT]): decimal_places: int = ... def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., max_digits: Optional[int] = ..., decimal_places: Optional[int] = ..., @@ -275,7 +275,7 @@ class DecimalField(Field[_ST, _GT]): auto_created: bool = ..., serialize: bool = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -289,7 +289,7 @@ class CharField(Field[_ST, _GT]): _pyi_lookup_exact_type: Any def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., primary_key: bool = ..., max_length: Optional[int] = ..., @@ -305,7 +305,7 @@ class CharField(Field[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -319,7 +319,7 @@ class CommaSeparatedIntegerField(CharField[_ST, _GT]): ... class SlugField(CharField[_ST, _GT]): def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., primary_key: bool = ..., unique: bool = ..., @@ -333,7 +333,7 @@ class SlugField(CharField[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -349,7 +349,7 @@ class EmailField(CharField[_ST, _GT]): ... class URLField(CharField[_ST, _GT]): def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., *, primary_key: bool = ..., @@ -366,7 +366,7 @@ class URLField(CharField[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., auto_created: bool = ..., @@ -381,7 +381,7 @@ class TextField(Field[_ST, _GT]): _pyi_lookup_exact_type: Any def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., primary_key: bool = ..., max_length: Optional[int] = ..., @@ -397,7 +397,7 @@ class TextField(Field[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -443,7 +443,7 @@ class GenericIPAddressField(Field[_ST, _GT]): auto_created: bool = ..., serialize: bool = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -458,7 +458,7 @@ class DateField(DateTimeCheckMixin, Field[_ST, _GT]): _pyi_lookup_exact_type: Union[str, date] def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., auto_now: bool = ..., auto_now_add: bool = ..., @@ -474,7 +474,7 @@ class DateField(DateTimeCheckMixin, Field[_ST, _GT]): auto_created: bool = ..., serialize: bool = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -486,7 +486,7 @@ class TimeField(DateTimeCheckMixin, Field[_ST, _GT]): _pyi_private_get_type: time def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., auto_now: bool = ..., auto_now_add: bool = ..., @@ -501,7 +501,7 @@ class TimeField(DateTimeCheckMixin, Field[_ST, _GT]): auto_created: bool = ..., serialize: bool = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -518,7 +518,7 @@ class UUIDField(Field[_ST, _GT]): _pyi_private_get_type: uuid.UUID def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., *, name: Optional[str] = ..., primary_key: bool = ..., @@ -535,7 +535,7 @@ class UUIDField(Field[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., auto_created: bool = ..., @@ -551,7 +551,7 @@ class FilePathField(Field[_ST, _GT]): allow_folders: bool = ... def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., path: Union[str, Callable[..., str]] = ..., match: Optional[str] = ..., @@ -570,7 +570,7 @@ class FilePathField(Field[_ST, _GT]): auto_created: bool = ..., serialize: bool = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., diff --git a/django-stubs/db/models/fields/files.pyi b/django-stubs/db/models/fields/files.pyi index 8467b5d..b604b05 100644 --- a/django-stubs/db/models/fields/files.pyi +++ b/django-stubs/db/models/fields/files.pyi @@ -8,6 +8,7 @@ from django.db.models.base import Model from django.db.models.fields import Field, _ErrorMessagesT, _FieldChoices from django.db.models.query_utils import DeferredAttribute from django.utils._os import _PathCompatible +from django.utils.functional import _StrOrPromise from typing_extensions import Protocol class FieldFile(File): @@ -46,7 +47,7 @@ class FileField(Field): upload_to: Union[_PathCompatible, _UploadToCallable] = ... def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., upload_to: Union[_PathCompatible, _UploadToCallable] = ..., storage: Optional[Union[Storage, Callable[[], Storage]]] = ..., @@ -64,7 +65,7 @@ class FileField(Field): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -92,7 +93,7 @@ class ImageFieldFile(ImageFile, FieldFile): class ImageField(FileField): def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., width_field: Optional[str] = ..., height_field: Optional[str] = ..., diff --git a/django-stubs/db/models/fields/json.pyi b/django-stubs/db/models/fields/json.pyi index 7268b2b..5aacf54 100644 --- a/django-stubs/db/models/fields/json.pyi +++ b/django-stubs/db/models/fields/json.pyi @@ -5,6 +5,7 @@ from django.db.backends.base.base import BaseDatabaseWrapper from django.db.models import lookups from django.db.models.lookups import PostgresOperatorLookup, Transform from django.db.models.sql.compiler import SQLCompiler +from django.utils.functional import _StrOrPromise from . import Field from .mixins import CheckFieldDefaultMixin @@ -14,7 +15,7 @@ class JSONField(CheckFieldDefaultMixin, Field): decoder: Optional[Type[json.JSONDecoder]] def __init__( self, - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., encoder: Optional[Type[json.JSONEncoder]] = ..., decoder: Optional[Type[json.JSONDecoder]] = ..., diff --git a/django-stubs/db/models/fields/related.pyi b/django-stubs/db/models/fields/related.pyi index 3b9fc61..d104cbc 100644 --- a/django-stubs/db/models/fields/related.pyi +++ b/django-stubs/db/models/fields/related.pyi @@ -20,6 +20,7 @@ from django.db.models.fields.reverse_related import ManyToOneRel as ManyToOneRel from django.db.models.fields.reverse_related import OneToOneRel as OneToOneRel from django.db.models.manager import RelatedManager from django.db.models.query_utils import FilteredRelation, PathInfo, Q +from django.utils.functional import _StrOrPromise from typing_extensions import Literal _T = TypeVar("_T", bound=models.Model) @@ -75,7 +76,7 @@ class ForeignObject(RelatedField[_ST, _GT]): swappable: bool = ..., *, db_constraint: bool = ..., - verbose_name: Optional[str] = ..., + verbose_name: Optional[_StrOrPromise] = ..., name: Optional[str] = ..., primary_key: bool = ..., unique: bool = ..., @@ -87,7 +88,7 @@ class ForeignObject(RelatedField[_ST, _GT]): auto_created: bool = ..., serialize: bool = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -120,7 +121,7 @@ class ForeignKey(ForeignObject[_ST, _GT]): to_field: Optional[str] = ..., db_constraint: bool = ..., *, - verbose_name: Optional[Union[str, bytes]] = ..., + verbose_name: Optional[Union[_StrOrPromise, bytes]] = ..., name: Optional[str] = ..., primary_key: bool = ..., max_length: Optional[int] = ..., @@ -136,7 +137,7 @@ class ForeignKey(ForeignObject[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -169,7 +170,7 @@ class OneToOneField(ForeignKey[_ST, _GT]): limit_choices_to: Optional[_AllLimitChoicesTo] = ..., parent_link: bool = ..., db_constraint: bool = ..., - verbose_name: Optional[Union[str, bytes]] = ..., + verbose_name: Optional[Union[_StrOrPromise, bytes]] = ..., name: Optional[str] = ..., primary_key: bool = ..., max_length: Optional[int] = ..., @@ -185,7 +186,7 @@ class OneToOneField(ForeignKey[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., @@ -229,7 +230,7 @@ class ManyToManyField(RelatedField[_ST, _GT]): db_table: Optional[str] = ..., swappable: bool = ..., *, - verbose_name: Optional[Union[str, bytes]] = ..., + verbose_name: Optional[Union[_StrOrPromise, bytes]] = ..., name: Optional[str] = ..., primary_key: bool = ..., max_length: Optional[int] = ..., @@ -245,7 +246,7 @@ class ManyToManyField(RelatedField[_ST, _GT]): unique_for_month: Optional[str] = ..., unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., db_column: Optional[str] = ..., db_tablespace: Optional[str] = ..., validators: Iterable[validators._ValidatorCallable] = ..., diff --git a/django-stubs/db/models/options.pyi b/django-stubs/db/models/options.pyi index 8ce2e9d..42c5b13 100644 --- a/django-stubs/db/models/options.pyi +++ b/django-stubs/db/models/options.pyi @@ -12,6 +12,7 @@ from django.db.models.fields.reverse_related import ForeignObjectRel from django.db.models.manager import Manager from django.db.models.query_utils import PathInfo from django.utils.datastructures import ImmutableList, _ListOrTuple +from django.utils.functional import _StrOrPromise from typing_extensions import Literal PROXY_PARENTS: object @@ -46,8 +47,8 @@ class Options(Generic[_M]): base_manager_name: Optional[str] = ... default_manager_name: Optional[str] = ... model_name: Optional[str] = ... - verbose_name: Optional[str] = ... - verbose_name_plural: Optional[str] = ... + verbose_name: Optional[_StrOrPromise] = ... + verbose_name_plural: Optional[_StrOrPromise] = ... db_table: str = ... ordering: Optional[Sequence[str]] = ... indexes: List[Any] = ... diff --git a/django-stubs/forms/boundfield.pyi b/django-stubs/forms/boundfield.pyi index ccfee34..54b3e3b 100644 --- a/django-stubs/forms/boundfield.pyi +++ b/django-stubs/forms/boundfield.pyi @@ -5,6 +5,7 @@ from django.forms.forms import BaseForm from django.forms.renderers import BaseRenderer from django.forms.utils import ErrorList from django.forms.widgets import Widget +from django.utils.functional import _StrOrPromise from django.utils.safestring import SafeString _AttrsT = Dict[str, Union[str, bool]] @@ -16,8 +17,8 @@ class BoundField: html_name: str = ... html_initial_name: str = ... html_initial_id: str = ... - label: str = ... - help_text: str = ... + label: _StrOrPromise = ... + help_text: _StrOrPromise = ... def __init__(self, form: BaseForm, field: Field, name: str) -> None: ... @property def subwidgets(self) -> List[BoundWidget]: ... diff --git a/django-stubs/forms/fields.pyi b/django-stubs/forms/fields.pyi index 79ac424..15d00c1 100644 --- a/django-stubs/forms/fields.pyi +++ b/django-stubs/forms/fields.pyi @@ -10,6 +10,7 @@ from django.forms.boundfield import BoundField from django.forms.forms import BaseForm from django.forms.widgets import ChoiceWidget, Widget from django.utils.datastructures import _PropertyDescriptor +from django.utils.functional import _StrOrPromise # Problem: attribute `widget` is always of type `Widget` after field instantiation. # However, on class level it can be set to `Type[Widget]` too. @@ -22,7 +23,7 @@ _ClassLevelWidgetT = Any class Field: initial: Any - label: Optional[str] + label: Optional[_StrOrPromise] required: bool widget: _ClassLevelWidgetT = ... hidden_widget: Type[Widget] = ... @@ -30,7 +31,7 @@ class Field: default_error_messages: _ErrorMessagesT = ... empty_values: Sequence[Any] = ... show_hidden_initial: bool = ... - help_text: str = ... + help_text: _StrOrPromise = ... disabled: bool = ... label_suffix: Optional[str] = ... localize: bool = ... @@ -42,9 +43,9 @@ class Field: *, required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -77,9 +78,9 @@ class CharField(Field): empty_value: Optional[str] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -101,9 +102,9 @@ class IntegerField(Field): min_value: Optional[int] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -122,9 +123,9 @@ class FloatField(IntegerField): min_value: Union[int, float, None] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -148,9 +149,9 @@ class DecimalField(IntegerField): decimal_places: Optional[int] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -170,9 +171,9 @@ class BaseTemporalField(Field): input_formats: Optional[Any] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -214,9 +215,9 @@ class RegexField(CharField): empty_value: Optional[str] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -235,9 +236,9 @@ class EmailField(CharField): empty_value: Optional[str] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -255,9 +256,9 @@ class FileField(Field): allow_empty_file: bool = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -284,9 +285,9 @@ class URLField(CharField): empty_value: Optional[str] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -322,9 +323,9 @@ class ChoiceField(Field): choices: Union[_FieldChoices, _ChoicesCallable] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -352,9 +353,9 @@ class TypedChoiceField(ChoiceField): choices: Union[_FieldChoices, _ChoicesCallable] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -380,9 +381,9 @@ class TypedMultipleChoiceField(MultipleChoiceField): choices: Union[_FieldChoices, _ChoicesCallable] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -401,9 +402,9 @@ class ComboField(Field): *, required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -423,9 +424,9 @@ class MultiValueField(Field): require_all_fields: bool = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -456,9 +457,9 @@ class FilePathField(ChoiceField): choices: Union[_FieldChoices, _ChoicesCallable] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -477,9 +478,9 @@ class SplitDateTimeField(MultiValueField): require_all_fields: bool = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -498,9 +499,9 @@ class GenericIPAddressField(CharField): unpack_ipv4: bool = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., @@ -522,9 +523,9 @@ class SlugField(CharField): empty_value: Optional[str] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., error_messages: Optional[_ErrorMessagesT] = ..., show_hidden_initial: bool = ..., validators: Sequence[_ValidatorCallable] = ..., diff --git a/django-stubs/forms/models.pyi b/django-stubs/forms/models.pyi index 881babe..2c9dd1e 100644 --- a/django-stubs/forms/models.pyi +++ b/django-stubs/forms/models.pyi @@ -33,6 +33,7 @@ from django.forms.renderers import BaseRenderer from django.forms.utils import ErrorList, _DataT, _FilesT from django.forms.widgets import ChoiceWidget, Input, Widget from django.utils.datastructures import _IndexableCollection, _ListOrTuple, _PropertyDescriptor +from django.utils.functional import _StrOrPromise from typing_extensions import Literal ALL_FIELDS: Literal["__all__"] @@ -233,7 +234,7 @@ def inlineformset_factory( class InlineForeignKeyField(Field): disabled: bool - help_text: str + help_text: _StrOrPromise required: bool show_hidden_initial: bool widget: _ClassLevelWidgetT = ... @@ -268,13 +269,13 @@ class ModelChoiceIterator: class ModelChoiceField(ChoiceField): disabled: bool error_messages: Dict[str, str] - help_text: str + help_text: _StrOrPromise required: bool show_hidden_initial: bool validators: List[Any] default_error_messages: Dict[str, str] = ... iterator: Type[ModelChoiceIterator] = ... - empty_label: Optional[str] = ... + empty_label: Optional[_StrOrPromise] = ... queryset: Optional[QuerySet[models.Model]] = ... limit_choices_to: Optional[_AllLimitChoicesTo] = ... to_field_name: Optional[str] = ... @@ -282,12 +283,12 @@ class ModelChoiceField(ChoiceField): self, queryset: Union[None, Manager[models.Model], QuerySet[models.Model]], *, - empty_label: Optional[str] = ..., + empty_label: Optional[_StrOrPromise] = ..., required: bool = ..., widget: Optional[Union[Widget, Type[Widget]]] = ..., - label: Optional[str] = ..., + label: Optional[_StrOrPromise] = ..., initial: Optional[Any] = ..., - help_text: str = ..., + help_text: _StrOrPromise = ..., to_field_name: Optional[str] = ..., limit_choices_to: Optional[_AllLimitChoicesTo] = ..., blank: bool = ..., @@ -306,8 +307,8 @@ class ModelChoiceField(ChoiceField): class ModelMultipleChoiceField(ModelChoiceField): disabled: bool - empty_label: Optional[str] - help_text: str + empty_label: Optional[_StrOrPromise] + help_text: _StrOrPromise required: bool show_hidden_initial: bool widget: _ClassLevelWidgetT = ... diff --git a/django-stubs/utils/functional.pyi b/django-stubs/utils/functional.pyi index 677582b..e45c3d4 100644 --- a/django-stubs/utils/functional.pyi +++ b/django-stubs/utils/functional.pyi @@ -43,6 +43,7 @@ class _StrPromise(Promise, Sequence[str]): # Mypy requires this for the attribute hook to take effect def __getattribute__(self, __name: str) -> Any: ... +_StrOrPromise = Union[str, _StrPromise] _C = TypeVar("_C", bound=Callable) def lazy(func: _C, *resultclasses: Any) -> _C: ... diff --git a/django_stubs_ext/django_stubs_ext/__init__.py b/django_stubs_ext/django_stubs_ext/__init__.py index d82aea6..6fd35f3 100644 --- a/django_stubs_ext/django_stubs_ext/__init__.py +++ b/django_stubs_ext/django_stubs_ext/__init__.py @@ -1,7 +1,16 @@ +from .aliases import StrOrPromise, StrPromise from .aliases import ValuesQuerySet as ValuesQuerySet from .annotations import Annotations as Annotations from .annotations import WithAnnotations as WithAnnotations from .patch import monkeypatch as monkeypatch from .types import AnyAttrAllowed as AnyAttrAllowed -__all__ = ["monkeypatch", "ValuesQuerySet", "WithAnnotations", "Annotations", "AnyAttrAllowed"] +__all__ = [ + "monkeypatch", + "ValuesQuerySet", + "WithAnnotations", + "Annotations", + "AnyAttrAllowed", + "StrPromise", + "StrOrPromise", +] diff --git a/django_stubs_ext/django_stubs_ext/aliases.py b/django_stubs_ext/django_stubs_ext/aliases.py index 7ff4dbe..90ab07d 100644 --- a/django_stubs_ext/django_stubs_ext/aliases.py +++ b/django_stubs_ext/django_stubs_ext/aliases.py @@ -2,9 +2,15 @@ import typing if typing.TYPE_CHECKING: from django.db.models.query import _T, _QuerySet, _Row + from django.utils.functional import _StrOrPromise as StrOrPromise + from django.utils.functional import _StrPromise as StrPromise ValuesQuerySet = _QuerySet[_T, _Row] else: from django.db.models.query import QuerySet + from django.utils.functional import Promise as StrPromise ValuesQuerySet = QuerySet + StrOrPromise = typing.Union[str, StrPromise] + +__all__ = ["StrOrPromise", "StrPromise", "ValuesQuerySet"]