Skip to content

Commit b9f677b

Browse files
committed
Record module name in TypeInfo
This commit modifies TypeInfo so it records the name of the module in which the class (or NewType or namedtuple) was defined in. This does not modify the behavior of mypy, but will make it easier to perform introspection and analysis at later stages. This information is also a part of the TypeInfo's fullname, but is difficult to extract in the case of nested classes. For example, if we have a fully qualified name of a.b.c.d, it's not always obvious whether or not c is a module name or is a class name, and so forth.
1 parent e9d946a commit b9f677b

File tree

3 files changed

+23
-8
lines changed

3 files changed

+23
-8
lines changed

mypy/nodes.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,10 @@ class is generic then it will be a type constructor of higher kind.
17771777
"""
17781778

17791779
_fullname = None # type: str # Fully qualified name
1780+
# Fully qualified name for the module this type was defined in. This
1781+
# information is also in the fullname, but is harder to extract in the
1782+
# case of nested class definitions.
1783+
module_name = None # type: str
17801784
defn = None # type: ClassDef # Corresponding ClassDef
17811785
# Method Resolution Order: the order of looking up attributes. The first
17821786
# value always to refers to this class.
@@ -1828,10 +1832,11 @@ class is generic then it will be a type constructor of higher kind.
18281832
# Alternative to fullname() for 'anonymous' classes.
18291833
alt_fullname = None # type: Optional[str]
18301834

1831-
def __init__(self, names: 'SymbolTable', defn: ClassDef) -> None:
1835+
def __init__(self, names: 'SymbolTable', defn: ClassDef, module_name: str) -> None:
18321836
"""Initialize a TypeInfo."""
18331837
self.names = names
18341838
self.defn = defn
1839+
self.module_name = module_name
18351840
self.subtypes = set()
18361841
self.type_vars = []
18371842
self.bases = []
@@ -1985,6 +1990,7 @@ def __str__(self) -> str:
19851990
def serialize(self) -> Union[str, JsonDict]:
19861991
# NOTE: This is where all ClassDefs originate, so there shouldn't be duplicates.
19871992
data = {'.class': 'TypeInfo',
1993+
'module_name': self.module_name,
19881994
'fullname': self.fullname(),
19891995
'alt_fullname': self.alt_fullname,
19901996
'names': self.names.serialize(self.alt_fullname or self.fullname()),
@@ -2006,7 +2012,8 @@ def serialize(self) -> Union[str, JsonDict]:
20062012
def deserialize(cls, data: JsonDict) -> 'TypeInfo':
20072013
names = SymbolTable.deserialize(data['names'])
20082014
defn = ClassDef.deserialize(data['defn'])
2009-
ti = TypeInfo(names, defn)
2015+
module_name = data['module_name']
2016+
ti = TypeInfo(names, defn, module_name)
20102017
ti._fullname = data['fullname']
20112018
ti.alt_fullname = data['alt_fullname']
20122019
# TODO: Is there a reason to reconstruct ti.subtypes?

mypy/semanal.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ def analyze_unbound_tvar(self, t: Type) -> Tuple[str, TypeVarExpr]:
734734
def setup_class_def_analysis(self, defn: ClassDef) -> None:
735735
"""Prepare for the analysis of a class definition."""
736736
if not defn.info:
737-
defn.info = TypeInfo(SymbolTable(), defn)
737+
defn.info = TypeInfo(SymbolTable(), defn, self.cur_mod_id)
738738
defn.info._fullname = defn.info.name()
739739
if self.is_func_scope() or self.type:
740740
kind = MDEF
@@ -1410,7 +1410,7 @@ def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance)
14101410
class_def.fullname = self.qualified_name(name)
14111411

14121412
symbols = SymbolTable()
1413-
info = TypeInfo(symbols, class_def)
1413+
info = TypeInfo(symbols, class_def, self.cur_mod_id)
14141414
info.mro = [info] + base_type.type.mro
14151415
info.bases = [base_type]
14161416
info.is_newtype = True
@@ -1683,7 +1683,7 @@ def build_namedtuple_typeinfo(self, name: str, items: List[str],
16831683
symbols = SymbolTable()
16841684
class_def = ClassDef(name, Block([]))
16851685
class_def.fullname = self.qualified_name(name)
1686-
info = TypeInfo(symbols, class_def)
1686+
info = TypeInfo(symbols, class_def, self.cur_mod_id)
16871687
# Add named tuple items as attributes.
16881688
# TODO: Make them read-only.
16891689
for item, typ in zip(items, types):
@@ -2606,7 +2606,7 @@ def visit_overloaded_func_def(self, func: OverloadedFuncDef) -> None:
26062606
def visit_class_def(self, cdef: ClassDef) -> None:
26072607
self.sem.check_no_global(cdef.name, cdef)
26082608
cdef.fullname = self.sem.qualified_name(cdef.name)
2609-
info = TypeInfo(SymbolTable(), cdef)
2609+
info = TypeInfo(SymbolTable(), cdef, self.sem.cur_mod_id)
26102610
info.set_line(cdef.line)
26112611
cdef.info = info
26122612
self.sem.globals[cdef.name] = SymbolTableNode(GDEF, info,
@@ -2616,11 +2616,12 @@ def visit_class_def(self, cdef: ClassDef) -> None:
26162616
def process_nested_classes(self, outer_def: ClassDef) -> None:
26172617
for node in outer_def.defs.body:
26182618
if isinstance(node, ClassDef):
2619-
node.info = TypeInfo(SymbolTable(), node)
2619+
node.info = TypeInfo(SymbolTable(), node, self.sem.cur_mod_id)
26202620
if outer_def.fullname:
26212621
node.info._fullname = outer_def.fullname + '.' + node.info.name()
26222622
else:
26232623
node.info._fullname = node.info.name()
2624+
node.fullname = node.info._fullname
26242625
symbol = SymbolTableNode(MDEF, node.info)
26252626
outer_def.info.names[node.name] = symbol
26262627
self.process_nested_classes(node)

mypy/typefixture.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ def callable_var_arg(self, min_args, *a):
193193
a[-1], self.function)
194194

195195
def make_type_info(self, name: str,
196+
module_name: str = None,
196197
is_abstract: bool = False,
197198
mro: List[TypeInfo] = None,
198199
bases: List[Instance] = None,
@@ -203,6 +204,12 @@ def make_type_info(self, name: str,
203204
class_def = ClassDef(name, Block([]), None, [])
204205
class_def.fullname = name
205206

207+
if module_name is None:
208+
if '.' in name:
209+
module_name = name.rsplit('.', 1)[0]
210+
else:
211+
module_name = '__main__'
212+
206213
if typevars:
207214
v = [] # type: List[TypeVarDef]
208215
for id, n in enumerate(typevars, 1):
@@ -213,7 +220,7 @@ def make_type_info(self, name: str,
213220
v.append(TypeVarDef(n, id, None, self.o, variance=variance))
214221
class_def.type_vars = v
215222

216-
info = TypeInfo(SymbolTable(), class_def)
223+
info = TypeInfo(SymbolTable(), class_def, module_name)
217224
if mro is None:
218225
mro = []
219226
if name != 'builtins.object':

0 commit comments

Comments
 (0)