You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Return types for (Base)ExceptionGroup.derive(), .subgroup(), and .split() should not use Self #9219
I only mostly stick to runtime evil tricks, good to be here 😁
That all sounds good; just note under the derive examples that when b = BaseExceptionGroup('m', [ValueError()])b is an instance of ExceptionGroup due to the unusual nature of BaseExceptionGroup.__new__! In fact that should maybe be added as an overload, though it gets tricky thinking through the subclasses...🤔
staticPyObject*BaseExceptionGroup_new(PyTypeObject*type, PyObject*args, PyObject*kwds)
{
struct_Py_exc_state*state=get_exc_state();
PyTypeObject*PyExc_ExceptionGroup=
(PyTypeObject*)state->PyExc_ExceptionGroup;
PyObject*message=NULL;
PyObject*exceptions=NULL;
if (!PyArg_ParseTuple(args,
"UO:BaseExceptionGroup.__new__",
&message,
&exceptions)) {
returnNULL;
}
if (!PySequence_Check(exceptions)) {
PyErr_SetString(
PyExc_TypeError,
"second argument (exceptions) must be a sequence");
returnNULL;
}
exceptions=PySequence_Tuple(exceptions);
if (!exceptions) {
returnNULL;
}
/* We are now holding a ref to the exceptions tuple */Py_ssize_tnumexcs=PyTuple_GET_SIZE(exceptions);
if (numexcs==0) {
PyErr_SetString(
PyExc_ValueError,
"second argument (exceptions) must be a non-empty sequence");
goto error;
}
boolnested_base_exceptions= false;
for (Py_ssize_ti=0; i<numexcs; i++) {
PyObject*exc=PyTuple_GET_ITEM(exceptions, i);
if (!exc) {
goto error;
}
if (!PyExceptionInstance_Check(exc)) {
PyErr_Format(
PyExc_ValueError,
"Item %d of second argument (exceptions) is not an exception",
i);
goto error;
}
intis_nonbase_exception=PyObject_IsInstance(exc, PyExc_Exception);
if (is_nonbase_exception<0) {
goto error;
}
elseif (is_nonbase_exception==0) {
nested_base_exceptions= true;
}
}
PyTypeObject*cls=type;
if (cls==PyExc_ExceptionGroup) {
if (nested_base_exceptions) {
PyErr_SetString(PyExc_TypeError,
"Cannot nest BaseExceptions in an ExceptionGroup");
goto error;
}
}
elseif (cls== (PyTypeObject*)PyExc_BaseExceptionGroup) {
if (!nested_base_exceptions) {
/* All nested exceptions are Exception subclasses, * wrap them in an ExceptionGroup */cls=PyExc_ExceptionGroup;
}
}
else {
/* Do nothing - we don't interfere with subclasses */
}
if (!cls) {
/* Don't crash during interpreter shutdown * (PyExc_ExceptionGroup may have been cleared) */cls= (PyTypeObject*)PyExc_BaseExceptionGroup;
}
PyBaseExceptionGroupObject*self=_PyBaseExceptionGroupObject_cast(BaseException_new(cls, args, kwds));
if (!self) {
goto error;
}
self->msg=Py_NewRef(message);
self->excs=exceptions;
return (PyObject*)self;
error:
Py_DECREF(exceptions);
returnNULL;
}
.. method:: subgroup(condition)
Returns an exception group that contains only the exceptions from the
current group that match *condition*, or ``None`` if the result is empty.
The condition can be either a function that accepts an exception and returns
true for those that should be in the subgroup, or it can be an exception type
or a tuple of exception types, which is used to check for a match using the
same check that is used in an ``except`` clause.
Ok, this is quite tricky. This function is firstly called with ExceptionGroup itself.
Then it is called with exceptions only if the first call returned False. If the first call returns True, it is not called anymore.
Activity
sobolevn commentedon Nov 17, 2022
Hi @Zac-HD! Glad to see you in typing-land! 👋
Related PRs:
Yes, looks like
Selfcontract is not always respected. Examples:split
Selfis only preserved when no split happens in the left part (I think it is not really important, we can always useExceptionGroup).derive
I cannot find a case, where
Selfis preserved.subgroup
So, it can either be
NoneorExceptionGrouporMyGroup: so we can go withExceptionGroup.I would like to work on it, if no one has objections.
Zac-HD commentedon Nov 17, 2022
I only mostly stick to runtime evil tricks, good to be here 😁
That all sounds good; just note under the derive examples that when
b = BaseExceptionGroup('m', [ValueError()])bis an instance ofExceptionGroupdue to the unusual nature ofBaseExceptionGroup.__new__! In fact that should maybe be added as an overload, though it gets tricky thinking through the subclasses...🤔sobolevn commentedon Nov 17, 2022
I will take a look, I've missed this part. Thanks!
sobolevn commentedon Nov 17, 2022
For the record:
sobolevn commentedon Nov 17, 2022
Looks like I found a bug in
ExceptionGroup.subgroup:Notice that
pis called:TypeErrorandOSError)ExceptionGroupinstanceWhile the docs say:
sobolevn commentedon Nov 17, 2022
The same happens with
.split:sobolevn commentedon Nov 17, 2022
Ok, this is quite tricky. This function is firstly called with
ExceptionGroupitself.Then it is called with exceptions only if the first call returned
False. If the first call returnsTrue, it is not called anymore.AlexWaygood commentedon Nov 23, 2022
Has this been resolved by #9230, or is there more still to do?
sobolevn commentedon Nov 23, 2022
I think so! (I cannot close issues, please send help 😆 )
Thanks, @Zac-HD, for the report!
AlexWaygood commentedon Nov 23, 2022
Yes, thanks @Zac-HD for the report and thanks @sobolevn for the fix! If there's any further problems, please feel free to report them!
Zac-HD commentedon Nov 23, 2022
Happy to help, and I will!