Return a dotted module name based on the given path, anchored on root. For example: path="projects/src/tests/test_foo.py" and root="/projects", the resulting module name will be "src.tests.test_foo".
(path: Path, root: Path)
| 759 | |
| 760 | |
| 761 | def module_name_from_path(path: Path, root: Path) -> str: |
| 762 | """ |
| 763 | Return a dotted module name based on the given path, anchored on root. |
| 764 | |
| 765 | For example: path="projects/src/tests/test_foo.py" and root="/projects", the |
| 766 | resulting module name will be "src.tests.test_foo". |
| 767 | """ |
| 768 | path = path.with_suffix("") |
| 769 | try: |
| 770 | relative_path = path.relative_to(root) |
| 771 | except ValueError: |
| 772 | # If we can't get a relative path to root, use the full path, except |
| 773 | # for the first part ("d:\\" or "/" depending on the platform, for example). |
| 774 | path_parts = path.parts[1:] |
| 775 | else: |
| 776 | # Use the parts for the relative path to the root path. |
| 777 | path_parts = relative_path.parts |
| 778 | |
| 779 | # Module name for packages do not contain the __init__ file, unless |
| 780 | # the `__init__.py` file is at the root. |
| 781 | if len(path_parts) >= 2 and path_parts[-1] == "__init__": |
| 782 | path_parts = path_parts[:-1] |
| 783 | |
| 784 | # Module names cannot contain ".", normalize them to "_". This prevents |
| 785 | # a directory having a "." in the name (".env.310" for example) causing extra intermediate modules. |
| 786 | # Also, important to replace "." at the start of paths, as those are considered relative imports. |
| 787 | path_parts = tuple(x.replace(".", "_") for x in path_parts) |
| 788 | |
| 789 | return ".".join(path_parts) |
| 790 | |
| 791 | |
| 792 | def insert_missing_modules(modules: dict[str, ModuleType], module_name: str) -> None: |
searching dependent graphs…