4. Raising#
Every helper sets the exception and returns error.PythonError, so a binding writes return py.raise.... Below: the call: what it raises.
py.raiseTypeError(fmt, args),raiseValueError,raiseIndexError,raiseRuntimeError: that built-in, with a formatted messageraiseOverflowError,raiseNotImplementedError,raiseAttributeError(the same): (up to 511 bytes, cut after that)py.raise(c.PyExc_ZeroDivisionError, fmt, args): anyc.PyExc_*py.raiseErrno(errno):OSError(errno, strerror); CPython picks the subclass (FileNotFoundError, ...)try py.checkErrno(res):reswhen>= 0, elseOSErrorfor the errno-res;resis any signed intpy.raiseOSError(errno, fmt, args):OSError(errno, msg)with your messagepy.raiseWith(exc, .{ errno, "msg" }):exc(*args), each item converted like a resultpy.raiseNoMemory():MemoryError(a failed Zig allocation)MyError.raise(fmt, args),MyError.raiseWith(.{...}): an exception class of the extension (below)py.setError(err): any Zig error as a Python exception (what the trampolines do for you)
An exception class of the extension, found by the scan under the pub const's name, __module__ the extension's:
/// An `OSError` of the extension's own: `ExtraError(errno, msg)` sets `.errno` / `.strerror`. pub const ExtraError = setu.Exception(.{ .doc = "An `OSError` of the extension's own: `ExtraError(errno, msg)` sets `.errno` / `.strerror`.", .base = .OSError, // a `c.PyExc_*` name; default `.Exception` }); /// A plain `Exception` subclass. pub const PlainError = setu.Exception(.{ .doc = "A plain `Exception` subclass." }); /// Raises `ExtraError(errno, msg)` (`raiseWith`). pub fn raise_extra(errno: i32, msg: []const u8) Error!void { return ExtraError.raiseWith(.{ errno, msg }); // `.errno` set, like `OSError` } /// Raises `PlainError` with a formatted message (`raise`). pub fn raise_plain(n: i64) Error!void { return PlainError.raise("plain {d}", .{n}); } /// Is `exc` a `PlainError` (an instance or the class, or a subclass)? (`matches`) pub fn is_plain(exc: *c.Object) bool { return PlainError.matches(exc); }
In Python:
>>> from pkg import ExtraError, PlainError, is_plain, raise_extra, raise_plain >>> raise_extra(95, 'not here') Traceback (most recent call last): ... pkg.ExtraError: [Errno 95] not here >>> try: ... raise_extra(2, 'gone') ... except OSError as e: # the base catches it ... e.errno, e.strerror (2, 'gone') >>> raise_plain(3) Traceback (most recent call last): ... pkg.PlainError: plain 3 >>> is_plain(PlainError('x')), is_plain(ValueError()) (True, False)
Two setu.Exceptions with the same doc and base are one Zig type: give each its own doc.