diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 2c8a79865d32..2b061fefba00 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -263,7 +263,7 @@ public class PyOverrideImplementUtil { return pyFunctionBuilder; } - private static boolean raisesNotImplementedError(@NotNull PyFunction function) { + public static boolean raisesNotImplementedError(@NotNull PyFunction function) { for (PyStatement statement : function.getStatementList().getStatements()) { if (!(statement instanceof PyRaiseStatement)) { continue; diff --git a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java index 70e311c6fbcc..dcf0fcd15bdd 100644 --- a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java @@ -59,20 +59,27 @@ public class PyAbstractClassInspection extends PyInspection { @Override public void visitPyClass(PyClass node) { - Set toBeImplemented = new HashSet(); + final Set toBeImplemented = new HashSet(); final Collection functions = PyOverrideImplementUtil.getAllSuperFunctions(node); for (PyFunction method : functions) { - final String methodName = method.getName(); - if (methodName != null && PyUtil.isDecoratedAsAbstract(method) && - node.findMethodByName(methodName, false) == null && node.findClassAttribute(methodName, false) == null) { + if (isAbstractMethodForClass(method, node)) { toBeImplemented.add(method); } } final ASTNode nameNode = node.getNameNode(); if (!toBeImplemented.isEmpty() && nameNode != null) { - registerProblem(nameNode.getPsi(), PyBundle.message("INSP.NAME.abstract.class.$0.must.implement", node.getName()), + registerProblem(nameNode.getPsi(), + PyBundle.message("INSP.NAME.abstract.class.$0.must.implement", node.getName()), new PyImplementMethodsQuickFix(node, toBeImplemented)); } } + + private static boolean isAbstractMethodForClass(@NotNull PyFunction method, @NotNull PyClass cls) { + final String methodName = method.getName(); + if (methodName == null || cls.findMethodByName(methodName, false) != null || cls.findClassAttribute(methodName, false) != null) { + return false; + } + return PyUtil.isDecoratedAsAbstract(method) || PyOverrideImplementUtil.raisesNotImplementedError(method); + } } } diff --git a/python/testData/inspections/PyAbstractClassInspection/superMethodRaisesNotImplementerError.py b/python/testData/inspections/PyAbstractClassInspection/superMethodRaisesNotImplementerError.py new file mode 100644 index 000000000000..dbfb779ce6b4 --- /dev/null +++ b/python/testData/inspections/PyAbstractClassInspection/superMethodRaisesNotImplementerError.py @@ -0,0 +1,6 @@ +class Abstract: + def method(self): + raise NotImplementedError() + +class Concrete(Abstract): + pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java index 99da99befb55..cf1bba172199 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java @@ -28,6 +28,10 @@ public class PyAbstractClassInspectionTest extends PyInspectionTestCase { doTest(); } + public void testSuperMethodRaisesNotImplementerError() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() {