Batu Lab NotesPractical developer guides

Find a version in pyproject.toml without parsing every tool config

By Batu ยท English technical notes

Also published in our Blogger archive.

Direct answer

tomllib.loads provides a precise parsing boundary for a readiness scanner. This article supports exactly one source: a string at [project].version. It deliberately returns unavailable for a dynamic declaration because packaging metadata can obtain version from a build-time provider rather than this table. It also catches TOMLDecodeError, so broken syntax cannot be misreported as a discovered version. The three assertions distinguish static metadata, dynamic metadata, and malformed text. The helper does not inspect tool-specific tables, invoke a backend, or validate a version scheme. Supporting another convention should be an explicit documented branch with its own test, not an unbounded search that can confuse a tool version with the project version.

Complete example

import tomllib


def project_version(text: str) -> str | None:
    try:
        project = tomllib.loads(text).get("project", {})
    except tomllib.TOMLDecodeError:
        return None
    value = project.get("version")
    return value if isinstance(value, str) else None

assert project_version("[project]\nversion = \"1.2.3\"") == "1.2.3"
assert project_version("[project]\ndynamic = [\"version\"]") is None
assert project_version("[project\nversion =") is None
print("static=1.2.3 dynamic=unavailable malformed=unavailable")

Expected stdout:

static=1.2.3 dynamic=unavailable malformed=unavailable

Sources

- tomllib documentation

Prepared with AI assistance. The example uses synthetic data; its stated limits apply.