Python
1. What's in the catalogue
Five published lines, 3.10.21 through 3.14.7, floating with security updates; pin with @3.10 … @3.14. As of catalogue 2026.35.22 (2026-08-25):
| Tool | Caps | Requires | Notes |
|---|---|---|---|
python | rw | — | no network by default; uv provider available for env builds |
pip | net, rw | python | plain pip, single requirements.txt file |
uv | net, rw | python | lockfile provider; also the default for env builds (see below) |
flake8 | ro | [email protected] | style/logic checker, no writes |
mypy | rw | [email protected] | plus dmypy (daemon), stubgen, stubtest |
pylint | ro | python | plus the pyreverse binary |
black | rw | [email protected] | formatter |
bandit | rw | [email protected] | security linter; bandit-baseline, bandit-config-generator |
pytest | rw | python | test runner |
Declared, not yet runnable: ruff, jupyter, ipython, poetry. Their images are in the signed payload but no tool is bound, so kapsl --info ruff reports unknown tool. Don't write recipes against them until they publish.
kapsl --info python LINES RESOLVES TO
▸ @latest 3.14.7 in use
@3.14 3.14.7
@3.13 3.13.15
@3.12 3.12.14
@3.11 3.11.16
@3.10 3.10.21
lines float — kapsl carries security updates onto them
pin one with python@<version> · a digest never moves
CAPS rw2. The five-minute version
kapsl python --version
Python 3.14.7
No Python on the host, no install, nothing to uninstall. The first run pulls the image and scans it; warm runs are sub-second.
Run a script:
kapsl python script.py
The inline package form — python:pyyaml builds a one-shot environment with that package, scanned, then runs:
kapsl python:pyyaml -c "import yaml; print('pyyaml', yaml.__version__)"
pyyaml 6.0.3
The file-based form — a pinned requirements.txt next to the script:
kapsl -e @pip:requirements.txt python script.py
requests 2.34.2
Both environment forms are described in Always current; the -e file is content-hashed, so the built environment image is cached and reused unchanged across runs and machines until the file changes.
3. The environment story: why the default is uv, not pip
python is the only major ecosystem in the catalogue whose default package provider is not its own native manager. The inline form kapsl python:… and the bare -e dispatch route to uv; -e @pip:requirements.txt stays plain pip, exactly as asked.
The reason is lockfiles, not speed. Every other ecosystem records what it resolved, so an unpinned manifest is still reproducible. Plain pip produces no resolved set at all, and requirements.txt is a manifest, not a lock. uv can emit one, so routing the default through uv is what lets Python join the rest of the design instead of being permanently exempt from it. If you want pip's exact behaviour — no resolver changes, no lockfile — name it: kapsl -e @pip:requirements.txt python script.py works exactly as pip does, and -e @uv:pyproject.toml uses uv directly.
Two concrete consequences:
- Package rules can grant capabilities. The catalogue carries
package_rulesentries forrequests,flask,django,fastapi, … — when a built environment contains one of those packages, the run getsnetautomatically. AroPython container that importsrequestsand then fails on the socket would be a confusing failure, so the grant is baked in by the catalogue. Your own internal packages can get the same treatment via a project'spackage_rules(see Project configuration). - The environment image is the unit of caching.
kapsl -e @pip:requirements.txtbuildskapsl-env-python-latest:pip-<hash>; change one pin and you get a new hash, a new image, a new scan. The basepythonimage is untouched.
4. Tooling
The published linter set is the classic five: flake8, mypy, pylint, black, bandit, plus pytest. Each runs in its own signed image against your mounted working tree, so a linter upgrade never touches the runtime and the runtime never touches the linter.
kapsl flake8 app.py
kapsl mypy app.py
kapsl black --check app.py
kapsl bandit -r .
kapsl pytest
ruff — the consolidator that most projects have moved to — is declared, not published: its image is in the catalogue payload with no tool bound yet. Check kapsl --info ruff before relying on it.
The IDE and linters use case covers running these from an editor, the language-server shapes, and why ro linters are the safest tools to run unattended.
5. Project patterns
The examples corpus has the deepest Python coverage of any language. All are runnable as written; each README carries the captured transcript.
flask-quickstart— a real Flask app:requirements.txt,-e @pip, the trust prompt on first run, and the server bound to0.0.0.0behind a published port. Its README documents the failure modes too: what happens when you forget the port, and why--watchand.envinteract badly in a container.django-quickstart— the canonicalsubcommand_index: 1case.args[0]is always the literalmanage.py, so the overlay keys on the next argument and publishes port 8000 only forrunserver—migrateandtestget no port.fastapi-quickstart— uvicorn with--reload, thepackage_rulesnet grant forfastapidoing its job, and the reload-watcher caveats on macOS.pip-python-file— the three levels of integration in one project: barekapsl python, plus a.kapslrcthat setsenv_file: requirements.txtso a barekapsl pythonbehaves like an activated venv, plus a shim. Its README is the best write-up of whykapsl pip installevaporates (it installs into the tool's own ephemeral container, not your environment) and of the first-run trust review.pip-python-lifecycle— the workflow for evolving dependencies: edit the file, re-run, watch the environment image rebuild and rescan.uv-python—-e @uv:pyproject.tomlend to end, including the lockfile.
The .kapslrc from django-quickstart is the shortest complete example of a real project overlay:
tools:
python:
env_file: requirements.txt
subcommand_index: 1
subcommands:
runserver:
ports: ["8000"]6. Known limitations
These are real, from the example transcripts:
kapsl pip installdoes not persist. It runs in thepiptool's own container; when the container exits, the install is gone. Persistent dependencies belong in an environment (-e @pip:requirements.txtor-e @uv:pyproject.toml). This trips up everyone coming frompip installmuscle memory.- The CA bundle. The Python images don't carry the host's CA store. TLS to an internal endpoint signed by a private CA fails with
CERTIFICATE_VERIFY_FAILEDuntil you pointREQUESTS_CA_BUNDLE/SSL_CERT_FILEat the bundle — thepip-python-fileREADME walks through the exact env-var wiring. --watch/--reloadon macOS. File-watch extensions are unreliable on the bind mount; the Flask and FastAPI examples document the failure and the workaround (polling, or running the watcher outside the container). The same examples note that a--watchrun and a published port don't compose — the watcher restarts the child outside the port's scope.- pip takes one file. The
@pipprovider installs a singlerequirements.txt-style file; multi-file or editable installs want the@uvprovider.