Skip to main content

pyproject-doctor

pyproject-doctor logo

Offline deep validator for pyproject.toml that catches the semantic mistakes other tools miss.

Most validators only check TOML syntax. pyproject-doctor goes further: it validates that your versions are PEP 440 compliant, your requires-python is a valid specifier set, your dependencies are PEP 508 compliant, your version constraints are actually satisfiable, your referenced files exist, your URLs are real URLs, your email addresses look right, and your entry-point references are correctly formatted.

What it checks

Code Description
version-invalid project.version is not a valid PEP 440 version
requires-python-invalid project.requires-python is empty, malformed, not a valid PEP 440 specifier set, or unsatisfiable (e.g. >=3.12,<3.8)
dep-invalid A dependency in project.dependencies, project.optional-dependencies, or build-system.requires is not a valid PEP 508 requirement
constraint-unsatisfiable A dependency's version specifiers form an impossible range (e.g. >=2.0,<1.0)
file-missing A file referenced by project.readme, project.license, or an entry-point module does not exist
url-invalid A value in project.urls is not a valid absolute URL
email-invalid An author or maintainer email address is malformed
entry-point-invalid A script or entry-point value is not in valid module:attr format
classifier-unknown A classifier in project.classifiers is not a known trove classifier (requires pip install 'pyproject-doctor[classifiers]')
dynamic-malformed project.dynamic is not a list of strings
dynamic-name-forbidden name appears in project.dynamic (PEP 621 requires it to always be static)
dynamic-field-unknown An entry in project.dynamic is not a recognized [project] field name
dynamic-static-conflict A field listed in project.dynamic is also set statically in [project]
license-expression-invalid project.license in its modern PEP 639 string form is not a valid SPDX license expression: empty, an unknown license or exception identifier, a deprecated identifier, the disallowed + suffix (use the -or-later form), a misplaced operator, or unbalanced parentheses. The legacy table form ({ file = ... } / { text = ... }) is not treated as an expression
build-system-requires-invalid build-system.requires is missing, not a list, or an empty list, when [build-system] is present
build-backend-package-missing A recognized build-system.build-backend (setuptools, hatchling, poetry-core, flit-core, pdm-backend, maturin, scikit-build-core, or meson-python) is declared, but its own package is not listed in build-system.requires. Skipped for unrecognized backends and for in-tree backends (backend-path set)
build-backend-tool-mismatch [tool.poetry] declares project metadata (name, version, or dependencies) while build-system.build-backend is not a poetry-core backend, or [tool.hatch] has configuration while the backend is not hatchling.build
poetry-pep621-conflict version or dependencies is set statically in both [project] and [tool.poetry], where the two tables use incompatible syntaxes and can silently diverge

Install

pip install pyproject-doctor

Or with classifier validation:

pip install "pyproject-doctor[classifiers]"

Usage

# Validate pyproject.toml in the current directory
pyproject-doctor

# Validate a specific file
pyproject-doctor /path/to/pyproject.toml

# JSON output
pyproject-doctor --format json

# SARIF 2.1.0 output (for GitHub code scanning and other SARIF consumers)
pyproject-doctor --format sarif

Exit code is 1 if any error-level diagnostic is found, 0 otherwise.

The sarif format emits a SARIF 2.1.0 log: each diagnostic becomes one result, the diagnostic code is the ruleId, every result points at the analyzed pyproject.toml, and the SARIF level (error, warning, note) is derived from the diagnostic's level.

Pre-commit

Add to .pre-commit-config.yaml:

repos:
  - repo: https://github.com/amaar-mc/pyproject-doctor
    rev: v0.5.0
    hooks:
      - id: pyproject-doctor

Example output

error project.version: version-invalid: 'not.a.version' is not a valid PEP 440 version
error project.dependencies[0]: constraint-unsatisfiable: Dependency 'requests': constraint '>=3.0,<2.0' is unsatisfiable (lower bound 3.0 exceeds upper bound 2.0)
error project.urls.Homepage: url-invalid: URL 'not-a-url' is not a valid absolute URL (must have scheme and host)

License

MIT. Copyright (c) 2026 Amaar Chughtai.

Metadata

Release files for pyproject-doctor 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyproject-doctor 0.5.0
File Size Uploaded
pyproject_doctor-0.5.0.tar.gz 962.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyproject-doctor 0.5.0
File Interpreter ABI Platform
pyproject_doctor-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 987.9 kB

Release files / pyproject_doctor-0.5.0.tar.gz

Download URL pyproject_doctor-0.5.0.tar.gz
Size 962.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e2f16fb7f51fae6dcfa087f1ea1adb4a13d50a6785229f641cbd7ad600194e36
BLAKE2b-256 checksum
How to use checksums
9105d932ae7254c6067c5a4bf2ecb9d47e1e84f6aff28951b7162ec8268fd011
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / pyproject_doctor-0.5.0-py3-none-any.whl

Download URL pyproject_doctor-0.5.0-py3-none-any.whl
Size 25.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d73e322ac5768b1abb4c8ff6a41c2453e0059e44be78f1d9ce214b97e923f179
BLAKE2b-256 checksum
How to use checksums
774520617ca53b949a2dd2f7a572e9364c7e8148f1297fd9130ccdcac34f20e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page