Skip to main content

Build and run any commit of CPython

Project description

every-python

Build and run any commit of CPython, inspired by every-ts.

Why does this exist?

Building CPython from source is time-consuming. every-python makes it easy to:

  • Test your code against different Python versions
  • Reproduce bugs in specific commits
  • Test experimental features like the JIT compiler
  • Bisect to find which commit introduced a regression

Features

  • Build any CPython commit - main, release tags, or specific commits
  • Build with experimental JIT support - Build with --enable-experimental-jit (includes LLVM version detection)
  • Build with PGO + LTO - Optimized release builds via --pgo
  • Build free-threaded (no-GIL) - Build with --disable-gil via --nogil (3.13+)
  • Smart caching - Builds cached in ~/.every-python/builds/ for instant reuse
  • Git bisect integration - Automatically find which commit introduced a bug

How it works

every-python makes a blobless clone of the CPython repository (~200MB), checks out the version you want, and builds it locally with --with-pydebug. Built versions are cached in ~/.every-python/builds/ for reuse.

Installation

uv tool install every-python
# or
pipx install every-python
# or
pip install every-python

# Development install from source
git clone https://github.com/yourusername/every-python.git
cd every-python
uv sync

Requirements

Platform support

  • macOS / Linux: builds via ./configure --with-pydebug + make.
  • Windows: builds via PCbuild\build.bat -c Debug -p <arch> (requires Visual Studio with C++ workload, as documented in PCbuild/readme.txt). The platform is auto-detected from the host (x64, ARM64, or Win32) and artifacts are copied from the matching PCbuild\<arch> directory into the cache. The resulting binary is python_d.exe.

Usage

Build and install a Python version

# Build from main branch
every-python install main

# Build from a release tag
every-python install v3.13.0

# Build from a specific commit
every-python install abc123d

# Show build output (useful for debugging build failures)
every-python install main --verbose

Run Python with a specific version

# Run Python REPL
every-python run main -- python

# Run a script
every-python run v3.13.0 -- python your_script.py

# Run with arguments
every-python run main -- python -c "print('Hello!')"

If the version isn't built yet, it will build it automatically.

Build with JIT compiler (experimental)

Build Python with the experimental JIT compiler:

# Build with JIT enabled
every-python install main --jit

# Run with JIT-enabled build
every-python run main --jit -- python -c "print('Hello from JIT!')"

# Bisect with JIT to find JIT-specific bugs
every-python bisect --good v3.13.0 --bad main --jit --run "python test.py"

JIT Requirements: every-python will attempt to detect the correct version of LLVM for the commit being built from LLVM_VERSION specified in Tools/jit/_llvm.py at the time of the commit. If you are missing the required LLVM version, you will see an error during the build. For more information on installing LLVM, see CPython JIT documentation.

Note: LLVM is only needed at build time, not at runtime. JIT and non-JIT builds are stored separately.

Build with PGO + LTO

Build Python with profile-guided optimization and link-time optimization:

# Build with PGO + LTO
every-python install main --pgo

# Combine with JIT
every-python install main --jit --pgo

On Unix this maps to --enable-optimizations; on Windows it triggers the PGInstrument/PGUpdate configuration cycle. Both produce PGO + LTO builds. Expect the build to take significantly longer than a regular debug build.

Build free-threaded (no-GIL)

Build Python with the GIL disabled (PEP 703, available in 3.13+):

# Build a free-threaded Python
every-python install main --nogil

# Combine flags
every-python install main --pgo --nogil

every-python checks whether the commit supports --disable-gil before building. Pre-3.13 commits silently accept the flag but produce a regular GIL-enabled build, so the tool will warn and ask before continuing.

Note: --jit and --nogil together is a degenerate configuration upstream. The build succeeds and free-threading is enabled, but the JIT code is compiled in and never actually used at runtime (configure.ac emits a warning, see GH-133171).

List built versions

every-python list-builds

Clean up builds

# Remove a specific build
every-python clean v3.13.0

# Remove all builds
every-python clean --all

Bisect to find bugs

Use git bisect to automatically find which commit introduced a bug:

# Find when a test started failing
# Exit with code 0 = good commit, 1 = bad commit
every-python bisect \
  --good v3.13.0 \
  --bad main \
  --run "python test_my_feature.py"

# Bisect with JIT-enabled builds
every-python bisect \
  --good v3.12.0 \
  --bad main \
  --jit \
  --run "python test_jit_api.py"

This will:

  1. Resolve the good and bad commits
  2. Start a git bisect
  3. Build each commit that git bisect tests
  4. Run your test command
  5. Automatically mark commits as good/bad based on exit code:
    • Exit 0 = good commit
    • Exit 1-127 (except 125) = bad commit
    • Exit 125 = skip this commit (can't test it)
  6. Find the exact commit that introduced the change

Note on bisecting across branches: Bisecting between release tags and main can be tricky due to backporting. For best results, bisect within a single branch (e.g., use commit hashes on main instead of crossing from v3.12.0 to main).

Writing test scripts for bisect: Your test script should exit with code 0 for "good" (old/expected behavior) and 1 for "bad" (new/broken behavior). For example, if I wanted to find when _jit was added to the sys module, I could use this script:

import sys
# Exit 0 (good) = feature doesn't exist yet
# Exit 1 (bad) = feature exists
if hasattr(sys, "_jit"):
    sys.exit(1)  # Feature exists - mark as "bad"
sys.exit(0)  # Feature doesn't exist - mark as "good"

Project Structure

~/.every-python/
├── cpython/          # Blobless clone of CPython repository
└── builds/           # Cached builds
    ├── abc123d/              # Build for commit abc123d
    ├── abc123d-jit/          # JIT build
    ├── abc123d-pgo/          # PGO + LTO build
    ├── abc123d-nogil/        # Free-threaded build
    ├── abc123d-jit-pgo-nogil/  # All flags combined
    └── def456e/              # Build for commit def456e

License

MIT

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

every_python-0.6.0.tar.gz (30.6 kB view details)

Uploaded Source

Built Distribution

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

every_python-0.6.0-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file every_python-0.6.0.tar.gz.

File metadata

  • Download URL: every_python-0.6.0.tar.gz
  • Upload date:
  • Size: 30.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for every_python-0.6.0.tar.gz
Algorithm Hash digest
SHA256 2d7e6250ec680d5126aea04b2b3b0e99be0ee5b8ac8ee3518a1bbd268981cb4c
MD5 a063ba2b73c8dc9878fbf2cb1ae16d8a
BLAKE2b-256 3b4821691a6a2d96b4784cb612701f4454256546b77dac50a7f0b83ec278a442

See more details on using hashes here.

File details

Details for the file every_python-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: every_python-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 17.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for every_python-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1da459847a9e1b1b139fb0c4b700e75ece68dee3514d85f4556f6ad44a67ae02
MD5 afac84b8ecc0dc6b60110b4f3df00852
BLAKE2b-256 96cb67f4bdd1397656b17a36a66a4ba2e6a56f4e35a74950dbb717a4baf4042c

See more details on using hashes here.

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