summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2014-01-01 19:54:06 +0200
committercpopa <devnull@localhost>2014-01-01 19:54:06 +0200
commit737dc750f6756e5f87294143bc9fe309feeeb495 (patch)
tree88c7cf1084496d2682adbf90a72573a46ea1be3a
parent3927b761d923c9d8d32290c5a694acda9083480b (diff)
downloadpylint-737dc750f6756e5f87294143bc9fe309feeeb495.tar.gz
Fix false positive for catching-non-exception, for C based exceptions.
-rw-r--r--checkers/exceptions.py30
-rw-r--r--test/input/func_catching_non_exception.py15
-rw-r--r--test/messages/func_catching_non_exception.txt6
3 files changed, 45 insertions, 6 deletions
diff --git a/checkers/exceptions.py b/checkers/exceptions.py
index 9843001..175c77b 100644
--- a/checkers/exceptions.py
+++ b/checkers/exceptions.py
@@ -25,6 +25,23 @@ from pylint.checkers import BaseChecker
from pylint.checkers.utils import is_empty, is_raising, check_messages
from pylint.interfaces import IAstroidChecker
+def infer_bases(klass):
+ """ Fully infer the bases of the klass node.
+
+ This doesn't use .ancestors(), because we need
+ the non-inferable nodes (YES nodes),
+ which can't be retrieved from .ancestors()
+ """
+ for base in klass.bases:
+ try:
+ inferit = base.infer().next()
+ except astroid.InferenceError:
+ continue
+ if inferit is YES:
+ yield inferit
+ else:
+ for base in infer_bases(inferit):
+ yield base
OVERGENERAL_EXCEPTIONS = ('Exception',)
@@ -214,9 +231,16 @@ class ExceptionsChecker(BaseChecker):
if (not inherit_from_std_ex(exc) and
exc.root().name != BUILTINS_NAME):
- self.add_message('catching-non-exception',
- node=handler.type,
- args=(exc.name, ))
+ # try to see if the exception is based on a C based
+ # exception, by infering all the base classes and
+ # looking for inference errors
+ bases = infer_bases(exc)
+ fully_infered = not any(inferit is YES
+ for inferit in bases)
+ if fully_infered:
+ self.add_message('catching-non-exception',
+ node=handler.type,
+ args=(exc.name, ))
exceptions_classes += excs
diff --git a/test/input/func_catching_non_exception.py b/test/input/func_catching_non_exception.py
index e6bfc57..d8e0e2d 100644
--- a/test/input/func_catching_non_exception.py
+++ b/test/input/func_catching_non_exception.py
@@ -1,5 +1,6 @@
"""test non-exceptions catched
"""
+import socket
__revision__ = 1
@@ -19,6 +20,16 @@ class MySecondGoodException(MyGoodException):
""" custom 'exception' """
pass
+class SkipException(socket.error):
+ """ This gave false positives for Python 2,
+ but not for Python 3, due to exception
+ hierarchy rewrite.
+ """
+
+class SecondSkipException(SkipException):
+ """ This too shouldn't give false
+ positives. """
+
try:
1 + 1
except MyException:
@@ -39,3 +50,7 @@ try:
except (MyGoodException, MySecondGoodException):
print "should work"
+try:
+ 1 + 3
+except (SkipException, SecondSkipException):
+ print "should work"
diff --git a/test/messages/func_catching_non_exception.txt b/test/messages/func_catching_non_exception.txt
index 9dc23eb..19f22ab 100644
--- a/test/messages/func_catching_non_exception.txt
+++ b/test/messages/func_catching_non_exception.txt
@@ -1,3 +1,3 @@
-E: 24: Catching an exception which doesn't inherit from BaseException: MyException
-E: 29: Catching an exception which doesn't inherit from BaseException: MyException
-E: 29: Catching an exception which doesn't inherit from BaseException: MySecondException \ No newline at end of file
+E: 35: Catching an exception which doesn't inherit from BaseException: MyException
+E: 40: Catching an exception which doesn't inherit from BaseException: MyException
+E: 40: Catching an exception which doesn't inherit from BaseException: MySecondException \ No newline at end of file