Skip to content
This repository was archived by the owner on Apr 3, 2026. It is now read-only.

Commit ee15a32

Browse files
committed
Make error msg comptime and check call args types
1 parent af9cd1b commit ee15a32

1 file changed

Lines changed: 28 additions & 12 deletions

File tree

py.zig

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub inline fn errorSetObject(exc: *Object, value: *Object) void {
100100
// String formatting is done using zig's std.fmt.
101101
// Does not steal a reference to exc.
102102
// This uses the global python allocator to allocate the message
103-
pub inline fn errorFormat(exc: *Object, format: []const u8, args: anytype) Error!void {
103+
pub inline fn errorFormat(exc: *Object, comptime format: []const u8, args: anytype) Error!void {
104104
if (comptime args.len == 0) {
105105
c.PyErr_SetString(@ptrCast(exc), @ptrCast(format));
106106
return error.PyError;
@@ -112,51 +112,51 @@ pub inline fn errorFormat(exc: *Object, format: []const u8, args: anytype) Error
112112
}
113113

114114
// Helper that is the equivalent to `TypeError(msg)`
115-
pub inline fn typeError(msg: [:0]const u8, args: anytype) !void {
115+
pub inline fn typeError(comptime msg: [:0]const u8, args: anytype) !void {
116116
return errorFormat(@ptrCast(c.PyExc_TypeError), msg, args);
117117
}
118118

119-
pub inline fn typeErrorObject(comptime value: anytype, msg: [:0]const u8, args: anytype) @TypeOf(value) {
119+
pub inline fn typeErrorObject(comptime value: anytype, comptime msg: [:0]const u8, args: anytype) @TypeOf(value) {
120120
typeError(msg, args) catch {};
121121
return value;
122122
}
123123

124124
// Helper that is the equivalent to `SystemError(msg)`
125-
pub inline fn systemError(msg: [:0]const u8, args: anytype) !void {
125+
pub inline fn systemError(comptime msg: [:0]const u8, args: anytype) !void {
126126
return errorFormat(@ptrCast(c.PyExc_SystemError), msg, args);
127127
}
128128

129-
pub inline fn systemErrorObject(comptime value: anytype, msg: [:0]const u8, args: anytype) @TypeOf(value) {
129+
pub inline fn systemErrorObject(comptime value: anytype, comptime msg: [:0]const u8, args: anytype) @TypeOf(value) {
130130
systemError(msg, args) catch {};
131131
return value;
132132
}
133133

134134
// Helper that is the equivalent to `ValueError(msg)`
135-
pub inline fn valueError(msg: [:0]const u8, args: anytype) !void {
135+
pub inline fn valueError(comptime msg: [:0]const u8, args: anytype) !void {
136136
return errorFormat(@ptrCast(c.PyExc_ValueError), msg, args);
137137
}
138138

139-
pub inline fn valueErrorObject(comptime value: anytype, msg: [:0]const u8, args: anytype) @TypeOf(value) {
139+
pub inline fn valueErrorObject(comptime value: anytype, comptime msg: [:0]const u8, args: anytype) @TypeOf(value) {
140140
valueError(msg, args) catch {};
141141
return value;
142142
}
143143

144144
// Helper that is the equivalent to `AttributeError(msg)`
145-
pub inline fn attributeError(msg: [:0]const u8, args: anytype) !void {
145+
pub inline fn attributeError(comptime msg: [:0]const u8, args: anytype) !void {
146146
return errorFormat(@ptrCast(c.PyExc_AttributeError), msg, args);
147147
}
148148

149-
pub inline fn attributeErrorObject(comptime value: anytype, msg: [:0]const u8, args: anytype) @TypeOf(value) {
149+
pub inline fn attributeErrorObject(comptime value: anytype, comptime msg: [:0]const u8, args: anytype) @TypeOf(value) {
150150
attributeError(msg, args) catch {};
151151
return value;
152152
}
153153

154154
// Helper that is the equivalent to `KeyError(msg)`
155-
pub inline fn keyError(msg: [:0]const u8, args: anytype) !void {
155+
pub inline fn keyError(comptime msg: [:0]const u8, args: anytype) !void {
156156
return errorFormat(@ptrCast(c.PyExc_KeyError), msg, args);
157157
}
158158

159-
pub inline fn keyErrorObject(comptime value: anytype, msg: [:0]const u8, args: anytype) @TypeOf(value) {
159+
pub inline fn keyErrorObject(comptime value: anytype, comptime msg: [:0]const u8, args: anytype) @TypeOf(value) {
160160
keyError(msg, args) catch {};
161161
return value;
162162
}
@@ -412,6 +412,16 @@ pub inline fn canCastToOptionalObjectPtr(comptime T: type) bool {
412412
};
413413
}
414414

415+
// Check at comptime that a zig tuple of arguments can all be casted to *Object
416+
pub inline fn checkArgsAreObjects(comptime label: []const u8, args: anytype) void {
417+
inline for (args, 0..) |arg, i| {
418+
const ArgType = @TypeOf(arg);
419+
if (comptime !canCastToObject(ArgType)) {
420+
@compileError(std.fmt.comptimePrint("{s} args must be castable to *Object, got {} for argument {}", .{ label, ArgType, i }));
421+
}
422+
}
423+
}
424+
415425
// Object Protocol
416426
pub inline fn ObjectProtocol(comptime T: type) type {
417427
return struct {
@@ -772,7 +782,7 @@ pub inline fn ObjectProtocol(comptime T: type) type {
772782
}
773783

774784
// Format
775-
pub fn format(
785+
pub fn formatObject(
776786
self: *const T,
777787
comptime fmt: []const u8,
778788
options: std.fmt.FormatOptions,
@@ -788,6 +798,8 @@ pub inline fn ObjectProtocol(comptime T: type) type {
788798
try writer.print("{s}", .{s.data()});
789799
}
790800
}
801+
// Use custom format if defined
802+
pub const format = if (@hasDecl(T, "format")) T.format else formatObject;
791803

792804
// Add the mapping protocol
793805
pub usingnamespace MappingProtocol(T);
@@ -876,6 +888,7 @@ pub inline fn CallProtocol(comptime T: type) type {
876888
// Calls PyObject_CallNoArgs. PyObject_CallOneArg, or
877889
// Return the result of the call on success, or raise an exception and return NULL on failure.
878890
pub inline fn callArgsUnchecked(self: *T, args: anytype) ?*Object {
891+
checkArgsAreObjects("callArgs", args);
879892
return @ptrCast(switch (comptime args.len) {
880893
0 => c.PyObject_CallNoArgs(@ptrCast(self)),
881894
1 => c.PyObject_CallOneArg(@ptrCast(self), @ptrCast(args[0])),
@@ -919,6 +932,7 @@ pub inline fn CallProtocol(comptime T: type) type {
919932

920933
// Same as callMethod with no error checking
921934
pub inline fn callMethodUnchecked(self: *T, name: *Str, args: anytype) ?*Object {
935+
checkArgsAreObjects("callMethod", args);
922936
return @ptrCast(switch (comptime args.len) {
923937
0 => c.PyObject_CallMethodNoArgs(@ptrCast(self), @ptrCast(name)),
924938
1 => c.PyObject_CallMethodOneArg(@ptrCast(self), @ptrCast(name), @ptrCast(args[0])),
@@ -944,6 +958,7 @@ pub inline fn CallProtocol(comptime T: type) type {
944958
}
945959

946960
pub inline fn vectorCallUnchecked(self: *T, args: anytype, kwnames: ?*Object) ?*Object {
961+
checkArgsAreObjects("vectorCall", args);
947962
return @ptrCast(c.PyObject_Vectorcall(@ptrCast(self), args, args.len, kwnames));
948963
}
949964

@@ -955,6 +970,7 @@ pub inline fn CallProtocol(comptime T: type) type {
955970
}
956971

957972
pub inline fn vectorCallMethodUnchecked(self: *T, name: *Str, args: anytype, kwnames: ?*Object) ?*Object {
973+
checkArgsAreObjects("vectorCallMethod", args);
958974
return @ptrCast(c.PyObject_Vectorcall(@ptrCast(name), .{self} + args, args.len + 1, kwnames));
959975
}
960976
};

0 commit comments

Comments
 (0)