Skip to content

Commit

Permalink
Make ignore_missing_imports work for libs which had bundled stubs (#1…
Browse files Browse the repository at this point in the history
…0582)

It has to be specified as a per-module option, if the library used
to have bundled stubs. This way mypy won't silently start ignoring
these missing stubs.

This makes ignore_missing_imports special by making it work a bit
differently, depending on whether it's set globally or per module.

The new behavior is less surprising. This makes it possible to ignore
arbitrary missing third-party stub packages, even those which used to
have bundled stubs.

Fixes #10283.

Originally implemented by @TheCleric in #10283. This is somewhat
simpler alternative implementation which is easier to reason about and
may perform better in some cases of very large configs.
  • Loading branch information
JukkaL committed Jun 4, 2021
1 parent 159f382 commit 4642a31
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
4 changes: 3 additions & 1 deletion mypy/build.py
Expand Up @@ -2449,7 +2449,9 @@ def find_module_and_diagnose(manager: BuildManager,
# otherwise updating mypy can silently result in new false
# negatives.
global_ignore_missing_imports = manager.options.ignore_missing_imports
if top_level in legacy_bundled_packages and global_ignore_missing_imports:
if (top_level in legacy_bundled_packages
and global_ignore_missing_imports
and not options.ignore_missing_imports_per_module):
ignore_missing_imports = False

if skip_diagnose:
Expand Down
6 changes: 6 additions & 0 deletions mypy/options.py
Expand Up @@ -82,6 +82,8 @@ def __init__(self) -> None:
self.no_silence_site_packages = False
self.no_site_packages = False
self.ignore_missing_imports = False
# Is ignore_missing_imports set in a per-module section
self.ignore_missing_imports_per_module = False
self.follow_imports = 'normal' # normal|silent|skip|error
# Whether to respect the follow_imports setting even for stub files.
# Intended to be used for disabling specific stubs.
Expand Down Expand Up @@ -325,6 +327,10 @@ def apply_changes(self, changes: Dict[str, object]) -> 'Options':
replace_object_state(new_options, self, copy_dict=True)
for key, value in changes.items():
setattr(new_options, key, value)
if changes.get("ignore_missing_imports"):
# This is the only option for which a per-module and a global
# option sometimes beheave differently.
new_options.ignore_missing_imports_per_module = True
return new_options

def build_per_module_cache(self) -> None:
Expand Down
32 changes: 31 additions & 1 deletion test-data/unit/check-modules.test
Expand Up @@ -3011,7 +3011,6 @@ certifi.x # E: Expression has type "Any"
certifi.x # E: Expression has type "Any"
1() # E: "int" not callable


[case testDoNotLimitImportErrorVolume]
# flags: --disallow-any-expr --soft-error-limit=3
import xyz1 # E: Cannot find implementation or library stub for module named "xyz1" \
Expand Down Expand Up @@ -3064,3 +3063,34 @@ certifi.x # E: Expression has type "Any"
certifi.x # E: Expression has type "Any"
certifi.x # E: Expression has type "Any"
certifi.x # E: Expression has type "Any"

[case testIgnoreErrorFromMissingStubs1]
# flags: --config-file tmp/pyproject.toml
import certifi
from foobar1 import x
import foobar2
[file pyproject.toml]
\[tool.mypy]
ignore_missing_imports = true
\[[tool.mypy.overrides]]
module = "certifi"
ignore_missing_imports = true
\[[tool.mypy.overrides]]
module = "foobar1"
ignore_missing_imports = true

[case testIgnoreErrorFromMissingStubs2]
# flags: --config-file tmp/pyproject.toml
import certifi
from foobar1 import x
import foobar2 # E: Cannot find implementation or library stub for module named "foobar2" \
# N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
[file pyproject.toml]
\[tool.mypy]
ignore_missing_imports = false
\[[tool.mypy.overrides]]
module = "certifi"
ignore_missing_imports = true
\[[tool.mypy.overrides]]
module = "foobar1"
ignore_missing_imports = true

0 comments on commit 4642a31

Please sign in to comment.