forked from python/mypy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlookup.py
59 lines (53 loc) · 2.04 KB
/
lookup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""
This is a module for various lookup functions:
functions that will find a semantic node by its name.
"""
from mypy.nodes import MypyFile, SymbolTableNode, TypeInfo
from typing import Dict, Optional
# TODO: gradually move existing lookup functions to this module.
def lookup_fully_qualified(name: str, modules: Dict[str, MypyFile], *,
raise_on_missing: bool = False) -> Optional[SymbolTableNode]:
"""Find a symbol using it fully qualified name.
The algorithm has two steps: first we try splitting the name on '.' to find
the module, then iteratively look for each next chunk after a '.' (e.g. for
nested classes).
This function should *not* be used to find a module. Those should be looked
in the modules dictionary.
"""
head = name
rest = []
# 1. Find a module tree in modules dictionary.
while True:
if '.' not in head:
if raise_on_missing:
assert '.' in head, "Cannot find module for %s" % (name,)
return None
head, tail = head.rsplit('.', maxsplit=1)
rest.append(tail)
mod = modules.get(head)
if mod is not None:
break
names = mod.names
# 2. Find the symbol in the module tree.
if not rest:
# Looks like a module, don't use this to avoid confusions.
if raise_on_missing:
assert rest, "Cannot find %s, got a module symbol" % (name,)
return None
while True:
key = rest.pop()
if key not in names:
if raise_on_missing:
assert key in names, "Cannot find component %r for %r" % (key, name)
return None
stnode = names[key]
if not rest:
return stnode
node = stnode.node
# In fine-grained mode, could be a cross-reference to a deleted module
# or a Var made up for a missing module.
if not isinstance(node, TypeInfo):
if raise_on_missing:
assert node, "Cannot find %s" % (name,)
return None
names = node.names