Find the root path of a package, or the path that contains a module. If it cannot be found, returns the current working directory. Not to be confused with the value returned by :func:`find_package`. :meta private:
(import_name: str)
| 341 | |
| 342 | |
| 343 | def get_root_path(import_name: str) -> str: |
| 344 | """Find the root path of a package, or the path that contains a |
| 345 | module. If it cannot be found, returns the current working |
| 346 | directory. |
| 347 | |
| 348 | Not to be confused with the value returned by :func:`find_package`. |
| 349 | |
| 350 | :meta private: |
| 351 | """ |
| 352 | # Module already imported and has a file attribute. Use that first. |
| 353 | mod = sys.modules.get(import_name) |
| 354 | |
| 355 | if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: |
| 356 | return os.path.dirname(os.path.abspath(mod.__file__)) |
| 357 | |
| 358 | # Next attempt: check the loader. |
| 359 | try: |
| 360 | spec = importlib.util.find_spec(import_name) |
| 361 | |
| 362 | if spec is None: |
| 363 | raise ValueError |
| 364 | except (ImportError, ValueError): |
| 365 | loader = None |
| 366 | else: |
| 367 | loader = spec.loader |
| 368 | |
| 369 | # Loader does not exist or we're referring to an unloaded main |
| 370 | # module or a main module without path (interactive sessions), go |
| 371 | # with the current working directory. |
| 372 | if loader is None: |
| 373 | return os.getcwd() |
| 374 | |
| 375 | if hasattr(loader, "get_filename"): |
| 376 | filepath = loader.get_filename(import_name) # pyright: ignore |
| 377 | else: |
| 378 | # Fall back to imports. |
| 379 | __import__(import_name) |
| 380 | mod = sys.modules[import_name] |
| 381 | filepath = getattr(mod, "__file__", None) |
| 382 | |
| 383 | # If we don't have a file path it might be because it is a |
| 384 | # namespace package. In this case pick the root path from the |
| 385 | # first module that is contained in the package. |
| 386 | if filepath is None: |
| 387 | raise RuntimeError( |
| 388 | "No root path can be found for the provided module" |
| 389 | f" {import_name!r}. This can happen because the module" |
| 390 | " came from an import hook that does not provide file" |
| 391 | " name information or because it's a namespace package." |
| 392 | " In this case the root path needs to be explicitly" |
| 393 | " provided." |
| 394 | ) |
| 395 | |
| 396 | # filepath is import_name.py for a module, or __init__.py for a package. |
| 397 | return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return] |
no test coverage detected
searching dependent graphs…