PyPI Open-Source Python Libraries

Python packages

PyrixOS is a reproducible, declarative Linux distribution written in Python. Its building blocks are released as separate Python packages on PyPI, and each can be used on its own in other projects. All six are pure Python, need Python 3.12 or later, are licensed GPL-2.0-only, and are released from GitHub with PyPI trusted publishing and build provenance attestations.

Browse packages PyrixOS project PyrixOS documentation GitHub ↗

Packages on PyPI

PyPI package Import name Version Command Description Links
pybonsai-lang pybonsai 1.2.0 none A hermetic subset of Python 3.12 for configuration that gives the same result on every machine PyPI ↗ · GitHub ↗ · Docs
cloche cloche 1.2.0 cloche Run a program in an unprivileged Linux sandbox, from Python or the command line PyPI ↗ · GitHub ↗ · Docs
trellis-kconfig trellis 1.1.0 trellis Configure a system from Kconfig option trees, checked with a SAT solver PyPI ↗ · GitHub ↗
pyrixos-lattice lattice 0.13.0 lattice Lattice, the PyrixOS package manager PyPI ↗ · GitHub ↗ · Docs
pyrixos-espalier espalier 1.0.0 none Data models validated from type annotations, a pure-Python subset of the Pydantic 2 interface PyPI ↗ · GitHub ↗
pyrixos-ed25519 pyrixos_ed25519 1.0.0 none Ed25519 signatures after RFC 8032, with no compiled code PyPI ↗ · GitHub ↗

Dependencies between the packages

Nothing in the tree depends on Rust or on a C extension, so every package installs from source on any machine with Python 3.12.

Package Runtime dependencies
pybonsai-lang None
cloche pyrixos-espalier
trellis-kconfig pyrixos-espalier
pyrixos-lattice pybonsai-lang, cloche, pyrixos-espalier, pyrixos-ed25519; trellis-kconfig with the config extra
pyrixos-espalier None
pyrixos-ed25519 None

PyBonsai (pybonsai-lang)

PyBonsai is a restricted subset of Python 3.12 for writing configuration that must give the same result on every machine. A PyBonsai file is ordinary Python syntax, but it is never run by CPython: PyBonsai parses it, rejects every construct outside an allow list, and interprets the syntax tree itself. A file cannot import modules, read files or the environment, loop without a bound or mutate shared state. It plays the part Starlark plays for Bazel, for any Python program that wants a hermetic configuration language with its own functions and types.

pip install pybonsai-lang
from pybonsai import evaluate_source

names = evaluate_source("xs = [i * i for i in range(4)]")
assert names["xs"] == (0, 1, 4, 9)

PyPI (1.2.0) ↗ Source repository ↗ Changelog ↗ PyrixOS documentation →

Cloche (cloche)

Cloche runs a program in an unprivileged Linux sandbox. It needs no root, no daemon and no container image: the program sees only the host paths bound into the sandbox, read-only, and a few empty writable directories, under a seccomp system call filter and resource limits. When the program succeeds, the declared outputs are copied out. The same sandbox can run under a rootless OCI runtime, or in a small virtual machine with its own kernel (Firecracker or Cloud Hypervisor). Version 1.2 adds the system call filters for riscv64 and aarch64 builders.

pip install cloche
import tempfile

from cloche import Bind, Command, Limits, run

command = Command(
    name="hello",
    program="/usr/bin/sh",
    args=("-c", "echo hello > /build/greeting"),
    binds=tuple(Bind(source=p, destination=p) for p in ("/usr", "/lib", "/lib64")),
    outputs={"greeting": "/build/greeting"},
)
outcome = run(command, tempfile.mkdtemp(), Limits(timeout=60))
print(open(outcome.outputs["greeting"]).read())  # hello

PyPI (1.2.0) ↗ Source repository ↗ Changelog ↗ PyrixOS documentation →

Trellis (trellis-kconfig)

Trellis configures a build from a tree of options written in a subset of the Linux Kconfig language. The user's choices are kept in a defconfig, and a SAT solver resolves them into one value for every option. When choices cannot all hold, Trellis names the smallest set of choices and rules in conflict and lists the changes that would remove it, instead of quietly turning an option off. It is a Python library with a command, a line prompter and a full-screen menu on top.

pip install trellis-kconfig
from trellis import Configurator

configurator = Configurator.load("Kconfig", "defconfig")
configurator.set("WIFI", "m")
print(configurator.resolve().values)

conflict = configurator.conflict("NET", "n")
if conflict is not None:
    print(conflict.describe())
    for fix in configurator.fixes("NET", "n"):
        print("drop", fix.dropped, "changes", fix.changes)

configurator.save("defconfig", "config.pyb")

PyPI (1.1.0) ↗ Source repository ↗ Changelog ↗

Lattice (pyrixos-lattice)

Lattice is the package manager of PyrixOS. It reads package and system descriptions written in PyBonsai, turns them into derivations (exact build recipes identified by a hash of their contents), builds them in the Cloche sandbox, and keeps the results in an immutable, content-addressed store. It switches whole machines between generations with rollback, and fetches signed binaries from caches. Everything the lattice command does is available from Python through the Lattice class, and through a daemon with a local and a remote API. Lattice stays below 1.0 until PyrixOS 1.0.

pip install pyrixos-lattice
pip install "pyrixos-lattice[config]"   # adds lattice config, through Trellis
from lattice import Lattice, LatticeError, Settings

lattice = Lattice(Settings(sandbox_backend="namespaces"))
try:
    result = lattice.evaluate("hello.pyb")
except LatticeError as error:
    print(error)
else:
    for name, drv in result.derivations.items():
        print(name, drv.store_path)

PyPI (0.13.0) ↗ Source repository ↗ Changelog ↗ PyrixOS documentation →

Espalier (pyrixos-espalier)

Espalier gives Python classes validation from their type annotations, with the interface of Pydantic 2 (BaseModel, Field, ConfigDict, validators, TypeAdapter, model_validate, model_dump_json and the rest that PyrixOS uses), implemented in pure Python. Pydantic's validation core is written in Rust; Espalier lets a project that wants an all-Python dependency tree keep the same model code. It supports strict and lax modes, frozen models, forbidden extra fields, aliases, discriminated unions and JSON round trips. It is slower than Pydantic, so it suits configuration and API models more than bulk data.

pip install pyrixos-espalier
from typing import Annotated, Literal

from espalier import BaseModel, ConfigDict, Field, ValidationError


class Mount(BaseModel):
    model_config = ConfigDict(frozen=True, extra="forbid", strict=True)

    source: str = Field(min_length=1)
    target: str
    mode: Literal["ro", "rw"] = "ro"
    size: Annotated[int, Field(ge=0)] = 0


mount = Mount.model_validate_json('{"source": "/a", "target": "/b"}')
print(mount.model_dump_json())  # {"source":"/a","target":"/b","mode":"ro","size":0}

try:
    Mount(source="", target="/b", size=-1)
except ValidationError as error:
    print(error)

PyPI (1.0.0) ↗ Source repository ↗ Changelog ↗

pyrixos-ed25519

pyrixos-ed25519 creates and checks Ed25519 signatures as RFC 8032 specifies, in Python with no compiled code, and is tested against the RFC 8032 test vectors. Lattice uses it to sign and verify its binary caches. Keys are the 32-byte seeds and public keys of the RFC, so they interoperate with other Ed25519 implementations. Python integers give no constant-time arithmetic, so signing time depends on the secret key: the package suits places where an attacker cannot time many signatures, such as signing build outputs on a build host. Signing takes about 2 ms and verification about 10 ms on a current x86_64 core.

pip install pyrixos-ed25519
from pyrixos_ed25519 import BadSignatureError, SigningKey, VerifyingKey

key = SigningKey.generate()            # or SigningKey(seed), 32 bytes
signature = key.sign(b"message")       # 64 bytes
public = key.verifying_key.encoded     # 32 bytes

try:
    VerifyingKey(public).verify(signature, b"message")
except BadSignatureError:
    ...

PyPI (1.0.0) ↗ Source repository ↗ Changelog ↗

Releases and verification

Each package is released from its own GitHub repository by pushing a version tag. The release workflow runs the quality gates (formatting, lint, type checking and tests with a coverage floor) on Python 3.12 and 3.13, builds the source distribution and the wheel once, publishes them to PyPI through trusted publishing with PEP 740 attestations, and creates the GitHub release with a build provenance attestation and the changelog notes. A downloaded wheel can be checked with:

pip download --no-deps pyrixos-espalier
gh attestation verify pyrixos_espalier-*-py3-none-any.whl --repo PacketFive/espalier

Each repository has a CHANGELOG.md with the changes of every release. The PyrixOS repository is at github.com/PacketFive/PyrixOS ↗ and its documentation is at packetfive.com/pyrixos/docs/.