Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Development environment

This page describes what you need to know to work on the Pymetropolis codebase itself (as opposed to using it to run simulations). It assumes you are already familiar with the Pipeline (Steps, MetroFiles, Parameters).

Setting up

Pymetropolis uses uv for dependency management. After cloning the repository and installing uv, install the project and its development dependencies (pytest, ruff, ty) with:

uv sync

Use uv add <package> / uv remove <package> to change dependencies rather than hand-editing pyproject.toml, and uv run <command> to run any tool inside the project’s virtual environment (e.g. uv run pymetropolis my-config.toml) rather than manually activating it.

pyproject.toml declares requires-python = ">=3.12"; write code that targets that version, using modern syntax (X | None rather than Optional[X], builtin generics such as list[int] rather than typing.List[int]).

Code style

Formatting and linting are handled by ruff:

uv run ruff format
uv run ruff check --fix

The project’s [tool.ruff] settings (in pyproject.toml) set a 100-character line length and disable the “magic trailing comma” formatting behavior. Two lint rules are intentionally disabled: C408 (so list()/dict() calls are allowed) and RUF012 (so a Step’s input_files/ output_files class attributes can stay plain mutable dict literals, which is the pattern the Pipeline relies on).

Type-checking is handled by ty:

uv run ty check

Type-hint every new or modified function signature.

Tests

Tests live under tests/ and run with pytest:

uv run pytest

Existing tests (see tests/pipeline_test.py, tests/population_test.py) follow a consistent, lightweight style: plain test_* functions (no fixtures or test classes), a handful of small throwaway Step/MetroFile classes defined at module level for the scenario being tested, and tempfile.TemporaryDirectory() combined with Config({...}) / MetroPipeline(...) to exercise the Pipeline without touching real files. Follow this style for new tests rather than introducing a new testing pattern.

Submitting changes

The contributing guidelines and code of conduct in the repository apply to every contribution. In short:

  1. Fork the repository and create a feature branch.
  2. Make your changes, and run uv run ruff format, uv run ruff check --fix, and uv run ty check until they report no issues.
  3. Run uv run pytest and make sure every test passes; add tests for new behavior.
  4. Update CHANGELOG.md if the change is user-visible.
  5. Open a pull request. The PR template checklist covers code style, documentation, tests, and licensing — fill it in.

Every pull request and every push to main is checked by GitHub Actions (.github/workflows/lint.yml): ruff format --check, ruff check, ty check, and the full test suite must all pass before a PR can be merged.

Note

Releasing a new version (tagging, building, and publishing to PyPI) is handled by maintainers via the publish-to-pypi.yml workflow, triggered by pushing a v* tag. As a contributor, you do not need to do this yourself.

Regenerating the reference documentation

The Steps, Parameters, and MetroFiles reference pages in this book are partly generated from the Pymetropolis codebase, by introspecting every registered Step/Parameter/MetroFile (their docstrings, Parameter descriptions, Column schemas, etc.). If you add or modify a Step, Parameter, or MetroFile, an official maintainer will regenerate these pages from the Pymetropolis repository with:

uv run python -m pymetropolis.bin.generate_doc <path-to-this-book>/src/pymetropolis/references/

This overwrites steps-generated.md, parameters-generated.md, and files-generated.md in the book’s repository.

Warning

Only what is exported through your package’s STEPS/FILES lists (and, transitively, aggregated into pymetropolis.schema) is picked up — see the Creating MetroFiles and Creating Steps with Parameters pages for the registration convention.