summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-09-04 01:53:07 +0300
committerClaudiu Popa <pcmanticore@gmail.com>2015-09-04 01:53:07 +0300
commit20e9b6581038b21b13e6db6349a881027526ec3b (patch)
treebcc4991b04ae33bd5348d2581c3b725870a68578
parente0a6f98dca977ee29d34690877da8220467bc030 (diff)
downloadpylint-20e9b6581038b21b13e6db6349a881027526ec3b.tar.gz
Add a new error, 'misplaced-bare-raise'.
The error is used when a bare raise is not used inside a try suite. This can generate a RuntimeError in Python, if there are no active exceptions to be reraised. While it works in Python 2 due to the fact that the exception leaks outside of the except block, it's nevertheless a behaviour that an user shouldn't depend upon, since it's not obvious to the reader of the code what exception will be raised and it will not be compatible with Python 3 anyhow. Closes issue #633.
-rw-r--r--ChangeLog12
-rw-r--r--pylint/checkers/exceptions.py35
2 files changed, 43 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 8fcb2ea..8678b84 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -264,7 +264,17 @@ ChangeLog for Pylint
* --comment flag is obsoleted and it will be removed in Pylint 1.6.
* --profile flag is obsoleted and it will be removed in Pylint 1.6.
-
+
+ * Add a new error, 'misplaced-bare-raise'.
+
+ The error is used when a bare raise is not used inside a try suite.
+ This can generate a RuntimeError in Python, if there are no active exceptions
+ to be reraised. While it works in Python 2 due to the fact that the exception
+ leaks outside of the except block, it's nevertheless a behaviour that
+ an user shouldn't depend upon, since it's not obvious to the reader of the code
+ what exception will be raised and it will not be compatible with Python 3 anyhow.
+ Closes issue #633.
+
2015-03-14 -- 1.4.3
diff --git a/pylint/checkers/exceptions.py b/pylint/checkers/exceptions.py
index 00bd214..3a11401 100644
--- a/pylint/checkers/exceptions.py
+++ b/pylint/checkers/exceptions.py
@@ -79,6 +79,14 @@ MSGS = {
'where the exception context is not an exception, '
'nor None.',
{'minversion': (3, 0)}),
+ 'E0704': ('The raise statement is not inside a try suite',
+ 'misplaced-bare-raise',
+ 'Used when a bare raise is not used inside a try suite. '
+ 'This generates an error, since there are no active exceptions '
+ 'to be reraised. An exception to this rule is represented by '
+ 'a bare raise inside a finally clause, which might work, as long '
+ 'as an exception is raised inside the try block, but it is '
+ 'nevertheless a code smell that must not be relied upon.'),
'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 \
@@ -140,13 +148,13 @@ class ExceptionsChecker(BaseChecker):
self.builtin_exceptions = _builtin_exceptions()
super(ExceptionsChecker, self).open()
- @check_messages('nonstandard-exception',
+ @check_messages('nonstandard-exception', 'misplaced-bare-raise',
'raising-bad-type', 'raising-non-exception',
'notimplemented-raised', 'bad-exception-context')
def visit_raise(self, node):
- """visit raise possibly inferring value"""
- # ignore empty raise
+ """visit raise possibly inferring value"""
if node.exc is None:
+ self._check_misplaced_bare_raise(node)
return
if PY3K and node.cause:
self._check_bad_exception_context(node)
@@ -161,6 +169,27 @@ class ExceptionsChecker(BaseChecker):
return
self._check_raise_value(node, value)
+ def _check_misplaced_bare_raise(self, node):
+ # Filter out if it's present in __exit__.
+ scope = node.scope()
+ if (isinstance(scope, astroid.FunctionDef)
+ and scope.is_method()
+ and scope.name == '__exit__'):
+ return
+
+ current = node
+ # Stop when a new scope is generated or when the raise
+ # statement is found inside a TryFinally.
+ ignores = (astroid.ExceptHandler, astroid.TryExcept,
+ astroid.FunctionDef, astroid.TryFinally)
+ while current and not isinstance(current.parent, ignores):
+ current = current.parent
+
+ expected = (astroid.ExceptHandler, astroid.TryExcept)
+ if (not current
+ or not isinstance(current.parent, expected)):
+ self.add_message('misplaced-bare-raise', node=node)
+
def _check_bad_exception_context(self, node):
"""Verify that the exception context is properly set.