Skip to content

Handle dataclass kw_only keyword correctly #1764

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 5 commits into from
Sep 5, 2022

Conversation

DanielNoord
Copy link
Collaborator

@DanielNoord DanielNoord commented Sep 5, 2022

Steps

  • For new features or bug fixes, add a ChangeLog entry describing what your PR does.
  • Write a good description on what the PR does.

Description

Type of Changes

Type
βœ“ πŸ› Bug fix

Related Issue

Closes pylint-dev/pylint#7290

Edit after merge: Closes pylint-dev/pylint#6550

@DanielNoord DanielNoord added Bug πŸͺ³ Needs backport python 3.10 pylint-tested PRs that don't cause major regressions with pylint labels Sep 5, 2022
@DanielNoord DanielNoord added this to the 2.12.6 milestone Sep 5, 2022
@coveralls
Copy link

coveralls commented Sep 5, 2022

Pull Request Test Coverage Report for Build 2993872918

  • 47 of 47 (100.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.05%) to 92.4%

Totals Coverage Status
Change from base Build 2989127382: 0.05%
Covered Lines: 9750
Relevant Lines: 10552

πŸ’› - Coveralls

Copy link
Member

@jacobtylerwalls jacobtylerwalls left a comment

Choose a reason for hiding this comment

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

Looking good, but I think the string contains test for the argument names needs to be more robust.

new_params_string = ", ".join(params)

try:
base: ClassDef = next(next(iter(node.bases)).infer())
Copy link
Member

Choose a reason for hiding this comment

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

I see that it works, but for my understanding can you explain the iteration going on here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

node.bases are nodes.Name. So, I get the first base node which then gets inferred, of which I get the first inference result. This should be the ClassDef.

This works because we mangle the __init__ of each dataclass so there is no need to iterate over all base classes, the last base is fine.

I use next(iter( as it is a nice safe guard against not finding any bases using the try ... except I needed anyway for the call to .infer().

Comment on lines 245 to 247
arguments = ", ".join(
i for i in all_arguments if i.split(":")[0] not in new_params_string
)
Copy link
Member

Choose a reason for hiding this comment

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

I managed to break this assumption because "e" is contained in "ee":

This test will now fail:

diff --git a/tests/unittest_brain_dataclasses.py b/tests/unittest_brain_dataclasses.py
index a2077d1c..92a61a85 100644
--- a/tests/unittest_brain_dataclasses.py
+++ b/tests/unittest_brain_dataclasses.py
@@ -761,7 +761,7 @@ def test_kw_only_decorator() -> None:
     @dataclass(kw_only=True)
     class Foo:
         a: int
-        b: str
+        e: str
 
 
     @dataclass(kw_only=False)
@@ -776,7 +776,7 @@ def test_kw_only_decorator() -> None:
 
     @dataclass(kw_only=True)
     class Dee(Cee):
-        e: int
+        ee: int
 
 
     Foo.__init__  #@
@@ -789,31 +789,31 @@ def test_kw_only_decorator() -> None:
     foo_init: bases.UnboundMethod = next(foodef.infer())
     if PY310_PLUS:
         assert [a.name for a in foo_init.args.args] == ["self"]
-        assert [a.name for a in foo_init.args.kwonlyargs] == ["a", "b"]
+        assert [a.name for a in foo_init.args.kwonlyargs] == ["a", "e"]
     else:
-        assert [a.name for a in foo_init.args.args] == ["self", "a", "b"]
+        assert [a.name for a in foo_init.args.args] == ["self", "a", "e"]
         assert [a.name for a in foo_init.args.kwonlyargs] == []
 
     bar_init: bases.UnboundMethod = next(bardef.infer())
     if PY310_PLUS:
         assert [a.name for a in bar_init.args.args] == ["self", "c"]
-        assert [a.name for a in bar_init.args.kwonlyargs] == ["a", "b"]
+        assert [a.name for a in bar_init.args.kwonlyargs] == ["a", "e"]
     else:
-        assert [a.name for a in bar_init.args.args] == ["self", "a", "b", "c"]
+        assert [a.name for a in bar_init.args.args] == ["self", "a", "e", "c"]
         assert [a.name for a in bar_init.args.kwonlyargs] == []
 
     cee_init: bases.UnboundMethod = next(cee.infer())
     if PY310_PLUS:
         assert [a.name for a in cee_init.args.args] == ["self", "c", "d"]
-        assert [a.name for a in cee_init.args.kwonlyargs] == ["a", "b"]
+        assert [a.name for a in cee_init.args.kwonlyargs] == ["a", "e"]
     else:
-        assert [a.name for a in cee_init.args.args] == ["self", "a", "b", "c", "d"]
+        assert [a.name for a in cee_init.args.args] == ["self", "a", "e", "c", "d"]
         assert [a.name for a in cee_init.args.kwonlyargs] == []
 
     dee_init: bases.UnboundMethod = next(dee.infer())
     if PY310_PLUS:
         assert [a.name for a in dee_init.args.args] == ["self", "c", "d"]
-        assert [a.name for a in dee_init.args.kwonlyargs] == ["a", "b", "e"]
+        assert [a.name for a in dee_init.args.kwonlyargs] == ["a", "e", "e"]
     else:
-        assert [a.name for a in dee_init.args.args] == ["self", "a", "b", "c", "d", "e"]
+        assert [a.name for a in dee_init.args.args] == ["self", "a", "e", "c", "d", "ee"]
         assert [a.name for a in dee_init.args.kwonlyargs] == []

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

πŸ˜…

@DanielNoord DanielNoord merged commit e0a2d6c into pylint-dev:main Sep 5, 2022
@DanielNoord DanielNoord deleted the dataclasses-KW-ONLY branch September 5, 2022 14:28
@DanielNoord
Copy link
Collaborator Author

DanielNoord commented Sep 5, 2022

This also closed pylint-dev/pylint#6550 and pylint-dev/pylint#5857

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug πŸͺ³ pylint-tested PRs that don't cause major regressions with pylint python 3.10
Projects
None yet
4 participants