Repository: python/mypy (Python)

Issue:
Add flag to ignore 'Skipping analyzing ...'
**Pitch**

Currently `--ignore-missing-imports` silences all 3 different errors listed in [missing-imports](https://mypy.readthedocs.io/en/stable/running_mypy.html?highlight=skipping%20analyzing#missing-imports), but [missing-type-hints-for-third-party-library](https://mypy.readthedocs.io/en/stable/running_mypy.html?highlight=skipping%20analyzing#missing-type-hints-for-third-party-library) is closer to a warning than an error.

The current solution is to list the packages to ignore in a configuration file, which is particularly onerous when there are many packages being built and type-checked.

**Feature**

Add a flag (eg. `--ignore-untyped-imports`) that either ignores this error, or downgrades it to a warning:
```
error: Skipping analyzing X: found module but no type hints or library stubs
```

Alternatively:
- the [unable-to-find-module](https://mypy.readthedocs.io/en/stable/running_mypy.html?highlight=skipping%20analyzing#unable-to-find-module) error could be changed to no longer be skipped by `--ignore-missing-imports`, as that is nearly always a misconfiguration of mypy
- each case could be guarded by a separate flag. 

**Implementation**

https://github.com/python/mypy/blob/master/mypy/build.py#L2410-L2411 and other references to `options.ignore_missing_imports` would need to be changed.


Hints:
Reasonable request, although I'm wary of adding more knobs to mypy's import following... I think in practice people don't even understand the existing ones very well and they're a common source of confusion. I'd also phrase it as `--ignore-untyped-imports`.
Note that of those three errors, you won't run into one of them since typeshed is virtually complete wrt stdlib right now. In fact, I recently removed documentation of that error in #9675.
Finally, I'd personally contend with the assertion that it's closer to a warning than an error :-) All three of them have the same potential effect: causing a lot of your code to go unchecked.
I think the distinction I see is that "untyped-imports" is not _really_
something most users can/will fix, but "missing-imports" almost certainly
means something is broken that the user needs to fix. I would advocate for
removing `--ignore-missing-imports`, but the docs vaguely allude to errors
in import finding that can't be fixed otherwise.

On Wed, Dec 9, 2020 at 6:34 PM Shantanu <notifications@github.com> wrote:

> Reasonable request, although I'm wary of adding more knobs to mypy's
> import following... I think in practice people don't even understand the
> existing ones very well and they're a common source of confusion. I'd also
> phrase it as --ignore-untyped-imports.
> Note that of those three errors, you won't run into one of them since
> typeshed is virtually complete wrt stdlib right now. In fact, I recently
> removed documentation of that error in #9675
> <https://github.com/python/mypy/pull/9675>.
> Finally, I'd personally contend with the assertion that it's closer to a
> warning than an error :-) All three of them have the same potential effect:
> causing a lot of your code to go unchecked.
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/python/mypy/issues/9789#issuecomment-742130981>, or
> unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAROG6EQYHNROHOGH57OYI3SUACSBANCNFSM4UUDJHXA>
> .
>

I'd counter that this is an excellent feature request.  Here's why:

Often what mypy calls "errors" of "missing stubs" involve a 3rd party external library that the user is merely importing to extend their own code.

It boils down to how much the user trusts these 3rd party libraries.

For instance, I've gotten the `Skipping analyzing "numpy": module is installed, but missing library stubs` error when importing the `numpy` and `pandas` libraries.  Those are some of most heavily used python libraries and most users ascribe to them a reasonable amount of trust that they work.  Therefore, mypy should not throw errors for those library imports.

Now I will concede that other 3rd party libraries that are not as well tested as the two above could very well cause a lot of your code to go unchecked, and therefore it would be reasonable for mypy to throw an error if those libraries are missing stubs.

So in summary, `numpy` and `pandas` should probably not throw errors if missing library stubs.
But `my_random_untested_3rd_party_library` probably should, at least by default.

Also I agree with @mfarrugi, as most users will probably not bother fixing "untyped-imports" from a 3rd party library that they are likely not familiar with aside from how to call functions to use within their code.
But "missing-imports" is obviously a much more serious error that they will fix.
The two errors do not have the same level of "actionable" fixes.

Patch:
diff --git a/mypy/build.py b/mypy/build.py
--- a/mypy/build.py
+++ b/mypy/build.py
@@ -2776,7 +2776,16 @@ def module_not_found(
     else:
         daemon = manager.options.fine_grained_incremental
         msg, notes = reason.error_message_templates(daemon)
-        errors.report(line, 0, msg.format(module=target), code=codes.IMPORT)
+        if reason == ModuleNotFoundReason.NOT_FOUND:
+            code = codes.IMPORT_NOT_FOUND
+        elif (
+            reason == ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS
+            or reason == ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
+        ):
+            code = codes.IMPORT_UNTYPED
+        else:
+            code = codes.IMPORT
+        errors.report(line, 0, msg.format(module=target), code=code)
         top_level, second_level = get_top_two_prefixes(target)
         if second_level in legacy_bundled_packages or second_level in non_bundled_packages:
             top_level = second_level
diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py
--- a/mypy/errorcodes.py
+++ b/mypy/errorcodes.py
@@ -96,6 +96,12 @@ def __str__(self) -> str:
 IMPORT: Final = ErrorCode(
     "import", "Require that imported module can be found or has stubs", "General"
 )
+IMPORT_NOT_FOUND: Final = ErrorCode(
+    "import-not-found", "Require that imported module can be found", "General", sub_code_of=IMPORT
+)
+IMPORT_UNTYPED: Final = ErrorCode(
+    "import-untyped", "Require that imported module has stubs", "General", sub_code_of=IMPORT
+)
 NO_REDEF: Final = ErrorCode("no-redef", "Check that each name is defined once", "General")
 FUNC_RETURNS_VALUE: Final = ErrorCode(
     "func-returns-value", "Check that called function returns a value in value context", "General"
diff --git a/mypy/errors.py b/mypy/errors.py
--- a/mypy/errors.py
+++ b/mypy/errors.py
@@ -8,7 +8,7 @@
 from typing_extensions import Final, Literal, TypeAlias as _TypeAlias
 
 from mypy import errorcodes as codes
-from mypy.errorcodes import IMPORT, ErrorCode
+from mypy.errorcodes import IMPORT, IMPORT_NOT_FOUND, IMPORT_UNTYPED, ErrorCode
 from mypy.message_registry import ErrorMessage
 from mypy.options import Options
 from mypy.scope import Scope
@@ -491,7 +491,11 @@ def add_error_info(self, info: ErrorInfo) -> None:
             if info.message in self.only_once_messages:
                 return
             self.only_once_messages.add(info.message)
-        if self.seen_import_error and info.code is not IMPORT and self.has_many_errors():
+        if (
+            self.seen_import_error
+            and info.code not in (IMPORT, IMPORT_UNTYPED, IMPORT_NOT_FOUND)
+            and self.has_many_errors()
+        ):
             # Missing stubs can easily cause thousands of errors about
             # Any types, especially when upgrading to mypy 0.900,
             # which no longer bundles third-party library stubs. Avoid


Test patch:
diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test
--- a/test-data/unit/check-errorcodes.test
+++ b/test-data/unit/check-errorcodes.test
@@ -181,7 +181,7 @@ from defusedxml import xyz  # type: ignore[import]
 
 [case testErrorCodeBadIgnore]
 import nostub # type: ignore xyz  # E: Invalid "type: ignore" comment  [syntax] \
-                                  # E: Cannot find implementation or library stub for module named "nostub"  [import] \
+                                  # E: Cannot find implementation or library stub for module named "nostub"  [import-not-found] \
                                   # N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
 import nostub # type: ignore[  # E: Invalid "type: ignore" comment  [syntax]
 import nostub # type: ignore[foo  # E: Invalid "type: ignore" comment  [syntax]
@@ -209,7 +209,7 @@ def f(x,  # type: int  # type: ignore[
     pass
 [out]
 main:2: error: Invalid "type: ignore" comment  [syntax]
-main:2: error: Cannot find implementation or library stub for module named "nostub"  [import]
+main:2: error: Cannot find implementation or library stub for module named "nostub"  [import-not-found]
 main:2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
 main:3: error: Invalid "type: ignore" comment  [syntax]
 main:4: error: Invalid "type: ignore" comment  [syntax]
@@ -520,12 +520,12 @@ if int() is str():  # E: Non-overlapping identity check (left operand type: "int
 [builtins fixtures/primitives.pyi]
 
 [case testErrorCodeMissingModule]
-from defusedxml import xyz  # E: Cannot find implementation or library stub for module named "defusedxml"  [import]
-from nonexistent import foobar  # E: Cannot find implementation or library stub for module named "nonexistent"  [import]
-import nonexistent2  # E: Cannot find implementation or library stub for module named "nonexistent2"  [import]
-from nonexistent3 import *  # E: Cannot find implementation or library stub for module named "nonexistent3"  [import]
+from defusedxml import xyz  # E: Cannot find implementation or library stub for module named "defusedxml"  [import-not-found]
+from nonexistent import foobar  # E: Cannot find implementation or library stub for module named "nonexistent"  [import-not-found]
+import nonexistent2  # E: Cannot find implementation or library stub for module named "nonexistent2"  [import-not-found]
+from nonexistent3 import *  # E: Cannot find implementation or library stub for module named "nonexistent3"  [import-not-found]
 from pkg import bad  # E: Module "pkg" has no attribute "bad"  [attr-defined]
-from pkg.bad2 import bad3  # E: Cannot find implementation or library stub for module named "pkg.bad2"  [import] \
+from pkg.bad2 import bad3  # E: Cannot find implementation or library stub for module named "pkg.bad2"  [import-not-found] \
                            # N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
 [file pkg/__init__.py]