| name | koopa-python-release |
| description | Acid Genomics Python package release — python.acidgenomics.com PEP 503 S3+CloudFront index, koopa app python publish/reindex, quality gate, CHANGELOG format, smoke test. Use when releasing or publishing an Acid Genomics Python package. |
Acid Genomics Python Package Release
Hosting
Python packages are hosted at python.acidgenomics.com — a private PEP 503
"simple" index backed by S3 (bucket in _BUCKET in lang/python/src/koopa/pypi.py) and served
via CloudFront. Packages are NOT published to public pypi.org.
- Packages:
s3://…/packages/<file>
- Index: served at the bucket root (
/) — index.html + <name>/index.html
- Publish tooling:
koopa app python publish <package-dir> (calls koopa.pypi.publish)
- Reindex tooling:
koopa app python reindex
- Implementation:
lang/python/src/koopa/pypi.py
Consumer install
uv pip install --index-url 'https://python.acidgenomics.com/' syntactic
[[tool.uv.index]]
url = "https://python.acidgenomics.com/"
Release checklist (e.g. py-syntactic)
Applies to any package in ~/git/personal/py-<name> that uses bumpver +
uv_build. Adapt as needed for other projects.
Pre-flight
- Confirm version in
pyproject.toml (version = "X.Y.Z" and
current_version = "vX.Y.Z" under [tool.bumpver]).
- Run all quality gates:
ruff format --check src/ tests/ docs/
ruff check src/ tests/ docs/
pyright
ty check
pytest
- All gates must be green before proceeding.
bumpver (if version not yet bumped)
bumpver is configured with tag = false, push = false, commit = true.
Running bumpver update --patch (or --minor/--major) bumps two lines in
pyproject.toml and creates a single commit — no tag, no push. The user owns
tagging and pushing.
Quality gate notes
pyright and ty check must exclude tests/ (test files import pytest,
a PATH dev tool not in the venv). Add to pyproject.toml:
[tool.pyright]
exclude = ["tests", ".venv"]
[tool.ty.src]
exclude = [".venv", "**/__pycache__", "**/.*", "tests"]
ty check can fail with Invalid VIRTUAL_ENV if the shell has a stale env
var (e.g. after moving the repo). Fix with:
[tool.ty.environment]
python = ".venv"
This overrides VIRTUAL_ENV and points ty directly at the local venv.
pytest needs pythonpath = ["src"] in [tool.pytest.ini_options] for
src-layout packages to be importable without a venv install.
Publish
koopa app python publish ~/git/personal/py-syntactic
This runs uv build, uploads wheel + sdist to S3, regenerates the PEP 503
index HTML at the bucket root, syncs it (with --exclude "packages/*" to
protect wheels from --delete), and invalidates CloudFront /*.
Requires: AWS profile acidgenomics configured; AWS_CLOUDFRONT_DISTRIBUTION_ID_PYTHON
set (or AWS_CLOUDFRONT_DISTRIBUTION_ID as fallback) — loaded from
<koopa-root>/.env if not already in the environment.
User-owned (git)
git tag vX.Y.Z
git push origin main
git push origin vX.Y.Z
Merging develop→main via PR before tagging is the standard flow.
Verification
After publish, confirm the package is installable:
tmp=$(mktemp -d)
uv venv --quiet "$tmp/venv"
uv pip install --python "$tmp/venv/bin/python" \
--index-url 'https://python.acidgenomics.com/' \
syntactic
"$tmp/venv/bin/python" -c "import syntactic; print(syntactic.__all__)"
rm -rf "$tmp"
pypi.py index layout
The index is served at the domain root (not /simple/). The S3 bucket
structure is:
packages/ ← wheels + sdists (never touched by reindex sync)
index.html ← root listing: <a href="syntactic/">syntactic</a>
syntactic/index.html ← per-package: links to ../packages/<file>#sha256=…
_sync_index_to_s3 uses --exclude "packages/*" with --delete so that
reindexing never wipes uploaded artifacts.
CHANGELOG format (py-* packages)
Keep-a-Changelog style, version at top. Example heading:
## 0.1.0 (2026-06-19)
Sections: ### Features, ### Bug Fixes, ### Changes, ### Tests.
Omit empty sections.
Documentation hosting
Rendered Sphinx docs are hosted at python-docs.acidgenomics.com — a separate
S3 bucket + CloudFront distribution from the package index, so the two are fully
independent (reindex never touches docs).
- Docs URL:
https://python-docs.acidgenomics.com/<name>/
- Bucket role:
python-docs → python-docs-<acct>-us-east-1-an
(via koopa_s3_bucket("python-docs") in aws.py)
- CloudFront env var:
AWS_CLOUDFRONT_DISTRIBUTION_ID_PYTHON_DOCS
(fallback: AWS_CLOUDFRONT_DISTRIBUTION_ID)
- Publish tooling:
koopa app python publish-docs <package-dir>
(calls koopa.pypi.publish_docs)
- Implementation:
lang/python/src/koopa/pypi.py — publish_docs()
publish-docs workflow
koopa app python publish-docs ~/git/personal/py-syntactic
This:
- Reads
[project] name from pyproject.toml, PEP 503-normalises it.
- Runs
uv run --extra docs sphinx-build -W -b html docs/ <tmp>/html.
- Syncs
<tmp>/html/ → s3://python-docs-<acct>-us-east-1-an/syntactic/
with --delete (scoped to that package's subtree only).
- Invalidates CloudFront
/* on the docs distribution.
Requires: AWS profile acidgenomics configured;
AWS_CLOUDFRONT_DISTRIBUTION_ID_PYTHON_DOCS set in <koopa-root>/.env.
User-owned AWS provisioning (one-time setup)
- S3 bucket
python-docs-<acct>-us-east-1-an (same region/account as the
package index bucket).
- CloudFront distribution: origin = docs bucket, alias =
python-docs.acidgenomics.com, ACM cert, default root object index.html.
- Route53 record
python-docs.acidgenomics.com → CloudFront distribution.
- Add
AWS_CLOUDFRONT_DISTRIBUTION_ID_PYTHON_DOCS to <koopa-root>/.env.
Verification
cd ~/git/personal/py-syntactic
uv run --extra docs sphinx-build -W -b html docs/ /tmp/docs-test
curl -sI https://python-docs.acidgenomics.com/syntactic/ | head -5
koopa app python reindex
curl -sI https://python-docs.acidgenomics.com/syntactic/ | head -5
R analog
R packages are hosted at r.acidgenomics.com via a drat repo in
~/git/personal/r-acidgenomics-com, using the same AWS account/profile/
CloudFront pattern. The Python index reuses that infra with a hand-rolled
PEP 503 generator in place of drat.