From a target name, return module/target names and the func def. The 'key' argument can be in one of two formats: * As the function full name, e.g., package.module.Cls.method * As the function location as file and line separated by column, e.g., path/to/file.py:42
(self, key: str)
| 540 | return f"({', '.join(args)})" |
| 541 | |
| 542 | def find_node(self, key: str) -> tuple[str, str, FuncDef]: |
| 543 | """From a target name, return module/target names and the func def. |
| 544 | |
| 545 | The 'key' argument can be in one of two formats: |
| 546 | * As the function full name, e.g., package.module.Cls.method |
| 547 | * As the function location as file and line separated by column, |
| 548 | e.g., path/to/file.py:42 |
| 549 | """ |
| 550 | # TODO: Also return OverloadedFuncDef -- currently these are ignored. |
| 551 | node: SymbolNode | None = None |
| 552 | if ":" in key: |
| 553 | # A colon might be part of a drive name on Windows (like `C:/foo/bar`) |
| 554 | # and is also used as a delimiter between file path and lineno. |
| 555 | # If a colon is there for any of those reasons, it must be a file+line |
| 556 | # reference. |
| 557 | platform_key_count = 2 if sys.platform == "win32" else 1 |
| 558 | if key.count(":") > platform_key_count: |
| 559 | raise SuggestionFailure( |
| 560 | "Malformed location for function: {}. Must be either" |
| 561 | " package.module.Class.method or path/to/file.py:line".format(key) |
| 562 | ) |
| 563 | file, line = key.rsplit(":", 1) |
| 564 | if not line.isdigit(): |
| 565 | raise SuggestionFailure(f"Line number must be a number. Got {line}") |
| 566 | line_number = int(line) |
| 567 | modname, node = self.find_node_by_file_and_line(file, line_number) |
| 568 | tail = node.fullname[len(modname) + 1 :] # add one to account for '.' |
| 569 | else: |
| 570 | target = split_target(self.fgmanager.graph, key) |
| 571 | if not target: |
| 572 | raise SuggestionFailure(f"Cannot find module for {key}") |
| 573 | modname, tail = target |
| 574 | node = self.find_node_by_module_and_name(modname, tail) |
| 575 | |
| 576 | if isinstance(node, Decorator): |
| 577 | node = self.extract_from_decorator(node) |
| 578 | if not node: |
| 579 | raise SuggestionFailure(f"Object {key} is a decorator we can't handle") |
| 580 | |
| 581 | if not isinstance(node, FuncDef): |
| 582 | raise SuggestionFailure(f"Object {key} is not a function") |
| 583 | |
| 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. |
no test coverage detected