summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2013-12-28 15:14:03 +0200
committercpopa <devnull@localhost>2013-12-28 15:14:03 +0200
commit74796a1eb4a79fc2f85e3208e74945b7a2db9af4 (patch)
tree0cc032a0e9a54a7185660155a572deefff833633
parent3927b761d923c9d8d32290c5a694acda9083480b (diff)
downloadpylint-74796a1eb4a79fc2f85e3208e74945b7a2db9af4.tar.gz
Add bad-exception-context warning for checking that `raise ... from ...` sets a proper exception context.
-rw-r--r--ChangeLog5
-rw-r--r--checkers/exceptions.py27
-rw-r--r--test/input/func_bad_exception_context_py30.py17
-rw-r--r--test/messages/func_bad_exception_context_py30.txt2
4 files changed, 49 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index f5b7192..6ed61d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,11 @@
ChangeLog for Pylint
====================
+--
+ * Add new warning 'bad-exception-context', checking
+ that `raise ... from ...` uses a proper exception context
+ (None or an exception).
+
2013-12-22 -- 1.1.0
* Add new check for use of deprecated pragma directives "pylint:disable-msg"
or "pylint:enable-msg" (I0022, deprecated-pragma) which was previously
diff --git a/checkers/exceptions.py b/checkers/exceptions.py
index 9843001..693e0f5 100644
--- a/checkers/exceptions.py
+++ b/checkers/exceptions.py
@@ -25,7 +25,7 @@ from pylint.checkers import BaseChecker
from pylint.checkers.utils import is_empty, is_raising, check_messages
from pylint.interfaces import IAstroidChecker
-
+PY3K = sys.version_info >= (3, 0)
OVERGENERAL_EXCEPTIONS = ('Exception',)
MSGS = {
@@ -38,6 +38,13 @@ MSGS = {
'raising-bad-type',
'Used when something which is neither a class, an instance or a \
string is raised (i.e. a `TypeError` will be raised).'),
+ 'E0703': ('Exception context set to something which is not an '
+ 'exception, nor None',
+ 'bad-exception-context',
+ 'Used when using the syntax "raise ... from ...", '
+ 'where the exception context is not an exception, '
+ 'nor None.',
+ {'minversion': (3, 0)}),
'E0710': ('Raising a new style class which doesn\'t inherit from BaseException',
'raising-non-exception',
'Used when a new style class which doesn\'t inherit from \
@@ -109,12 +116,28 @@ class ExceptionsChecker(BaseChecker):
),
)
- @check_messages('W0701', 'W0710', 'E0702', 'E0710', 'E0711')
+ @check_messages('W0701', 'W0710', 'E0702', 'E0710', 'E0711',
+ 'bad-exception-context')
def visit_raise(self, node):
"""visit raise possibly inferring value"""
# ignore empty raise
if node.exc is None:
return
+ if PY3K and node.cause:
+ if isinstance(node.cause, astroid.Const):
+ if node.cause.value is not None:
+ self.add_message('bad-exception-context',
+ node=node)
+ else:
+ try:
+ cause = node.cause.infer().next()
+ except astroid.InferenceError:
+ pass
+ else:
+ if (not isinstance(cause, astroid.Class) and
+ not inherit_from_std_ex(cause)):
+ self.add_message('bad-exception-context',
+ node=node)
expr = node.exc
if self._check_raise_value(node, expr):
return
diff --git a/test/input/func_bad_exception_context_py30.py b/test/input/func_bad_exception_context_py30.py
new file mode 100644
index 0000000..b520e68
--- /dev/null
+++ b/test/input/func_bad_exception_context_py30.py
@@ -0,0 +1,17 @@
+"""Check that raise ... from .. uses a proper exception context """
+
+# pylint: disable=unreachable
+
+__revision__ = 0
+
+class ExceptionSubclass(Exception):
+ """ subclass """
+
+def test():
+ """ docstring """
+ raise IndexError from 1
+ raise IndexError from None
+ raise IndexError from ZeroDivisionError
+ raise IndexError from object()
+ raise IndexError from ExceptionSubclass
+
diff --git a/test/messages/func_bad_exception_context_py30.txt b/test/messages/func_bad_exception_context_py30.txt
new file mode 100644
index 0000000..0a4b3ec
--- /dev/null
+++ b/test/messages/func_bad_exception_context_py30.txt
@@ -0,0 +1,2 @@
+E: 12:test: Exception context set to something which is not an exception, nor None
+E: 15:test: Exception context set to something which is not an exception, nor None \ No newline at end of file