Skip to content
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

Fix a crash for Enum class decorated with dataclass #9104

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/9100.other
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix a crash when an enum class which is also decorated with a ``dataclasses.dataclass`` decorator is defined.

Closes #9100
5 changes: 4 additions & 1 deletion pylint/checkers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2281,5 +2281,8 @@ def is_enum_member(node: nodes.AssignName) -> bool:
):
return False

enum_member_objects = frame.locals.get("__members__")[0].items
try:
enum_member_objects = frame.locals.get("__members__")[0].items
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shall we do a check if the get returns None? In the future I think we will ask ourselves what kind of error we are catching here whereas seeing an is not None check is very explicit.

Copy link
Member Author

Choose a reason for hiding this comment

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

I went for try/except since in the majority of cases this code is run, there should be a __members__ present; the only case I know of where it breaks currently, is when the dataclass decorator is used.
You make a good point though - at first glance it would be a bit difficult to see where the cause of the exception is. We could simplify it:

+    members = frame.locals.get("__members__")
     try:
-        enum_member_objects = frame.locals.get("__members__")[0].items
+        enum_member_objects = members[0].items
     except TypeError:
         return False
     return node.name in [name_obj.name for value, name_obj in enum_member_objects]

Or your suggestion:

 
-    try:
-        enum_member_objects = frame.locals.get("__members__")[0].items
-    except TypeError:
-        return False
-    return node.name in [name_obj.name for value, name_obj in enum_member_objects]
+    members = frame.locals.get("__members__")
+    if members is not None:
+        enum_member_objects = members[0].items
+        return node.name in [name_obj.name for value, name_obj in enum_member_objects]
+    return False

Copy link
Collaborator

Choose a reason for hiding this comment

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

I prefer the second diff, but perhaps with an early exit for if members is None and then doing the rest of the checks.

We can just add a comment saying that "due to unforeseen circumstances members is not always present" πŸ˜„

except TypeError:
return False
return node.name in [name_obj.name for value, name_obj in enum_member_objects]
9 changes: 9 additions & 0 deletions tests/functional/i/invalid/invalid_name/invalid_name_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# pylint: disable=too-few-public-methods


from dataclasses import dataclass
from enum import Enum


Expand All @@ -28,3 +29,11 @@ def __init__(self, red: int, green: int, blue: int) -> None:
def as_hex(self) -> str:
"""Get hex 'abcdef' representation for a color."""
return f'{self.red:0{2}x}{self.green:0{2}x}{self.blue:0{2}x}'


@dataclass
class Something(str, Enum):
""" A false positive for ``invalid-name``
which should be fixed by https://github.com/pylint-dev/astroid/issues/2317
"""
ASD: str = 1 # [invalid-name]
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
invalid-name:16:4:16:14:Color:"Class constant name ""aquamarine"" doesn't conform to UPPER_CASE naming style":HIGH
invalid-name:17:4:17:14:Color:"Class constant name ""aquamarine"" doesn't conform to UPPER_CASE naming style":HIGH
invalid-name:39:4:None:None:Something:"Attribute name ""ASD"" doesn't conform to snake_case naming style":HIGH