Add test to ensure certain names are not imported from typing_extensions (#6619)

This commit is contained in:
Alex Waygood
2021-12-17 22:50:25 +00:00
committed by GitHub
parent 0b75d71303
commit ae725c3f10
3 changed files with 56 additions and 4 deletions

View File

@@ -244,10 +244,13 @@ instead in typeshed stubs. This currently affects:
- `Literal` (new in Python 3.8)
- `SupportsIndex` (new in Python 3.8)
- `TypedDict` (new in Python 3.8)
- `Concatenate` (new in Python 3.10)
- `ParamSpec` (new in Python 3.10)
- `TypeGuard` (new in Python 3.10)
An exception is `Protocol`: although it was added in Python 3.8, it
can be used in stubs regardless of Python version.
Two exceptions are `Protocol` and `runtime_checkable`: although
these were added in Python 3.8, they can be used in stubs regardless
of Python version.
### What to include

View File

@@ -12,8 +12,8 @@ from _typeshed import (
from abc import ABCMeta, abstractmethod
from importlib.machinery import ModuleSpec
from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper
from typing import IO, Any, BinaryIO, Iterator, Mapping, NoReturn, Protocol, Sequence, Union, overload
from typing_extensions import Literal, runtime_checkable
from typing import IO, Any, BinaryIO, Iterator, Mapping, NoReturn, Protocol, Sequence, Union, overload, runtime_checkable
from typing_extensions import Literal
_Path = Union[bytes, str]

View File

@@ -12,6 +12,23 @@ STUBS_SUPPORTING_PYTHON_2 = frozenset(
CONTEXT_MANAGER_ALIASES = {"ContextManager": "AbstractContextManager", "AsyncContextManager": "AbstractAsyncContextManager"}
CONTEXTLIB_ALIAS_ALLOWLIST = frozenset({Path("stdlib/contextlib.pyi"), Path("stdlib/typing_extensions.pyi")})
IMPORTED_FROM_TYPING_NOT_TYPING_EXTENSIONS = frozenset(
{"ClassVar", "Type", "NewType", "overload", "Text", "Protocol", "runtime_checkable", "NoReturn"}
)
IMPORTED_FROM_COLLECTIONS_ABC_NOT_TYPING_EXTENSIONS = frozenset(
{"Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator", "AsyncGenerator"}
)
# The values in the mapping are what these are called in `collections`
IMPORTED_FROM_COLLECTIONS_NOT_TYPING_EXTENSIONS = {
"Counter": "Counter",
"Deque": "deque",
"DefaultDict": "defaultdict",
"OrderedDict": "OrderedDict",
"ChainMap": "ChainMap",
}
def check_new_syntax(tree: ast.AST, path: Path) -> list[str]:
errors = []
@@ -85,6 +102,38 @@ def check_new_syntax(tree: ast.AST, path: Path) -> list[str]:
if any(cls.name == "Set" for cls in imported_classes):
self.set_from_collections_abc = True
elif node.module == "typing_extensions":
for imported_object in node.names:
imported_object_name = imported_object.name
if imported_object_name in IMPORTED_FROM_TYPING_NOT_TYPING_EXTENSIONS:
errors.append(
f"{path}:{node.lineno}: "
f"Use `typing.{imported_object_name}` instead of `typing_extensions.{imported_object_name}`"
)
elif imported_object_name in IMPORTED_FROM_COLLECTIONS_ABC_NOT_TYPING_EXTENSIONS:
errors.append(
f"{path}:{node.lineno}: "
f"Use `collections.abc.{imported_object_name}` or `typing.{imported_object_name}` "
f"instead of `typing_extensions.{imported_object_name}`"
)
elif imported_object_name in IMPORTED_FROM_COLLECTIONS_NOT_TYPING_EXTENSIONS:
errors.append(
f"{path}:{node.lineno}: "
f"Use `collections.{IMPORTED_FROM_COLLECTIONS_NOT_TYPING_EXTENSIONS[imported_object_name]}` "
f"or `typing.{imported_object_name}` instead of `typing_extensions.{imported_object_name}`"
)
elif imported_object_name in CONTEXT_MANAGER_ALIASES:
if python_2_support_required:
errors.append(
f"{path}:{node.lineno}: "
f"Use `typing.{imported_object_name}` instead of `typing_extensions.{imported_object_name}`"
)
else:
errors.append(
f"{path}:{node.lineno}: Use `contextlib.{CONTEXT_MANAGER_ALIASES[imported_object_name]}` "
f"instead of `typing_extensions.{imported_object_name}`"
)
elif not python_2_support_required and path not in CONTEXTLIB_ALIAS_ALLOWLIST and node.module == "typing":
for imported_class in node.names:
imported_class_name = imported_class.name