Repository: python/mypy

Issue:
mypy 1.1.1 no longer respects `# type: ignore[attr-defined]` when importing from `typing`
Springtime salutations, wonderful mypy devs! The Sun shines bright, the Canadian nights are still as cold as an icepick, and the bugs infest every corner of my codebase.

<!--
If you're not sure whether what you're experiencing is a mypy bug, please see the "Question and Help" form instead.
Please consider:

- checking our common issues page: https://mypy.readthedocs.io/en/stable/common_issues.html
- searching our issue tracker: https://github.com/python/mypy/issues to see if it's already been reported
- asking on gitter chat: https://gitter.im/python/typing
-->

**Bug Report**

<!--
If you're reporting a problem with a specific library function, the typeshed tracker is better suited for this report: https://github.com/python/typeshed/issues

If the project you encountered the issue in is open source, please provide a link to the project.
-->

mypy ≤ 1.0.0 correctly respected `# type: ignore[attr-defined]` comments when importing `typing` attributes *not* available in the current version of Python.

mypy ≥ 1.1.1 no longer does so, instead emitting an erroneous warning referring to an irrelevant error code (i.e., `"misc"`) as well as one warning for each such attribute. Examples follow or my middle name isn't "Beardy Bald Guy".

**To Reproduce**

```python
from typing import (  # type: ignore[attr-defined]
    LiteralString as LiteralString,  # pyright: ignore[reportGeneralTypeIssues]
    Never as Never,  # pyright: ignore[reportGeneralTypeIssues]
    NotRequired as NotRequired,  # pyright: ignore[reportGeneralTypeIssues]
    Required as Required,  # pyright: ignore[reportGeneralTypeIssues]
    Self as Self,  # pyright: ignore[reportGeneralTypeIssues]
    TypeVarTuple as TypeVarTuple,  # pyright: ignore[reportGeneralTypeIssues]
    Unpack as Unpack,  # pyright: ignore[reportGeneralTypeIssues]
    assert_never as assert_never,  # pyright: ignore[reportGeneralTypeIssues]
    assert_type as assert_type,  # pyright: ignore[reportGeneralTypeIssues]
    clear_overloads as clear_overloads,  # pyright: ignore[reportGeneralTypeIssues]
    dataclass_transform as dataclass_transform,  # pyright: ignore[reportGeneralTypeIssues]
    reveal_type as reveal_type,  # pyright: ignore[reportGeneralTypeIssues]
    get_overloads as get_overloads,  # pyright: ignore[reportGeneralTypeIssues]
    reveal_type as reveal_type,  # pyright: ignore[reportGeneralTypeIssues]
)
```

The above code is copied verbatim from the @beartype codebase, which I maintain for the good of QA-kind. The above code used to pass muster under both mypy and pyright. Now, only pyright remains happy:

```
$ pyright
Loading configuration file at /home/leycec/py/beartype/pyrightconfig.json
Assuming Python version 3.11
Assuming Python platform Linux
Searching for source files
Found 223 source files
pyright 1.1.298
0 errors, 0 warnings, 0 informations 
Completed in 10.842sec

$ python3.11 -m mypy
Success: no issues found in 223 source files

$ python3.10 -m mypy
beartype/typing/__init__.py:192: note: Use `from typing_extensions import LiteralString` instead
beartype/typing/__init__.py:192: note: Error code "misc" not covered by "type: ignore" comment
beartype/typing/__init__.py:192: note: See https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-new-additions-to-the-typing-module
beartype/typing/__init__.py:192: note: Use `from typing_extensions import Never` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import NotRequired` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import Required` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import Self` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import TypeVarTuple` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import Unpack` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import assert_never` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import assert_type` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import clear_overloads` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import dataclass_transform` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import reveal_type` instead
beartype/typing/__init__.py:192: note: Use `from typing_extensions import get_overloads` instead
Success: no issues found in 223 source files
```

All is no longer well here. @beartype's userbase will now be assaulted with spurious warnings they can do absolutely nothing about. Even I can't do anything about these warnings! And I'm the @beartype guy.

Moreover, these warnings are arguably harmful with respect to runtime typing. The `typing_extensions` module may be an unconditional improvement over the `typing` module with respect to *static* typing – but that definitely doesn't extend to *runtime* typing. Why? Because the runtime API of type hints defined by the `typing_extensions` module **substantially differs in non-standard and non-trivial ways** from that defined by the `typing` module. It's effectively infeasible for runtime type-checkers to support both. Ergo, runtime type-checkers typically only support type hints defined by the `typing` module.

@beartype breaks this trend a bit. We actively support a subset of type hints defined by the `typing_extensions` module (e.g., `typing_extensions.Literal[...]`), despite those type hints providing a non-standard runtime API – but that's only a subset and that's only because Microsoft themselves vociferously complained on our issue tracker about this. What Microsoft wants, one gives to Microsoft.

**Expected Behavior**

<!--
How did you expect mypy to behave? It’s fine if you’re not sure your understanding is correct.
Write down what you thought would happen. If you expected no errors, delete this section.
-->

Silence! Sweet, blessed silence!

**Actual Behavior**

<!-- What went wrong? Paste mypy's output. -->

Loudness! Horrid, accursed loudness! <sup>Please see above.</sup>

**Your Environment**

<!-- Include as many relevant details about the environment you experienced the bug in -->

- Mypy version used: mypy 1.1.1
- Mypy command-line flags: None.
- Mypy configuration options from `mypy.ini` (and other config files): None.
- Python version used: Python 3.11, 3.10, 3.9, 3.8, and 3.7. Literally everything that has yet to hit EOL.

<!-- You can freely edit this text, please remove all the lines you believe are unnecessary. -->

Thanks so much for all the tremendous volunteerism over these many, long years. You are dedication incarnate. Much :heart: from the snow-encrusted Canadian wilderness.

— @leycec, the @beartype guy


Discussion:
Cc. @hauntsaninja -- the change in error code from `attr-defined` to `misc` seems to bisect to https://github.com/python/mypy/commit/0929773801ee2d7a1eca5c64ae9575f43e661a6f

Resolving patch:
diff --git a/mypy/semanal.py b/mypy/semanal.py
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -2616,11 +2616,14 @@ def report_missing_module_attribute(
                 typing_extensions = self.modules.get("typing_extensions")
                 if typing_extensions and source_id in typing_extensions.names:
                     self.msg.note(
-                        f"Use `from typing_extensions import {source_id}` instead", context
+                        f"Use `from typing_extensions import {source_id}` instead",
+                        context,
+                        code=codes.ATTR_DEFINED,
                     )
                     self.msg.note(
                         "See https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-new-additions-to-the-typing-module",
                         context,
+                        code=codes.ATTR_DEFINED,
                     )
 
     def process_import_over_existing_name(


Test patch: