Feature or enhancement
Proposal:
Currently, the ExceptionGroup API only supports sequences of exceptions to its second parameter excs.
This ticket suggests either:
- additively changing the API to support non-sequence iterables as inputs as well.
or
- documenting why only sequences are supported.
Currently, this Python code would work:
ExceptionGroup("list", [ValueError(), AttributeError()]) # OK
ExceptionGroup("tuple", (ValueError(), AttributeError())) # OK
class Niche:
def __getitem__(self, i):
if i == 0:
return ValueError()
if i == 1:
return AttributeError()
raise StopIteration
ExceptionGroup("niche", Niche()) # OK
Note
AFAIK, ExceptionGroup objects do not store the sequence passed to them, unless it's a tuple object (excluding tuple subclasses). They export a new tuple (created from the passed-in sequence) or passed-in tuple via .exceptions.
Quick illustration:
assert ExceptionGroup("", excs := [ValueError()]).exceptions is not excs # OK
assert ExceptionGroup("", excs := (ValueError(),)).exceptions is excs # OK
assert ExceptionGroup("", excs := type("", (tuple,), {})([ValueError(),])).exceptions is not excs # OK
This is a minimal example of a use case I would desire, which is not currently supported:
def cb1():
raise ValueError
def cb2():
raise AttributeError
errors = {}
callbacks = {"module1": cb1, "module2": cb2}
for mod, cb in callbacks.items():
try:
cb()
except Exception as exc:
errors[mod] = exc
if errors:
raise ExceptionGroup(f"got errors in {', '.join(errors)}", errors.values())
Important
While this can be simply worked around by converting the values' view into a sequence, the question is more fundamental: why?
There are some other variants of this on GitHub, too (including my humble one).
It was an intentional decision to only support sequences, justifying the very first part of the constructor test:
|
def test_bad_EG_construction__bad_excs_sequence(self): |
|
MSG = r'second argument \(exceptions\) must be a sequence' |
|
with self.assertRaisesRegex(TypeError, MSG): |
|
ExceptionGroup('errors not sequence', {ValueError(42)}) |
Before writing this issue, I did a research in some places that seemed like they could explain why only sequences made a cut. Namely, I:
I didn't have the time to read them very in depth, so I might have overlooked something; I only found this thread relevant:
Which leads me to think that supporting Iterable was initially planned (the author meant Iterable[Exception] instead of Iterable[ExceptionGroup]), but then implicitly ignored for the sake of predicted use cases only being with sequences (lists/tuples).
Please note that the considerations about variadic constructor of BaseExceptionGroup are not relevant to this ticket.
Before writing this, I also reached out to @ZeroIntensity and @Eclips4 to discuss the topic.
@Eclips4 confirmed that he saw no hard requirement for the exception sequence to be a sequence specifically, and applying this simple patch
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 154cde93168..f97eb33953f 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -871,7 +871,8 @@ BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
- if (!PySequence_Check(exceptions)) {
+ PyTypeObject *t = Py_TYPE(exceptions);
+ if (t->tp_iter == NULL) {
PyErr_SetString(
PyExc_TypeError,
"second argument (exceptions) must be a sequence");
only causes test_bad_EG_construction__bad_excs_sequence to fail.
CC @iritkatriel @gvanrossum @1st1
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response
Feature or enhancement
Proposal:
Currently, the
ExceptionGroupAPI only supports sequences of exceptions to its second parameterexcs.This ticket suggests either:
or
Currently, this Python code would work:
Note
AFAIK,
ExceptionGroupobjects do not store the sequence passed to them, unless it's a tuple object (excluding tuple subclasses). They export a new tuple (created from the passed-in sequence) or passed-in tuple via.exceptions.Quick illustration:
This is a minimal example of a use case I would desire, which is not currently supported:
Important
While this can be simply worked around by converting the values' view into a sequence, the question is more fundamental: why?
There are some other variants of this on GitHub, too (including my humble one).
It was an intentional decision to only support sequences, justifying the very first part of the constructor test:
cpython/Lib/test/test_exception_group.py
Lines 39 to 42 in 1bccd6c
Before writing this issue, I did a research in some places that seemed like they could explain why only sequences made a cut. Namely, I:
I didn't have the time to read them very in depth, so I might have overlooked something; I only found this thread relevant:
Which leads me to think that supporting
Iterablewas initially planned (the author meantIterable[Exception]instead ofIterable[ExceptionGroup]), but then implicitly ignored for the sake of predicted use cases only being with sequences (lists/tuples).Please note that the considerations about variadic constructor of
BaseExceptionGroupare not relevant to this ticket.Before writing this, I also reached out to @ZeroIntensity and @Eclips4 to discuss the topic.
@Eclips4 confirmed that he saw no hard requirement for the exception sequence to be a sequence specifically, and applying this simple patch
only causes
test_bad_EG_construction__bad_excs_sequenceto fail.CC @iritkatriel @gvanrossum @1st1
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response