Find symbol node by module id and qualified name. Raise SuggestionFailure if can't find one.
(self, modname: str, tail: str)
| 584 | return modname, tail, node |
| 585 | |
| 586 | def find_node_by_module_and_name(self, modname: str, tail: str) -> SymbolNode | None: |
| 587 | """Find symbol node by module id and qualified name. |
| 588 | |
| 589 | Raise SuggestionFailure if can't find one. |
| 590 | """ |
| 591 | tree = self.ensure_loaded(self.fgmanager.graph[modname]) |
| 592 | |
| 593 | # N.B. This is reimplemented from update's lookup_target |
| 594 | # basically just to produce better error messages. |
| 595 | |
| 596 | names: SymbolTable = tree.names |
| 597 | |
| 598 | # Look through any classes |
| 599 | components = tail.split(".") |
| 600 | for i, component in enumerate(components[:-1]): |
| 601 | if component not in names: |
| 602 | raise SuggestionFailure( |
| 603 | "Unknown class {}.{}".format(modname, ".".join(components[: i + 1])) |
| 604 | ) |
| 605 | node: SymbolNode | None = names[component].node |
| 606 | if not isinstance(node, TypeInfo): |
| 607 | raise SuggestionFailure( |
| 608 | "Object {}.{} is not a class".format(modname, ".".join(components[: i + 1])) |
| 609 | ) |
| 610 | names = node.names |
| 611 | |
| 612 | # Look for the actual function/method |
| 613 | funcname = components[-1] |
| 614 | if funcname not in names: |
| 615 | key = modname + "." + tail |
| 616 | raise SuggestionFailure( |
| 617 | "Unknown {} {}".format("method" if len(components) > 1 else "function", key) |
| 618 | ) |
| 619 | return names[funcname].node |
| 620 | |
| 621 | def find_node_by_file_and_line(self, file: str, line: int) -> tuple[str, SymbolNode]: |
| 622 | """Find symbol node by path to file and line number. |
no test coverage detected