sagepypi is a Python packaging workflow tool that compiles packages to bytecode, builds wheels, and publishes to PyPI/TestPyPI.
- Copy a package tree and compile
.pyβ.pyc(keeps__init__.pyand_version.py). - Auto-adjust
pyproject.toml/MANIFEST.into include compiled artifacts and binary extensions. - Build wheels with
python -m build. - π NEW: Smart
--for-pypimode - one command for perfect PyPI publishing! - NEW: Universal wheel support - one wheel works on all Python 3.x versions!
- NEW: Source distribution (sdist) support - users can install from source on any version
- Upload via
twine(with--dry-runby default). - Simple Typer-based CLI.
Problem: Your package declares support for Python 3.8-3.12, but you only upload a wheel for Python 3.11. Users on other versions can't install it!
Solution: sagepypi now uses Smart Mode by default π―
# That's it! No extra flags needed - smart mode is automatic
sagepypi build . --upload --no-dry-runWhat happens automatically:
- β Pure Python packages: Builds universal wheel (py3-none-any) that works on ALL Python 3.x versions!
- β Packages with C extensions: Builds for current Python + provides source code for others
- β Always includes source distribution (sdist) as fallback
- β No need to build wheels for each Python version separately!
Why this works:
- Universal wheel (py3-none-any): One file works on Python 3.8, 3.9, 3.10, 3.11, 3.12, and future versions!
- Source distribution: If universal wheel doesn't work, users can compile from source
- Zero configuration: Works perfectly out of the box!
# From the local checkout
python -m pip install -e .
# From GitHub (recommended until the first public PyPI release)
python -m pip install "sagepypi @ git+https://github.com/intellistream/sagepypi.git@main"
# After the first public release lands on PyPI
python -m pip install sagepypi# 1. Update the single version source
vi src/sagepypi/_version.py
# 2. Validate the repository locally
PYTHONPATH=src python -m pytest tests -q
# 3. Publish to TestPyPI first
python -m pip install -e .
sagepypi build . --upload -r testpypi --no-dry-run
# 4. Publish to production PyPI
sagepypi build . --upload -r pypi --no-dry-run- Until
sagepypihas a public PyPI release, downstream repositories should install it fromgit+https://github.com/intellistream/sagepypi.git@main. - After the first public release, downstream install instructions can switch to
python -m pip install sagepypi. - The canonical repository is
intellistream/sagepypi; oldwheelwrightreferences should be treated as historical only.
π― Simplest Usage (Smart Mode - Default!)
# Just build - automatically chooses best strategy!
sagepypi build .
# Build and upload to TestPyPI
sagepypi build . --upload -r testpypi
# Build and upload to PyPI (production)
sagepypi build . --upload --no-dry-run -r pypiWhat Smart Mode Does (Automatically):
- π Detects if your package is pure Python or has C extensions
- π¦ Pure Python β builds universal wheel (works on ALL Python 3.x!)
- π§ C extensions β builds for current Python version
- π Always includes source distribution (sdist)
- β Perfect for packages declaring Python 3.8+ support!
Manual Control (Advanced):
# Disable smart mode (old behavior - current Python only)
sagepypi build . --no-for-pypi
# Force universal wheel
sagepypi build . --universal
# Force specific mode
sagepypi build . --mode publicsagepypi --help
# π― Simplest: Build with smart mode (default!)
sagepypi build .
# Build and upload to PyPI
sagepypi build . --upload --no-dry-run
# Compile only (bytecode mode by default)
sagepypi compile /path/to/pkg -o /tmp/out
# Compile in public mode (keep source)
sagepypi compile /path/to/pkg -o /tmp/out --mode public
# Disable smart mode (old behavior)
sagepypi build /path/to/pkg --no-for-pypi
# Force universal wheel (manual override)
sagepypi build /path/to/pkg --universal
# Force manylinux build for C/C++ extensions
sagepypi build /path/to/pkg --force-manylinux
# Upload an existing wheel
sagepypi upload dist/yourpkg-0.1.0-py3-none-any.whl -r pypi --no-dry-run--mode private(default): Compile to.pycbytecode (δΏε―ζ¨‘εΌ - protects source code)--mode public: Keep.pysource files (ε ¬εΌζ¨‘εΌ - open source)- Aliases:
bytecode=private,source=public
from pathlib import Path
from sagepypi.compiler import BytecodeCompiler
# Create compiler
compiler = BytecodeCompiler(Path("/path/to/pkg"), mode="private")
compiled = compiler.compile_package()
# Build wheel
wheel = compiler.build_wheel(compiled)
# Upload to TestPyPI (safe default)
compiler.upload_wheel(wheel, repository="testpypi", dry_run=True)- Smart Mode (default): Automatically chooses packaging strategy for PyPI.
--no-for-pypi: Disable smart mode and use current-interpreter build behavior.--universal: Forcepy3-none-anywheel (pure Python only).--sdist: Also build source distribution (.tar.gz).
For C/C++ extension packages targeting multiple Python versions, use cibuildwheel in CI.
sagepypi provides intelligent git hooks to simplify version management and PyPI publishing.
sagepypi install-hooks .- Version Guard: Detects if the current version is already published on PyPI.
- Auto-bump on Conflict: Can auto-bump patch version when a duplicate release is detected.
- Interactive Flow: Keeps release behavior explicit and visible during push.
- Requires
python -m buildandtwineavailable. - No backward compatibility with
sage-devCLI; PyPI commands have been removed from SAGE. - Designed to be monorepo-friendly but works with any package path that contains
pyproject.toml.