Skip to content

Commit 54f1df9

Browse files
authored
Fix serialization and deserialization of metaclasses (#3328)
This has some overlap with #3304.
1 parent 5788635 commit 54f1df9

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

mypy/fixup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ def visit_type_info(self, info: TypeInfo) -> None:
6666
info.tuple_type.accept(self.type_fixer)
6767
if info.typeddict_type:
6868
info.typeddict_type.accept(self.type_fixer)
69+
if info.declared_metaclass:
70+
info.declared_metaclass.accept(self.type_fixer)
71+
if info.metaclass_type:
72+
info.metaclass_type.accept(self.type_fixer)
6973
finally:
7074
self.current_info = save_info
7175

mypy/nodes.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,8 @@ def serialize(self) -> JsonDict:
21802180
'_promote': None if self._promote is None else self._promote.serialize(),
21812181
'declared_metaclass': (None if self.declared_metaclass is None
21822182
else self.declared_metaclass.serialize()),
2183+
'metaclass_type':
2184+
None if self.metaclass_type is None else self.metaclass_type.serialize(),
21832185
'tuple_type': None if self.tuple_type is None else self.tuple_type.serialize(),
21842186
'typeddict_type':
21852187
None if self.typeddict_type is None else self.typeddict_type.serialize(),
@@ -2202,7 +2204,9 @@ def deserialize(cls, data: JsonDict) -> 'TypeInfo':
22022204
else mypy.types.deserialize_type(data['_promote']))
22032205
ti.declared_metaclass = (None if data['declared_metaclass'] is None
22042206
else mypy.types.Instance.deserialize(data['declared_metaclass']))
2205-
# NOTE: ti.metaclass_type and ti.mro will be set in the fixup phase.
2207+
ti.metaclass_type = (None if data['metaclass_type'] is None
2208+
else mypy.types.Instance.deserialize(data['metaclass_type']))
2209+
# NOTE: ti.mro will be set in the fixup phase.
22062210
ti.tuple_type = (None if data['tuple_type'] is None
22072211
else mypy.types.TupleType.deserialize(data['tuple_type']))
22082212
ti.typeddict_type = (None if data['typeddict_type'] is None

test-data/unit/check-incremental.test

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,49 @@ main:4: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fall
19001900
main:2: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fallback=b.A)'
19011901
main:4: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fallback=b.A)'
19021902

1903+
[case testSerializeMetaclass]
1904+
import b
1905+
reveal_type(b.A.f())
1906+
m: b.M = b.A
1907+
reveal_type(b.a.f())
1908+
[file b.py]
1909+
from typing import Type
1910+
1911+
class M(type):
1912+
def f(cls) -> int: return 0
1913+
class A(metaclass=M): pass
1914+
a: Type[A]
1915+
[out]
1916+
main:2: error: Revealed type is 'builtins.int'
1917+
main:4: error: Revealed type is 'builtins.int'
1918+
[out2]
1919+
main:2: error: Revealed type is 'builtins.int'
1920+
main:4: error: Revealed type is 'builtins.int'
1921+
1922+
[case testSerializeMetaclassInImportCycle1]
1923+
import b
1924+
import c
1925+
reveal_type(b.A.f())
1926+
m: c.M = b.A
1927+
reveal_type(b.a.f())
1928+
[file b.py]
1929+
from typing import Type
1930+
from c import M
1931+
class A(metaclass=M): pass
1932+
a: Type[A]
1933+
[file c.py]
1934+
class M(type):
1935+
def f(cls) -> int: return 0
1936+
[out]
1937+
main:3: error: Revealed type is 'builtins.int'
1938+
main:5: error: Revealed type is 'builtins.int'
1939+
[out2]
1940+
main:3: error: Revealed type is 'builtins.int'
1941+
main:5: error: Revealed type is 'builtins.int'
1942+
1943+
-- TODO: Add another test for metaclass in import cycle (reversed from the above test).
1944+
-- This currently doesn't work.
1945+
19031946
[case testQuickAndDirty1]
19041947
# flags: --quick-and-dirty
19051948
import b, c

0 commit comments

Comments
 (0)