diff --git a/mypy/semanal.py b/mypy/semanal.py index 31abc8c1a515..1256133cb5f3 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2597,6 +2597,16 @@ def report_missing_module_attribute( ): # Yes. Generate a helpful note. self.msg.add_fixture_note(fullname, context) + else: + 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 + ) + self.msg.note( + "See https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-new-additions-to-the-typing-module", + context, + ) def process_import_over_existing_name( self, diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index ed7349aaa296..b9551870ddfc 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -2198,3 +2198,17 @@ def foo(x: int) -> Union[Generator[A, None, None], Generator[B, None, None]]: [case testNoCrashOnStarRightHandSide] x = *(1, 2, 3) # E: Can use starred expression only as assignment target [builtins fixtures/tuple.pyi] + + +[case testTypingExtensionsSuggestion] +from typing import _FutureFeatureFixture + +# This import is only needed in tests. In real life, mypy will always have typing_extensions in its +# build due to its pervasive use in typeshed. This assumption may one day prove False, but when +# that day comes this suggestion will also be less helpful than it is today. +import typing_extensions +[out] +main:1: error: Module "typing" has no attribute "_FutureFeatureFixture" +main:1: note: Use `from typing_extensions import _FutureFeatureFixture` instead +main:1: note: See https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-new-additions-to-the-typing-module +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/lib-stub/typing_extensions.pyi b/test-data/unit/lib-stub/typing_extensions.pyi index 89f7108fe83c..b03fc7e6df14 100644 --- a/test-data/unit/lib-stub/typing_extensions.pyi +++ b/test-data/unit/lib-stub/typing_extensions.pyi @@ -59,3 +59,5 @@ def TypedDict(typename: str, fields: Dict[str, Type[_T]], *, total: Any = ...) - def reveal_type(__obj: T) -> T: pass def dataclass_transform() -> Callable[[T], T]: ... + +_FutureFeatureFixture = 0