Skip to content

Commit 0a8e100

Browse files
committed
Add _StrPromise as a special type for Promise objects for str.
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 <[email protected]>
1 parent b2dceae commit 0a8e100

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

django-stubs/utils/functional.pyi

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import sys
22
from functools import wraps as wraps # noqa: F401
3-
from typing import Any, Callable, Generic, List, Optional, Tuple, Type, TypeVar, Union, overload
3+
from typing import Any, Callable, Generic, List, Optional, Sequence, Tuple, Type, TypeVar, Union, overload
44

55
from django.db.models.base import Model
6+
from typing_extensions import SupportsIndex
67

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

35+
class _StrPromise(Promise, Sequence[str]):
36+
def __add__(self, __s: str) -> str: ...
37+
# Incompatible with Sequence.__contains__
38+
def __contains__(self, __o: str) -> bool: ... # type: ignore[override]
39+
def __ge__(self, __x: str) -> bool: ...
40+
def __getitem__(self, __i: SupportsIndex | slice) -> str: ...
41+
def __gt__(self, __x: str) -> bool: ...
42+
def __le__(self, __x: str) -> bool: ...
43+
def __lt__(self, __x: str) -> bool: ...
44+
def __mod__(self, __x: Any) -> str: ...
45+
def __mul__(self, __n: SupportsIndex) -> str: ...
46+
def __rmul__(self, __n: SupportsIndex) -> str: ...
47+
def __getnewargs__(self) -> tuple[str]: ...
48+
3449
_C = TypeVar("_C", bound=Callable)
3550

3651
def lazy(func: _C, *resultclasses: Any) -> _C: ...
37-
def lazystr(text: Any) -> str: ...
52+
def lazystr(text: Any) -> _StrPromise: ...
3853
def keep_lazy(*resultclasses: Any) -> Callable: ...
3954
def keep_lazy_text(func: Callable) -> Callable: ...
4055

django-stubs/utils/translation/__init__.pyi

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ from contextlib import ContextDecorator
44
from typing import Any, Callable, Optional, Type, Union
55

66
from django.http.request import HttpRequest
7-
from django.utils.functional import Promise
7+
from django.utils.functional import _StrPromise
88

99
LANGUAGE_SESSION_KEY: str
1010

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

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

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

0 commit comments

Comments
 (0)