Skip to content

[Backport maintenance/2.13.x] Fix issues with typing_extensions.TypeVar #1974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ What's New in astroid 2.13.4?
=============================
Release date: TBA

* Fix issues with ``typing_extensions.TypeVar``.



What's New in astroid 2.13.3?
Expand Down
12 changes: 10 additions & 2 deletions astroid/brain/brain_namedtuple_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,15 @@
"enum.IntFlag",
}
ENUM_QNAME: Final[str] = "enum.Enum"
TYPING_NAMEDTUPLE_BASENAMES: Final[set[str]] = {"NamedTuple", "typing.NamedTuple"}
TYPING_NAMEDTUPLE_QUALIFIED: Final = {
"typing.NamedTuple",
"typing_extensions.NamedTuple",
}
TYPING_NAMEDTUPLE_BASENAMES: Final = {
"NamedTuple",
"typing.NamedTuple",
"typing_extensions.NamedTuple",
}


def _infer_first(node, context):
Expand Down Expand Up @@ -542,7 +550,7 @@ def infer_typing_namedtuple(
except (InferenceError, StopIteration) as exc:
raise UseInferenceDefault from exc

if func.qname() != "typing.NamedTuple":
if func.qname() not in TYPING_NAMEDTUPLE_QUALIFIED:
raise UseInferenceDefault

if len(node.args) != 2:
Expand Down
16 changes: 13 additions & 3 deletions astroid/brain/brain_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from __future__ import annotations

import sys
import typing
from collections.abc import Iterator
from functools import partial
Expand Down Expand Up @@ -34,9 +35,18 @@
from astroid.nodes.scoped_nodes import ClassDef, FunctionDef
from astroid.util import Uninferable

TYPING_NAMEDTUPLE_BASENAMES = {"NamedTuple", "typing.NamedTuple"}
if sys.version_info >= (3, 8):
from typing import Final
else:
from typing_extensions import Final

TYPING_TYPEVARS = {"TypeVar", "NewType"}
TYPING_TYPEVARS_QUALIFIED = {"typing.TypeVar", "typing.NewType"}
TYPING_TYPEVARS_QUALIFIED: Final = {
"typing.TypeVar",
"typing.NewType",
"typing_extensions.TypeVar",
}
TYPING_TYPEDDICT_QUALIFIED: Final = {"typing.TypedDict", "typing_extensions.TypedDict"}
TYPING_TYPE_TEMPLATE = """
class Meta(type):
def __getitem__(self, item):
Expand Down Expand Up @@ -186,7 +196,7 @@ def _looks_like_typedDict( # pylint: disable=invalid-name
node: FunctionDef | ClassDef,
) -> bool:
"""Check if node is TypedDict FunctionDef."""
return node.qname() in {"typing.TypedDict", "typing_extensions.TypedDict"}
return node.qname() in TYPING_TYPEDDICT_QUALIFIED


def infer_old_typedDict( # pylint: disable=invalid-name
Expand Down
1 change: 1 addition & 0 deletions requirements_test_brain.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ types-python-dateutil
six
types-six
urllib3
typing_extensions>=4.4.0
32 changes: 32 additions & 0 deletions tests/unittest_brain.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@
except ImportError:
HAS_SIX = False

try:
import typing_extensions # pylint: disable=unused-import

HAS_TYPING_EXTENSIONS = True
HAS_TYPING_EXTENSIONS_TYPEVAR = hasattr(typing_extensions, "TypeVar")
except ImportError:
HAS_TYPING_EXTENSIONS = False
HAS_TYPING_EXTENSIONS_TYPEVAR = False


def assertEqualMro(klass: ClassDef, expected_mro: list[str]) -> None:
"""Check mro names."""
Expand Down Expand Up @@ -2148,6 +2157,29 @@ class A:
assert inferred.value == 42


@pytest.mark.skipif(
not HAS_TYPING_EXTENSIONS,
reason="These tests require the typing_extensions library",
)
class TestTypingExtensions:
@staticmethod
@pytest.mark.skipif(
not HAS_TYPING_EXTENSIONS_TYPEVAR,
reason="Need typing_extensions>=4.4.0 to test TypeVar",
)
def test_typing_extensions_types() -> None:
ast_nodes = builder.extract_node(
"""
from typing_extensions import TypeVar
TypeVar('MyTypeVar', int, float, complex) #@
TypeVar('AnyStr', str, bytes) #@
"""
)
for node in ast_nodes:
inferred = next(node.infer())
assert isinstance(inferred, nodes.ClassDef)


class ReBrainTest(unittest.TestCase):
def test_regex_flags(self) -> None:
names = [name for name in dir(re) if name.isupper()]
Expand Down