Skip to content

Commit cd7c856

Browse files
committed
Make errors always throw error.PyError instead of return null
1 parent c3995e1 commit cd7c856

File tree

2 files changed

+24
-28
lines changed

2 files changed

+24
-28
lines changed

example/pyzigtest.zig

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ const Module = py.Module;
99
pub fn add(mod: *Module, args: [*]*Object, n: isize) ?*Object {
1010
_ = mod;
1111
if (n != 2) {
12-
return py.typeError("sum requires 2 arguments", .{});
12+
return py.typeError("sum requires 2 arguments", .{}) catch null;
1313
}
1414
// We can now safely access indexes 0 and 1
1515
if (!Int.check(args[0]) or !Int.check(args[1])) {
16-
return py.typeError("both arguments must be ints!", .{});
16+
return py.typeError("both arguments must be ints!", .{}) catch null;
1717
}
1818

1919
// We can now safely cast to Int objects and access their methods
@@ -47,10 +47,7 @@ pub export fn py_mod_exec(mod: *py.Module) c_int {
4747
// py.zig uses error.PyError for any error caught from the python c-api
4848
error.PyError => -1, // Python error
4949
// Any other errors need to set an error in python
50-
else => blk: {
51-
_ = py.systemError("module init failed", .{});
52-
break :blk -1;
53-
},
50+
else => py.systemError("module init failed", .{}) catch -1,
5451
};
5552
}
5653

py.zig

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub inline fn errorClear() void {
6363
// Call this function only when the error indicator is set.
6464
// Otherwise it will cause a fatal error!
6565
pub inline fn errorPrint() void {
66-
if (errorOccurred()) {
66+
if (errorOccurred()) |_| {
6767
errorPrintUnchecked();
6868
}
6969
}
@@ -89,43 +89,46 @@ pub inline fn errorSetObject(exc: *Object, value: *Object) void {
8989
// String formatting is done using zig's std.fmt.
9090
// Does not steal a reference to exc.
9191
// This uses the global python allocator to allocate the message
92-
pub inline fn errorFormat(exc: *Object, format: []const u8, args: anytype) ?*Object {
92+
pub inline fn errorFormat(exc: *Object, format: []const u8, args: anytype) Error!void {
9393
if (comptime args.len == 0) {
9494
c.PyErr_SetString(@ptrCast(exc), @ptrCast(format));
95-
return null;
95+
return error.PyError;
9696
}
9797
const data = std.fmt.allocPrint(allocator, format, args) catch {
9898
return memoryError(); // TODO: This squashes the error
9999
};
100100
defer allocator.free(data);
101101
// TODO: is there a way to avoid a copy?
102-
const msg = Str.fromSlice(data) catch return null;
102+
const msg = try Str.fromSlice(data); // TODO: This squashes the error
103103
defer msg.decref();
104104
c.PyErr_SetObject(@ptrCast(exc), @ptrCast(msg));
105-
return null;
105+
return error.PyError;
106106
}
107107

108108
// Helper that is the equivalent to `TypeError(msg)`
109-
pub inline fn typeError(msg: [:0]const u8, args: anytype) ?*Object {
109+
pub inline fn typeError(msg: [:0]const u8, args: anytype) !void {
110110
return errorFormat(@ptrCast(c.PyExc_TypeError), msg, args);
111111
}
112112

113+
113114
// Helper that is the equivalent to `SystemError(msg)`
114-
pub inline fn systemError(msg: [:0]const u8, args: anytype) ?*Object {
115+
pub inline fn systemError(msg: [:0]const u8, args: anytype) !void {
115116
return errorFormat(@ptrCast(c.PyExc_SystemError), msg, args);
116117
}
117118

118119
// Helper that is the equivalent to `ValueError(msg)`
119-
pub inline fn valueError(msg: [:0]const u8, args: anytype) ?*Object {
120+
pub inline fn valueError(msg: [:0]const u8, args: anytype) !void {
120121
return errorFormat(@ptrCast(c.PyExc_ValueError), msg, args);
121122
}
122123

123-
pub inline fn attributeError(msg: [:0]const u8, args: anytype) ?*Object {
124+
// Helper that is the equivalent to `AttributeError(msg)`
125+
pub inline fn attributeError(msg: [:0]const u8, args: anytype) !void {
124126
return errorFormat(@ptrCast(c.PyExc_AttributeError), msg, args);
125127
}
126128

127-
pub inline fn memoryError() ?*Object {
128-
return @ptrCast(c.PyErr_NoMemory());
129+
pub inline fn memoryError() !void {
130+
_ = c.PyErr_NoMemory();
131+
return error.PyError;
129132
}
130133

131134
// Clear a reference to **Object or *?*Object
@@ -467,8 +470,7 @@ pub inline fn ObjectProtocol(comptime T: type) type {
467470
pub inline fn iter(self: *T) !*Iter {
468471
if (self.iterUnchecked()) |r| {
469472
if (!Iter.check(r)) {
470-
_ = typeError("iter did not return an iterator", .{});
471-
return error.PyError;
473+
return typeError("iter did not return an iterator", .{});
472474
}
473475
return @ptrCast(r);
474476
}
@@ -486,7 +488,7 @@ pub inline fn ObjectProtocol(comptime T: type) type {
486488
return @ptrCast(s);
487489
}
488490
// Set an error message
489-
_ = typeError("str did not return a str", .{});
491+
return typeError("str did not return a str", .{});
490492
}
491493
return error.PyError;
492494
}
@@ -712,7 +714,7 @@ pub inline fn CallProtocol(comptime T: type) type {
712714
// Calls PyObject_CallNoArgs. PyObject_CallOneArg, or
713715
// Return the result of the call on success, or raise an exception and return NULL on failure.
714716
pub inline fn callArgsUnchecked(self: *T, args: anytype) ?*Object {
715-
return @ptrCast(switch (args.len) {
717+
return @ptrCast(switch (comptime args.len) {
716718
0 => c.PyObject_CallNoArgs(@ptrCast(self)),
717719
1 => c.PyObject_CallOneArg(@ptrCast(self), @ptrCast(args[0])),
718720
else => blk: {
@@ -754,7 +756,7 @@ pub inline fn CallProtocol(comptime T: type) type {
754756

755757
// Same as callMethod with no error checking
756758
pub inline fn callMethodUnchecked(self: *T, name: *Str, args: anytype) ?*Object {
757-
return @ptrCast(switch (args.len) {
759+
return @ptrCast(switch (comptime args.len) {
758760
0 => c.PyObject_CallMethodNoArgs(@ptrCast(self), @ptrCast(name)),
759761
1 => c.PyObject_CallMethodOneArg(@ptrCast(self), @ptrCast(name), @ptrCast(args[0])),
760762
else => blk: {
@@ -1297,8 +1299,7 @@ pub const Tuple = extern struct {
12971299
pub inline fn parseTyped(self: *Tuple, args: anytype) !void {
12981300
const n = try self.size();
12991301
if (n != args.len) {
1300-
_ = typeError("Expected {} arguments got {}", .{args.len, n}); // TODO: Better message
1301-
return error.PyError;
1302+
return typeError("Expected {} arguments got {}", .{args.len, n}); // TODO: Better message
13021303
}
13031304
inline for(args, 0..) |arg, i| {
13041305
const T = @TypeOf(arg);
@@ -1310,8 +1311,7 @@ pub const Tuple = extern struct {
13101311
const ArgType = @typeInfo(@typeInfo(T).Pointer.child).Pointer.child;
13111312
const obj = try self.get(i);
13121313
if (!ArgType.check(obj)) {
1313-
_ = typeError("Argument at {} must be {}", .{i, ArgType});
1314-
return error.PyError;
1314+
return typeError("Argument at {} must be {}", .{i, ArgType});
13151315
}
13161316
arg.* = @ptrCast(obj);
13171317
}
@@ -1372,8 +1372,7 @@ pub const Tuple = extern struct {
13721372
// Returns new reference
13731373
pub inline fn concat(a: *Tuple, b: *Tuple) !*Tuple {
13741374
if (!Tuple.checkExact(a) or !Tuple.checkExact(b)) {
1375-
_ = typeError("concat() both arguments must be tuples", .{});
1376-
return error.PyError;
1375+
return typeError("concat() both arguments must be tuples", .{});
13771376
}
13781377
const n1 = try a.size();
13791378
const n2 = try b.size();

0 commit comments

Comments
 (0)