Get the imports a given module makes. Args: module_fname (`str`): The name of the file of the module where we want to look at the imports (given relative to the root of the repo). cache (Dictionary `str` to `List[str]`, *optional*): To sp
(module_fname: str, cache: Dict[str, List[str]] = None)
| 474 | |
| 475 | |
| 476 | def extract_imports(module_fname: str, cache: Dict[str, List[str]] = None) -> List[str]: |
| 477 | """ |
| 478 | Get the imports a given module makes. |
| 479 | |
| 480 | Args: |
| 481 | module_fname (`str`): |
| 482 | The name of the file of the module where we want to look at the imports (given relative to the root of |
| 483 | the repo). |
| 484 | cache (Dictionary `str` to `List[str]`, *optional*): |
| 485 | To speed up this function if it was previously called on `module_fname`, the cache of all previously |
| 486 | computed results. |
| 487 | |
| 488 | Returns: |
| 489 | `List[str]`: The list of module filenames imported in the input `module_fname` (a submodule we import from that |
| 490 | is a subfolder will give its init file). |
| 491 | """ |
| 492 | if cache is not None and module_fname in cache: |
| 493 | return cache[module_fname] |
| 494 | |
| 495 | with open(PATH_TO_REPO / module_fname, "r", encoding="utf-8") as f: |
| 496 | content = f.read() |
| 497 | |
| 498 | # Filter out all docstrings to not get imports in code examples. As before we need to deactivate formatting to |
| 499 | # keep this as escaped quotes and avoid this function failing on this file. |
| 500 | # fmt: off |
| 501 | splits = content.split('\"\"\"') |
| 502 | # fmt: on |
| 503 | content = "".join(splits[::2]) |
| 504 | |
| 505 | module_parts = str(module_fname).split(os.path.sep) |
| 506 | imported_modules = [] |
| 507 | |
| 508 | # Let's start with relative imports |
| 509 | relative_imports = _re_single_line_relative_imports.findall(content) |
| 510 | relative_imports = [ |
| 511 | (mod, imp) for mod, imp in relative_imports if "# tests_ignore" not in imp and imp.strip() != "(" |
| 512 | ] |
| 513 | multiline_relative_imports = _re_multi_line_relative_imports.findall(content) |
| 514 | relative_imports += [(mod, imp) for mod, imp in multiline_relative_imports if "# tests_ignore" not in imp] |
| 515 | |
| 516 | # We need to remove parts of the module name depending on the depth of the relative imports. |
| 517 | for module, imports in relative_imports: |
| 518 | level = 0 |
| 519 | while module.startswith("."): |
| 520 | module = module[1:] |
| 521 | level += 1 |
| 522 | |
| 523 | if len(module) > 0: |
| 524 | dep_parts = module_parts[: len(module_parts) - level] + module.split(".") |
| 525 | else: |
| 526 | dep_parts = module_parts[: len(module_parts) - level] |
| 527 | imported_module = os.path.sep.join(dep_parts) |
| 528 | imported_modules.append((imported_module, [imp.strip() for imp in imports.split(",")])) |
| 529 | |
| 530 | # Let's continue with direct imports |
| 531 | direct_imports = _re_single_line_direct_imports.findall(content) |
| 532 | direct_imports = [(mod, imp) for mod, imp in direct_imports if "# tests_ignore" not in imp and imp.strip() != "("] |
| 533 | multiline_direct_imports = _re_multi_line_direct_imports.findall(content) |
no outgoing calls
no test coverage detected