Skip to content

Commit d7c69a0

Browse files
committed
Fix serialization and deserialization of metaclasses
This has some overlap with #3304.
1 parent 8ea1aa5 commit d7c69a0

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
@@ -1943,6 +1943,49 @@ main:4: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fall
19431943
main:2: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fallback=b.A)'
19441944
main:4: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fallback=b.A)'
19451945

1946+
[case testSerializeMetaclass]
1947+
import b
1948+
reveal_type(b.A.f())
1949+
m: b.M = b.A
1950+
reveal_type(b.a.f())
1951+
[file b.py]
1952+
from typing import Type
1953+
1954+
class M(type):
1955+
def f(cls) -> int: return 0
1956+
class A(metaclass=M): pass
1957+
a: Type[A]
1958+
[out]
1959+
main:2: error: Revealed type is 'builtins.int'
1960+
main:4: error: Revealed type is 'builtins.int'
1961+
[out2]
1962+
main:2: error: Revealed type is 'builtins.int'
1963+
main:4: error: Revealed type is 'builtins.int'
1964+
1965+
[case testSerializeMetaclassInImportCycle1]
1966+
import b
1967+
import c
1968+
reveal_type(b.A.f())
1969+
m: c.M = b.A
1970+
reveal_type(b.a.f())
1971+
[file b.py]
1972+
from typing import Type
1973+
from c import M
1974+
class A(metaclass=M): pass
1975+
a: Type[A]
1976+
[file c.py]
1977+
class M(type):
1978+
def f(cls) -> int: return 0
1979+
[out]
1980+
main:3: error: Revealed type is 'builtins.int'
1981+
main:5: error: Revealed type is 'builtins.int'
1982+
[out2]
1983+
main:3: error: Revealed type is 'builtins.int'
1984+
main:5: error: Revealed type is 'builtins.int'
1985+
1986+
-- TODO: Add another test for metaclass in import cycle (reversed from the above test).
1987+
-- This currently doesn't work.
1988+
19461989
[case testQuickAndDirty1]
19471990
# flags: --quick-and-dirty
19481991
import b, c

0 commit comments

Comments
 (0)