Skip to content

Commit 7ce5692

Browse files
GabDugsobolevn
andauthored
Type django.utils.* against Django 4.2 (#1575)
* Type all utils.* against Django 4.2 * fix: cached_property.name could be None * fix: SessionMiddleware was not typed properly * fix: conditional_escape should return SafeString, closes #1474 * chore: remove utils from allowlist * chore: remove unrelated unused ignores from allowlist for CI * chore: mark Protocols as type_check_only * Update scripts/stubtest/allowlist.txt Co-authored-by: Nikita Sobolev <[email protected]> * Update django-stubs/utils/deprecation.pyi Co-authored-by: Nikita Sobolev <[email protected]> * fix: MultieValueDict should return Self * fixes from MR review * chore: close #1269 * chore: remove legacy Self import from _typeshed * chore: move async with its sync counterpart * chore: remove Trans from typings * chore: fix tests * Apply suggestions from code review Co-authored-by: Nikita Sobolev <[email protected]> * chore: use decorator syntax for cached_property --------- Co-authored-by: Nikita Sobolev <[email protected]>
1 parent 43e4ef0 commit 7ce5692

25 files changed

+178
-249
lines changed

django-stubs/utils/autoreload.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import threading
22
import types
33
from collections.abc import Callable, Iterable, Iterator
4+
from logging import Logger
45
from pathlib import Path
56
from typing import Any
67

@@ -11,6 +12,7 @@ from typing_extensions import ParamSpec
1112

1213
_P = ParamSpec("_P")
1314

15+
logger: Logger
1416
autoreload_started: Signal
1517
file_changed: Signal
1618
DJANGO_AUTORELOAD_ENV: str

django-stubs/utils/connection.pyi

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from collections.abc import Iterator, Mapping, Sequence
22
from typing import Any, Generic, TypeVar
33

4+
from django.utils.functional import cached_property
5+
46
class ConnectionProxy:
57
def __init__(self, connections: Mapping[str, Any], alias: str) -> None: ...
68
def __getattr__(self, item: str) -> Any: ...
@@ -17,13 +19,14 @@ class BaseConnectionHandler(Generic[_T]):
1719
settings_name: str | None
1820
exception_class: type[Exception]
1921
thread_critical: bool
20-
def __init__(self, settings: Any | None = ...) -> None: ...
21-
@property
22+
@cached_property
2223
def settings(self) -> dict[str, Any]: ...
24+
def __init__(self, settings: Any | None = ...) -> None: ...
2325
def configure_settings(self, settings: dict[str, Any] | None) -> dict[str, Any]: ...
2426
def create_connection(self, alias: str) -> _T: ...
2527
def __getitem__(self, alias: str) -> _T: ...
2628
def __setitem__(self, key: str, value: _T) -> None: ...
2729
def __delitem__(self, key: str) -> None: ...
2830
def __iter__(self) -> Iterator[str]: ...
29-
def all(self) -> Sequence[_T]: ...
31+
def all(self, initialized_only: bool = ...) -> Sequence[_T]: ...
32+
def close_all(self) -> None: ...

django-stubs/utils/crypto.pyi

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from collections.abc import Callable
22
from hmac import HMAC
33

4-
using_sysrandom: bool
54
RANDOM_STRING_CHARS: str
65

6+
class InvalidAlgorithm(ValueError): ...
7+
78
def salted_hmac(
89
key_salt: bytes | str, value: bytes | str, secret: bytes | str | None = ..., *, algorithm: str = ...
910
) -> HMAC: ...
10-
def get_random_string(length: int = ..., allowed_chars: str = ...) -> str: ...
11+
def get_random_string(length: int, allowed_chars: str = ...) -> str: ...
1112
def constant_time_compare(val1: bytes | str, val2: bytes | str) -> bool: ...
1213
def pbkdf2(
1314
password: bytes | str,

django-stubs/utils/datastructures.pyi

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from collections.abc import Collection, Iterable, Iterator, Mapping, MutableSet
2-
from typing import Any, Generic, Protocol, Tuple, TypeVar, overload # noqa: Y022
1+
from collections.abc import Collection, Iterable, Iterator, Mapping, MutableMapping, MutableSet
2+
from typing import Any, Generic, NoReturn, Protocol, Tuple, TypeVar, overload # noqa: Y022
33

4-
from _typeshed import Self
5-
from typing_extensions import TypeAlias
4+
from _typeshed import Incomplete
5+
from typing_extensions import Self, TypeAlias
66

77
_K = TypeVar("_K")
88
_V = TypeVar("_V")
@@ -39,13 +39,14 @@ class _IndexableCollection(Protocol[_I], Collection[_I]):
3939
@overload
4040
def __getitem__(self, index: int) -> _I: ...
4141
@overload
42-
def __getitem__(self: Self, index: slice) -> Self: ...
42+
def __getitem__(self, index: slice) -> Self: ...
4343

4444
class OrderedSet(MutableSet[_K]):
4545
dict: dict[_K, None]
4646
def __init__(self, iterable: Iterable[_K] | None = ...) -> None: ...
4747
def __contains__(self, item: object) -> bool: ...
4848
def __iter__(self) -> Iterator[_K]: ...
49+
def __reversed__(self) -> Iterator[_K]: ...
4950
def __bool__(self) -> bool: ...
5051
def __len__(self) -> int: ...
5152
def add(self, item: _K) -> None: ...
@@ -74,7 +75,7 @@ class MultiValueDict(dict[_K, _V]):
7475
def items(self) -> Iterator[tuple[_K, _V | list[object]]]: ... # type: ignore
7576
def lists(self) -> Iterable[tuple[_K, list[_V]]]: ...
7677
def dict(self) -> dict[_K, _V | list[object]]: ...
77-
def copy(self: Self) -> Self: ...
78+
def copy(self) -> Self: ...
7879
def __getitem__(self, key: _K) -> _V | list[object]: ... # type: ignore
7980
def __setitem__(self, key: _K, value: _V) -> None: ...
8081
# These overrides are needed to convince mypy that this isn't an abstract class
@@ -83,11 +84,13 @@ class MultiValueDict(dict[_K, _V]):
8384
def __iter__(self) -> Iterator[_K]: ...
8485
# Fake to make `values` work properly
8586
def values(self) -> Iterator[_V | list[object]]: ... # type: ignore[override]
87+
def __copy__(self) -> Self: ...
88+
def __deepcopy__(self, memo: MutableMapping[int, Incomplete]) -> Self: ...
8689

8790
class ImmutableList(tuple[_V, ...]):
8891
warning: str
89-
def __new__(cls: type[Self], *args: Any, warning: str = ..., **kwargs: Any) -> Self: ...
90-
def complain(self, *args: Any, **kwargs: Any) -> None: ...
92+
def __new__(cls, *args: Any, warning: str = ..., **kwargs: Any) -> Self: ...
93+
def complain(self, *args: Any, **kwargs: Any) -> NoReturn: ...
9194

9295
class _ItemCallable(Protocol[_V]):
9396
"""Don't mess with arguments when assigning in class body in stub"""

django-stubs/utils/datetime_safe.pyi

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ from datetime import date as real_date
22
from datetime import datetime as real_datetime
33
from datetime import time as real_time
44

5-
class date(real_date): ...
6-
class datetime(real_datetime): ...
7-
class time(real_time): ...
5+
class date(real_date):
6+
def strftime(self, fmt: str) -> str: ...
7+
8+
class datetime(real_datetime):
9+
def strftime(self, fmt: str) -> str: ...
10+
@classmethod
11+
def combine(cls, date: real_date, time: real_time) -> datetime: ... # type: ignore
812

913
def new_date(d: real_date) -> date: ...
1014
def new_datetime(d: real_date | real_datetime) -> datetime: ...

django-stubs/utils/decorators.pyi

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
from collections.abc import Awaitable, Callable, Iterable
2-
from typing import Protocol, TypeVar
1+
from collections.abc import Callable, Iterable
2+
from typing import TypeVar
33

4-
from django.http.request import HttpRequest
5-
from django.http.response import HttpResponseBase
64
from django.utils.deprecation import MiddlewareMixin
7-
from django.utils.functional import classproperty as classproperty
85
from django.views.generic.base import View
96

107
_T = TypeVar("_T", bound=View | Callable) # Any callable
@@ -16,10 +13,6 @@ def method_decorator(decorator: Callable | Iterable[Callable], name: str = ...)
1613
def decorator_from_middleware_with_args(middleware_class: type) -> Callable: ...
1714
def decorator_from_middleware(middleware_class: type) -> Callable: ...
1815
def make_middleware_decorator(middleware_class: type[MiddlewareMixin]) -> Callable: ...
19-
20-
class AsyncGetResponseCallable(Protocol):
21-
def __call__(self, __request: HttpRequest) -> Awaitable[HttpResponseBase]: ...
22-
2316
def sync_and_async_middleware(func: _CallableType) -> _CallableType: ...
2417
def sync_only_middleware(func: _CallableType) -> _CallableType: ...
2518
def async_only_middleware(func: _CallableType) -> _CallableType: ...

django-stubs/utils/deprecation.pyi

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
from collections.abc import Callable
1+
from collections.abc import Awaitable, Callable
22
from typing import Any, Protocol
33

44
from django.http.request import HttpRequest
55
from django.http.response import HttpResponseBase
66
from typing_extensions import TypeAlias
77

8-
class RemovedInDjango40Warning(DeprecationWarning): ...
9-
class RemovedInDjango41Warning(PendingDeprecationWarning): ...
8+
class RemovedInDjango50Warning(DeprecationWarning): ...
9+
class RemovedInDjango51Warning(PendingDeprecationWarning): ...
1010

11-
RemovedInNextVersionWarning: TypeAlias = RemovedInDjango40Warning
11+
RemovedInNextVersionWarning: TypeAlias = RemovedInDjango50Warning
12+
RemovedAfterNextVersionWarning: TypeAlias = RemovedInDjango51Warning
1213

1314
class warn_about_renamed_method:
1415
class_name: str
@@ -29,10 +30,17 @@ class DeprecationInstanceCheck(type):
2930
deprecation_warning: type[Warning]
3031
def __instancecheck__(self, instance: Any) -> bool: ...
3132

32-
class GetResponseCallable(Protocol):
33+
class _GetResponseCallable(Protocol):
3334
def __call__(self, __request: HttpRequest) -> HttpResponseBase: ...
3435

36+
class _AsyncGetResponseCallable(Protocol):
37+
def __call__(self, __request: HttpRequest) -> Awaitable[HttpResponseBase]: ...
38+
3539
class MiddlewareMixin:
36-
get_response: GetResponseCallable
37-
def __init__(self, get_response: GetResponseCallable = ...) -> None: ...
40+
sync_capable: bool
41+
async_capable: bool
42+
43+
get_response: _GetResponseCallable | _AsyncGetResponseCallable
44+
def __init__(self, get_response: _GetResponseCallable | _AsyncGetResponseCallable) -> None: ...
3845
def __call__(self, request: HttpRequest) -> HttpResponseBase: ...
46+
async def __acall__(self, request: HttpRequest) -> HttpResponseBase: ...

django-stubs/utils/encoding.pyi

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ def smart_str(s: _PT, encoding: str = ..., strings_only: Literal[True] = ..., er
2626
def smart_str(s: _S, encoding: str = ..., strings_only: bool = ..., errors: str = ...) -> _S: ...
2727
@overload
2828
def smart_str(s: Any, encoding: str = ..., strings_only: bool = ..., errors: str = ...) -> str: ...
29-
30-
smart_text = smart_str # Deprecated
31-
3229
def is_protected_type(obj: Any) -> TypeGuard[_PT]: ...
3330
@overload
3431
def force_str(s: _S, encoding: str = ..., *, errors: str = ...) -> _S: ...
@@ -40,9 +37,6 @@ def force_str(s: _PT, encoding: str = ..., strings_only: Literal[True] = ..., er
4037
def force_str(s: _S, encoding: str = ..., strings_only: bool = ..., errors: str = ...) -> _S: ...
4138
@overload
4239
def force_str(s: Any, encoding: str = ..., strings_only: bool = ..., errors: str = ...) -> str: ...
43-
44-
force_text = force_str # Deprecated
45-
4640
@overload
4741
def smart_bytes(s: _P, encoding: str = ..., strings_only: bool = ..., errors: str = ...) -> _P: ...
4842
@overload

django-stubs/utils/feedgenerator.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class Enclosure:
6464

6565
class RssFeed(SyndicationFeed):
6666
content_type: str
67+
def rss_attributes(self) -> dict[str, str]: ...
6768
def write_items(self, handler: ContentHandler) -> None: ...
6869
def endChannelElement(self, handler: ContentHandler) -> None: ...
6970

django-stubs/utils/formats.pyi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ FORMAT_SETTINGS: frozenset[str]
1010

1111
def reset_format_cache() -> None: ...
1212
def iter_format_modules(lang: str, format_module_path: list[str] | str | None = ...) -> Iterator[types.ModuleType]: ...
13-
def get_format_modules(lang: str | None = ..., reverse: bool = ...) -> list[types.ModuleType]: ...
13+
def get_format_modules(lang: str | None = ...) -> list[types.ModuleType]: ...
1414
def get_format(format_type: str, lang: str | None = ..., use_l10n: bool | None = ...) -> Any: ...
1515

1616
get_format_lazy: Any
@@ -42,3 +42,4 @@ def localize_input( # type: ignore
4242
@overload
4343
def localize_input(value: _T, default: str | None = ...) -> _T: ...
4444
def sanitize_separators(value: _T) -> _T: ...
45+
def sanitize_strftime_format(fmt: str) -> str: ...

0 commit comments

Comments
 (0)