Skip to content
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
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ What's New in astroid 3.0.1?
============================
Release date: TBA

* Fix crashes linting code using PEP 695 (Python 3.12) generic type syntax.

Closes pylint-dev/pylint#9098


What's New in astroid 3.0.0?
Expand Down
15 changes: 15 additions & 0 deletions astroid/nodes/node_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3405,6 +3405,11 @@ def _infer(
) -> Iterator[ParamSpec]:
yield self

assigned_stmts = protocols.generic_type_assigned_stmts
"""Returns the assigned statement (non inferred) according to the assignment type.
See astroid/protocols.py for actual implementation.
"""


class Pass(_base_nodes.NoChildrenNode, _base_nodes.Statement):
"""Class representing an :class:`ast.Pass` node.
Expand Down Expand Up @@ -4153,6 +4158,11 @@ def _infer(
) -> Iterator[TypeVar]:
yield self

assigned_stmts = protocols.generic_type_assigned_stmts
"""Returns the assigned statement (non inferred) according to the assignment type.
See astroid/protocols.py for actual implementation.
"""


class TypeVarTuple(_base_nodes.AssignTypeNode):
"""Class representing a :class:`ast.TypeVarTuple` node.
Expand Down Expand Up @@ -4192,6 +4202,11 @@ def _infer(
) -> Iterator[TypeVarTuple]:
yield self

assigned_stmts = protocols.generic_type_assigned_stmts
"""Returns the assigned statement (non inferred) according to the assignment type.
See astroid/protocols.py for actual implementation.
"""


UNARY_OP_METHOD = {
"+": "__pos__",
Expand Down
14 changes: 14 additions & 0 deletions astroid/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -915,3 +915,17 @@ def match_as_assigned_stmts(
and self.pattern is None
):
yield self.parent.parent.subject


@decorators.yes_if_nothing_inferred
def generic_type_assigned_stmts(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modeled on the 3.10 match work just above this.

self: nodes.TypeVar | nodes.TypeVarTuple | nodes.ParamSpec,
node: nodes.AssignName,
context: InferenceContext | None = None,
assign_path: None = None,
) -> Generator[nodes.NodeNG, None, None]:
"""Return empty generator (return -> raises StopIteration) so inferred value
is Uninferable.
"""
return
yield
29 changes: 28 additions & 1 deletion tests/test_protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import astroid
from astroid import extract_node, nodes
from astroid.const import PY310_PLUS
from astroid.const import PY310_PLUS, PY312_PLUS
from astroid.exceptions import InferenceError
from astroid.manager import AstroidManager
from astroid.util import Uninferable, UninferableBase
Expand Down Expand Up @@ -415,3 +415,30 @@ def test_assigned_stmts_match_as():
assert match_as.name
assigned_match_as = next(match_as.name.assigned_stmts())
assert assigned_match_as == subject


@pytest.mark.skipif(not PY312_PLUS, reason="Generic typing syntax requires python 3.12")
class TestGenericTypeSyntax:
@staticmethod
def test_assigned_stmts_type_var():
"""The result is 'Uninferable' and no exception is raised."""
assign_stmts = extract_node("type Point[T] = tuple[float, float]")
type_var: nodes.TypeVar = assign_stmts.type_params[0]
assigned = next(type_var.name.assigned_stmts())
assert assigned is Uninferable

@staticmethod
def test_assigned_stmts_type_var_tuple():
"""The result is 'Uninferable' and no exception is raised."""
assign_stmts = extract_node("type Alias[*Ts] = tuple[*Ts]")
type_var_tuple: nodes.TypeVarTuple = assign_stmts.type_params[0]
assigned = next(type_var_tuple.name.assigned_stmts())
assert assigned is Uninferable

@staticmethod
def test_assigned_stmts_param_spec():
"""The result is 'Uninferable' and no exception is raised."""
assign_stmts = extract_node("type Alias[**P] = Callable[P, int]")
param_spec: nodes.ParamSpec = assign_stmts.type_params[0]
assigned = next(param_spec.name.assigned_stmts())
assert assigned is Uninferable