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

* Fix base class inference for dataclasses using the PEP 695 typing syntax.

Refs pylint-dev/pylint#10788



What's New in astroid 4.0.2?
Expand Down
5 changes: 3 additions & 2 deletions astroid/brain/brain_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def is_decorated_with_dataclass(
)


def dataclass_transform(node: nodes.ClassDef) -> None:
def dataclass_transform(node: nodes.ClassDef) -> nodes.ClassDef | None:
"""Rewrite a dataclass to be easily understood by pylint."""
node.is_dataclass = True

Expand All @@ -70,7 +70,7 @@ def dataclass_transform(node: nodes.ClassDef) -> None:
node.instance_attrs[name] = [rhs_node]

if not _check_generate_dataclass_init(node):
return
return None

kw_only_decorated = False
if node.decorators.nodes:
Expand Down Expand Up @@ -102,6 +102,7 @@ def dataclass_transform(node: nodes.ClassDef) -> None:
new_assign = parse(f"{DEFAULT_FACTORY} = object()").body[0]
new_assign.parent = root
root.locals[DEFAULT_FACTORY] = [new_assign.targets[0]]
return node


def _get_dataclass_attributes(
Expand Down
30 changes: 29 additions & 1 deletion tests/test_scoped_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
util,
)
from astroid.bases import BoundMethod, Generator, Instance, UnboundMethod
from astroid.const import WIN32
from astroid.const import PY312_PLUS, WIN32
from astroid.exceptions import (
AstroidBuildingError,
AttributeInferenceError,
Expand Down Expand Up @@ -1967,6 +1967,34 @@ class E(C[str], D): ...
cls, [".E", ".C", ".A", ".B", "typing.Generic", ".D", "builtins.object"]
)

@pytest.mark.skipif(not PY312_PLUS, reason="PEP 695 syntax requires Python 3.12")
def test_mro_generic_8(self):
cls = builder.extract_node(
"""
class A: ...
class B[T]: ...
class C[T](A, B[T]): ...
"""
)
assert isinstance(cls, nodes.ClassDef)
self.assertEqualMroQName(cls, [".C", ".A", ".B", "builtins.object"])

@pytest.mark.skipif(not PY312_PLUS, reason="PEP 695 syntax requires Python 3.12")
def test_mro_generic_9(self):
cls = builder.extract_node(
"""
from dataclasses import dataclass
@dataclass
class A: ...
@dataclass
class B[T]: ...
@dataclass
class C[T](A, B[T]): ...
"""
)
assert isinstance(cls, nodes.ClassDef)
self.assertEqualMroQName(cls, [".C", ".A", ".B", "builtins.object"])

def test_mro_generic_error_1(self):
cls = builder.extract_node(
"""
Expand Down