Development

This guide explains how to set up a local development environment for pgcraft, run tests, lint code, and build the documentation.

Prerequisites

You will need the following tools installed:

  • Python 3.10+

  • uv — dependency management and virtual environments

  • just — command runner

Install uv by following the uv installation instructions — prefer whatever method is listed as current there.

Install just by following the just installation instructions — prefer whatever method is listed as current there.

Fork and clone

Fork the repository on GitHub, then clone your fork:

git clone https://github.com/<your-username>/pgcraft
cd pgcraft

Install all dependency groups and activate the virtual environment:

uv sync --all-groups

Install the pre-commit hooks (runs ruff automatically on every commit):

just setup

That’s it. You’re ready to develop.

Running tests

pgcraft uses pytest for testing.

Tests are organised into three directories that mirror the source tree under src/pgcraft/:

tests/unit/

Pure Python tests with no database dependency. These run instantly and cover things like factory configuration logic and template rendering. Fixtures that require a live database are intentionally unavailable here — pytest will error if a unit test accidentally references one.

tests/integration/

Tests that exercise real PL/pgSQL behaviour against a live PostgreSQL instance. Each test runs inside a transaction that is rolled back on teardown, so nothing is left in the database after the suite finishes. These tests require DATABASE_URL to be set; they skip automatically when it is absent.

tests/migrations/

pytest-alembic tests that verify the migration history is consistent and round-trips cleanly.

For fast feedback during development, run pytest directly:

just dev-test

To run the full test suite with tox (installs the package into a clean environment, matching what CI does):

just test

Both commands pass arguments through to pytest:

just dev-test tests/unit
just dev-test tests/integration
just dev-test -k test_shoot
just test tests/unit

Note

Integration tests require a PostgreSQL instance. Set DATABASE_URL before running them, for example:

DATABASE_URL=postgresql+psycopg://postgres@localhost/pgcraft just dev-test tests/integration

Coverage

pgcraft uses slipcover for coverage reporting:

just coverage

This runs the full pytest suite under slipcover and prints a per-file coverage table to the terminal. Pass any pytest arguments to narrow the scope:

just coverage tests/unit
just coverage tests/integration

Benchmarks

pgcraft ships with a performance benchmark suite built on pytest-benchmark. Benchmarks exercise the trigger-based API views for each dimension type against a real PostgreSQL instance.

Benchmarks are excluded from normal test runs (just dev-test and just test) via the addopts = "--ignore=tests/benchmarks" setting in pyproject.toml. Run them explicitly with:

just bench

You can pass any pytest-benchmark flags through:

# Save results for later comparison
just bench --benchmark-save=baseline

# Compare against a saved baseline
just bench --benchmark-compare=0001_baseline

# Only run ledger benchmarks
just bench -k ledger

Each benchmark row in the output table shows:

Column

Meaning

Min

Fastest observed round

Max

Slowest observed round

Mean

Arithmetic mean across all rounds

StdDev

Standard deviation (lower is more consistent)

Median

Middle value (robust to outliers)

Rounds

Number of times the function was called

To re-run benchmarks and update the documentation tables:

just bench-docs

This saves the JSON results and regenerates the RST included by Benchmarks.

Linting and formatting

pgcraft uses ruff for linting and formatting. It runs automatically as a pre-commit hook, but you can also run it manually:

just lint

Ruff will check for style issues and verify formatting. To auto-fix and auto-format:

uv run --group lint ruff check --fix
uv run --group lint ruff format

Type checking

pgcraft uses ty for type checking:

just type-check

Documentation

The docs are built with Sphinx using the Furo theme.

The doc build generates schema diagrams and query examples from a live PostgreSQL database, so DATABASE_URL must be set. If it is not set, the build defaults to postgresql+psycopg:///pgcraft.

To build the docs:

just docs

To serve the docs locally with live reload at http://localhost:8000:

just serve-docs

Or with an explicit database URL:

DATABASE_URL=postgresql+psycopg://localhost/pgcraft just serve-docs

The docs will automatically rebuild whenever you save a file.

Commands reference

just bench <*args>

Run performance benchmarks (requires DATABASE_URL)

just bench-docs

Run benchmarks and regenerate docs/benchmarks.rst results

just coverage <*args>

Run tests with coverage report (branch + line coverage)

just coverage-ci <*args>

Run coverage and write XML output (used by CI)

just dev-test <*args>

Run tests directly via uv (faster, for local development)

just docs

Build HTML docs for all versions (output in docs/_build/html)

just lint

Run ruff linter, formatter check, and sqlfluff lint

just serve-docs-autoreload

Serve docs with live reload for editing (http://127.0.0.1:8000)

just serve-docs-static

Serve the full versioned docs build (http://localhost:8000)

just setup

Install git hooks (run once after cloning)

just sql-format

Fix .sql files with sqlfluff

just sql-lint

Lint .sql files with sqlfluff

just test <*args>

Run tests via tox (full isolation, builds package as sdist)

just type-check

Run ty type checker

Contributing

Contributions are welcome. Fork the repository, make your changes with tests where applicable, verify the test suite and linter pass (see the sections above), then open a pull request against main.

Type annotations are required on all public API.

To report a bug, open a GitHub issue with a minimal reproduction case, what you expected, what happened, and your Python version and OS.

For security vulnerabilities, see SECURITY.md rather than opening a public issue.