docs: user guide for the substrait.dataframe API (Zensical)#214
Open
nielspardon wants to merge 8 commits into
Open
docs: user guide for the substrait.dataframe API (Zensical)#214nielspardon wants to merge 8 commits into
nielspardon wants to merge 8 commits into
Conversation
nielspardon
requested review from
andrew-coleman,
benbellick,
bestbeforetoday,
tokoko and
vbarua
July 14, 2026 07:52
Adds a multi-page guide for the ergonomic DataFrame/Expr API (from substrait-io#204), built with Zensical + mkdocstrings, plus a README introduction pointing to it. - docs/: 16-page guide (data sources, types, expressions, the `f` namespace, transformations, joins, aggregations, set ops, window functions, subqueries, parameters/context, DDL & writes, custom extensions, consuming plans) and a mkdocstrings-generated API reference. Every code example is verified against the real API. - zensical.toml: Material theme, nav, and the mkdocstrings Python handler pointed at src/. - pyproject.toml: `docs` dependency group (zensical, mkdocstrings-python) and a pixi `docs` environment with `docs-build`/`docs-serve` tasks. - .github/workflows/docs.yml: build-check on PRs (no deploy; a ready-to-enable GitHub Pages deploy job is included as a comment). - README.md: new "Building plans with the DataFrame API" section; the raw-proto examples are reframed as the low-level API. 🤖 Generated with AI
The substrait.dataframe docstrings used reStructuredText constructs that render as literal text under mkdocstrings' Markdown renderer. Convert them so the generated API reference reads well: - RST literal blocks (`::` + indented code) -> fenced ```python blocks. - Inline roles (:class:/:meth:/:func:/:mod:`...`) -> backticked names. - Fix two illustrative examples that would not resolve (`f.substring(..., 1, 3)` -> `f.upper(...)`; substring needs i32 offsets). Docstrings only; no behavior change. The 295 dataframe tests still pass and the 93 verified guide snippets are unaffected. 🤖 Generated with AI
Adds multi-version documentation publishing using the Zensical-compatible fork of mike, which commits each version to the gh-pages branch as a subdirectory of site_url. - zensical.toml: set site_url (required for versioning) and add [project.extra.version] (provider = "mike") to render the version selector. - .github/workflows/docs-deploy.yml: deploy job that runs on release tags (v*.*.*) and via workflow_dispatch. The manual trigger bootstraps the gh-pages branch so Pages can be pointed at it; tag pushes then publish each release as its minor series with a `latest` alias + root redirect. mike is installed ad-hoc (git-only), so uv.lock is untouched. - docs.yml: the PR build-check now points at docs-deploy.yml for publishing instead of the old single-version artifact-deploy note. Enabling it needs a one-time manual run (creates gh-pages) plus flipping Settings -> Pages -> Source to the gh-pages branch. 🤖 Generated with AI
Add a Documentation section covering local preview/build (pixi run docs-serve / docs-build), the Markdown-over-RST docstring convention, and where docs are published. 🤖 Generated with AI
The setup step referenced 'uv sync --extra test', but there is no 'test' extra (it errors). Test dependencies live in the default 'dev' dependency group, so plain 'uv sync' is the correct setup command. 🤖 Generated with AI
Keep the workflow header to a concise description of what it does; the Pages/gh-pages bootstrap runbook doesn't belong in the workflow file. 🤖 Generated with AI
Previously every ```python fence in the guide was inline text. `zensical
build` only renders those fences, so a snippet that went stale against the
API would render fine while being broken — the guide's code was never
executed.
Move each snippet into a runnable script under examples/guide/ and include
it into the page with pymdownx.snippets (`--8<-- "examples/guide/<page>.py:
<section>"`), mirroring the substrait-java approach. Then:
- Enable pymdownx.snippets in zensical.toml with check_paths=true, so a bad
include path or section name fails the docs build.
- Add tests/docs/test_guide_snippets.py, which executes every
examples/guide/*.py end to end. Snippets that build a DataFrame call
.to_plan(), so the test validates plan construction *and* resolution;
this surfaced and fixed several previously-broken examples (e.g. joins
referencing non-existent columns).
- Document the convention in CONTRIBUTING.md.
- The two engine-handoff snippets (DuckDB/ADBC tabs) stay inline: they need
network + an external engine and are exercised by examples/{duckdb,adbc}_
example.py (run by example.yml). Also add dataframe_example.py to that
workflow's matrix (it was omitted).
Resolve the pixi.lock conflict from rebasing the docs branch onto the updated main (pixi bumped to 0.73.0, substrait-io#229) by regenerating the lock with `pixi lock` so it carries both main's dependencies and the docs environment. uv.lock needed no change.
nielspardon
force-pushed
the
docs/dataframe-guide
branch
from
July 21, 2026 16:49
8031207 to
895a1a6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds user-facing documentation for the ergonomic native DataFrame/Expr API
(
substrait.dataframe) introduced in #204, plus a README introduction pointingto it. There was previously no guide for the new API — the README still led with
the verbose raw-
protoconstruction.Built with Zensical (Material-style,
zensical.toml) andmkdocstrings for the generated API reference.
The guide's code is not inline: every snippet is pulled from a runnable script
that CI executes, so a documented example that goes stale against the API fails
CI instead of silently rendering.
Contents
docs/— a multi-page guide: overview, getting started, data sources,types & schemas, expressions, the
ffunction namespace, transformations,joins, aggregations, set operations, window functions, subqueries, parameters
& context, DDL & writes, custom extensions, consuming plans, and a
mkdocstrings-generated API reference.
examples/guide/+tests/docs/— the guide's snippets live in runnablescripts, not in the Markdown. Each
```pythonfence is apymdownx.snippetsinclude (
--8<-- "examples/guide/<page>.py:<section>") pulling from a scriptunder
examples/guide/, andtests/docs/test_guide_snippets.pyexecutes everyone of those scripts end to end. Snippets that build a DataFrame call
.to_plan(), so the test validates construction and resolution — thissurfaced and fixed several previously-broken examples (joins on non-existent
columns,
user_defined(...), a nullable-struct schema). Amy_functions.yamlfixture backs the custom-extension snippets. The two engine-handoff snippets
(the DuckDB/ADBC tabs) stay inline since they need network + an external engine;
they are exercised by
examples/{duckdb,adbc}_example.py.zensical.toml— theme, nav,site_url, the mkdocstrings Python handler(pointed at
src/), themikeversion provider for multi-version docs, andpymdownx.snippets(withcheck_paths = true, so a bad include path orsection name fails the build).
pyproject.toml— adocsdependency group (zensical,mkdocstrings-python) plus a pixidocsenvironment withdocs-build/docs-servetasks; a per-file ruff ignore forexamples/guide/(its importsintentionally follow the docs rather than module conventions).
.github/workflows/docs.ymlruns a build-check on every PR (which nowalso validates every
--8<--include). The existingtest.ymlpicks up thenew
tests/docs/suite automatically.example.ymlgainsdataframe_example.py(it was previously omitted from the matrix).
docs-deploy.ymlpublishesversioned docs to the
gh-pagesbranch viamike, on release tags (v*.*.*)and via
workflow_dispatch.README.md— new "Building plans with the DataFrame API" section; theraw-
protoexamples are reframed as the low-level API.CONTRIBUTING.md— a Documentation section (local preview/build, docstringconvention) plus a Guide code snippets section describing the
pymdownx.snippetsworkflow; also corrects the dev-setup command (uv sync,not the non-existent
--extra test).substrait.dataframedocstrings fromreStructuredText (
::literal blocks,:class:/:meth:roles) to Markdown sothe generated reference renders cleanly. Docstrings only; no behavior change.
Building locally
pixi run docs-serve # or: uv run --group docs zensical serveEnabling GitHub Pages (one-time, after merge)
Versioned publishing needs the
gh-pagesbranch to exist before Pages can pointat it:
gh-pages).gh-pages/ (root).v*.*.*release tag publishes that minor series andupdates the
latestalias. Adjustsite_urlinzensical.tomlif the siteis served from a custom domain.
Verification
zensical buildcompletes with no issues (includes link validation); withcheck_paths, a wrong--8<--path or section name fails the build.tests/docs/, which runs every guidesnippet against the real API. A deliberately broken snippet fails that suite.
🤖 Generated with AI