Contributing to tabsight¶
Thanks for helping. A few ground rules keep the package predictable.
Principles every change must keep¶
- Never change the user's DataFrame. Work on copies.
- Every guess has a default and an override.
- Warn, don't block (unless the user asks for strict mode).
- Same input gives the same output. No randomness, no clock, no network.
- Every data value that reaches HTML is escaped.
Setup¶
See the "Development setup" section in README.md.
Before opening a pull request¶
python -m pytestpasses (Node tests run when Node.js is installed)python -m ruff check .andpython -m ruff format --check .passpython -m mypypasses- New behaviour has tests, including the "input DataFrame unchanged" check for public functions
- Code uses Python 3.11 syntax only (no 3.12+ features)
CHANGELOG.mdhas an entry under "Unreleased"
Branches and commits¶
- Never push to
maindirectly: it is protected. Work on a branch named after the change, for examplefix/kpi-compare-labelorfeat/server-mode, and open a pull request. - Write commit messages in the Conventional Commits
style:
type(scope): summary, in the imperative and under 72 characters. For example:fix(dashboard): keep drill crumbs after a theme switch. Types:feat,fix,docs,test,refactor,perf,build,ci,chore,security. - Explain why in the commit body when it isn't obvious. Mark breaking changes with
!(feat(spec)!: ...) and aBREAKING CHANGE:line. - Keep each pull request to one change. Pull requests are squash-merged, so the title must follow the same commit style.
- CI must be green: tests on Python 3.11–3.14, lint, types and the dependency audit.
- Never commit data files, secrets,
.envfiles, built sites (site/) or notebooks with outputs.
Reporting security problems¶
Don't open a public issue. Follow SECURITY.md and use GitHub's private vulnerability reporting.
Third-party files¶
Never edit files in src/tabsight/render/static/ that come from upstream. Change the pinned version in tools/fetch_vendor.py, run python tools/fetch_vendor.py --update, and update NOTICE.
Releasing (maintainer)¶
- In a pull request, set the version in
src/tabsight/_version.py(for example0.1.0) and rename the changelog's "Unreleased" heading to that version and date. - Once it is merged and CI is green, tag
mainand push the tag:git tag v0.1.0 && git push origin v0.1.0. - The Release workflow checks that the tag matches the version, builds the sdist and wheel, checks them, and publishes to PyPI with trusted publishing (no token stored anywhere). The first time, add the repository as a trusted publisher on pypi.org: project
tabsight, workflowrelease.yml, environmentpypi.
Release tags can't be moved or deleted (a ruleset protects v*), so a published version always matches its tag.
Working on the documentation¶
The documentation is the Markdown in docs/. It reads well on GitHub and is built into a website with Zensical (the successor to Material for MkDocs), which reads mkdocs.yml:
python -m pip install -e ".[docs]"
zensical serve # live preview at http://localhost:8000
zensical build --strict # warnings, such as broken links, fail the build
Every Python example in the docs runs. To show what an example prints, put an empty block right after it:
```text title="Output"
```
Then run python tools/render_doc_outputs.py, which runs the page and fills in the real output. tests/test_docs.py fails if any shown output no longer matches what the code prints, so the docs can't drift from the package. Start a code block with # not run if it only illustrates.
A few habits keep the docs readable: start a page with the problem it solves, show a small real example before any options, explain why in plain sentences, and save tables for genuine reference lists.