From c9c729073417d0936cb944ab8585ad236ab30321 Mon Sep 17 00:00:00 2001 From: Federico Bond Date: Wed, 16 Oct 2024 04:03:21 -0300 Subject: [PATCH] Fix TypedDictType crash with mypy 1.12.x (#2408) * Fix TypedDictType crash with mypy 1.12.x * Add missing generic parameter for builtins.memoryview --- mypy_django_plugin/lib/helpers.py | 12 ++++++++++-- mypy_django_plugin/transformers/models.py | 1 + mypy_django_plugin/transformers/querysets.py | 9 +++++++-- requirements.txt | 2 +- setup.py | 2 +- tests/typecheck/fields/test_base.yml | 2 +- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py index d9d10499a..cea674d4d 100644 --- a/mypy_django_plugin/lib/helpers.py +++ b/mypy_django_plugin/lib/helpers.py @@ -396,13 +396,21 @@ def convert_any_to_type(typ: MypyType, referred_to_type: MypyType) -> MypyType: def make_typeddict( - api: Union[SemanticAnalyzer, CheckerPluginInterface], fields: Dict[str, MypyType], required_keys: Set[str] + api: Union[SemanticAnalyzer, CheckerPluginInterface], + fields: Dict[str, MypyType], + required_keys: Set[str], + readonly_keys: Set[str], ) -> TypedDictType: if isinstance(api, CheckerPluginInterface): fallback_type = api.named_generic_type("typing._TypedDict", []) else: fallback_type = api.named_type("typing._TypedDict", []) - typed_dict_type = TypedDictType(fields, required_keys=required_keys, fallback=fallback_type) + typed_dict_type = TypedDictType( + fields, + required_keys=required_keys, + readonly_keys=readonly_keys, + fallback=fallback_type, + ) return typed_dict_type diff --git a/mypy_django_plugin/transformers/models.py b/mypy_django_plugin/transformers/models.py index 3906c006a..4425c0fca 100644 --- a/mypy_django_plugin/transformers/models.py +++ b/mypy_django_plugin/transformers/models.py @@ -1183,6 +1183,7 @@ def get_annotated_type( api, fields={**annotations.items, **fields_dict.items}, required_keys={*annotations.required_keys, *fields_dict.required_keys}, + readonly_keys={*annotations.readonly_keys, *fields_dict.readonly_keys}, ) else: annotated_model = helpers.lookup_fully_qualified_typeinfo(api, model_type.type.fullname + "@AnnotatedWith") diff --git a/mypy_django_plugin/transformers/querysets.py b/mypy_django_plugin/transformers/querysets.py index 52c2bea64..2bc98d717 100644 --- a/mypy_django_plugin/transformers/querysets.py +++ b/mypy_django_plugin/transformers/querysets.py @@ -275,7 +275,12 @@ def extract_proper_type_queryset_annotate(ctx: MethodContext, django_context: Dj fields_dict = None if field_types is not None: - fields_dict = helpers.make_typeddict(api, fields=field_types, required_keys=set(field_types.keys())) + fields_dict = helpers.make_typeddict( + api, + fields=field_types, + required_keys=set(field_types.keys()), + readonly_keys=set(), + ) if fields_dict is not None: annotated_type = get_annotated_type(api, model_type, fields_dict=fields_dict) @@ -349,5 +354,5 @@ def extract_proper_type_queryset_values(ctx: MethodContext, django_context: Djan column_types[field_lookup] = field_lookup_type - row_type = helpers.make_typeddict(ctx.api, column_types, set(column_types.keys())) + row_type = helpers.make_typeddict(ctx.api, column_types, set(column_types.keys()), set()) return helpers.reparametrize_instance(default_return_type, [model_type, row_type]) diff --git a/requirements.txt b/requirements.txt index 9e53c0094..b64a2b08d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,5 +14,5 @@ Django==5.1.2; python_version >= '3.10' -e .[redis,compatible-mypy,oracle] # Overrides: -mypy==1.11.2 +mypy==1.12.0 pyright==1.1.384 diff --git a/setup.py b/setup.py index fe124aef0..0767f0464 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ def find_stub_files(name: str) -> List[str]: # Keep compatible-mypy major.minor version pinned to what we use in CI (requirements.txt) extras_require = { - "compatible-mypy": ["mypy~=1.11.0"], + "compatible-mypy": ["mypy~=1.12.0"], "redis": ["redis"], "oracle": ["oracledb"], } diff --git a/tests/typecheck/fields/test_base.yml b/tests/typecheck/fields/test_base.yml index 4c65dc54b..42f20966d 100644 --- a/tests/typecheck/fields/test_base.yml +++ b/tests/typecheck/fields/test_base.yml @@ -171,7 +171,7 @@ message = models.BinaryField() obj = EncodedMessage(b'\x010') - reveal_type(obj.message) # N: Revealed type is "Union[builtins.bytes, builtins.memoryview]" + reveal_type(obj.message) # N: Revealed type is "Union[builtins.bytes, builtins.memoryview[builtins.int]]" - case: test_small_auto_field_class_presents_as_int main: |