Skip to content

Commit c48c45a

Browse files
tushar-deepsourcejacobtylerwallsDanielNoordPierre-Sassoulas
committed
Fix E1102 / not-callable false positive for property that returns a lambda function conditionally (#6068)
Co-authored-by: Jacob Walls <[email protected]> Co-authored-by: Daniël van Noord <[email protected]> Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent e7a0faf commit c48c45a

File tree

4 files changed

+43
-10
lines changed

4 files changed

+43
-10
lines changed

ChangeLog

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ Release date: TBA
2424
* functions & classes which contain both a docstring and an ellipsis.
2525
* A body which contains an ellipsis ``nodes.Expr`` node & at least one other statement.
2626

27+
* Only raise ``not-callable`` when all the inferred values of a property are not callable.
28+
29+
Closes #5931
2730

2831

2932
What's New in Pylint 2.13.4?

doc/whatsnew/2.13.rst

+4
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,7 @@ Other Changes
575575
separated (e.g. by parens).
576576

577577
Closes #5769
578+
579+
* Only raise ``not-callable`` when all the inferred values of a property are not callable.
580+
581+
Closes #5931

pylint/checkers/typecheck.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -1217,20 +1217,22 @@ def _check_uninferable_call(self, node):
12171217
# Decorated, see if it is decorated with a property.
12181218
# Also, check the returns and see if they are callable.
12191219
if decorated_with_property(attr):
1220-
12211220
try:
1222-
all_returns_are_callable = all(
1223-
return_node.callable() or return_node is astroid.Uninferable
1224-
for return_node in attr.infer_call_result(node)
1225-
)
1221+
call_results = list(attr.infer_call_result(node))
12261222
except astroid.InferenceError:
12271223
continue
12281224

1229-
if not all_returns_are_callable:
1230-
self.add_message(
1231-
"not-callable", node=node, args=node.func.as_string()
1232-
)
1233-
break
1225+
if all(
1226+
return_node is astroid.Uninferable for return_node in call_results
1227+
):
1228+
# We were unable to infer return values of the call, skipping
1229+
continue
1230+
1231+
if any(return_node.callable() for return_node in call_results):
1232+
# Only raise this issue if *all* the inferred values are not callable
1233+
continue
1234+
1235+
self.add_message("not-callable", node=node, args=node.func.as_string())
12341236

12351237
def _check_argument_order(self, node, call_site, called, called_param_names):
12361238
"""Match the supplied argument names against the function parameters.

tests/functional/n/not_callable.py

+24
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,27 @@ def get_number(arg):
200200

201201

202202
get_number(10)() # [not-callable]
203+
204+
class Klass:
205+
def __init__(self):
206+
self._x = None
207+
208+
@property
209+
def myproperty(self):
210+
if self._x is None:
211+
self._x = lambda: None
212+
return self._x
213+
214+
myobject = Klass()
215+
myobject.myproperty()
216+
217+
class Klass2:
218+
@property
219+
def something(self):
220+
if __file__.startswith('s'):
221+
return str
222+
223+
return 'abcd'
224+
225+
obj2 = Klass2()
226+
obj2.something()

0 commit comments

Comments
 (0)