Skip to main content

Python source bundler that produces a single .py file from multi-module projects

Project description

Cribo: Python Source Bundler

PyPI npm codecov License: MIT

Cribo is a CLI and Python library that produces a single .py file from a multi-module Python project by inlining all first-party source files. This approach is inspired by JavaScript bundlers and aims to simplify deployment, especially in constrained environments like PySpark jobs, AWS Lambdas, and notebooks.

Features

  • ๐Ÿฆ€ Rust-based CLI using Ruff's Python AST parser
  • ๐Ÿ Python 3.10+ support
  • ๐ŸŒฒ Tree-shaking logic to inline only the modules that are actually used
  • ๐Ÿ”„ Circular dependency resolution using Tarjan's strongly connected components (SCC) analysis and function-level lazy import transformations, with detailed diagnostics
  • ๐Ÿงน Unused import trimming to clean up Python files standalone
  • ๐Ÿ“ฆ Requirements generation with optional requirements.txt output
  • ๐Ÿ”ง Configurable import classification and source directories
  • ๐Ÿš€ Fast and memory-efficient
  • ๐Ÿ“Š Performance tracking with built-in benchmarking

Installation

๐Ÿ” Supply Chain Security: All npm and pypi packages include provenance attestations for enhanced security and verification.

From PyPI (Python Package)

pip install cribo

From npm (Node.js CLI)

# Global installation
npm install -g cribo

# One-time use
bunx cribo --help

Binary Downloads

Download pre-built binaries for your platform from the latest release:

  • Linux x86_64: cribo_<version>_linux_x86_64.tar.gz
  • Linux ARM64: cribo_<version>_linux_arm64.tar.gz
  • macOS x86_64: cribo_<version>_darwin_x86_64.tar.gz
  • macOS ARM64: cribo_<version>_darwin_arm64.tar.gz
  • Windows x86_64: cribo_<version>_windows_x86_64.zip
  • Windows ARM64: cribo_<version>_windows_arm64.zip

Each binary includes a SHA256 checksum file for verification.

Package Manager Installation

Aqua

If you use Aqua, add to your aqua.yaml:

registries:
  - type: standard
    ref: latest
packages:
  - name: ophidiarium/cribo@latest

Then run:

aqua install

UBI (Universal Binary Installer)

Using UBI:

# Install latest version
ubi --project ophidiarium/cribo

# Install specific version
ubi --project ophidiarium/cribo --tag v0.4.1

# Install to specific directory
ubi --project ophidiarium/cribo --in /usr/local/bin

From Source

git clone https://github.com/ophidiarium/cribo.git
cd cribo
cargo build --release

Quick Start

Command Line Usage

# Basic bundling
cribo --entry src/main.py --output bundle.py

# Generate requirements.txt
cribo --entry src/main.py --output bundle.py --emit-requirements

# Verbose output (can be repeated for more detail: -v, -vv, -vvv)
cribo --entry src/main.py --output bundle.py -v
cribo --entry src/main.py --output bundle.py -vv    # debug level
cribo --entry src/main.py --output bundle.py -vvv   # trace level

# Custom config file
cribo --entry src/main.py --output bundle.py --config my-cribo.toml

CLI Options

  • -e, --entry <PATH>: Entry point Python script (required)
  • -o, --output <PATH>: Output bundled Python file (required)
  • -v, --verbose...: Increase verbosity level. Can be repeated for more detail:
    • No flag: warnings and errors only
    • -v: informational messages
    • -vv: debug messages
    • -vvv or more: trace messages
  • -c, --config <PATH>: Custom configuration file path
  • --emit-requirements: Generate requirements.txt with third-party dependencies
  • --target-version <VERSION>: Target Python version (e.g., py38, py39, py310, py311, py312, py313)
  • -h, --help: Print help information
  • -V, --version: Print version information

The verbose flag is particularly useful for debugging bundling issues. Each level provides progressively more detail:

# Default: only warnings and errors
cribo --entry main.py --output bundle.py

# Info level: shows progress messages
cribo --entry main.py --output bundle.py -v

# Debug level: shows detailed processing steps
cribo --entry main.py --output bundle.py -vv

# Trace level: shows all internal operations
cribo --entry main.py --output bundle.py -vvv

The verbose levels map directly to Rust's log levels and can also be controlled via the RUST_LOG environment variable for more fine-grained control:

# Equivalent to -vv
RUST_LOG=debug cribo --entry main.py --output bundle.py

# Module-specific logging
RUST_LOG=cribo::bundler=trace,cribo::resolver=debug cribo --entry main.py --output bundle.py

Configuration

Cribo supports hierarchical configuration with the following precedence (highest to lowest):

  1. CLI-provided config (--config flag)
  2. Environment variables (with CRIBO_ prefix)
  3. Project config (cribo.toml in current directory)
  4. User config (~/.config/cribo/cribo.toml)
  5. System config (/etc/cribo/cribo.toml on Unix, %SYSTEMDRIVE%\ProgramData\cribo\cribo.toml on Windows)
  6. Default values

Configuration File Format

Create a cribo.toml file:

# Source directories to scan for first-party modules
src = ["src", ".", "lib"]

# Known first-party module names
known_first_party = [
    "my_internal_package",
]

# Known third-party module names
known_third_party = [
    "requests",
    "numpy",
    "pandas",
]

# Whether to preserve comments in the bundled output
preserve_comments = true

# Whether to preserve type hints in the bundled output
preserve_type_hints = true

# Target Python version for standard library checks
# Supported: "py38", "py39", "py310", "py311", "py312", "py313"
target-version = "py310"

Environment Variables

All configuration options can be overridden using environment variables with the CRIBO_ prefix:

# Comma-separated lists
export CRIBO_SRC="src,lib,custom_dir"
export CRIBO_KNOWN_FIRST_PARTY="mypackage,myotherpackage"
export CRIBO_KNOWN_THIRD_PARTY="requests,numpy"

# Boolean values (true/false, 1/0, yes/no, on/off)
export CRIBO_PRESERVE_COMMENTS="false"
export CRIBO_PRESERVE_TYPE_HINTS="true"

# String values
export CRIBO_TARGET_VERSION="py312"

Configuration Locations

  • Project: ./cribo.toml
  • User:
    • Linux/macOS: ~/.config/cribo/cribo.toml
    • Windows: %APPDATA%\cribo\cribo.toml
  • System:
    • Linux/macOS: /etc/cribo/cribo.toml or /etc/xdg/cribo/cribo.toml
    • Windows: %SYSTEMDRIVE%\ProgramData\cribo\cribo.toml

How It Works

  1. Module Discovery: Scans configured source directories to discover first-party Python modules
  2. Import Classification: Classifies imports as first-party, third-party, or standard library
  3. Dependency Graph: Builds a dependency graph and performs topological sorting
  4. Circular Dependency Resolution: Detects and intelligently resolves function-level circular imports
  5. Tree Shaking: Only includes modules that are actually imported (directly or transitively)
  6. Code Generation: Generates a single Python file with proper module separation
  7. Requirements: Optionally generates requirements.txt with third-party dependencies

Architecture Overview

Cribo uses a two-stage architecture for clean separation of concerns:

  • BundleOrchestrator (orchestrator.rs): Handles the high-level bundling workflow

    • Module discovery and import resolution
    • Dependency graph construction and analysis
    • Circular dependency detection using Tarjan's algorithm
    • Coordination of the overall bundling process
  • HybridStaticBundler (code_generator.rs): Manages Python code generation

    • Implements the sys.modules-based bundling approach
    • Generates deterministic module names using content hashing
    • Handles AST transformations and import rewriting
    • Integrates unused import trimming
    • Produces the final bundled Python output

Output Structure

The bundled output follows this structure:

#!/usr/bin/env python3
# Generated by Cribo - Python Source Bundler

# Preserved imports (stdlib and third-party)
import os
import sys
import requests

# โ”€ Module: utils/helpers.py โ”€
def greet(name: str) -> str:
    return f"Hello, {name}!"

# โ”€ Module: models/user.py โ”€
class User:
    def **init**(self, name: str):
        self.name = name

# โ”€ Entry Module: main.py โ”€
from utils.helpers import greet
from models.user import User

def main():
    user = User("Alice")
    print(greet(user.name))

if **name** == "**main**":
    main()

Use Cases

PySpark Jobs

Deploy complex PySpark applications as a single file:

cribo --entry spark_job.py --output dist/spark_job_bundle.py --emit-requirements
spark-submit dist/spark_job_bundle.py

AWS Lambda

Package Python Lambda functions with all dependencies:

cribo --entry lambda_handler.py --output deployment/handler.py
# Upload handler.py + requirements.txt to Lambda

Special Considerations

Pydantic Compatibility

Cribo preserves class identity and module structure to ensure Pydantic models work correctly:

# Original: models/user.py
class User(BaseModel):
    name: str

# Bundled output preserves **module** and class structure

Pandera Decorators

Function and class decorators are preserved with their original module context:

# Original: validators/schemas.py
@pa.check_types
def validate_dataframe(df: DataFrame[UserSchema]) -> DataFrame[UserSchema]:
    return df

# Bundled output maintains decorator functionality

Circular Dependencies

Cribo intelligently handles circular dependencies with advanced detection and resolution:

Resolvable Cycles (Function-Level)

Function-level circular imports are automatically resolved and bundled successfully:

# module_a.py
from module_b import process_b
def process_a(): return process_b() + "->A"

# module_b.py  
from module_a import get_value_a
def process_b(): return f"B(using_{get_value_a()})"

Result: โœ… Bundles successfully with warning log

Unresolvable Cycles (Module Constants)

Temporal paradox patterns are detected and reported with detailed diagnostics:

# constants_a.py
from constants_b import B_VALUE
A_VALUE = B_VALUE + 1  # โŒ Unresolvable

# constants_b.py
from constants_a import A_VALUE  
B_VALUE = A_VALUE * 2  # โŒ Temporal paradox

Result: โŒ Fails with detailed error message and resolution suggestions:

Unresolvable circular dependencies detected:

Cycle 1: constants_b โ†’ constants_a
  Type: ModuleConstants
  Reason: Module-level constant dependencies create temporal paradox - cannot be resolved through bundling

Comparison with Other Tools

Tool Language Tree Shaking Import Cleanup Circular Deps PySpark Ready Type Hints
Cribo Rust โœ… โœ… โœ… Smart Resolution โœ… โœ…
PyInstaller Python โŒ โŒ โŒ Fails โŒ โœ…
Nuitka Python โŒ โŒ โŒ Fails โŒ โœ…
Pex Python โŒ โŒ โŒ Fails โŒ โœ…

Development

Building from Source

git clone https://github.com/ophidiarium/cribo.git
cd cribo

# Build Rust CLI
cargo build --release

# Build Python package
pip install maturin
maturin develop

# Run tests
cargo test

Performance Benchmarking

Cribo uses Bencher.dev for comprehensive performance tracking with statistical analysis and regression detection:

# Run all benchmarks
cargo bench

# Save a performance baseline
./scripts/bench.sh --save-baseline main

# Compare against baseline
./scripts/bench.sh --baseline main

# View detailed HTML report
./scripts/bench.sh --open

Key benchmarks:

  • End-to-end bundling: Full project bundling performance (Criterion.rs)
  • AST parsing: Python code parsing speed (Criterion.rs)
  • Module resolution: Import resolution efficiency (Criterion.rs)
  • CLI performance: Command-line interface speed (Hyperfine)

CI Integration:

  • Automated PR comments with performance comparisons and visual charts
  • Historical performance tracking with trend analysis
  • Statistical significance testing to prevent false positives
  • Dashboard available at bencher.dev/perf/cribo

See docs/benchmarking.md for detailed benchmarking guide.

Project Structure

cribo/
โ”œโ”€โ”€ src/                    # Rust source code
โ”‚   โ”œโ”€โ”€ main.rs            # CLI entry point
โ”‚   โ”œโ”€โ”€ orchestrator.rs    # Bundle orchestration and coordination
โ”‚   โ”œโ”€โ”€ code_generator.rs  # Python code generation (sys.modules approach)
โ”‚   โ”œโ”€โ”€ resolver.rs        # Import resolution
โ”‚   โ”œโ”€โ”€ dependency_graph.rs # Dependency analysis and circular detection
โ”‚   โ”œโ”€โ”€ unused_imports.rs  # Unused import trimming
โ”‚   โ””โ”€โ”€ ...
โ”œโ”€โ”€ python/cribo/          # Python package
โ”œโ”€โ”€ tests/                 # Test suites
โ”‚   โ””โ”€โ”€ fixtures/          # Test projects
โ”œโ”€โ”€ docs/                  # Documentation
โ””โ”€โ”€ Cargo.toml            # Rust dependencies

Contributing

Development Setup

# Clone the repository
git clone https://github.com/ophidiarium/cribo.git
cd cribo

# Install Rust toolchain and components
rustup component add llvm-tools-preview
cargo install cargo-llvm-cov

# Build Rust CLI
cargo build --release

# Build Python package
pip install maturin
maturin develop

# Run tests
cargo test

Code Coverage

The project uses cargo-llvm-cov for code coverage analysis:

# Generate text coverage report (Istanbul-style)
cargo coverage-text

# Generate HTML coverage report and open in browser
cargo coverage

# Generate LCOV format for CI
cargo coverage-lcov

# Clean coverage data
cargo coverage-clean

Branch Coverage (Experimental):

# Requires nightly Rust for branch coverage
cargo +nightly coverage-branch

Coverage reports are automatically generated in CI and uploaded to Codecov. See docs/coverage.md for detailed coverage documentation.

Note: If you see zeros in the "Branch Coverage" column in HTML reports, this is expected with stable Rust. Branch coverage requires nightly Rust and is experimental.

Contributing Guidelines

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

License

This project uses a dual licensing approach:

What this means:

  • For the source code: You can freely use, modify, and distribute the code for any purpose with minimal restrictions under the MIT license.
  • For the documentation: You can share, adapt, and use the documentation for any purpose (including commercially) as long as you provide appropriate attribution under CC BY 4.0.

See the LICENSE file for the MIT license text and docs/LICENSE for the CC BY 4.0 license text.

Acknowledgments

  • Ruff: Python AST parsing and import resolution logic inspiration
  • Maturin: Python-Rust integration

Roadmap

  • Smart circular dependency resolution - โœ… Completed in v0.4.4+
  • Source maps for debugging
  • Parallel processing
  • Package flattening mode
  • Comment and type hint stripping
  • Plugin system for custom transformations

For more examples and detailed documentation, visit our documentation site.

For detailed documentation on the unused import trimmer, see docs/unused_import_trimmer.md.

Project details


Download files

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

Source Distribution

cribo-0.4.24.tar.gz (172.6 kB view details)

Uploaded Source

Built Distributions

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

cribo-0.4.24-py3-none-win_arm64.whl (1.9 MB view details)

Uploaded Python 3Windows ARM64

cribo-0.4.24-py3-none-win_amd64.whl (2.1 MB view details)

Uploaded Python 3Windows x86-64

cribo-0.4.24-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

cribo-0.4.24-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.1 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

cribo-0.4.24-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl (2.3 MB view details)

Uploaded Python 3manylinux: glibc 2.5+ x86-64

cribo-0.4.24-py3-none-macosx_11_0_arm64.whl (2.0 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

cribo-0.4.24-py3-none-macosx_10_12_x86_64.whl (2.1 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file cribo-0.4.24.tar.gz.

File metadata

  • Download URL: cribo-0.4.24.tar.gz
  • Upload date:
  • Size: 172.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for cribo-0.4.24.tar.gz
Algorithm Hash digest
SHA256 3d112b6aa13cff696e5fd2dbf870a4998fa3ce49e90b999af78d0d2a5da9fa26
MD5 3fcf9defb1bc785a6678cbefc192904a
BLAKE2b-256 5640301cc22ac08d54d14127494a80dda44b429b8e7143400167930374a6d283

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24.tar.gz:

Publisher: release.yml on ophidiarium/cribo

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

File details

Details for the file cribo-0.4.24-py3-none-win_arm64.whl.

File metadata

  • Download URL: cribo-0.4.24-py3-none-win_arm64.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for cribo-0.4.24-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 a1add85416e37a81406919204dba3170cbf5bc01cf6703f9fee0c0e2e474ad0a
MD5 eb8ebb6ac4723ee5fc1895237a09a23b
BLAKE2b-256 1d552285fa6b05ef2f671695f5988ee0fd979013d099d41af3f0aa02e122facb

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24-py3-none-win_arm64.whl:

Publisher: release.yml on ophidiarium/cribo

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

File details

Details for the file cribo-0.4.24-py3-none-win_amd64.whl.

File metadata

  • Download URL: cribo-0.4.24-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.1 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for cribo-0.4.24-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 3576d921b85b15284941701fb0fcf9fe65a31dd47447e3942304f7ed86c344a5
MD5 91efac3cf61842a9429bdd921658d92e
BLAKE2b-256 6903373db5566605c9ce68814197ab83f14652446a25efbea254297c88b0d252

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24-py3-none-win_amd64.whl:

Publisher: release.yml on ophidiarium/cribo

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

File details

Details for the file cribo-0.4.24-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for cribo-0.4.24-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5b8b1d8d1f4eb4c8cdbf79310acac8e104c8bfb15b1a66f012597e656164986d
MD5 2795ff450e8ff34da9c7b72a8cefadcd
BLAKE2b-256 2e0a5c79255f1814551e22f21a07afc8ae3a78f3981fa48f168240244858c88b

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on ophidiarium/cribo

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

File details

Details for the file cribo-0.4.24-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for cribo-0.4.24-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 cee21ec04811952a8220447aeeca147149cb260d1578e6ae7b9cfde3b60e4e71
MD5 f4cdf5703bf92910cf5938df5de0cc75
BLAKE2b-256 21105cfab30774ac9eb6574c6a391f5cda37b5d1fb14f2725ffe9f8ba8e56d8a

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on ophidiarium/cribo

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

File details

Details for the file cribo-0.4.24-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for cribo-0.4.24-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 01a421d2c9d475a3ecc4a160065a4c8220c17a9b1590bdc05cebdfeebcea4611
MD5 8a0db1f44038de70c8e2418044f4bd72
BLAKE2b-256 de5af9b04211a210f979c7165829208dbc462f60c8dd341fb13f1d03d5f0d41f

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl:

Publisher: release.yml on ophidiarium/cribo

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

File details

Details for the file cribo-0.4.24-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for cribo-0.4.24-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 844b362abd1d530df8a3c21600b12702a264e1f51d732a282f7e288d58a785d5
MD5 da92d81329ab6cd72e003c6f5036eb3f
BLAKE2b-256 ca8bd42cb9c0fcef974f99fd3c5a1c66cad5eceda8b10a2facd7b40004bef098

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on ophidiarium/cribo

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

File details

Details for the file cribo-0.4.24-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for cribo-0.4.24-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 04e82d47a7af56d57fb4d4846185aa4514c6cfdd5398a4ebd5a0566b426b67c5
MD5 e43b01276384167e3ad58da018135091
BLAKE2b-256 cb21e6049244be41fe4560604618b063fcd4e6e664e0b638d990499b4e684197

See more details on using hashes here.

Provenance

The following attestation bundles were made for cribo-0.4.24-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on ophidiarium/cribo

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