| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- """
- This is a module for various lookup functions:
- functions that will find a semantic node by its name.
- """
- from __future__ import annotations
- from mypy.nodes import MypyFile, SymbolTableNode, TypeInfo
- # TODO: gradually move existing lookup functions to this module.
- def lookup_fully_qualified(
- name: str, modules: dict[str, MypyFile], *, raise_on_missing: bool = False
- ) -> SymbolTableNode | None:
- """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, f"Cannot find module for {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, f"Cannot find {name}, got a module symbol"
- return None
- while True:
- key = rest.pop()
- if key not in names:
- if raise_on_missing:
- assert key in names, f"Cannot find component {key!r} for {name!r}"
- 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, f"Cannot find {name}"
- return None
- names = node.names
|