This project has been archived by its maintainers, and is no longer receiving any updates.
Serpen: Python Source Bundler
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.txtoutput - 🔧 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):
- CLI-provided config (
--configflag) - Environment variables (with
SERPEN_prefix) - Project config (
serpen.tomlin current directory) - User config (
~/.config/serpen/serpen.toml) - System config (
/etc/serpen/serpen.tomlon Unix,%SYSTEMDRIVE%\ProgramData\serpen\serpen.tomlon Windows) - 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
- Linux/macOS:
- System:
- Linux/macOS:
/etc/serpen/serpen.tomlor/etc/xdg/serpen/serpen.toml - Windows:
%SYSTEMDRIVE%\ProgramData\serpen\serpen.toml
- Linux/macOS:
How It Works
- Module Discovery: Scans configured source directories to discover first-party Python modules
- Import Classification: Classifies imports as first-party, third-party, or standard library
- Dependency Graph: Builds a dependency graph and performs topological sorting
- Circular Dependency Resolution: Detects and intelligently resolves function-level circular imports
- Tree Shaking: Only includes modules that are actually imported (directly or transitively)
- Code Generation: Generates a single Python file with proper module separation
- Requirements: Optionally generates
requirements.txtwith 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
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
This project uses a dual licensing approach:
- Source Code: Licensed under the MIT License
- Documentation: Licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0)
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.
Metadata
Release files for serpen 0.4.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| serpen-0.4.7.tar.gz | 150.6 kB | With provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| serpen-0.4.7-py3-none-win_arm64.whl | Python 3 | none | Windows ARM64 | Details |
| serpen-0.4.7-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| serpen-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details |
| serpen-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64 | Details |
| serpen-0.4.7-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl | Python 3 | none | Linux glibc 2.5+ x86-64 | Details |
| serpen-0.4.7-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| serpen-0.4.7-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size: 20.3 MB
Release files / serpen-0.4.7.tar.gz
| Download URL | serpen-0.4.7.tar.gz |
|---|---|
| Size | 150.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f2deebe0d239132dfe065b6c4c7cbaf5f9f2f1bbde484879e0e2cfa17cd283a0
|
|
BLAKE2b-256 checksum How to use checksums |
57ca97b6315ef228fea1e4f2bcf8c2aee5da58f86fdd72046685ccf512add691
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logRelease files / serpen-0.4.7-py3-none-win_arm64.whl
| Download URL | serpen-0.4.7-py3-none-win_arm64.whl |
|---|---|
| Size | 2.7 MB |
| Tags | Python 3 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
71b63f106e510cec9f7f49783d77e0711788722ce082ecf40ca56eeba3c0b1ad
|
|
BLAKE2b-256 checksum How to use checksums |
413ae37c6086a692d5807177c1b6c6add4508a85c3515e3797d502160d1f627f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logRelease files / serpen-0.4.7-py3-none-win_amd64.whl
| Download URL | serpen-0.4.7-py3-none-win_amd64.whl |
|---|---|
| Size | 2.8 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
a60308f2a779795f6f30e91be98a42022f1937967090a4186a3ea74fd8f62d7e
|
|
BLAKE2b-256 checksum How to use checksums |
7a0cdaa510fbefbfb8a21bebe4b92c07216d4b73ac2a40b1565b428efdc553d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logRelease files / serpen-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | serpen-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 3.0 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
6fcf0053359471f51e253c5eb43f37265e40e97a2c15f150f76875fea09adab0
|
|
BLAKE2b-256 checksum How to use checksums |
660b78701daf6e526228eee23aecec10e2f401bcb3542428bdc4930bc3e8c1f1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logRelease files / serpen-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | serpen-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
d9276e1c82efb5f0295a3de799374ec996db11f4019d09bfe850ef77c7e066fd
|
|
BLAKE2b-256 checksum How to use checksums |
e917812b335ba0e44c77ec09ed859f1db01bc522b1ba4e76cbabd1f5a6fae36f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logRelease files / serpen-0.4.7-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl
| Download URL | serpen-0.4.7-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | Linux glibc 2.5+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
c6d665696bd1c36c9673fc99729dda2c21200d137052464b29b9f3bca1999bb6
|
|
BLAKE2b-256 checksum How to use checksums |
92288da783e21f18fe0ff16484288cb9dd1445d8373eb815de6146914a86383a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logRelease files / serpen-0.4.7-py3-none-macosx_11_0_arm64.whl
| Download URL | serpen-0.4.7-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.8 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
2db3557090755d9311f8812d8f321d26665c792aa0e875a09c537acdf9847638
|
|
BLAKE2b-256 checksum How to use checksums |
765d27386086912de46df66d5acb8da3a244d778e5bb7c29a109f27b3e63cb12
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logRelease files / serpen-0.4.7-py3-none-macosx_10_12_x86_64.whl
| Download URL | serpen-0.4.7-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
4c40dea312d33ce9296951e790edcf193766a1b29f841da49c4f4c8a60a0017c
|
|
BLAKE2b-256 checksum How to use checksums |
fd213ff26bddd41d3f3c1910d8bcd15ebce3b833572407a49087d28518532d4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logSecurity for serpen 0.4.7
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 8 files in this release have been uploaded with provenance metadata.
Attestation for serpen-0.4.7.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2025.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.