Home > other >  except* fails on unhashable exceptions - documented behaviour or a bug?
except* fails on unhashable exceptions - documented behaviour or a bug?

Time:11-07

Consider the following code block:

class MyException(Exception):
    __hash__ = None

try:
    raise ExceptionGroup("Foo", [
        MyException("Bar")
    ])
except* Exception:
    pass

The except* should catch any number of exceptions of any kind, thrown together as an ExceptionGroup (or a single exception of any kind if thrown alone, come to that). Instead, an unhandled TypeError occurs during handling of our ExceptionGroup, allegedly at "line -1" of our module:

    Exception Group Traceback (most recent call last):
  |   File "C:\Users\Josep\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_62.py", line 6, in <module>
  |     raise ExceptionGroup("Foo", [
  | ExceptionGroup: Foo (1 sub-exception)
   - ---------------- 1 ----------------
    | MyException: Bar
     ------------------------------------

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Josep\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_62.py", line -1, in <module>
TypeError: unhashable type: 'MyException'

(If we replace the except* Exception with something more specific, say except* ValueError or except* MyException, the same thing happens. If we try to just raise a single MyException and catch it normally with except MyException, that works fine.)

Normal except clauses don't care whether exceptions are hashable. I could not find this quirk of except* documented in PEP-654 or the Python 3.11 release notes. Is this intended behavior, or is it simply a bug in the Python implementation I'm using?

(For those who want to reproduce this behavior, I'm using Python 3.11.0, 64-bit, on Windows.)

CodePudding user response:

This was reported at https://github.com/python/cpython/issues/99181 and we have a PR to fix it. Should be fixed in 3.11.1.

CodePudding user response:

I wouldn't really call it a bug; it's the programmer fault for breaking the promise Exception class makes (implementing __hash__ method); therefore it's programmer who is responsible for making sure things work as intended after doing this. After all, would you call following snippet a "bug" or "programmer mistake"?

class MyInt(int):
    __hash__ = None

d = {}
d[MyInt(2)] = 2 # TypeError: unhashable type: 'MyInt'

Yours example isn't much different.

  • Related