Skip to content

Add support for mypy v1.16 #2703

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

Merged
merged 11 commits into from
Jun 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions django-stubs/contrib/gis/db/backends/oracle/features.pyi
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
from typing import Any

from django.contrib.gis.db.backends.base.features import BaseSpatialFeatures
from django.db.backends.oracle.features import DatabaseFeatures as OracleDatabaseFeatures
from django.utils.functional import cached_property

class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
supports_add_srs_entry: bool
supports_geometry_field_introspection: bool
supports_geometry_field_unique_index: bool
supports_perimeter_geodetic: bool
supports_dwithin_distance_expr: bool
@cached_property
def django_test_skips(self) -> dict[str, Any]: ... # type: ignore[override]
4 changes: 2 additions & 2 deletions django-stubs/db/backends/postgresql/features.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
has_json_operators: bool
json_key_contains_list_matching_requires_list: bool
@property
def is_postgresql_14(self) -> bool: ...
@property
def is_postgresql_15(self) -> bool: ...
@cached_property
def is_postgresql_16(self) -> bool: ...
@property
def is_postgresql_17(self) -> bool: ...
has_brin_autosummarize: bool
has_websearch_to_tsquery: bool
supports_table_partitions: bool
Expand Down
2 changes: 1 addition & 1 deletion django-stubs/db/models/fields/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]):
model: type[Model]
name: str
verbose_name: _StrOrPromise
description: str | _Getter[str]
description: _StrOrPromise | _Getter[_StrOrPromise]
blank: bool
null: bool
unique: bool
Expand Down
4 changes: 3 additions & 1 deletion django-stubs/utils/datastructures.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ class MultiValueDict(dict[_K, _V]):
def __init__(self, key_to_list_mapping: Mapping[_K, list[_V] | None]) -> None: ...
@overload
def __init__(self, key_to_list_mapping: Iterable[tuple[_K, list[_V]]] = ()) -> None: ...
@overload # type: ignore[override]
def get(self, key: _K, default: None = None) -> _V | None: ...
@overload
def get(self, key: _K) -> _V | None: ...
def get(self, key: _K, default: _V) -> _V: ...
@overload
def get(self, key: _K, default: _Z) -> _V | _Z: ...
def getlist(self, key: _K, default: _Z | None = None) -> list[_V] | _Z: ...
Expand Down
3 changes: 2 additions & 1 deletion django-stubs/utils/functional.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ class classproperty(Generic[_Get]):

@type_check_only
class _Getter(Protocol[_Get]): # noqa: PYI046
"""Type fake to declare some read-only properties (until `property` builtin is generic)
"""
Type fake to declare some read-only properties (until `property` builtin is generic).

We can use something like `Union[_Getter[str], str]` in base class to avoid errors
when redefining attribute with property or property with attribute.
Expand Down
4 changes: 2 additions & 2 deletions ext/django_stubs_ext/db/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class TypedModelMeta:
required_db_vendor: ClassVar[Literal["sqlite", "postgresql", "mysql", "oracle"]]
select_on_save: ClassVar[bool] # default: False
indexes: ClassVar[_ListOrTuple[Index]]
unique_together: ClassVar[Sequence[Sequence[str]] | Sequence[str]]
index_together: ClassVar[Sequence[Sequence[str]] | Sequence[str]] # Deprecated in Django 4.2
unique_together: ClassVar[Sequence[Sequence[str]]]
index_together: ClassVar[Sequence[Sequence[str]]] # Deprecated in Django 4.2
constraints: ClassVar[_ListOrTuple[BaseConstraint]]
verbose_name: ClassVar[StrOrPromise]
verbose_name_plural: ClassVar[StrOrPromise]
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ dependencies = [
]

[project.optional-dependencies]
compatible-mypy = ["mypy>=1.13,<1.16"]
compatible-mypy = ["mypy>=1.13,<1.17"]
oracle = ["oracledb"]
redis = ["redis", "types-redis"]

Expand All @@ -59,7 +59,7 @@ tests = [
"jinja2==3.1.6",
"pyyaml==6.0.2",
# typing:
"mypy==1.15.0",
"mypy==1.16.0",
"django-stubs[compatible-mypy,oracle,redis]",
]
pyright = ["pyright==1.1.401"]
Expand Down
302 changes: 6 additions & 296 deletions scripts/stubtest/allowlist.txt

Large diffs are not rendered by default.

13 changes: 2 additions & 11 deletions scripts/stubtest/allowlist_todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ django.contrib.gis.db.models.JSONField.get_transform
django.contrib.gis.db.models.Lookup.get_prep_lhs
django.contrib.gis.db.models.Lookup.allowed_default
django.contrib.gis.db.models.Lookup.lookup_name
django.contrib.gis.db.models.Lookup.output_field
django.contrib.gis.db.models.ManyToManyField.__get__
django.contrib.gis.db.models.ManyToManyField.formfield
django.contrib.gis.db.models.ManyToManyField.path_infos
Expand Down Expand Up @@ -414,14 +413,7 @@ django.core.management.commands.makemessages.TranslatableFile.path
django.core.servers.basehttp.ServerHandler.__init__
django.core.servers.basehttp.ThreadedWSGIServer.__init__
django.db.backends.ddl_references.Expressions
django.db.backends.mysql.base.DatabaseWrapper.data_type_check_constraints
django.db.backends.mysql.base.DatabaseWrapper.display_name
django.db.backends.mysql.base.DatabaseWrapper.mysql_is_mariadb
django.db.backends.mysql.base.DatabaseWrapper.mysql_server_data
django.db.backends.mysql.base.DatabaseWrapper.mysql_server_info
django.db.backends.mysql.base.DatabaseWrapper.mysql_version
django.db.backends.mysql.base.DatabaseWrapper.ops
django.db.backends.mysql.base.DatabaseWrapper.sql_mode
django.db.backends.mysql.features.DatabaseFeatures.can_rename_index
django.db.backends.mysql.features.DatabaseFeatures.can_return_rows_from_bulk_insert
django.db.backends.mysql.features.DatabaseFeatures.django_test_skips
Expand All @@ -437,8 +429,10 @@ django.db.backends.mysql.introspection.InfoLine._fields
django.db.backends.mysql.introspection.InfoLine.comment
django.db.backends.mysql.introspection.TableInfo
django.db.backends.mysql.schema.DatabaseSchemaEditor.sql_alter_column_comment
django.db.backends.oracle.features.DatabaseFeatures.django_test_skips
django.db.backends.oracle.features.DatabaseFeatures.introspected_field_types
django.db.backends.oracle.features.DatabaseFeatures.supports_collation_on_charfield
django.db.backends.oracle.features.DatabaseFeatures.supports_frame_exclusion
django.db.backends.postgresql.base.DatabaseWrapper.Database
django.db.backends.postgresql.base.DatabaseWrapper.ops
django.db.backends.postgresql.base.DatabaseWrapper.tzinfo_factory
Expand Down Expand Up @@ -595,7 +589,6 @@ django.db.models.JSONField.get_transform
django.db.models.Lookup.get_prep_lhs
django.db.models.Lookup.lookup_name
django.db.models.Lookup.allowed_default
django.db.models.Lookup.output_field
django.db.models.ManyToManyField.__get__
django.db.models.ManyToManyField.formfield
django.db.models.ManyToManyField.path_infos
Expand Down Expand Up @@ -870,7 +863,6 @@ django.db.models.lookups.IExact.process_rhs
django.db.models.lookups.Lookup.get_prep_lhs
django.db.models.lookups.Lookup.allowed_default
django.db.models.lookups.Lookup.lookup_name
django.db.models.lookups.Lookup.output_field
django.db.models.lookups.PatternLookup.process_rhs
django.db.models.query.EmptyQuerySet.__init__
django.db.models.query.QuerySet.__deepcopy__
Expand Down Expand Up @@ -909,7 +901,6 @@ django.db.models.sql.where.WhereNode.get_group_by_cols
django.db.models.sql.where.WhereNode.get_lookup
django.db.models.sql.where.WhereNode.get_source_expressions
django.db.models.sql.where.WhereNode.leaves
django.db.models.sql.where.WhereNode.output_field
django.db.models.sql.where.WhereNode.replace_expressions
django.db.models.sql.where.WhereNode.set_source_expressions
django.db.models.sql.where.WhereNode.split_having
Expand Down
1 change: 0 additions & 1 deletion scripts/stubtest/allowlist_todo_django52.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ django.db.backends.postgresql.base.DatabaseWrapper.close_pool
django.db.backends.postgresql.base.DatabaseWrapper.pool
django.db.backends.postgresql.compiler
django.db.backends.postgresql.features.DatabaseFeatures.django_test_skips
django.db.backends.postgresql.features.DatabaseFeatures.is_postgresql_17
django.db.backends.postgresql.features.DatabaseFeatures.supports_nulls_distinct_unique_constraints
django.db.backends.postgresql.psycopg_any
django.db.backends.sqlite3.base.DatabaseWrapper.transaction_modes
Expand Down
5 changes: 4 additions & 1 deletion tests/typecheck/contrib/admin/test_options.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
class TestModel(models.Model):
pass

class TestModelForm(ModelForm[TestModel]):
pass

class A(admin.ModelAdmin[TestModel]):
# BaseModelAdmin
autocomplete_fields = ("strs",)
Expand All @@ -32,7 +35,7 @@
("group", {"fields": ("c",), "classes": ("a",), "description": "foo"}),
(_("lazy"), {"fields": ["bar"]})
]
form = ModelForm
form = TestModelForm
filter_vertical = ("fields",)
filter_horizontal = ("plenty", "of", "fields")
radio_fields = {
Expand Down
8 changes: 8 additions & 0 deletions tests/typecheck/db/models/test_fields_choices.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
main:4: note: def __iter__(self) -> Iterator[Union[Tuple[Any, Any], Tuple[str, Iterable[Tuple[Any, Any]]]]]
main:4: note: Got:
main:4: note: def __iter__(self) -> Iterator[str]
main:4: note: Expected:
main:4: note: def __iter__(self) -> Iterator[Union[Tuple[Any, Any], Tuple[str, Iterable[Tuple[Any, Any]]]]]
main:4: note: Got:
main:4: note: def __iter__(self) -> Iterator[str]
Comment on lines +14 to +17
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is annoying and perhaps a new bug in mypy v1.16? It doubles this note for some reason.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, looks like so. Please, report upsteam.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reported in python/mypy#19240


- case: db_models_integerfield_invalid_choices
main: |
Expand All @@ -25,6 +29,10 @@
main:4: note: def __iter__(self) -> Iterator[Union[Tuple[Any, Any], Tuple[str, Iterable[Tuple[Any, Any]]]]]
main:4: note: Got:
main:4: note: def __iter__(self) -> Iterator[str]
main:4: note: Expected:
main:4: note: def __iter__(self) -> Iterator[Union[Tuple[Any, Any], Tuple[str, Iterable[Tuple[Any, Any]]]]]
main:4: note: Got:
main:4: note: def __iter__(self) -> Iterator[str]

- case: db_models_valid_choices
main: |
Expand Down
4 changes: 2 additions & 2 deletions tests/typecheck/fields/test_related.yml
Original file line number Diff line number Diff line change
Expand Up @@ -779,10 +779,10 @@
- case: resolve_primary_keys_for_foreign_keys_with_abstract_self_model
main: |
from myapp.models import User
reveal_type(User().parent) # N: Revealed type is "myapp.models.User"
reveal_type(User().parent) # N: Revealed type is "myapp.models.AbstractUser"
reveal_type(User().parent_id) # N: Revealed type is "builtins.int"

reveal_type(User().parent2) # N: Revealed type is "Union[myapp.models.User, None]"
reveal_type(User().parent2) # N: Revealed type is "Union[myapp.models.AbstractUser, None]"
reveal_type(User().parent2_id) # N: Revealed type is "Union[builtins.int, None]"
installed_apps:
- myapp
Expand Down
2 changes: 0 additions & 2 deletions tests/typecheck/models/test_create.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
main: |
from myapp.models import Child4
Child4.objects.create(name1='n1', name2='n2', value=1, value4=4)
out: |
myapp/models:9: error: Definition of "child1" in base class "Parent1" is incompatible with definition in base class "Parent2" [misc]
installed_apps:
- myapp
files:
Expand Down
2 changes: 1 addition & 1 deletion tests/typecheck/models/test_meta_options.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
class Meta(TypedModelMeta):
abstract = 7 # E: Incompatible types in assignment (expression has type "int", base class "TypedModelMeta" defined the type as "bool") [assignment]
verbose_name = ['test'] # E: Incompatible types in assignment (expression has type "List[str]", base class "TypedModelMeta" defined the type as "Union[str, _StrPromise]") [assignment]
unique_together = {1: 2} # E: Incompatible types in assignment (expression has type "Dict[int, int]", base class "TypedModelMeta" defined the type as "Union[Sequence[Sequence[str]], Sequence[str]]") [assignment]
unique_together = {1: 2} # E: Incompatible types in assignment (expression has type "Dict[int, int]", base class "TypedModelMeta" defined the type as "Sequence[Sequence[str]]") [assignment]
unknown_attr = True # can't check this


Expand Down
Loading
Loading