-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement B036 check for except BaseException
without re-raising
#438
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured Exception should maybe be a separate, optional one.
I agree here, this will be much more controversial.
It only checks for re-raises at the top-level of the except. I thought maybe checking all branches of of a complex except block to see they all re-raise might be overkill - WDYT?
I'm happy to start simple here and we can add to it if people complain about to much noise ... But covering as many re-raises as we can will be key.
So those would also need to be updated, and should probably change that wording - what do you think should be suggested instead? Or just "use a more specific exception" or something like that?
I'm happy with "please use a more specific exception" in the wording. Using BaseException shouldn't really be needed in any non core cpython/runtime libraries imo.
Please fix the unit tests. Did black break it?
@@ -195,6 +195,8 @@ second usage. Save the result to a list if the result is needed multiple times. | |||
|
|||
**B035**: Found dict comprehension with a static key - either a constant value or variable not from the comprehension expression. This will result in a dict with a single key that was repeatedly overwritten. | |||
|
|||
**B036**: Found ``except BaseException:`` without re-raising (no ``raise`` in the top-level of the ``except`` block). This catches all kinds of things (Exception, SystemExit, KeyboardInterrupt...) and may prevent a program from exiting as expected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also catch a bare except
here and error?
@@ -677,7 +683,7 @@ def check_for_b017(self, node): | |||
and item_context.func.id == "raises" | |||
and isinstance(item_context.func.ctx, ast.Load) | |||
and "pytest.raises" in self._b005_imports | |||
and "match" not in [kwd.arg for kwd in item_context.keywords] | |||
and "match" not in (kwd.arg for kwd in item_context.keywords) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just making tuples since they don't need to be immutable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually not a tuple, just parenthesizing the generator:
>>> x = [i for i in range(3)]
>>> x
[0, 1, 2]
>>> x = (i for i in range(3))
>>> x
<generator object <genexpr> at 0x0000021C2DFCAA80>
Just a tiny efficiency improvement, rather than having iterate the generator to construct a list, then iterate through the list to find the thing... just iterate the generator directly
try: | ||
pass | ||
except BaseException: # bad | ||
print("aaa") | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add and make this work easily? If not, no worries.
try: | |
pass | |
except BaseException: # bad | |
print("aaa") | |
pass | |
try: | |
pass | |
except: # bad | |
print("aaa") | |
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look like bare except already caught by both flake8 and bugbear:
try:
pass
except:
pass
gives both:
- B001 Do not use bare
except:
, it also catches unexpected events like memory errors, interrupts, system exit, and so on. Preferexcept Exception:
. If you're sure what you're doing, be explicit and writeexcept BaseException:
. - E722 do not use bare 'except'
Should this be consolidated with B001, rather than a new error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm - that's a good question. I'd like that, but I wonder if that would upset people?
I vote yes, but lets see if any other contributors / maintainers weigh in here ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess keeping separate also gives you the flexibility to enable/disable either one? Maybe that's the safer option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah ok, I like this now the more I think about it.
Oh I think the unittests broken currently because the B001 test is now throwing new B036 errors in addition to the expected ones. I might change the "good" examples in the B001 test to something other than |
Ok fixed up the unittests and wording. Regarding finding the re- I could imagine some weird intentional case where you might have something like except BaseException as e:
if ...:
raise e
else:
# don't raise WDYT? |
That sounds good to me for a first effort finding re-raises. Did you check out what flake8-trio did that was mention on the issue? Could maybe steal some logic. |
Took a look at it, seems like they're trying to check all paths. I just added a basic recursive search for a corresponding It ignores |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds a good start to me. Thanks for working through and iterating!
Started implementing this new check per #174
Currently just looking for
BaseException
- I figuredException
should maybe be a separate, optional one.It only checks for re-raises at the top-level of the except. I thought maybe checking all branches of of a complex
except
block to see they all re-raise might be overkill - WDYT?This does contradict the advice (and failing test-cases) of B001:
So those would also need to be updated, and should probably change that wording - what do you think should be suggested instead? Or just "use a more specific exception" or something like that?