Skip to main content

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

This project has been archived.

The maintainers of this project have marked this project as archived. No new releases are expected.

Project description

Serpen: Python Source Bundler

PyPI npm codecov License: MIT

Serpen 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
  • ๐Ÿ”„ Smart circular dependency resolution 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

Installation

From PyPI (Python Package)

pip install serpen

From npm (Node.js CLI)

# Global installation
npm install -g serpen

# One-time use
npx serpen --help

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

Binary Downloads

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

  • Linux x86_64: serpen_*_linux_x86_64.tar.gz
  • Linux ARM64: serpen_*_linux_arm64.tar.gz
  • macOS x86_64: serpen_*_darwin_x86_64.tar.gz
  • macOS ARM64: serpen_*_darwin_arm64.tar.gz
  • Windows x86_64: serpen_*_windows_x86_64.zip
  • Windows ARM64: serpen_*_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: tinovyatkin/serpen@latest

Then run:

aqua install

UBI (Universal Binary Installer)

Using UBI:

# Install latest version
ubi --project tinovyatkin/serpen

# Install specific version
ubi --project tinovyatkin/serpen --tag v0.4.1

# Install to specific directory
ubi --project tinovyatkin/serpen --in /usr/local/bin

From Source

git clone https://github.com/tinovyatkin/serpen.git
cd serpen
cargo build --release

Quick Start

Command Line Usage

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

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

# Verbose output
serpen --entry src/main.py --output bundle.py --verbose

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

Configuration

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

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

Configuration File Format

Create a serpen.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 SERPEN_ prefix:

# Comma-separated lists
export SERPEN_SRC="src,lib,custom_dir"
export SERPEN_KNOWN_FIRST_PARTY="mypackage,myotherpackage"
export SERPEN_KNOWN_THIRD_PARTY="requests,numpy"

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

# String values
export SERPEN_TARGET_VERSION="py312"

Configuration Locations

  • Project: ./serpen.toml
  • User:
    • Linux/macOS: ~/.config/serpen/serpen.toml
    • Windows: %APPDATA%\serpen\serpen.toml
  • System:
    • Linux/macOS: /etc/serpen/serpen.toml or /etc/xdg/serpen/serpen.toml
    • Windows: %SYSTEMDRIVE%\ProgramData\serpen\serpen.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

Output Structure

The bundled output follows this structure:

#!/usr/bin/env python3
# Generated by Serpen - 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:

serpen --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:

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

Special Considerations

Pydantic Compatibility

Serpen 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

Serpen 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
Serpen Rust โœ… โœ… โœ… Smart Resolution โœ… โœ…
PyInstaller Python โŒ โŒ โŒ Fails โŒ โœ…
Nuitka Python โŒ โŒ โŒ Fails โŒ โœ…
Pex Python โŒ โŒ โŒ Fails โŒ โœ…

Development

Building from Source

git clone https://github.com/tinovyatkin/serpen.git
cd serpen

# Build Rust CLI
cargo build --release

# Build Python package
pip install maturin
maturin develop

# Run tests
cargo test

Project Structure

serpen/
โ”œโ”€โ”€ src/                    # Rust source code
โ”‚   โ”œโ”€โ”€ main.rs            # CLI entry point
โ”‚   โ”œโ”€โ”€ bundler.rs         # Core bundling logic
โ”‚   โ”œโ”€โ”€ resolver.rs        # Import resolution
โ”‚   โ”œโ”€โ”€ emit.rs            # Code generation
โ”‚   โ””โ”€โ”€ ...
โ”œโ”€โ”€ python/serpen/         # 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/tinovyatkin/serpen.git
cd serpen

# 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

serpen-0.4.7.tar.gz (150.6 kB view details)

Uploaded Source

Built Distributions

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

serpen-0.4.7-py3-none-win_arm64.whl (2.7 MB view details)

Uploaded Python 3Windows ARM64

serpen-0.4.7-py3-none-win_amd64.whl (2.8 MB view details)

Uploaded Python 3Windows x86-64

serpen-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

serpen-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.9 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

serpen-0.4.7-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl (3.1 MB view details)

Uploaded Python 3manylinux: glibc 2.5+ x86-64

serpen-0.4.7-py3-none-macosx_11_0_arm64.whl (2.8 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

serpen-0.4.7-py3-none-macosx_10_12_x86_64.whl (2.9 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file serpen-0.4.7.tar.gz.

File metadata

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

File hashes

Hashes for serpen-0.4.7.tar.gz
Algorithm Hash digest
SHA256 f2deebe0d239132dfe065b6c4c7cbaf5f9f2f1bbde484879e0e2cfa17cd283a0
MD5 2616870dc6997e543e1e6b29e5fd708c
BLAKE2b-256 57ca97b6315ef228fea1e4f2bcf8c2aee5da58f86fdd72046685ccf512add691

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7.tar.gz:

Publisher: release.yml on tinovyatkin/serpen

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

File details

Details for the file serpen-0.4.7-py3-none-win_arm64.whl.

File metadata

  • Download URL: serpen-0.4.7-py3-none-win_arm64.whl
  • Upload date:
  • Size: 2.7 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 serpen-0.4.7-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 71b63f106e510cec9f7f49783d77e0711788722ce082ecf40ca56eeba3c0b1ad
MD5 b8c5a6cd2ea89707995222b337df30b6
BLAKE2b-256 413ae37c6086a692d5807177c1b6c6add4508a85c3515e3797d502160d1f627f

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7-py3-none-win_arm64.whl:

Publisher: release.yml on tinovyatkin/serpen

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

File details

Details for the file serpen-0.4.7-py3-none-win_amd64.whl.

File metadata

  • Download URL: serpen-0.4.7-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.8 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 serpen-0.4.7-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 a60308f2a779795f6f30e91be98a42022f1937967090a4186a3ea74fd8f62d7e
MD5 0f2c5d6d01f24b52447d95609b4840b6
BLAKE2b-256 7a0cdaa510fbefbfb8a21bebe4b92c07216d4b73ac2a40b1565b428efdc553d3

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7-py3-none-win_amd64.whl:

Publisher: release.yml on tinovyatkin/serpen

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

File details

Details for the file serpen-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for serpen-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6fcf0053359471f51e253c5eb43f37265e40e97a2c15f150f76875fea09adab0
MD5 fcf147ea843b9c627a839371753a18ba
BLAKE2b-256 660b78701daf6e526228eee23aecec10e2f401bcb3542428bdc4930bc3e8c1f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on tinovyatkin/serpen

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

File details

Details for the file serpen-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for serpen-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 d9276e1c82efb5f0295a3de799374ec996db11f4019d09bfe850ef77c7e066fd
MD5 716a34a8745e0b939202cd76015c1c15
BLAKE2b-256 e917812b335ba0e44c77ec09ed859f1db01bc522b1ba4e76cbabd1f5a6fae36f

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on tinovyatkin/serpen

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

File details

Details for the file serpen-0.4.7-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for serpen-0.4.7-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 c6d665696bd1c36c9673fc99729dda2c21200d137052464b29b9f3bca1999bb6
MD5 c95bbb27a17b2bd49a721b8b7b177e67
BLAKE2b-256 92288da783e21f18fe0ff16484288cb9dd1445d8373eb815de6146914a86383a

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl:

Publisher: release.yml on tinovyatkin/serpen

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

File details

Details for the file serpen-0.4.7-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for serpen-0.4.7-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2db3557090755d9311f8812d8f321d26665c792aa0e875a09c537acdf9847638
MD5 cc57f41ba1c94d4c773a10eacc370b58
BLAKE2b-256 765d27386086912de46df66d5acb8da3a244d778e5bb7c29a109f27b3e63cb12

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on tinovyatkin/serpen

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

File details

Details for the file serpen-0.4.7-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for serpen-0.4.7-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4c40dea312d33ce9296951e790edcf193766a1b29f841da49c4f4c8a60a0017c
MD5 158ef2805c4f3825e56bb266fd7e502c
BLAKE2b-256 fd213ff26bddd41d3f3c1910d8bcd15ebce3b833572407a49087d28518532d4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for serpen-0.4.7-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on tinovyatkin/serpen

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