Find a module by name, respecting follow_imports and producing diagnostics. If the module is not found, then the ModuleNotFound exception is raised. Args: id: module to find options: the options for the module being loaded caller_state: the state of the importing module,
(
manager: BuildManager,
id: str,
options: Options,
caller_state: State | None = None,
caller_line: int = 0,
ancestor_for: State | None = None,
root_source: bool = False,
skip_diagnose: bool = False,
)
| 3716 | |
| 3717 | |
| 3718 | def find_module_and_diagnose( |
| 3719 | manager: BuildManager, |
| 3720 | id: str, |
| 3721 | options: Options, |
| 3722 | caller_state: State | None = None, |
| 3723 | caller_line: int = 0, |
| 3724 | ancestor_for: State | None = None, |
| 3725 | root_source: bool = False, |
| 3726 | skip_diagnose: bool = False, |
| 3727 | ) -> tuple[str, str]: |
| 3728 | """Find a module by name, respecting follow_imports and producing diagnostics. |
| 3729 | |
| 3730 | If the module is not found, then the ModuleNotFound exception is raised. |
| 3731 | |
| 3732 | Args: |
| 3733 | id: module to find |
| 3734 | options: the options for the module being loaded |
| 3735 | caller_state: the state of the importing module, if applicable |
| 3736 | caller_line: the line number of the import |
| 3737 | ancestor_for: the child module this is an ancestor of, if applicable |
| 3738 | root_source: whether this source was specified on the command line |
| 3739 | skip_diagnose: skip any error diagnosis and reporting (but ModuleNotFound is |
| 3740 | still raised if the module is missing) |
| 3741 | |
| 3742 | The specified value of follow_imports for a module can be overridden |
| 3743 | if the module is specified on the command line or if it is a stub, |
| 3744 | so we compute and return the "effective" follow_imports of the module. |
| 3745 | |
| 3746 | Returns a tuple containing (file path, target's effective follow_imports setting) |
| 3747 | """ |
| 3748 | result = find_module_with_reason(id, manager) |
| 3749 | if isinstance(result, str): |
| 3750 | # For non-stubs, look at options.follow_imports: |
| 3751 | # - normal (default) -> fully analyze |
| 3752 | # - silent -> analyze but silence errors |
| 3753 | # - skip -> don't analyze, make the type Any |
| 3754 | follow_imports = options.follow_imports |
| 3755 | if ( |
| 3756 | root_source # Honor top-level modules |
| 3757 | or ( |
| 3758 | result.endswith(".pyi") # Stubs are always normal |
| 3759 | and not options.follow_imports_for_stubs # except when they aren't |
| 3760 | ) |
| 3761 | or id in CORE_BUILTIN_MODULES # core is always normal |
| 3762 | ): |
| 3763 | follow_imports = "normal" |
| 3764 | if skip_diagnose: |
| 3765 | pass |
| 3766 | elif follow_imports == "silent": |
| 3767 | # Still import it, but silence non-blocker errors. |
| 3768 | manager.log(f"Silencing {result} ({id})") |
| 3769 | elif follow_imports == "skip" or follow_imports == "error": |
| 3770 | # In 'error' mode, produce special error messages. |
| 3771 | if id not in manager.missing_modules: |
| 3772 | manager.log(f"Skipping {result} ({id})") |
| 3773 | if follow_imports == "error": |
| 3774 | if ancestor_for: |
| 3775 | skipping_ancestor(manager, id, result, ancestor_for) |
no test coverage detected
searching dependent graphs…