Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broaden type annotation for verbose_name(_plural) to accept lazystr. #1139

Merged
merged 5 commits into from Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion django-stubs/apps/config.pyi
Expand Up @@ -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

Expand All @@ -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]] = ...
Expand Down
5 changes: 3 additions & 2 deletions django-stubs/contrib/admin/options.pyi
Expand Up @@ -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

Expand Down Expand Up @@ -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]] = ...
Expand Down
9 changes: 7 additions & 2 deletions django-stubs/contrib/admin/widgets.pyi
Expand Up @@ -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):
Expand Down
5 changes: 3 additions & 2 deletions django-stubs/contrib/gis/db/models/fields.pyi
Expand Up @@ -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")
Expand All @@ -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 = ...,
*,
Expand Down Expand Up @@ -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 = ...,
*,
Expand Down
5 changes: 3 additions & 2 deletions 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 = ...
Expand Down
24 changes: 12 additions & 12 deletions django-stubs/db/models/fields/__init__.pyi
Expand Up @@ -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: ...
Expand Down Expand Up @@ -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
Expand All @@ -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] = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down Expand Up @@ -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 = ...,
Expand Down Expand Up @@ -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 = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down Expand Up @@ -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 = ...,
Expand Down Expand Up @@ -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 = ...,
Expand Down Expand Up @@ -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 = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down
5 changes: 3 additions & 2 deletions django-stubs/db/models/fields/files.pyi
Expand Up @@ -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):
Expand Down Expand Up @@ -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]]] = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down
3 changes: 2 additions & 1 deletion django-stubs/db/models/fields/json.pyi
Expand Up @@ -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
Expand All @@ -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]] = ...,
Expand Down
9 changes: 5 additions & 4 deletions django-stubs/db/models/fields/related.pyi
Expand Up @@ -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)
Expand Down Expand Up @@ -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 = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down Expand Up @@ -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] = ...,
Expand Down
5 changes: 3 additions & 2 deletions django-stubs/db/models/options.pyi
Expand Up @@ -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
Expand Down Expand Up @@ -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] = ...
Expand Down
1 change: 1 addition & 0 deletions django-stubs/utils/functional.pyi
Expand Up @@ -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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe _StrPromise should be public? Since it'll be exposed to users, right?

So that one can do str | StrPromise if passing around/accepting gettext_lazy values

Suggested change
_StrOrPromise = Union[str, _StrPromise]
_StrOrPromise = Union[str, StrPromise]

_C = TypeVar("_C", bound=Callable)

def lazy(func: _C, *resultclasses: Any) -> _C: ...
Expand Down