Skip to content

Commit

Permalink
Recover after #909 (#925)
Browse files Browse the repository at this point in the history
* Fix stubs related to `(Async)RequestFactory` and `(Async)Client`

* Revert incorrect removal.

* Allow set as `unique_together`, use shared type alias.

* Revert `Q.__init__` to use only `*args, **kwargs` to remove false-positive with `Q(**{...})`

* Add abstract methods to `HttpResponseBase` to create common interface.

* Remove monkey-patched attributes from `HttpResponseBase` subclasses.

* Add QueryDict mutability checks (+ plugin support)

* Fix lint

* Return back GenericForeignKey to `Options.get_fields`

* Minor fixup

* Make plugin code typecheck with `--warn-unreachable`, minor performance increase.

* Better types for `{unique, index}_together` and Options.

* Fix odd type of `URLResolver.urlconf_name` which isn't a str actually.

* Better types for field migration operations.

* Revert form.files to `MultiValueDict[str, UploadedFile]`

* Compatibility fix (#916)

* Do not assume that `Annotated` is always related to django-stubs (fixes #893)

* Restrict `FormView.get_form` return type to `_FormT` (class type argument). Now it is resolved to `form_class` argument if present, but also errors if it is not subclass of _FormT

* Fix CI (make test runnable on 3.8)

* Fix CI (make test runnable on 3.8 _again_)
  • Loading branch information
sterliakov authored Apr 28, 2022
1 parent 16499a2 commit 6226381
Show file tree
Hide file tree
Showing 29 changed files with 380 additions and 138 deletions.
6 changes: 3 additions & 3 deletions django-stubs/core/handlers/asgi.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ from typing import (
)

from django.core.handlers import base as base
from django.http import HttpRequest, QueryDict
from django.http.request import HttpRequest, _ImmutableQueryDict
from django.http.response import HttpResponseBase
from django.urls.resolvers import ResolverMatch, URLResolver
from django.utils.datastructures import MultiValueDict
Expand All @@ -34,8 +34,8 @@ class ASGIRequest(HttpRequest):
META: Dict[str, Any] = ...
def __init__(self, scope: Mapping[str, Any], body_file: IO[bytes]) -> None: ...
@property
def GET(self) -> QueryDict: ... # type: ignore
POST: QueryDict = ...
def GET(self) -> _ImmutableQueryDict: ... # type: ignore
POST: _ImmutableQueryDict = ...
FILES: MultiValueDict = ...
@property
def COOKIES(self) -> Dict[str, str]: ... # type: ignore
Expand Down
12 changes: 6 additions & 6 deletions django-stubs/db/migrations/operations/fields.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Optional
from typing import Optional

from django.db.models.fields import Field

Expand All @@ -23,15 +23,15 @@ class AddField(FieldOperation):
class RemoveField(FieldOperation): ...

class AlterField(FieldOperation):
field: Any = ...
preserve_default: Any = ...
field: Field = ...
preserve_default: bool = ...
def __init__(self, model_name: str, name: str, field: Field, preserve_default: bool = ...) -> None: ...

class RenameField(FieldOperation):
old_name: Any = ...
new_name: Any = ...
old_name: str = ...
new_name: str = ...
def __init__(self, model_name: str, old_name: str, new_name: str) -> None: ...
@property
def old_name_lower(self): ...
def old_name_lower(self) -> str: ...
@property
def new_name_lower(self) -> str: ...
26 changes: 12 additions & 14 deletions django-stubs/db/migrations/operations/models.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union

from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.operations.base import Operation
Expand All @@ -7,9 +7,7 @@ from django.db.models.constraints import BaseConstraint
from django.db.models.fields import Field
from django.db.models.indexes import Index
from django.db.models.manager import Manager
from django.utils.datastructures import _ListOrTuple

_T = TypeVar("_T")
from django.db.models.options import _OptionTogetherT

class ModelOperation(Operation):
name: str = ...
Expand Down Expand Up @@ -53,10 +51,10 @@ class AlterTogetherOptionOperation(ModelOptionOperation):
def __init__(
self,
name: str,
option_value: _ListOrTuple[Tuple[str, str]],
option_value: Optional[_OptionTogetherT],
) -> None: ...
@property
def option_value(self) -> Set[Tuple[str, str]]: ...
def option_value(self) -> Optional[Set[Tuple[str, ...]]]: ...
def deconstruct(self) -> Tuple[str, Sequence[Any], Dict[str, Any]]: ...
def state_forwards(self, app_label: str, state: Any) -> None: ...
def database_forwards(
Expand All @@ -72,26 +70,26 @@ class AlterTogetherOptionOperation(ModelOptionOperation):

class AlterUniqueTogether(AlterTogetherOptionOperation):
option_name: str = ...
unique_together: _ListOrTuple[Tuple[str, str]] = ...
def __init__(self, name: str, unique_together: _ListOrTuple[Tuple[str, str]]) -> None: ...
unique_together: Optional[Set[Tuple[str, ...]]] = ...
def __init__(self, name: str, unique_together: Optional[_OptionTogetherT]) -> None: ...

class AlterIndexTogether(AlterTogetherOptionOperation):
option_name: str = ...
index_together: _ListOrTuple[Tuple[str, str]] = ...
def __init__(self, name: str, index_together: _ListOrTuple[Tuple[str, str]]) -> None: ...
index_together: Optional[Set[Tuple[str, ...]]] = ...
def __init__(self, name: str, index_together: Optional[_OptionTogetherT]) -> None: ...

class AlterOrderWithRespectTo(ModelOptionOperation):
order_with_respect_to: str = ...
def __init__(self, name: str, order_with_respect_to: str) -> None: ...

class AlterModelOptions(ModelOptionOperation):
ALTER_OPTION_KEYS: Any = ...
options: Dict[str, str] = ...
ALTER_OPTION_KEYS: List[str] = ...
options: Dict[str, Any] = ...
def __init__(self, name: str, options: Dict[str, Any]) -> None: ...

class AlterModelManagers(ModelOptionOperation):
managers: Any = ...
def __init__(self, name: Any, managers: Any) -> None: ...
managers: Sequence[Manager] = ...
def __init__(self, name: str, managers: Sequence[Manager]) -> None: ...

class IndexOperation(Operation):
option_name: str = ...
Expand Down
20 changes: 8 additions & 12 deletions django-stubs/db/migrations/operations/special.pyi
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import sys
from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple, Union
from typing import Any, Mapping, Optional, Sequence, Union

from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps

if sys.version_info < (3, 8):
from typing_extensions import Literal
else:
from typing import Literal
from django.utils.datastructures import _ListOrTuple

from .base import Operation

Expand All @@ -25,14 +21,14 @@ class SeparateDatabaseAndState(Operation):

class RunSQL(Operation):
noop: Literal[""] = ...
sql: Union[str, List[str], Tuple[str, ...]] = ...
reverse_sql: Optional[Union[str, List[str], Tuple[str, ...]]] = ...
sql: Union[str, _ListOrTuple[str]] = ...
reverse_sql: Optional[Union[str, _ListOrTuple[str]]] = ...
state_operations: Sequence[Operation] = ...
hints: Mapping[str, Any] = ...
def __init__(
self,
sql: Union[str, List[str], Tuple[str, ...]],
reverse_sql: Optional[Union[str, List[str], Tuple[str, ...]]] = ...,
sql: Union[str, _ListOrTuple[str]],
reverse_sql: Optional[Union[str, _ListOrTuple[str]]] = ...,
state_operations: Sequence[Operation] = ...,
hints: Optional[Mapping[str, Any]] = ...,
elidable: bool = ...,
Expand All @@ -44,13 +40,13 @@ class _CodeCallable(Protocol):
class RunPython(Operation):
code: _CodeCallable = ...
reverse_code: Optional[_CodeCallable] = ...
hints: Optional[Dict[str, Any]] = ...
hints: Mapping[str, Any] = ...
def __init__(
self,
code: _CodeCallable,
reverse_code: Optional[_CodeCallable] = ...,
atomic: Optional[bool] = ...,
hints: Optional[Dict[str, Any]] = ...,
hints: Optional[Mapping[str, Any]] = ...,
elidable: bool = ...,
) -> None: ...
@staticmethod
Expand Down
35 changes: 23 additions & 12 deletions django-stubs/db/models/options.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, Dict, Generic, Iterable, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union
import sys
from typing import Any, Dict, Generic, Iterable, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union, overload

from django.apps.config import AppConfig
from django.apps.registry import Apps
Expand All @@ -11,16 +12,26 @@ from django.db.models.fields.related import ManyToManyField, OneToOneField
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
from django.utils.datastructures import ImmutableList, _ListOrTuple

if sys.version_info < (3, 8):
from typing_extensions import Literal
else:
from typing import Literal

PROXY_PARENTS: object
EMPTY_RELATION_TREE: Any
IMMUTABLE_WARNING: str
DEFAULT_NAMES: Tuple[str, ...]

def normalize_together(
option_together: Union[List[Tuple[str, str]], Tuple[Tuple[str, str], ...], Tuple[()], Tuple[str, str]]
) -> Tuple[Tuple[str, str], ...]: ...
_OptionTogetherT = Union[_ListOrTuple[Union[_ListOrTuple[str], str]], Set[Tuple[str, ...]]]

@overload
def normalize_together(option_together: _ListOrTuple[Union[_ListOrTuple[str], str]]) -> Tuple[Tuple[str, ...], ...]: ...

# Any other value will be returned unchanged, but probably only set is semantically allowed
@overload
def normalize_together(option_together: Set[Tuple[str, ...]]) -> Set[Tuple[str, ...]]: ...

_T = TypeVar("_T")

Expand All @@ -45,18 +56,18 @@ class Options(Generic[_M]):
db_table: str = ...
ordering: Optional[Sequence[str]] = ...
indexes: List[Any] = ...
unique_together: Union[Sequence[Tuple[str, str]], Tuple[str, str]] = ...
index_together: Union[Sequence[Tuple[str, str]], Tuple[str, str]] = ...
unique_together: Sequence[Tuple[str]] = ... # Are always normalized
index_together: Sequence[Tuple[str]] = ... # Are always normalized
select_on_save: bool = ...
default_permissions: Sequence[str] = ...
permissions: List[Any] = ...
object_name: Optional[str] = ...
app_label: str = ...
get_latest_by: Optional[Sequence[str]] = ...
order_with_respect_to: Optional[Any] = ...
order_with_respect_to: Optional[str] = ...
db_tablespace: str = ...
required_db_features: List[Any] = ...
required_db_vendor: Any = ...
required_db_features: List[str] = ...
required_db_vendor: Optional[Literal["sqlite", "postgresql", "mysql", "oracle"]] = ...
meta: Optional[type] = ...
pk: Optional[Field] = ...
auto_field: Optional[AutoField] = ...
Expand Down Expand Up @@ -105,15 +116,15 @@ class Options(Generic[_M]):
def default_manager(self) -> Optional[Manager]: ...
@property
def fields(self) -> ImmutableList[Field[Any, Any]]: ...
def get_field(self, field_name: str) -> Union[Field, ForeignObjectRel]: ...
def get_field(self, field_name: str) -> Union[Field, ForeignObjectRel, GenericForeignKey]: ...
def get_base_chain(self, model: Type[Model]) -> List[Type[Model]]: ...
def get_parent_list(self) -> List[Type[Model]]: ...
def get_ancestor_link(self, ancestor: Type[Model]) -> Optional[OneToOneField]: ...
def get_path_to_parent(self, parent: Type[Model]) -> List[PathInfo]: ...
def get_path_from_parent(self, parent: Type[Model]) -> List[PathInfo]: ...
def get_fields(
self, include_parents: bool = ..., include_hidden: bool = ...
) -> List[Union[Field[Any, Any], ForeignObjectRel]]: ...
) -> List[Union[Field[Any, Any], ForeignObjectRel, GenericForeignKey]]: ...
@property
def total_unique_constraints(self) -> List[UniqueConstraint]: ...
@property
Expand Down
4 changes: 3 additions & 1 deletion django-stubs/db/models/query_utils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ class Q(tree.Node):
AND: str = ...
OR: str = ...
conditional: bool = ...
def __init__(self, *args: Any, _connector: Optional[Any] = ..., _negated: bool = ..., **kwargs: Any) -> None: ...
def __init__(self, *args: Any, **kwargs: Any) -> None: ...
# Fake signature, the real is
# def __init__(self, *args: Any, _connector: Optional[Any] = ..., _negated: bool = ..., **kwargs: Any) -> None: ...
def __or__(self, other: Q) -> Q: ...
def __and__(self, other: Q) -> Q: ...
def __invert__(self) -> Q: ...
Expand Down
2 changes: 2 additions & 0 deletions django-stubs/db/utils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class ConnectionRouter:
def __init__(self, routers: Optional[Iterable[Any]] = ...) -> None: ...
@property
def routers(self) -> List[Any]: ...
def db_for_read(self, model: Type[Model], **hints: Any) -> str: ...
def db_for_write(self, model: Type[Model], **hints: Any) -> str: ...
def allow_relation(self, obj1: Model, obj2: Model, **hints: Any) -> bool: ...
def allow_migrate(self, db: str, app_label: str, **hints: Any) -> bool: ...
def allow_migrate_model(self, db: str, model: Type[Model]) -> bool: ...
Expand Down
5 changes: 3 additions & 2 deletions django-stubs/forms/utils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ from datetime import datetime
from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Union

from django.core.exceptions import ValidationError
from django.core.files import File
from django.core.files.uploadedfile import UploadedFile
from django.utils.datastructures import MultiValueDict
from django.utils.safestring import SafeString

_DataT = Mapping[str, Any]
_FilesT = Mapping[str, Iterable[File]]
_FilesT = MultiValueDict[str, UploadedFile]

def pretty_name(name: str) -> str: ...
def flatatt(attrs: Dict[str, Any]) -> SafeString: ...
Expand Down
Loading

0 comments on commit 6226381

Please sign in to comment.