Currently, errors are raised (exclusively?) as Err exceptions (parallel to Rust's Err variant of its Result type), and the caller must pick them apart manually using isinstance() or similar:
try:
result = await_request(pending_request)
except Err as exc:
if isinstance(exc.value, Error_OptionalNone):
# There were no more requests within the timeout.
break
else:
# Something truly went wrong.
raise
else:
# Do the no-error case.
This should be shortenable to:
try:
result = await_request(pending_request)
except NoRequestError as exc:
break
else:
# Do the no-error case.
(This may not be the most motivating example, since await_request() should perhaps return None when there is no request. However, it serves to illustrate the form.)
Result is currently defined as Union[Ok[T], Err[E]]. It seems to me that we can achieve an idiomatic and lossless mapping onto Python's result/exception duality by having Result-returning functions raise E xor return T.
Note that currently we raise the entire Err(E), not merely E, necessitating further unpacking. I don't think it brings any benefit, since E is the only thing in the Err:
@dataclass(frozen=True)
class Err(Generic[E], Exception):
value: E
A notable speed bump is that the current error classes are root classes, not subclasses of BaseException, as is required for catching them.
@dataclass
class Error_OptionalNone:
pass
However, it appears the binding generator is aware those are errors…
Error = Union[Error_GenericError, Error_InvalidArgument, Error_BadHandle, Error_BufferLen, Error_Unsupported, Error_HttpInvalid, Error_HttpUser, Error_HttpIncomplete, Error_OptionalNone, Error_HttpHeadTooLarge, Error_HttpInvalidStatus, Error_LimitExceeded]
…so perhaps the fix is straightforward.
For completeness and in case fixing it closer to the source proves intractable: decorating Result-returning functions with one that catches any Err, unpacks it, and re-raises its E would domesticate them sufficiently. (The BaseException speed bump would still need to be solved first.)
Currently, errors are raised (exclusively?) as
Errexceptions (parallel to Rust'sErrvariant of itsResulttype), and the caller must pick them apart manually usingisinstance()or similar:This should be shortenable to:
(This may not be the most motivating example, since
await_request()should perhaps returnNonewhen there is no request. However, it serves to illustrate the form.)Resultis currently defined asUnion[Ok[T], Err[E]]. It seems to me that we can achieve an idiomatic and lossless mapping onto Python's result/exception duality by havingResult-returning functions raiseExor returnT.Note that currently we raise the entire
Err(E), not merelyE, necessitating further unpacking. I don't think it brings any benefit, sinceEis the only thing in theErr:A notable speed bump is that the current error classes are root classes, not subclasses of
BaseException, as is required for catching them.However, it appears the binding generator is aware those are errors…
…so perhaps the fix is straightforward.
For completeness and in case fixing it closer to the source proves intractable: decorating
Result-returning functions with one that catches anyErr, unpacks it, and re-raises itsEwould domesticate them sufficiently. (TheBaseExceptionspeed bump would still need to be solved first.)