diff options
author | Claudiu Popa <pcmanticore@gmail.com> | 2015-09-04 01:53:07 +0300 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2015-09-04 01:53:07 +0300 |
commit | 20e9b6581038b21b13e6db6349a881027526ec3b (patch) | |
tree | bcc4991b04ae33bd5348d2581c3b725870a68578 | |
parent | e0a6f98dca977ee29d34690877da8220467bc030 (diff) | |
download | pylint-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-- | ChangeLog | 12 | ||||
-rw-r--r-- | pylint/checkers/exceptions.py | 35 |
2 files changed, 43 insertions, 4 deletions
@@ -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. |