diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java
index 0e69c624de1d..af5de05d7450 100644
--- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java
@@ -120,13 +120,13 @@ public class PyPropertyDefinitionInspection extends PyInspection {
if (resolved instanceof PyFunction) callable = (PyFunction)resolved;
else if (resolved instanceof PyLambdaExpression) callable = (PyLambdaExpression)resolved;
else {
- reportStrangeArg(resolved, argument);
+ reportNonCallableArg(resolved, argument);
continue;
}
}
else if (argument instanceof PyLambdaExpression) callable = (PyLambdaExpression)argument;
else if (! "doc".equals(param_name)) {
- reportStrangeArg(argument, argument);
+ reportNonCallableArg(argument, argument);
continue;
}
if ("fget".equals(param_name)) checkGetter(callable, argument);
@@ -152,9 +152,18 @@ public class PyPropertyDefinitionInspection extends PyInspection {
}, false);
}
- void reportStrangeArg(PsiElement resolved, PsiElement being_checked) {
+ private void reportNonCallableArg(PsiElement resolved, PsiElement being_checked) {
if (! PyUtil.instanceOf(resolved, PySubscriptionExpression.class, PyNoneLiteralExpression.class)) {
- registerProblem(being_checked, PyBundle.message("INSP.strange.arg.want.callable"));
+ boolean is_not_callable = true;
+ if (resolved instanceof PyExpression) {
+ PyType expr_type = ((PyExpression)resolved).getType(myTypeEvalContext);
+ if (expr_type instanceof PyClassType) {
+ final PyClassType cls_type = (PyClassType)expr_type;
+ PyClass cls = cls_type.getPyClass();
+ if (cls != null && !cls_type.isDefinition()) is_not_callable = cls.findMethodByName("__call__", true) == null;
+ }
+ }
+ if (is_not_callable) registerProblem(being_checked, PyBundle.message("INSP.strange.arg.want.callable"));
}
}
diff --git a/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml b/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml
index 38414607ac1f..400806dc8848 100644
--- a/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml
+++ b/python/testData/inspections/PyPropertyDefinitionInspection25/expected.xml
@@ -45,5 +45,10 @@
48
Getter should return something
+
+ prop_test.py
+ 76
+ Strange argument; a callable expected
+
diff --git a/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py b/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py
index 48bcf70e200b..3590ccefe94f 100644
--- a/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py
+++ b/python/testData/inspections/PyPropertyDefinitionInspection25/src/prop_test.py
@@ -64,3 +64,14 @@ class A(object):
def bar(self):
return None
+class Ghostbusters(object):
+ def __call__(self):
+ return "Who do you call?"
+
+gb = Ghostbusters()
+
+class B(object):
+ x = property(gb) # pass
+ y = property(Ghostbusters()) # pass
+ z = property(Ghostbusters) # fail: not callable
+