From 2ffca1084507fcee6d59ef22d394c92991bede3a Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Wed, 3 Apr 2024 19:50:14 +0100 Subject: [PATCH] remove typing dependencies (#1126) Summary: This PR removes the `typing_extensions` and `typing_inspect` dependencies as we can now rely on the built-in `typing` module since Python 3.9. Test Plan: existing tests --- libcst/_exceptions.py | 4 +-- libcst/_nodes/expression.py | 4 +-- libcst/_type_enforce.py | 26 +++++++++---------- libcst/codegen/gen_matcher_classes.py | 3 +-- .../codemod/commands/convert_type_comments.py | 8 +++--- libcst/matchers/__init__.py | 4 +-- libcst/tests/test_type_enforce.py | 3 +-- pyproject.toml | 6 +---- 8 files changed, 22 insertions(+), 36 deletions(-) diff --git a/libcst/_exceptions.py b/libcst/_exceptions.py index 0ba689c27..5359ca3c0 100644 --- a/libcst/_exceptions.py +++ b/libcst/_exceptions.py @@ -4,9 +4,7 @@ # LICENSE file in the root directory of this source tree. from enum import auto, Enum -from typing import Any, Callable, Iterable, Optional, Sequence, Tuple, Union - -from typing_extensions import final +from typing import Any, Callable, final, Iterable, Optional, Sequence, Tuple, Union from libcst._parser.parso.pgen2.generator import ReservedString from libcst._parser.parso.python.token import PythonTokenTypes, TokenType diff --git a/libcst/_nodes/expression.py b/libcst/_nodes/expression.py index 074fc71f5..75f7da133 100644 --- a/libcst/_nodes/expression.py +++ b/libcst/_nodes/expression.py @@ -15,9 +15,7 @@ Imagnumber as IMAGNUMBER_RE, Intnumber as INTNUMBER_RE, ) -from typing import Callable, Generator, Optional, Sequence, Union - -from typing_extensions import Literal +from typing import Callable, Generator, Literal, Optional, Sequence, Union from libcst._add_slots import add_slots from libcst._maybe_sentinel import MaybeSentinel diff --git a/libcst/_type_enforce.py b/libcst/_type_enforce.py index b13c41de4..dded45253 100644 --- a/libcst/_type_enforce.py +++ b/libcst/_type_enforce.py @@ -5,17 +5,20 @@ from typing import ( Any, + ClassVar, ForwardRef, + get_args, + get_origin, Iterable, + Literal, Mapping, MutableMapping, MutableSequence, Tuple, + TypeVar, + Union, ) -from typing_extensions import Literal -from typing_inspect import get_args, get_origin, is_classvar, is_typevar, is_union_type - def is_value_of_type( # noqa: C901 "too complex" # pyre-fixme[2]: Parameter annotation cannot be `Any`. @@ -48,11 +51,11 @@ def is_value_of_type( # noqa: C901 "too complex" - Forward Refs -- use `typing.get_type_hints` to resolve these - Type[...] """ - if is_classvar(expected_type): + if expected_type is ClassVar or get_origin(expected_type) is ClassVar: classvar_args = get_args(expected_type) expected_type = (classvar_args[0] or Any) if classvar_args else Any - if is_typevar(expected_type): + if type(expected_type) is TypeVar: # treat this the same as Any # TODO: evaluate bounds return True @@ -62,13 +65,13 @@ def is_value_of_type( # noqa: C901 "too complex" if expected_origin_type == Any: return True - elif is_union_type(expected_type): + elif expected_type is Union or get_origin(expected_type) is Union: return any( is_value_of_type(value, subtype) for subtype in expected_type.__args__ ) elif isinstance(expected_origin_type, type(Literal)): - literal_values = get_args(expected_type, evaluate=True) + literal_values = get_args(expected_type) return any(value == literal for literal in literal_values) elif isinstance(expected_origin_type, ForwardRef): @@ -82,14 +85,11 @@ def is_value_of_type( # noqa: C901 "too complex" if not isinstance(value, tuple): return False - type_args = get_args(expected_type, evaluate=True) + type_args = get_args(expected_type) if len(type_args) == 0: # `Tuple` (no subscript) is implicitly `Tuple[Any, ...]` return True - if type_args is None: - return True - if len(value) != len(type_args): return False # TODO: Handle `Tuple[T, ...]` like `Iterable[T]` @@ -106,7 +106,7 @@ def is_value_of_type( # noqa: C901 "too complex" if not issubclass(type(value), expected_origin_type): return False - type_args = get_args(expected_type, evaluate=True) + type_args = get_args(expected_type) if len(type_args) == 0: # `Mapping` (no subscript) is implicitly `Mapping[Any, Any]`. return True @@ -143,7 +143,7 @@ def is_value_of_type( # noqa: C901 "too complex" if not issubclass(type(value), expected_origin_type): return False - type_args = get_args(expected_type, evaluate=True) + type_args = get_args(expected_type) if len(type_args) == 0: # `Iterable` (no subscript) is implicitly `Iterable[Any]`. return True diff --git a/libcst/codegen/gen_matcher_classes.py b/libcst/codegen/gen_matcher_classes.py index 8ac8a4667..b7940f973 100644 --- a/libcst/codegen/gen_matcher_classes.py +++ b/libcst/codegen/gen_matcher_classes.py @@ -443,8 +443,7 @@ def _get_fields(node: Type[cst.CSTNode]) -> Generator[Field, None, None]: generated_code.append("") generated_code.append("# This file was generated by libcst.codegen.gen_matcher_classes") generated_code.append("from dataclasses import dataclass") -generated_code.append("from typing import Optional, Sequence, Union") -generated_code.append("from typing_extensions import Literal") +generated_code.append("from typing import Literal, Optional, Sequence, Union") generated_code.append("import libcst as cst") generated_code.append("") generated_code.append( diff --git a/libcst/codemod/commands/convert_type_comments.py b/libcst/codemod/commands/convert_type_comments.py index e2c6e71cc..5863d94bf 100644 --- a/libcst/codemod/commands/convert_type_comments.py +++ b/libcst/codemod/commands/convert_type_comments.py @@ -11,8 +11,6 @@ import sys from typing import cast, Dict, List, Optional, Sequence, Set, Tuple, Union -from typing_extensions import TypeAlias - import libcst as cst import libcst.matchers as m from libcst.codemod import CodemodContext, VisitorBasedCodemodCommand @@ -143,9 +141,9 @@ class _ArityError(Exception): pass -UnpackedBindings: TypeAlias = Union[cst.BaseExpression, List["UnpackedBindings"]] -UnpackedAnnotations: TypeAlias = Union[str, List["UnpackedAnnotations"]] -TargetAnnotationPair: TypeAlias = Tuple[cst.BaseExpression, str] +UnpackedBindings = Union[cst.BaseExpression, List["UnpackedBindings"]] +UnpackedAnnotations = Union[str, List["UnpackedAnnotations"]] +TargetAnnotationPair = Tuple[cst.BaseExpression, str] class AnnotationSpreader: diff --git a/libcst/matchers/__init__.py b/libcst/matchers/__init__.py index 7e3761b82..e9698462f 100644 --- a/libcst/matchers/__init__.py +++ b/libcst/matchers/__init__.py @@ -6,9 +6,7 @@ # This file was generated by libcst.codegen.gen_matcher_classes from dataclasses import dataclass -from typing import Optional, Sequence, Union - -from typing_extensions import Literal +from typing import Literal, Optional, Sequence, Union import libcst as cst from libcst.matchers._decorators import call_if_inside, call_if_not_inside, leave, visit diff --git a/libcst/tests/test_type_enforce.py b/libcst/tests/test_type_enforce.py index 7c01b82bb..f6fecc7dd 100644 --- a/libcst/tests/test_type_enforce.py +++ b/libcst/tests/test_type_enforce.py @@ -11,6 +11,7 @@ Dict, Iterable, List, + Literal, Mapping, MutableMapping, NamedTuple, @@ -23,8 +24,6 @@ Union, ) -from typing_extensions import Literal - from libcst._type_enforce import is_value_of_type from libcst.testing.utils import data_provider, UnitTest diff --git a/pyproject.toml b/pyproject.toml index f8a2cfabf..d2481a1fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,11 +16,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] requires-python = ">=3.9" -dependencies = [ - "typing_extensions>=3.7.4.2", - "typing_inspect>=0.4.0", - "pyyaml>=5.2", -] +dependencies = ["pyyaml>=5.2"] [project.optional-dependencies] dev = [