Skip to content

Development Guide¤

Prerequisites¤

Python¤

This project is written in Python and requires a Python interpreter to be installed for development.

We recommend using uv to install and manage Python versions on your development system. uv is also used for the rest of the project's development workflow (see the uv section below).

First, follow the Installing uv documentation and make sure that the uv command is available in your shell.

uv --version

Next, use uv to install Python 3.10 or later. We'll install the latest version of Python provided by uv (currently 3.13 at the time of writing).

uv python install 3.13

Note

As long as you have Python 3.10 or later installed, you should be able to follow the remainder of this guide.

The simplest way to install Python is to download an official installer. Check out this article for an overview of some alternative installation options.

uv¤

This project uses uv for project management. This includes managing the project's dependencies, running project tasks (via poe), running tests against multiple versions of Python, building the docs, creating new releases, etc.

If you installed Python with uv in the previous section, you already have uv installed. Otherwise, follow the Installing uv documentation now.

The important thing is that at this point, you should be able to run the uv command.

uv --version

Node.js¤

Some of the project's development tools (e.g. the cspell spell checker that runs as part of uv run poe check) are distributed as npm packages and require Node.js to run. Install Node.js and make sure the node and npm commands are available in your shell.

node --version
npm --version

Next, install the project's Node.js development dependencies (declared in package.json).

npm ci

The npm ci command installs the exact versions of the tools recorded in package-lock.json into a node_modules directory at the project root. Some of the project's tasks invoke these tools via npx — for example, uv run poe check runs the cspell spell checker with npx cspell.

Pull Requests¤

Installation and setup¤

Fork the tinydantic repository, clone it, and change directory to the project root.

git clone git@github.com:<your GitHub username>/tinydantic.git
cd tinydantic

Install the project along with all of its development dependencies.

uv sync --all-groups

Behind the scenes, uv creates a Python virtual environment in a .venv directory at the project root, installs the tinydantic package in development mode by performing an editable installation, and installs all of the project's dependencies. The --all-groups flag ensures that every dependency group is installed (including the dev group, which pulls in everything needed for testing, linting, type-checking, and building the docs).

You can run any command inside this environment by prefixing it with uv run. For example, you should be able to start the python interpreter and import the tinydantic package.

uv run python
>>> import tinydantic

Install pre-commit hooks¤

tinydantic uses pre-commit to automatically run a series of quality checks against your code locally before it is committed to the repository. (The pre-commit command was installed into the virtual environment when you ran uv sync --all-groups above.)

Install the pre-commit hook scripts into your local git repository.

uv run pre-commit install

When you commit your changes (git commit ...), the git hook scripts will run automatically and check for issues in your code.

Normally, pre-commit only checks the files that were modified as part of the commit. A poe task is provided to run pre-commit manually on all the files if needed.

uv run poe pre-commit

Make your changes¤

Create a new branch for your changes.

git checkout -b my-new-feature-branch

Run tests¤

While you are making changes in your new branch, you can run the test suite to make sure you didn't break anything.

uv run poe test

You can also run the test suite together with a Coverage report showing which parts of the code were executed by the tests.

uv run poe test-cov

Note

The test and test-cov tasks run against the single Python version installed in your .venv. The full test matrix — every supported Python version (3.10–3.14) across Linux, macOS, and Windows — runs automatically in CI when you open a pull request, which can catch issues that only show up with a specific version of Python or a specific operating system.

To run the test suite against every supported Python version locally, use the test-matrix task. It uses uv to build a temporary environment from uv.lock for each Python version (downloading any missing interpreters automatically) and runs test-cov in each one, without touching your .venv. After the per-version runs, it combines their coverage data and prints a single report spanning all versions, so version-specific branches aren't flagged as missed — you can also follow up with uv run coverage html for a combined HTML report. This covers the Python-version axis of the CI matrix; the operating-system axis still only runs in CI.

uv run poe test-matrix

After running uv run poe test-cov, you can also generate an interactive HTML coverage report.

uv run coverage html

Run formatters and linters¤

Before committing your changes, you should format your code and run the project's checks. First, format your code and apply autofixes with the Ruff formatter and linter.

uv run poe fmt

Then run the full suite of checks (linting, license/SBOM checks, spell-checking, and type-checking).

uv run poe check

Build Documentation¤

If you have made any changes to the documentation (including changes to function signatures, class definitions, or docstrings that will appear in the API documentation), make sure it builds successfully.

The following command will build and serve the documentation locally on your machine. While the server is running, it will watch for any changes to the documentation files, rebuild the site, and refresh your browser automatically.

uv run poe docs-serve

Before committing your changes, it's good to build and run some validation checks on the built documentation.

uv run poe docs-build-check

Note

The documentation build downloads Sphinx object inventories so that cross-references to external documentation (Python, Pydantic, TinyDB) resolve to links.

However, Read the Docs has put the site behind a Cloudflare bot challenge which blocks mkdocstrings' mkdocstrings/0.15.0 user agent, rejecting the TinyDB inventory download (this shows up as mkdocstrings: Couldn't load inventory ... HTTP Error 429: Too Many Requests).

If that happens (to any of the inventories), set the corresponding environment variable in your shell to point the build at a downloaded copy of the objects.inv inventory instead, then run the docs task as usual (from the repo root). The file: URL is resolved against the current working directory, so build from the repo root (the poe docs... tasks already require this).

Environment variable Default inventory URL
PYTHON_OBJECTS_INV https://docs.python.org/3/objects.inv
PYDANTIC_OBJECTS_INV https://docs.pydantic.dev/latest/objects.inv
TINYDB_OBJECTS_INV https://tinydb.readthedocs.io/en/latest/objects.inv

For example, to override the TinyDB inventory:

# If this doesn't work, just download the file manually with a web browser
curl -fL https://tinydb.readthedocs.io/en/latest/objects.inv -o tinydb-objects.inv

export TINYDB_OBJECTS_INV="file:tinydb-objects.inv"
# PowerShell: $env:TINYDB_OBJECTS_INV = 'file:tinydb-objects.inv'
uv run poe docs-serve

Commit your changes¤

When you are done making changes, commit them to your new branch.

tinydantic follows the Conventional Commits specification to enforce some consistency across commit messages.

git commit -m "<type>[optional scope]: <description>"

This cheat sheet lists the allowed options for the <type> field.

Here's an example of a commit message that follows the spec.

fix: correct minor typos in code

See the issue for details on the typos fixed.

Closes issue #12

Tip

The development dependencies automatically install the Commitizen CLI tool (cz) which walks you through creating a conventional commit message via a questionnaire-style interface.

Instead of git commit ..., use the cz command to commit your changes.

# Make your changes...
uv run cz commit

Create a PR on GitHub¤

When your changes are ready for review, push your branch to GitHub and create a pull request. Link to any relevant issues and include a description of your changes.

Creating a pull request will kick off a series of automated checks that run as part of workflows in GitHub Actions. If any of the checks fail, fix the issues locally in your PR branch, create a new commit (or amend your existing commits), and push the changes to the remote PR branch. GitHub will automatically run the checks again when changes are pushed to the PR branch. Repeat this process until all checks have passed.

Release Process¤

The release process is automated using workflows in GitHub Actions. New releases are created and build artifacts are published automatically when a compliant SemVer release tag of the form v<MAJOR>.<MINOR>.<PATCH> is pushed to GitHub.

Because the main branch is protected (no direct pushes), the version bump travels in a pull request like any other change, and the release tag is pushed afterward — git tags are not governed by branch protection.

  1. Update CHANGELOG.md with a section for the new release. The changelog is curated by hand; cz bump does not generate it.

  2. On a release branch, let Commitizen determine the next SemVer-compliant version from the commit history and write it to pyproject.toml without committing or tagging, then refresh the lockfile to match:

    uv run cz bump --files-only
    uv lock
    
  3. Commit the result (for example bump: version 0.1.19 → 0.2.0), push, open a pull request, and merge it once CI passes.

  4. Tag the merged commit on main and push the tag:

    git fetch origin
    git tag -a v<MAJOR>.<MINOR>.<PATCH> -m "Release version <MAJOR>.<MINOR>.<PATCH>" origin/main
    git push origin v<MAJOR>.<MINOR>.<PATCH>
    

When the tag is pushed to GitHub, a GitHub Actions workflow verifies that the tag matches the version in pyproject.toml, builds and publishes the Python package, creates a release on GitHub, and updates the documentation site.

Note

Do not create the GitHub release manually in the web UI — the release workflow creates it from the tag and will fail if one already exists.

Editor Setup¤

Todo

Add VS Code setup instructions