Skip to content

Commit

Permalink
Fix inference regression with property setters (#2567) (#2568)
Browse files Browse the repository at this point in the history
Closes pylint-dev/pylint#9811

(cherry picked from commit 5a93a9f)
  • Loading branch information
jacobtylerwalls authored Sep 19, 2024
1 parent 5eae215 commit 3840ff6
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
5 changes: 4 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ What's New in astroid 3.3.3?
============================
Release date: TBA

* Fix inference regression with property setters.

Closes pylint-dev/pylint#9811

* Add annotation-only instance attributes to attrs classes to fix `no-member` false positives.

Closes #2514



What's New in astroid 3.3.2?
============================
Release date: 2024-08-11
Expand Down
12 changes: 11 additions & 1 deletion astroid/nodes/scoped_nodes/scoped_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2506,6 +2506,16 @@ def igetattr(
if attr.parent and attr.parent.scope() == first_scope
]
functions = [attr for attr in attributes if isinstance(attr, FunctionDef)]
setter = None
for function in functions:
dec_names = function.decoratornames(context=context)
for dec_name in dec_names:
if dec_name is util.Uninferable:
continue
if dec_name.split(".")[-1] == "setter":
setter = function
if setter:
break
if functions:
# Prefer only the last function, unless a property is involved.
last_function = functions[-1]
Expand All @@ -2529,7 +2539,7 @@ def igetattr(
elif isinstance(inferred, objects.Property):
function = inferred.function
if not class_context:
if not context.callcontext:
if not context.callcontext and not setter:
context.callcontext = CallContext(
args=function.args.arguments, callee=function
)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -4416,6 +4416,23 @@ def func():
inferred = list(node.inferred())
assert [const.value for const in inferred] == [42, False]

def test_infer_property_setter(self) -> None:
node = extract_node(
"""
class PropertyWithSetter:
@property
def host(self):
return self._host
@host.setter
def host(self, value: str):
self._host = value
PropertyWithSetter().host #@
"""
)
assert not isinstance(next(node.infer()), Instance)

def test_delayed_attributes_without_slots(self) -> None:
ast_node = extract_node(
"""
Expand Down

0 comments on commit 3840ff6

Please sign in to comment.