Thank you for helping make Tablassert reliable. Reliability here includes the developer experience: a new contributor should be able to build, test, and understand the project without guesswork.
- Python 3.11 or newer.
- A stable Rust toolchain with
cargo,rustfmt, andclippy. - uv for Python dependency and command management.
- GNU Make for the local task runner.
justis useful in many projects, but this repo uses a minimalMakefileso the default loop works on this tree without extra tooling.
git clone https://github.com/SkyeAv/Tablassert.git
cd Tablassert
uv sync --group dev --extra qc --extra log
uv run maturin develop --manifest-path rust/Cargo.toml
uv run tablassert --helpuv sync --group dev --extra qc --extra log installs the development tools plus the optional QC runtime and loguru logging. maturin develop builds the PyO3 extension from rust/ and installs it into the uv-managed environment.
Shortcut:
make setup# after changing Rust code, or when the extension may be stale
make dev
# fastest focused checks
uv run pytest tests/test_lib.py::test_idxname_single_letter
cargo test --manifest-path rust/Cargo.toml fullmap::tests::clean_strips_matching_and_duplicate_quotes
# before commit
make checkUse make build when you need a release-mode extension for local performance checks. Normal development should use make dev; a release build can hide debug-only behavior and a later debug build replaces the editable extension in the same environment.
The Makefile is intentionally small and mirrors the underlying commands:
| Target | Runs |
|---|---|
make setup |
uv sync --group dev --extra qc --extra log and debug maturin develop |
make dev |
Debug editable extension build |
make build |
Release editable extension build |
make test |
Python tests with coverage |
make test-rust |
Rust tests |
make lint |
Ruff lint |
make fmt |
Ruff format and cargo fmt |
make fmt-check |
Ruff format check and cargo fmt --check |
make typecheck |
Pyright |
make check |
Lint, format check, typecheck, Python tests, Rust tests, and clippy with -D warnings |
make clean |
Local build/test/doc artifacts |
src/tablassert/ Python package and CLI
rust/src/ PyO3 Rust extension exposed as tablassert.rs
tests/ Python tests and fixtures
docs/ MkDocs site
mkdocs.yml Documentation navigation and theme settings
pyproject.toml Python metadata, dependencies, pytest/ruff settings
rust/Cargo.toml Rust crate metadata and dependencies
.pre-commit-config.yaml Local pre-commit quality hooks
The layout is deliberately flat. Prefer small, direct changes over new framework layers.
Run the full local gate before opening a PR:
make checkThe stable commands are:
uv run ruff check .
uv run ruff format --check .
uv run pyright
uv run pytest -q
cargo fmt --check --manifest-path rust/Cargo.toml
cargo test --manifest-path rust/Cargo.toml
cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warningsWhat the gates cover:
- Ruff linting and formatting. The current tree enforces core pycodestyle/pyflakes safety checks plus stale-suppression detection. It also enforces an expanded rule set covering common bug patterns (bugbear), simplifications, Python-version upgrades, pytest style, import order, and comprehensions. Treat
uv run ruff check .anduv run ruff format --check .as the stable interface rather than relying on individual rule codes. - Pyright. Type checking runs through
uv run pyright; the project is tightening this as a strict-inference ratchet over time. - Python tests. The suite is offline and runs in parallel by default via pytest-xdist (
-n autoinpyproject.toml): over 600 tests in ~20-30 seconds, reporting around 90% coverage in the default CI environment (--extra qc). Disable parallelism for a single serial run withpytest -n 0. CI runs the suite as a single job rather than sharding it across runners: roughly 21 of every 36 seconds is fixed overhead (interpreter start, imports, xdist worker spin-up, coverage init) rather than test execution, so splitting the suite costs more in per-runner setup than it recovers. - Rust tests.
cargo test --manifest-path rust/Cargo.tomlcurrently runs 46 Rust unit tests for the extension. - Rust style and lints.
cargo fmt --checkenforces formatting; clippy runs all targets with warnings denied.
Install hooks after setup. The --install-hooks flag matters: the config registers a pre-push stage as well as pre-commit, and without it only the pre-commit hooks are wired up.
uv run pre-commit install --install-hooksHooks are split across two stages so that committing stays cheap while the checks that most often break CI still run before anything leaves your machine.
On every commit, fast and auto-fixing:
ruff: fixes lint issues where possible.ruff-format: formats Python files.cargo-fmt: runscargo fmt --check --manifest-path rust/Cargo.toml.uv-lock-check: runsuv lock --checkwhenpyproject.tomloruv.lockchanges, so a dependency edit that was never relocked fails here instead of as an opaque CI sync error.
On every push, the whole-repo gates:
pyright: the same type check CI runs.cargo-clippy: all targets, warnings denied.
The ruff hooks cover the whole tree, matching CI's ruff check .. They used to be scoped to src/ and tests/, which meant examples/ could only ever fail in CI.
The full pytest suite and cargo test are deliberately in neither stage; they rebuild the Rust extension, and CI shards them across four runners far faster than a local serial run. Use make check when you want everything locally.
# one Python test
uv run pytest tests/test_lib.py::test_idxname_single_letter
# Python tests by keyword
uv run pytest -k "encoding"
# Rust-only tests
cargo test --manifest-path rust/Cargo.toml
# one Rust test by name
cargo test --manifest-path rust/Cargo.toml fullmap::tests::clean_strips_matching_and_duplicate_quotesFullmap builds are the heaviest local workflow. The build tunables are documented in Fullmap: Build Tunables; keep that page as the source of truth for spill settings, producer counts, cache sizing, and related environment variables.
If a full BABEL build fails with EMFILE, Too many open files, or another NOFILE-limit error, raise the shell limit before rerunning:
ulimit -n 65535If your OS hard limit is lower, raise the system/user NOFILE limit first, then open a new shell and rerun the build.
- Use conventional commits (
docs:,fix:,feat:,test:,chore:, etc.). - Keep PRs focused on one concern.
- Include tests or explain why none are needed.
- Run
make checkand include the result in the PR description. - PRs are squash-merged to
main; write commits and PR titles so the squashed history stays clear.
Open bug reports and feature requests at github.com/SkyeAv/Tablassert/issues. Include reproduction steps, the command you ran, and relevant environment details.
By contributing to Tablassert, you agree that your contributions will be licensed under the Apache License 2.0.