github pyozig/PyOZ v0.9.0
PyOZ v0.9.0

latest releases: v0.12.2, v0.12.1, v0.12.0...
6 months ago

What's New in v0.9.0

Added

  • module-name config option - New [tool.pyoz] field that decouples the native .so name from the pip package name. Set module-name = "_mypackage" to produce _mypackage.so, allowing a Python wrapper package with the same base name (e.g., mypackage/) to coexist. This enables the standard Python pattern used by _sqlite3/sqlite3, _json/json, etc.
  • include-ext config option - New [tool.pyoz] field to control which file extensions are included from py-packages directories. Defaults to ["py"] for backwards compatibility. Set ["*"] to include all files, or list specific extensions like ["py", "zig", "json"]. Useful for packaging template files, data files, or other non-Python assets alongside your Python code.
  • Module.toPy() / Module.fromPy() - Module types now expose class-aware converters. Use Module.toPy(MyClass, instance) to convert registered class instances to Python objects when building raw Python containers (lists, dicts) manually. Unlike pyoz.Conversions (which has no class knowledge), the module converter knows about all registered classes and can wrap them into proper Python wrapper objects. Also exposes Module.ClassConverter for direct access to the full converter type.
  • Stub method__returns__ convention - Declare pub const children__returns__: []const u8 = "list[Node]" on a class struct to override the return type annotation in generated .pyi stubs. Useful for methods returning ?*pyoz.PyObject where the concrete Python type is known to the developer.
  • Stub method__params__ convention - Declare pub const find__params__: []const u8 = "rule_name" on a class struct to override parameter names in generated .pyi stubs. Accepts comma-separated names (excluding self). Falls back to arg0, arg1, ... when not declared. Needed because Zig's @typeInfo does not expose function parameter names.

Fixed

  • Stub generator: duplicate class for exception+class - When a type was registered as both a class and an exception (e.g., ParseError), the stub generator emitted two separate class definitions. Now they are merged into a single class ParseError(Exception): definition with all methods, properties, and the class docstring.
  • Stub generator: dunder return types were Any - Magic methods like __iter__, __next__, __getitem__, __call__, __enter__ used hardcoded Any return types. Now they introspect the actual Zig function signatures: __iter__ returns Iterator[Element], __next__ unwraps the optional to the element type, __getitem__ shows the actual key and value types, __enter__ resolves to the class name when returning *Self, and __call__ introspects its full signature.
  • Stub generator: class __doc__ was placeholder - Class docstrings declared via pub const __doc__ were detected but emitted as """...""" instead of the actual content. Now the full docstring text is propagated to the .pyi file.
  • Stub generator: method docstrings were ignored - Method docstrings declared via pub const method__doc__ (e.g., magnitude__doc__) were explicitly skipped during stub generation. Now they are emitted as Python docstrings in the generated .pyi file.
  • get_* property scanner treated non-functions as getters - The computed property system (properties.zig) and stub generator (stubs.zig) scanned for get_* declarations but didn't verify they were functions. Declarations like get_error__doc__ (a [*:0]const u8 docstring for a get_error method) were misinterpreted as computed property getters, causing "type '[*:0]const u8' not a function" errors. Both scanners now skip non-function get_* declarations.
  • __repr__/__str__ use-after-free - Fixed a memory safety bug where returning []const u8 from a stack-local bufPrint buffer in __repr__ or __str__ caused undefined behavior. The callee's stack frame was destroyed before PyOZ could copy the data into a Python string. Both methods now support a buffered signature fn __repr__(self: *const T, buf: []u8) []const u8 where PyOZ provides a 4096-byte buffer that stays alive through the toPy call. The legacy 1-parameter signature still works for string literals.
  • raiseValueError and friends required comptime or inline - Removed unnecessary comptime qualifier from the message parameter on all raise functions (raiseValueError, raiseTypeError, raiseException, custom raise, etc.). The comptime restriction prevented calling these from non-inline contexts and added no value since PyErr_SetString is a runtime C call. String literals still work as before; runtime strings are now also accepted.
  • Slot-handled dunders double-registered as methods - The method table generator (methods.zig) was registering protocol dunders like __repr__, __str__, __hash__, __add__, etc. as regular Python methods in addition to their protocol slots. This caused compilation errors when the dunder's signature didn't match the regular method wrapper expectations (e.g., the new buffered __repr__ with []u8 parameter). Now only slot-handled dunders are excluded; other dunders like __enter__, __exit__, and __missing__ still pass through to the method table as intended.
  • pyoz init remote fingerprint generation - Previously, pyoz init (without --local) generated a random fingerprint for build.zig.zon that Zig would reject on first build, requiring manual fix-ups. Now both local and remote paths use the same strategy: write without fingerprint, run zig build, and patch with the suggested value. Extracted shared patchFingerprint helper used by both code paths.

Documentation

  • Raw *pyoz.PyObject as return type - Documented that *pyoz.PyObject works as both parameter and return type in class methods. Added examples for building and returning raw Python objects from Zig methods.
  • One-liner raise pattern - Documented that raiseValueError() and friends return Null, enabling return pyoz.raiseValueError("msg") as a one-liner in any function returning an optional type.
  • GC __traverse__/__clear__ example - Added a complete code example showing correct signatures (c_int return, by-value GCVisitor), visitor return value checking, and Py_DecRef cleanup in __clear__.

Installation

Download the binary for your platform and add it to your PATH:

Platform Binary
Linux x86_64 pyoz-x86_64-linux
Linux ARM64 pyoz-aarch64-linux
macOS x86_64 pyoz-x86_64-macos
macOS ARM64 (Apple Silicon) pyoz-aarch64-macos
Windows x86_64 pyoz-x86_64-windows.exe
Windows ARM64 pyoz-aarch64-windows.exe

Source

Download PyOZ-0.9.0.tar.gz for the source code.

Quick Start

pyoz init mymodule
cd mymodule
pyoz build
pip install dist/*.whl

Don't miss a new PyOZ release

NewReleases is sending notifications on new releases.