Repository: python/mypy

Issue:
`type: ignore[import-untyped]` leaves a hard-to-suppress note
**Bug Report**

`type: ignore[import-untyped]` leaves a note that must be silenced with `type: ignore[import]`, but only for one of the locations.

**To Reproduce**

Consider two files, a.py and b.py, both with this content:
```python
import sentencepiece
```

Since sentencepiece is a third-party package without type information, mypy complains:
```
$ mypy *.py
b.py:1: error: Skipping analyzing "sentencepiece": module is installed, but missing library stubs or py.typed marker  [import-untyped]
a.py:1: error: Skipping analyzing "sentencepiece": module is installed, but missing library stubs or py.typed marker  [import-untyped]
a.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
Found 2 errors in 2 files (checked 2 source files)
```

So, let's try to shut up mypy, since our project can't do anything to fix that issue internally. First, I tried using disabled_error_codes in mypy.ini, and was met with issue #16002. Then, I tried adding `type: ignore` comments, like this:
```python
import sentencepiece  # type: ignore[import-untyped]
```

This doesn't really work:
```
$ mypy *.py
a.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
a.py:1: note: Error code "import" not covered by "type: ignore" comment
Success: no issues found in 2 source files
```

For one file only, mypy leaves a note providing a link to the documentation, with no associated error message.

This can be worked around by using `type: ignore[import]` on the line it complains about, but I don't know if that has to be done for just one of the files or all of them, and how mypy decides which one. I also don't want to hide other kinds of import errors, such as a package being missing entirely, or stubs that are available but not installed.

**Your Environment**

- Mypy version used: `mypy 1.7.0+dev.9a0aca14724eeef580eefcd3b340678313a1930a (compiled: no)`
- Python version used: Python 3.11.3
- Operating system and version: Arch Linux


Discussion:
I suspect we set the wrong error code when emitting the note. This should be an easy fix.

Resolving patch:
diff --git a/mypy/build.py b/mypy/build.py
--- a/mypy/build.py
+++ b/mypy/build.py
@@ -2798,7 +2798,7 @@ def module_not_found(
         for note in notes:
             if "{stub_dist}" in note:
                 note = note.format(stub_dist=stub_distribution_name(module))
-            errors.report(line, 0, note, severity="note", only_once=True, code=codes.IMPORT)
+            errors.report(line, 0, note, severity="note", only_once=True, code=code)
         if reason is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED:
             manager.missing_stub_packages.add(stub_distribution_name(module))
     errors.set_import_context(save_import_context)
diff --git a/mypy/errors.py b/mypy/errors.py
--- a/mypy/errors.py
+++ b/mypy/errors.py
@@ -469,7 +469,7 @@ def _add_error_info(self, file: str, info: ErrorInfo) -> None:
         self.error_info_map[file].append(info)
         if info.blocker:
             self.has_blockers.add(file)
-        if info.code is IMPORT:
+        if info.code in (IMPORT, IMPORT_UNTYPED, IMPORT_NOT_FOUND):
             self.seen_import_error = True
 
     def _filter_error(self, file: str, info: ErrorInfo) -> bool:
diff --git a/mypy/report.py b/mypy/report.py
--- a/mypy/report.py
+++ b/mypy/report.py
@@ -25,7 +25,7 @@
 from mypy.version import __version__
 
 try:
-    from lxml import etree  # type: ignore[import]
+    from lxml import etree  # type: ignore[import-untyped]
 
     LXML_INSTALLED = True
 except ImportError:


Test patch:
diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py
--- a/mypy/test/testcheck.py
+++ b/mypy/test/testcheck.py
@@ -26,7 +26,7 @@
 from mypy.test.update_data import update_testcase_output
 
 try:
-    import lxml  # type: ignore[import]
+    import lxml  # type: ignore[import-untyped]
 except ImportError:
     lxml = None
 
diff --git a/mypy/test/testcmdline.py b/mypy/test/testcmdline.py
--- a/mypy/test/testcmdline.py
+++ b/mypy/test/testcmdline.py
@@ -20,7 +20,7 @@
 )
 
 try:
-    import lxml  # type: ignore[import]
+    import lxml  # type: ignore[import-untyped]
 except ImportError:
     lxml = None
 
diff --git a/mypy/test/testreports.py b/mypy/test/testreports.py
--- a/mypy/test/testreports.py
+++ b/mypy/test/testreports.py
@@ -7,7 +7,7 @@
 from mypy.test.helpers import Suite, assert_equal
 
 try:
-    import lxml  # type: ignore[import]
+    import lxml  # type: ignore[import-untyped]
 except ImportError:
     lxml = None
 
@@ -22,7 +22,7 @@ def test_get_line_rate(self) -> None:
 
     @pytest.mark.skipif(lxml is None, reason="Cannot import lxml. Is it installed?")
     def test_as_xml(self) -> None:
-        import lxml.etree as etree  # type: ignore[import]
+        import lxml.etree as etree  # type: ignore[import-untyped]
 
         cobertura_package = CoberturaPackage("foobar")
         cobertura_package.covered_lines = 21
diff --git a/test-data/unit/pep561.test b/test-data/unit/pep561.test
--- a/test-data/unit/pep561.test
+++ b/test-data/unit/pep561.test
@@ -167,6 +167,7 @@ a.bf(False)
 b.bf(False)
 a.bf(1)
 b.bf(1)
+import typedpkg_ns.whatever as c  # type: ignore[import-untyped]
 [out]
 testNamespacePkgWStubs.py:4: error: Skipping analyzing "typedpkg_ns.b.bbb": module is installed, but missing library stubs or py.typed marker
 testNamespacePkgWStubs.py:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports