Skip to main content

pyproject.toml: The Project Contract

intermediate14 min readLesson 101 of 169

Metadata, dependencies, and build config in one standardized file.

Every modern Python project declares itself in pyproject.toml (TOML โ€” read it in the sandbox with tomllib):

[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "tasknoter"
version = "0.1.0"
description = "A typed, tested task manager"
requires-python = ">=3.12"
dependencies = []

[project.scripts]
tasknoter = "tasknoter.cli:main"

What each block promises:

  • build-system โ€” which tool turns this into an installable package (setuptools here; alternatives exist).
  • project โ€” identity: name, version, supported Python, and dependencies with version constraints (requests>=2.31,<3).
  • project.scripts โ€” console commands to generate (next lesson).

requires-python is a promise to your users: the tool refuses to install on older interpreters. Versioning your own project with semver-like bumps (0.1.0 โ†’ 0.2.0 for features, +0.0.1 for fixes) is the cheapest coordination tool you will ever adopt.

On your own machine, pip install -e . installs the project in editable mode โ€” the sandbox can't run pip (no network), so this course verifies the file is well-formed instead.

Now practice

pyproject.toml DrillsRead and validate project contracts with tomllib.2 challenges ยท ยท ~25 min