PEP 760 – No More Bare Excepts

:bangbang:Update: We have decided to withdraw the PEP as the consensus is that the benefits doesn’t justify the cost

———-

:wave: Hi everyone,

As the evil twin of PEP 758: Allow `except` and `except*` expressions without parentheses, @brettcannon and me present you PEP 760: No more bare excepts.

This PEP proposes disallowing bare except: clauses in Python’s exception-handling syntax. Currently, Python allows catching all exceptions with a bare except: clause, which can lead to overly broad exception handling and mask important errors. This PEP suggests requiring explicit exception types in all except clauses, promoting more precise and intentional error handling.

Please review the entire document before commenting as it contains several aspects of how to address the deprecation, tooling, rejected ideas and more.

Vote in this poll:

5 Likes

I know this is off-topic for this thread, but I raised this as an issue with the PEP 760 PR (the PEP itself hasn’t been published yet). I haven’t had time to look at the response from the PEP authors, but I would really like to preserve bare-except with an unconditional raise use case. If that can’t be done, I suggested an alias for BaseException called AnyException so at least the modified code would read better:

try:
    something()
except:
     transaction.abort()
     raise
else:
     transaction.commit()

would become

try:
    something()
except AnyException:
     transaction.abort()
     raise
else:
     transaction.commit()
6 Likes

Can I ask why? I don’t find that any clearer than except BaseException, and if you are using that pattern I feel you should understand what you’re doing. As such, I don’t think learning what BaseException means is too much to ask.

It’s the comma in the appropriate contex; not every comma makes a tuple, but you can’t syntactically make a tuple without a comma.

4 Likes

BaseException exposes the fact that it’s the root class in the exception hierarchy, and you have to connect that mentally to the fact that a) Python requires all exceptions to derive from it, and b) that pattern means “catch any exception”. The latter just makes that obvious. It’s obvious to us of course either way.

For me, I’d still prefer to allow a bare except if there’s an explicit empty raise in the body.

7 Likes

Ideally if you want to intercept an exception and pass it through, you would do it will finally:

It would be nice to not have to use sys. What if we added an option to bind the exception in a finally block, as in:

try:
    raise Exception("Hello")
finally e:
    if e is not None:
        e.add_note("World")
4 Likes

I don’t think that handles the original use case: abort an in-progress transaction and re-raise when any exception occurs, and commit the transaction if no exception occurs.

1 Like
try:
    transaction
finally e:
    if e is None:
         commit
    else:
         abort
2 Likes

I do wonder, is there a point to removing bare excepts just to re-introduce them with new syntax in finally blocks?

But presumably this is a discussion for the PEP 760 thread, when it arrives.

6 Likes

The finally block is not a bare except. It doesn’t suppress exceptions.

5 Likes

Now there’s an interesting idea: don’t make bare except illegal, make it have an implicit raise at the end (and disallow return, break, and continue).

We’re well and truly off-topic for this thread, though… (comment was moved to a thread where it is on-topic)

4 Likes

As an alternative to my finally suggestion? I don’t think it would be coherent if except sometimes eats the exception and sometimes not.

Should we take this to another thread? Are the moderators able to move the comments on this subtopic to a new thread?

1 Like

I have moved the relevant comments from PEP 758: Allow `except` and `except*` expressions without parentheses - #55 by pablogsal that pertain this discussion. Please flag any potential mistakes in the operation as discourse made this quite complex.

1 Like

I like the proposal, except that the bare-except-with-unconditional-bare-raise pattern:

except:
    <here cleanup / rollback / context-relevant log...>
    raise

– is IMHO too convenient (also when it comes to reading the code) to get rid of.

For me, the necessity to make it more verbose would be a clear loss.

3 Likes

+1 to keeping bare except: with raise.
For better or worse, it’s correct, idiomatic code; the “Motivation” reasons don’t really apply to it.
pylint and ruff allow this, and the the style guides their docs link to (PEP-8 and the Google style guide) also mention that it’s OK. (flake8 does flag it, though, and some of the other guides don’t list the exception.)
And unlike finally e: or implicit raise, the existing syntax is compatible with Python 1.0+.

It would make the implementation harder, though.

5 Likes

Although it’s straightforward the implementation would be quite verbose as this implies doing an entire ast visitor just to detect raises below the bare except (in C).

The task becomes much simpler if we restrict it to detecting raises only at the same level of nesting but that feels somewhat odd.

I think this is an interesting case but you could skip all of this by just doing except BaseException and then all is good.

Implicit raise is also compatible (or well just as compatible as mandatory raise inside bare except block).

This breaks so much existing code. Does the benefit outweigh this? IMHO it’s OK to emit warnings left and right, but outright rejecting bare excepts after just 3 releases of deprecation period seems… not cool. Please, be more conservative with breaking backward compatibility of the basic language. This is not an API of one standard library module, this is the Python language itself.

34 Likes

I think that a reasonable approach would be to require that a bare except block:

  • must not contain return, break or continue (at any level of nesting, except in nested defs)
  • must contain raise at its top-level (open question: should only a bare raise or any raise... be required?)
1 Like

I think requiring this is reasonable but I am uncomfortable with the maintenance consequences of having to keep an entire visitor just for restricting this too much. The exception also feels slightly odd to communicate when really we can avoid all of this by just writing except BaseException

2 Likes

How many releases you think its reasonable?