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 crash for object that does not support item assignment #1109

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ What's New in astroid 2.6.5?
============================
Release date: TBA

* Fix a crash when there would be a 'TypeError object does not support
item assignment' in the code we parse.

Closes PyCQA/pylint#4439


What's New in astroid 2.6.4?
Expand Down
33 changes: 18 additions & 15 deletions astroid/brain/brain_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
for attrs classes
"""
from astroid.manager import AstroidManager
from astroid.node_classes import AnnAssign, Assign, Call, Unknown
from astroid.node_classes import AnnAssign, Assign, AssignName, Call, Unknown
from astroid.scoped_nodes import ClassDef

ATTRIB_NAMES = frozenset(("attr.ib", "attrib", "attr.attrib"))
Expand All @@ -27,36 +27,39 @@ def is_decorated_with_attrs(node, decorator_names=ATTRS_NAMES):
return False


def attr_attributes_transform(node):
def attr_attributes_transform(node: ClassDef) -> None:
"""Given that the ClassNode has an attr decorator,
rewrite class attributes as instance attributes
"""
# Astroid can't infer this attribute properly
# Prevents https://github.com/PyCQA/pylint/issues/1884
node.locals["__attrs_attrs__"] = [Unknown(parent=node)]

for cdefbodynode in node.body:
if not isinstance(cdefbodynode, (Assign, AnnAssign)):
for cdef_body_node in node.body:
if not isinstance(cdef_body_node, (Assign, AnnAssign)):
continue
if isinstance(cdefbodynode.value, Call):
if cdefbodynode.value.func.as_string() not in ATTRIB_NAMES:
if isinstance(cdef_body_node.value, Call):
if cdef_body_node.value.func.as_string() not in ATTRIB_NAMES:
continue
else:
continue
targets = (
cdefbodynode.targets
if hasattr(cdefbodynode, "targets")
else [cdefbodynode.target]
cdef_body_node.targets
if hasattr(cdef_body_node, "targets")
else [cdef_body_node.target]
)
for target in targets:

rhs_node = Unknown(
lineno=cdefbodynode.lineno,
col_offset=cdefbodynode.col_offset,
parent=cdefbodynode,
lineno=cdef_body_node.lineno,
col_offset=cdef_body_node.col_offset,
parent=cdef_body_node,
)
node.locals[target.name] = [rhs_node]
node.instance_attrs[target.name] = [rhs_node]
if isinstance(target, AssignName):
# Could be a subscript if the code analysed is
# i = Optional[str] = ""
# See https://github.com/PyCQA/pylint/issues/4439
node.locals[target.name] = [rhs_node]
node.instance_attrs[target.name] = [rhs_node]


AstroidManager().register_transform(
Expand Down