From af0724ba515b61dbdead945f43baf29116d44d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Noord?= <13665637+DanielNoord@users.noreply.github.com> Date: Mon, 13 Sep 2021 12:28:30 +0200 Subject: [PATCH] Fix crash on datafields (#1165) * Fix crash on datafields Fixes the crash reported at PyCQA/pylint#4963 Tests added there. * Change to ``if not`` * Update astroid/brain/brain_dataclasses.py * Add tests * Update and merge test * Use ``raise UseInferenceDefault`` --- ChangeLog | 3 +++ astroid/brain/brain_dataclasses.py | 12 ++++++++++-- tests/unittest_brain_dataclasses.py | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 52c974a717..4d2ea83a84 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,9 @@ What's New in astroid 2.7.4? ============================ Release date: TBA +* Fixed bug in inference of dataclass field calls. + + Closes PyCQA/pylint#4963 What's New in astroid 2.7.3? diff --git a/astroid/brain/brain_dataclasses.py b/astroid/brain/brain_dataclasses.py index e010a51494..0bd394e353 100644 --- a/astroid/brain/brain_dataclasses.py +++ b/astroid/brain/brain_dataclasses.py @@ -12,10 +12,16 @@ from astroid import context, inference_tip from astroid.builder import parse from astroid.const import PY37_PLUS, PY39_PLUS -from astroid.exceptions import AstroidSyntaxError, InferenceError, MroError +from astroid.exceptions import ( + AstroidSyntaxError, + InferenceError, + MroError, + UseInferenceDefault, +) from astroid.manager import AstroidManager from astroid.nodes.node_classes import ( AnnAssign, + Assign, AssignName, Attribute, Call, @@ -231,9 +237,11 @@ def infer_dataclass_attribute( def infer_dataclass_field_call( - node: AssignName, ctx: context.InferenceContext = None + node: Call, ctx: Optional[context.InferenceContext] = None ) -> Generator: """Inference tip for dataclass field calls.""" + if not isinstance(node.parent, (AnnAssign, Assign)): + raise UseInferenceDefault field_call = node.parent.value default_type, default = _get_field_default(field_call) if not default_type: diff --git a/tests/unittest_brain_dataclasses.py b/tests/unittest_brain_dataclasses.py index b50d45757f..6710009b83 100644 --- a/tests/unittest_brain_dataclasses.py +++ b/tests/unittest_brain_dataclasses.py @@ -643,3 +643,21 @@ class A: ) init = next(node.infer()) assert init._proxied.parent.name == "object" + + +@parametrize_module +def test_annotated_enclosed_field_call(module: str): + """Test inference of dataclass attribute with a field call in another function call""" + node = astroid.extract_node( + f""" + from {module} import dataclass, field + from typing import cast + + @dataclass + class A: + attribute: int = cast(int, field(default_factory=dict)) + """ + ) + inferred = node.inferred() + assert len(inferred) == 1 and isinstance(inferred[0], nodes.ClassDef) + assert "attribute" in inferred[0].instance_attrs