Skip to content

Draft: bare except: capturing BaseException

Wout De Nolf requested to merge 3209-remove-bare-excepts-2 into master

Related to #3209

Absorbing a BaseException (including gevent.Timeout, gevent.GreenletExit, KeyboardInterrupt, ...) is only acceptable in these three cases:

  1. in the except of another BaseException

     try:
         ...
     except BaseException:
         try:
             ...
         except BaseException:
             pass  # to avoid masking the first base exception
         raise
  2. at the end of a function which you are sure is a greenlet main

     def greenlet_main():
         try:
             ...
         except gevent.hub.Hub.SYSTEM_ERROR:
             raise  # needs to be re-raise in the main greenlet
         except BaseException:
             pass   # avoid logging/printing of this exception

    Note: exceptions from greenlets are handled in Hub.handle_error (optionally logs/prints and absorb or re-raises in the main greenlet)

    • Hub.SYSTEM_ERROR: re-raise in main greenlet
    • Hub.NOT_ERROR: not logged/printed

    Whether it is a good idea to avoid logging/printing is another matter.

  3. at the end of a process main

     def main():
         try:
             ...
         except KeyboardInterrupt:
             pass   # avoid printing of this exception

In fact the first pattern is mandatory imo when capturing a BaseException:

    try:
        ...
    except BaseException:
        ...  # this should never raise any exception
        raise

This would also apply to a try ... finally. Hmmm not sure ...

def func():
    try:
        raise KeyboardInterrupt
    finally:
        raise RuntimeError("my cleanup raises an error")
        raise

try:
    func()
except Exception:
    print("O o we have a problem")

A real CTRL-C would stop the process though so I suppose it's fine ...

Edited by Wout De Nolf

Merge request reports