compilecode
compilecode compiles a project's Python modules to native .so extension
modules with Nuitka. The original .py sources and
bytecode are removed afterwards. There is no key and no runtime decryption:
the compiled modules are imported directly by Python.
Usage
Drop-in one-liner, run from the project root:
python -m compilecode .
Or, after installing the package (pip install -e .):
compilecode path/to/project
Options:
--strip-docstringsremoves docstrings from the compiled modules.--jobs N/-j Ncompiles that many modules in parallel. Each module is an independent Nuitka subprocess, so compiling a tree is roughly N× faster on an N-core box. The default ismin(4, CPU count)— capped because every job is a Nuitka + C-compiler process and uses real RAM. Pass--jobs 1to force serial compilation.--nuitka-jobs Ncaps how many C-compiler (cc1) jobs Nuitka forks per module. Nuitka's default is all cores, and on large modules eachcc1can use hundreds of MB — the usual cause of an out-of-memory kill. Lower this to cap peak memory.--low-memoryis the one switch for a small build host (~4 GB): it compiles one module at a time, with onecc1job, and turns on Nuitka's own low-memory mode. Slower, but it keeps the build from being OOM-killed. Combine it with a.compilecodeignore(below) that skips migrations, settings, and tests to cut the load further.
Running out of memory? A big Django/FastAPI project compiled on a small host can exhaust RAM: Nuitka forks several
cc1C-compilers (hundreds of MB each) per large module, and--jobs > 1multiplies that across modules. If the build grinds for a long time and then dies, reach for--low-memory, give the builder more RAM, or skip non-proprietary files via.compilecodeignore.
The exit code is 0 on success and 1 if any module failed to compile or
its source was not fully removed.
Drop-in swap (Docker)
The reference references/Dockerfile keeps the same compileit.sh one-liner
against $DOCKERHOME, so existing setups swap in without other changes. The line now
compiles the project to .so modules with Nuitka instead of encrypting it.
No key is generated or shipped in the image, so there is nothing to store or
rotate. The builder stage installs nuitka, and the runtime stage no longer
installs git, vim or dos2unix.
Ignoring files
Place a .compilecodeignore file in the project root to override which files
are compiled. It holds one pattern per line; blank lines and lines starting
with # are ignored. A pattern matches files that are left as plain Python.
A line starting with ! forces a file to be compiled even if another rule
would skip it.
Packaging
compileit.sh ships inside the installed compilecode/ package. It runs
python -m compilecode and honours the PYTHON environment variable to pick
the interpreter.
Releasing to PyPI / TestPyPI
release.sh versions, builds, and publishes the package. Everything runs
inside the docker compose test container — you only need Docker on the
host; build, twine, and setuptools_scm are never installed locally.
The version lives in git tags (via setuptools_scm): you never edit a
version by hand. release.sh computes the next one, tags the commit, builds
the sdist + wheel, uploads, and pushes the commit and tag back.
./release.sh <testpypi|pypi> [version] [options]
Version selection (pick at most one; default is a patch bump):
| You pass | Version used | Example |
|---|---|---|
| (nothing) | patch bump of the latest tag | 0.1.3 → 0.1.4 |
| (nothing), but HEAD is already on a tag | that tag is reused (so testpypi → pypi publishes the same version) |
0.1.3 |
--minor |
minor bump, patch reset | 0.1.3 → 0.2.0 |
--major |
major bump, minor+patch reset | 0.1.3 → 1.0.0 |
--version X.Y.Z |
exactly that | 2.5.1 |
Options
--dry-run— compute the version, build, andtwine checkonly. Makes no git changes, uploads nothing, pushes nothing. Run this first.--no-push— publish but skipgit push --follow-tags.
Authentication (only needed for a real upload). Either works:
-
A
.pypircwith[pypi]/[testpypi]sections (the default when no token env is set). It is searched as$PYPIRC, then./.pypirc, then~/.pypirc, mounted read-only into the container, and used viatwine upload --repository <target>. The[testpypi]section must include itsrepository = https://test.pypi.org/legacy/line:[pypi] username = __token__ password = pypi-AgEI... [testpypi] repository = https://test.pypi.org/legacy/ username = __token__ password = pypi-AgEI...
-
export TWINE_API_TOKEN="pypi-...."— a single token that takes precedence over.pypirc(matches twine's own env-over-file rule). Handy for CI.
Create tokens at https://pypi.org/manage/account/token/ (or test.pypi.org).
First release
./release.sh testpypi --version 0.1.0 --dry-run # rehearse, no side effects
./release.sh testpypi --version 0.1.0 # tag v0.1.0, publish to TestPyPI
./release.sh pypi --version 0.1.0 # same version → real PyPI
Routine release after merging new commits:
./release.sh testpypi --dry-run # shows the next patch, e.g. 0.1.1
./release.sh testpypi # tag v0.1.1, publish to TestPyPI, push
./release.sh pypi # HEAD on v0.1.1 → reuse → publish to PyPI
Verify a TestPyPI upload installs (its deps still come from real PyPI):
pip install --index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ compilecode
Try it end-to-end (smoke test)
references/examples/sample-project/ is a small app that exercises the tricky
cases (nested relative imports, a dataclass, a data file, an entry script). Its
smoke.sh builds the real two-stage Docker image — compile under full
python:3.13, run under python:3.13-slim — and asserts the compiled app
runs while its .py sources are gone:
./references/examples/sample-project/smoke.sh
Metadata
Release files for compilecode 0.1.1
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 | Actions |
|---|---|---|---|---|
| compilecode-0.1.1.tar.gz | 12.7 kB | Without provenance | Details for compilecode-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| compilecode-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for compilecode-0.1.1-py3-none-any.whl |
Total release size: 24.3 kB
Release files / compilecode-0.1.1.tar.gz
| Download URL | compilecode-0.1.1.tar.gz |
|---|---|
| Size | 12.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
15cef8ec7138396340285f4530b4a9200a51c7034ba5cbff0955e249d4108a95
|
|
BLAKE2b-256 checksum How to use checksums |
6e2dbdd5afc25994c2dd1e22343c892650140e42dea5a5f63169cd4c501a2460
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.18
|
Release files / compilecode-0.1.1-py3-none-any.whl
| Download URL | compilecode-0.1.1-py3-none-any.whl |
|---|---|
| Size | 11.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f3985423d7f85087f345ea92b5769936c176e18155cab0d5f6a6c2c0c0061504
|
|
BLAKE2b-256 checksum How to use checksums |
9f6b3c56894af284a3b9e8b0cf0810fe811b2b35c5b7da450bc849210eb07253
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.18
|
Security for compilecode 0.1.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.