Submodules¶
PyOZ supports creating nested module structures, allowing you to organize your API hierarchically (e.g., mymodule.math.sqrt()).
Creating Submodules¶
Use .module_init to add submodules during module initialization:
fn setupSubmodules(module: *pyoz.PyObject) callconv(.c) c_int {
const mod = pyoz.Module{ .ptr = module };
_ = mod.createSubmodule("math", "Math utilities", &math_methods) catch return -1;
_ = mod.createSubmodule("io", "I/O utilities", &io_methods) catch return -1;
return 0;
}
pub const MyModule = pyoz.module(.{
.name = "mymodule",
.module_init = &setupSubmodules,
// ...
});
Defining Submodule Methods¶
Create a method array with pyoz.methodDef() and terminate with pyoz.methodDefSentinel():
fn math_sqrt(x: f64) !f64 {
if (x < 0) return error.NegativeValue;
return @sqrt(x);
}
fn math_pow(base: f64, exp: f64) f64 {
return std.math.pow(f64, base, exp);
}
var math_methods = [_]pyoz.PyMethodDef{
pyoz.methodDef("sqrt", &pyoz.wrapFunc(math_sqrt), "Square root"),
pyoz.methodDef("pow", &pyoz.wrapFunc(math_pow), "Power"),
pyoz.methodDefSentinel(), // Required terminator
};
API Reference¶
| Function | Description |
|---|---|
pyoz.methodDef(name, fn, doc) |
Create method definition |
pyoz.methodDefSentinel() |
Required null terminator |
pyoz.wrapFunc(fn) |
Wrap Zig function for submodule use |
mod.createSubmodule(name, doc, methods) |
Create and attach submodule |
Usage in Python¶
import mymodule
from mymodule import math
# Via parent module
mymodule.math.sqrt(16) # 4.0
# Direct import
math.pow(2, 10) # 1024.0
Complete Example¶
const std = @import("std");
const pyoz = @import("PyOZ");
// Main module
fn version() []const u8 { return "1.0.0"; }
// Math submodule functions
fn math_sqrt(x: f64) !f64 {
if (x < 0) return error.NegativeValue;
return @sqrt(x);
}
var math_methods = [_]pyoz.PyMethodDef{
pyoz.methodDef("sqrt", &pyoz.wrapFunc(math_sqrt), "Square root"),
pyoz.methodDefSentinel(),
};
fn setupSubmodules(module: *pyoz.PyObject) callconv(.c) c_int {
const mod = pyoz.Module{ .ptr = module };
_ = mod.createSubmodule("math", "Math functions", &math_methods) catch return -1;
return 0;
}
pub const MyLib = pyoz.module(.{
.name = "mylib",
.module_init = &setupSubmodules,
.funcs = &.{ pyoz.func("version", version, "Get version") },
});
Auto-Scan Alternative¶
If you're using the .from API, you can create submodules declaratively with pyoz.sub() instead of writing manual init code:
const string_utils = @import("string_utils.zig");
const io_utils = @import("io_utils.zig");
pub const Example = pyoz.module(.{
.name = "example",
.from = &.{
math,
pyoz.sub("strings", string_utils),
pyoz.sub("io", io_utils),
},
});
All public functions, classes, enums, and constants in the namespace are auto-registered into the submodule. Submodule docstrings come from a pub const __doc__ in the namespace. You can also combine pyoz.sub() with pyoz.source() for filtering.
See Auto-Scan (.from) for the full guide.
Next Steps¶
- Auto-Scan (.from) - Declarative submodules with
pyoz.sub() - Stubs - Type stub generation
- Functions - Function definitions