Skip to main content

Build high-performance Python extensions in Zig with automatic memory management, hot-reload, and NumPy integration. Inspired by ziggy-pydust.

Project description

pyZ3 - Python Extensions in Zig

A high-performance framework for writing Python extension modules in Zig with automatic memory management, hot-reload, and NumPy integration.

🌟 Inspired by ziggy-pydust

Actions Package version Python version License


Documentation: https://github.com/amiyamandal-dev/pyz3

Source Code: https://github.com/amiyamandal-dev/pyz3


Overview

pyZ3 is a complete framework for building high-performance Python extension modules in Zig. It provides:

  • 🚀 Seamless Python-Zig Interop - Automatic argument marshalling and type conversion
  • 📊 NumPy Integration - Zero-copy array access with type-safe dtype mapping
  • 🔧 Complete CLI Toolkit - Maturin-style commands for project lifecycle management
  • 📦 Cross-Platform Builds - Build wheels for Linux, macOS, and Windows
  • 🔗 C/C++ Integration - Automatic binding generation for C/C++ libraries
  • 🧪 Testing Integration - Pytest plugin to discover and run Zig tests
  • Hot Reload - Watch mode with automatic rebuilding
  • 🛡️ Memory Safe - Leverages Zig's safety features with Python's GC

Quick Example

const py = @import("pyZ3");

pub fn fibonacci(args: struct { n: u64 }) u64 {
    if (args.n < 2) return args.n;

    var sum: u64 = 0;
    var last: u64 = 0;
    var curr: u64 = 1;
    for (1..args.n) |_| {
        sum = last + curr;
        last = curr;
        curr = sum;
    }
    return sum;
}

comptime {
    py.rootmodule(@This());
}
import mymodule
print(mymodule.fibonacci(10))  # Output: 55

NumPy Integration Example

const py = @import("pyZ3");

pub fn double_array(args: struct { arr: py.PyArray(@This()) }) !py.PyArray(@This()) {
    // Zero-copy access to NumPy array
    const data = try args.arr.asSliceMut(f64);

    for (data) |*val| {
        val.* *= 2.0;
    }

    return args.arr;
}

comptime {
    py.rootmodule(@This());
}
import numpy as np
import mymodule

arr = np.array([1.0, 2.0, 3.0])
result = mymodule.double_array(arr)
print(result)  # Output: [2.0, 4.0, 6.0]

Compatibility

  • Zig: 0.15.x (tested with 0.15.2)
  • Python: 3.11+ (CPython)
  • Platforms: Linux (x86_64, aarch64), macOS (x86_64, arm64), Windows (x64)

Installation

pip install pyZ3

Or with distribution extras for building wheels:

pip install pyZ3[dist]

Quick Start

1. Create a New Project

# Create project using cookiecutter template
pyZ3 init -n myproject --description "My awesome extension" --email "you@example.com" --no-interactive

cd myproject

2. Build Your Extension

# Development build
zig build

# Release build
zig build -Doptimize=ReleaseFast

# Watch mode (hot reload)
pyZ3 watch

3. Test Your Extension

# Run pytest
pytest

# Run specific test
pytest test/test_myproject.py -v

4. Package for Distribution

# Build wheel for current platform
python -m build --wheel

# Build for all platforms (uses cross-compilation)
pyZ3 build-wheel --all-platforms

# Publish to PyPI
pyZ3 deploy --repository testpypi  # Test first!
pyZ3 deploy --repository pypi       # Production

CLI Commands

pyZ3 provides a complete CLI for managing your extension projects:

pyZ3 init [OPTIONS]           # Initialize new project
pyZ3 build [OPTIONS]          # Build extension module
pyZ3 watch                    # Watch mode with hot reload
pyZ3 test [OPTIONS]           # Run tests
pyZ3 clean                    # Clean build artifacts
pyZ3 build-wheel [OPTIONS]        # Build distribution packages
pyZ3 deploy [OPTIONS]        # Publish to PyPI

Key Features

Type-Safe Python-Zig Bridge

Automatic conversion between Python and Zig types:

Zig Type Python Type
void None
bool bool
i32, i64 int
f32, f64 float
[]const u8 str
struct {...} dict
py.PyArray(root) numpy.ndarray

Classes and Methods

pub const Point = py.class(struct {
    pub const __doc__ = "A 2D point";
    const Self = @This();

    x: f64,
    y: f64,

    pub fn __init__(self: *Self, args: struct { x: f64, y: f64 }) !void {
        self.* = .{ .x = args.x, .y = args.y };
    }

    pub fn distance(self: *const Self) f64 {
        return @sqrt(self.x * self.x + self.y * self.y);
    }
});

Exception Handling

pub fn divide(args: struct { a: i64, b: i64 }) !i64 {
    if (args.b == 0) {
        return py.ZeroDivisionError(root).raise("division by zero");
    }
    return @divTrunc(args.a, args.b);
}

NumPy Integration

// Create arrays
pub fn create_zeros() !py.PyArray(@This()) {
    return try py.PyArray(@This()).zeros(f64, &[_]usize{10, 10});
}

// Array operations
pub fn array_stats(args: struct { arr: py.PyArray(@This()) }) !struct {
    min: f64,
    max: f64,
    mean: f64,
} {
    return .{
        .min = try args.arr.min(f64),
        .max = try args.arr.max(f64),
        .mean = try args.arr.mean(f64),
    };
}

Cross-Platform Distribution

Build wheels for multiple platforms:

# Using environment variables
ZIG_TARGET=x86_64-linux-gnu PYZ3_OPTIMIZE=ReleaseFast python -m build --wheel
ZIG_TARGET=aarch64-linux-gnu PYZ3_OPTIMIZE=ReleaseFast python -m build --wheel
ZIG_TARGET=x86_64-macos PYZ3_OPTIMIZE=ReleaseFast python -m build --wheel
ZIG_TARGET=aarch64-macos PYZ3_OPTIMIZE=ReleaseFast python -m build --wheel
ZIG_TARGET=x86_64-windows-gnu PYZ3_OPTIMIZE=ReleaseFast python -m build --wheel

The build system automatically:

  • Detects target platform
  • Cross-compiles for different architectures
  • Creates manylinux-compatible wheels
  • Handles platform-specific optimizations

Performance

pyZ3 leverages Zig's performance advantages:

  • Zero-cost abstractions - No runtime overhead
  • Compile-time optimizations - Zig's comptime for metaprogramming
  • SIMD support - Automatic vectorization where possible
  • Small binaries - Smaller than equivalent Rust extensions
  • Fast compilation - Faster than Rust, comparable to C

Benchmarks

Operation Python NumPy pyZ3 (Zig)
Fibonacci(30) 832 ms N/A 0.3 ms (2773x)
Array sum (1M elements) 45 ms 0.8 ms 0.4 ms (112x vs Python)
Matrix multiply (1000x1000) 1250 ms 42 ms 38 ms (32x vs Python)

Acknowledgments

This project is a hard fork of ziggy-pydust by Fulcrum.

Major differences in pyZ3:

  • ✅ Built-in NumPy integration with zero-copy array access
  • ✅ Enhanced cross-compilation support
  • ✅ Updated CLI commands and workflows
  • ✅ Comprehensive NumPy examples and tests
  • ✅ Improved documentation for data science use cases

Special thanks to the original ziggy-pydust contributors for creating an excellent foundation!

License

Apache License 2.0

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyz3-0.3.0-py3-none-any.whl (202.4 kB view details)

Uploaded Python 3

File details

Details for the file pyz3-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: pyz3-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 202.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyz3-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1bca8bf24a0515d79297bac24b52c6de673794db504986e4ca7bbf862e35ad58
MD5 0773ea78397691ce3ce6d8df55fb06a8
BLAKE2b-256 ac1e24dbd46519d86b1498b1307e2d8bed589dcfe2be99ed7ab5e487535c7378

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyz3-0.3.0-py3-none-any.whl:

Publisher: build-wheels.yml on amiyamandal-dev/pyz3

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page