Skip to content

Docs site, PyPI packaging, duckdb (1.0.0 prep) - #8

Merged
Claptar merged 8 commits into
devfrom
feat/phase3-docs-and-pypi
Sep 15, 2026
Merged

Claptar merged 8 commits into
devfrom
feat/phase3-docs-and-pypi

Conversation

@Claptar

@Claptar Claptar commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Phase 3, the last of the roadmap. Stacked on #7, which is stacked on #6 — this PR's own diff is docs, packaging and the Dockerfile.

PyPI

pip install adata-cli was not possible; several things blocked it.

  • Documentation = "README.md" is not a URL, and PyPI rejects it. Now points at the Pages site.
  • Added license-files = ["LICENSE"], Operating System and Typing :: Typed classifiers, Python 3.13, a py.typed marker, and a Changelog URL.
  • __version__ reads from installed metadata instead of being duplicated in a second place, and adata --version reports it.

New publish.yml uses trusted publishing (OIDC), so there is no API token to store. It:

  • reuses tests.yml through workflow_call, so a release cannot skip the suite;
  • refuses to publish when the tag does not match the version in pyproject.toml. Nothing enforced that before, which is how 0.3.2 came to be tagged against a tree declaring 0.3.1;
  • has a workflow_dispatch path targeting TestPyPI, so the first publish can be rehearsed.

Verified locally: uv buildtwine check passes, the wheel installs into a clean venv, and adata --version / adata ls / the deprecated h5ad alias all work from that install.

Docs site

GitHub Pages served from docs/ with plain Jekyll — no generator, so the files stay readable as markdown on github.com.

  • docs/index.md — landing page with a format support matrix
  • docs/COMMANDS.md — full reference for all eight commands, the query language, and Zarr format selection
  • Each ELEMENTS_*.md gains a "What adata-cli does with these elements" section. They were pure spec transcriptions that said nothing about the tool's own behaviour, so nothing in the repo recorded what was and wasn't supported.
  • Documents the null encoding, which is absent from the upstream prose spec but is what anndata 0.12+ writes for None in uns.
  • ELEMENTS_zarr.md gains a v2 vs v3 section covering the differences that actually matter when copying between stores — VLenUTF8 in filters versus the v3 string data type, compressor versus compressors, sharding — and why text is always written as variable-length UTF-8.
  • Fixed the README's broken link to the deleted docs/TESTING.md.

You still need to enable Pages in repo settings → Pages → Deploy from branch → main / /docs.

duckdb replaces csvkit

The tutorial now leads with --obs-query, which covers the exact example csvsql was there for, and keeps duckdb for filters that genuinely need SQL — joins, aggregates, window functions. duckdb reads the CSV in place with no import step, and -noheader -list emits exactly the one-name-per-line format --obs expects.

The Dockerfile drops the csvkit side-venv for a single static duckdb binary (no venv, so it cannot conflict with the project's dependencies), passes the --locked flag its comment already claimed but did not use, drops the stale "install git so we can clone the repo" step, and retargets the image to quay.io/cellgeni/adata-cli.

This also folds in what main's stranded 32520d3 was reaching for. Note the image is 820MB, largely the Python base — worth a separate look if that matters.

Verified with a real build: the image builds, and the documented duckdb workflow runs end to end inside it:

$ docker run --rm -v "$PWD":/data --entrypoint bash adata-cli:test -c '...'
duckdb selected 3 barcodes
An object with n_obs × n_var: 3 × 4

CHANGELOG

Added, covering the whole 0.5.0 line across all three phases, with the deprecation removals called out.

Before you tag

Two things still outstanding from planning, both needing a decision rather than code:

  • main and dev have diverged. main carries 32520d3 (duckdb-cli in the Dockerfile) which never reached dev; merging devmain as-is would revert it. This PR supersedes that commit's intent, so the simplest resolution is probably to take this branch's Dockerfile.
  • Tag 0.3.2 points at dev's tip, not at anything on main. Worth reconciling before publish.yml starts firing on tags.

🤖 Generated with Claude Code

Prepares the first PyPI release and gives the project documentation that
lives somewhere other than the repo root.

Packaging: `Documentation` was "README.md", which is not a URL and PyPI
rejects it. Adds license-files, Operating System and Typing classifiers,
Python 3.13, py.typed, and a Changelog URL. `__version__` reads from installed
metadata rather than being duplicated, and `adata --version` reports it.

publish.yml publishes on a tag using PyPI trusted publishing, so there is no
API token to hold. It reuses tests.yml via workflow_call, so a release cannot
skip the suite, and refuses to publish when the tag does not match the version
in pyproject.toml -- nothing enforced that before, and 0.3.2 was tagged against
a tree declaring 0.3.1. A workflow_dispatch path targets TestPyPI first.

Docs become a GitHub Pages site served from docs/ with plain Jekyll, so the
files stay readable as markdown on github.com. Adds index.md, a full
COMMANDS.md reference, and to each ELEMENTS doc a section on what this tool
actually does with each element -- they were pure spec transcriptions saying
nothing about the CLI. Documents the `null` encoding (absent from the upstream
prose spec but written by anndata 0.12+) and, for Zarr, the v2/v3 differences
that matter when copying between stores.

csvkit is replaced by duckdb in the tutorial and the image. The tutorial now
leads with `--obs-query`, which covers the example it used csvsql for, and
keeps duckdb for filters that genuinely need SQL. The image drops the csvkit
side-venv for a single static duckdb binary, and passes the --locked flag its
comment already claimed.

Verified: the wheel installs into a clean venv and runs; the image builds and
the documented duckdb workflow runs inside it end to end.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 15, 2026 11:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-15T11:33:48.998523Z 5d189b6 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown

Test Results (py3.13)

323 tests  +79   323 ✅ +79   28s ⏱️ -5s
  1 suites ± 0     0 💤 ± 0 
  1 files   ± 0     0 ❌ ± 0 

Results for commit f9894c6. ± Comparison against base commit a7cdf9a.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown

Test Results (py3.12)

323 tests  +79   323 ✅ +79   32s ⏱️ -2s
  1 suites ± 0     0 💤 ± 0 
  1 files   ± 0     0 ❌ ± 0 

Results for commit f9894c6. ± Comparison against base commit a7cdf9a.

♻️ This comment has been updated with latest results.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d189b60d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/publish.yml Outdated
Comment thread docs/index.md Outdated
Comment thread docs/COMMANDS.md
Claptar and others added 3 commits September 15, 2026 13:34
publish-pypi depended on check-version, which only runs for tags. GitHub skips
a job whose dependency was skipped, so a manual dispatch targeting PyPI would
never have published anything. Both publish jobs now use always() with the
success of build asserted explicitly, accepting check-version as either passed
or not applicable.

The Dockerfile sets ENTRYPOINT ["adata"], so the README and index examples
were running `adata adata view ...`, which Typer rejects. Dropped the repeated
executable; verified against the built image.

COMMANDS.md listed `--zarr-format` among split's options, but the flag did not
exist -- `adata split ... --zarr-format 2` failed with an unknown option.
Implemented it rather than deleting the claim: split already inherited the
source store's Zarr version, so only the override was missing.

Adds tests/test_docs_are_accurate.py, which extracts every `adata ...`
invocation from the README and docs and checks each command and option against
the real --help. That alone would not have caught this one, since the claim
lived in prose rather than a fenced example, so sentences naming an option and
the commands offering it are checked too. Both checks fail if the flag is
removed again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The docs test scraped `--help` output, which Rich wraps to the terminal width.
It passed on a wide local terminal and failed in CI, where the width is
narrower and long option names break across lines -- an assertion about
rendered UI rather than about the CLI.

Options now come from the Click command objects behind the Typer app, so the
check is exact and width-independent. Verified passing at COLUMNS 40 through
200, and still failing at both widths when --zarr-format is removed from
split again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The short name was free when this was planned but has since been claimed by an
unrelated "AData CLI" project, uploaded 2026-04-04. Publishing would have
failed against a project we do not own, so the distribution is now
`pyadata-cli`, matching the pending publisher configured on PyPI.

Only the distribution name changes. The repository, the import package, the
command and the documentation all stay `adata` / `adata-cli`, so the sole
user-visible difference is `pip install pyadata-cli`. That mismatch is
explained where the install is documented rather than left to surprise anyone.

__version__ reads its metadata under the new name, so `adata --version` keeps
working; verified by installing the built wheel into a clean environment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Claptar
Claptar changed the base branch from feat/phase2-commands to dev September 15, 2026 14:01
@Claptar
Claptar merged commit 8c76f2a into dev Sep 15, 2026
4 checks passed
@Claptar
Claptar deleted the feat/phase3-docs-and-pypi branch September 15, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants