Skip to content

Commit

Permalink
Add _StrPromise as a special type for Promise objects for str.
Browse files Browse the repository at this point in the history
This allows the user to access methods defined on lazy strings while
still letting mypy be aware of that they are not instances of `str`.

The definitions for some of the magic methods are pulled from typeshed. We need
those definitions in the stubs so that `_StrPromise` objects will work properly
with operators, as refining operator types is tricky with the mypy
plugins API.

The rest of the methods will be covered by an attribute hook.

Signed-off-by: Zixuan James Li <p359101898@gmail.com>
  • Loading branch information
PIG208 committed Aug 8, 2022
1 parent b2dceae commit 0a8e100
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 7 deletions.
19 changes: 17 additions & 2 deletions django-stubs/utils/functional.pyi
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import sys
from functools import wraps as wraps # noqa: F401
from typing import Any, Callable, Generic, List, Optional, Tuple, Type, TypeVar, Union, overload
from typing import Any, Callable, Generic, List, Optional, Sequence, Tuple, Type, TypeVar, Union, overload

from django.db.models.base import Model
from typing_extensions import SupportsIndex

if sys.version_info < (3, 8):
from typing_extensions import Protocol
Expand Down Expand Up @@ -31,10 +32,24 @@ class Promise:
def __radd__(self, other: Any) -> Any: ...
def __deepcopy__(self, memo: Any): ...

class _StrPromise(Promise, Sequence[str]):
def __add__(self, __s: str) -> str: ...
# Incompatible with Sequence.__contains__
def __contains__(self, __o: str) -> bool: ... # type: ignore[override]
def __ge__(self, __x: str) -> bool: ...
def __getitem__(self, __i: SupportsIndex | slice) -> str: ...
def __gt__(self, __x: str) -> bool: ...
def __le__(self, __x: str) -> bool: ...
def __lt__(self, __x: str) -> bool: ...
def __mod__(self, __x: Any) -> str: ...
def __mul__(self, __n: SupportsIndex) -> str: ...
def __rmul__(self, __n: SupportsIndex) -> str: ...
def __getnewargs__(self) -> tuple[str]: ...

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

def lazy(func: _C, *resultclasses: Any) -> _C: ...
def lazystr(text: Any) -> str: ...
def lazystr(text: Any) -> _StrPromise: ...
def keep_lazy(*resultclasses: Any) -> Callable: ...
def keep_lazy_text(func: Callable) -> Callable: ...

Expand Down
10 changes: 5 additions & 5 deletions django-stubs/utils/translation/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ from contextlib import ContextDecorator
from typing import Any, Callable, Optional, Type, Union

from django.http.request import HttpRequest
from django.utils.functional import Promise
from django.utils.functional import _StrPromise

LANGUAGE_SESSION_KEY: str

Expand Down Expand Up @@ -33,10 +33,10 @@ def pgettext(context: str, message: str) -> str: ...
def npgettext(context: str, singular: str, plural: str, number: int) -> str: ...

# lazy evaluated translation functions
def gettext_lazy(message: str) -> Promise: ...
def pgettext_lazy(context: str, message: str) -> Promise: ...
def ngettext_lazy(singular: str, plural: str, number: Union[int, str, None] = ...) -> Promise: ...
def npgettext_lazy(context: str, singular: str, plural: str, number: Union[int, str, None] = ...) -> Promise: ...
def gettext_lazy(message: str) -> _StrPromise: ...
def pgettext_lazy(context: str, message: str) -> _StrPromise: ...
def ngettext_lazy(singular: str, plural: str, number: Union[int, str, None] = ...) -> _StrPromise: ...
def npgettext_lazy(context: str, singular: str, plural: str, number: Union[int, str, None] = ...) -> _StrPromise: ...

# NOTE: These translation functions are deprecated and removed in Django 4.0. We should remove them when we drop
# support for 3.2
Expand Down

0 comments on commit 0a8e100

Please sign in to comment.