2025, Nov 05 07:00

How to access project.urls from pyproject.toml at runtime: two standard-library ways for CLIs

Read project.urls from pyproject.toml at runtime: parse with tomllib or fetch installed metadata via importlib.metadata. Make your CLI self-describing today.

How to read [project.urls] from pyproject.toml at runtime, inside an entry point? This is a common need when a CLI wants to surface package metadata like a Homepage link without hardcoding it. Below is a concise walkthrough of two practical approaches that rely only on standard library facilities available in Python’s packaging ecosystem.

Problem statement

You have a package configured via pyproject.toml and a script exposed through an entry point. The goal is to obtain the URL mapped to the Homepage key under [project.urls] from inside the function behind spam:main_cli.

[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
"Bug Tracker" = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"
[project.scripts]
spam-cli = "spam:main_cli"

What’s really going on

At runtime you either have access to the project’s source tree, including pyproject.toml, or you only have the installed package. In the first case, you can directly parse pyproject.toml and read the [project.urls] table. In the second, you can query the installed distribution metadata and fetch the project URLs exposed by the package manager.

Solution 1: read pyproject.toml with tomllib

If the CLI runs in an environment where the project’s pyproject.toml file is available, parse it and pick the Homepage value directly from the mapping.

import tomllib as tlib
from pathlib import Path
def load_homepage_from_pyproject(pyproject_path: str):
    cfg_path = Path(pyproject_path)
    with cfg_path.open("rb") as fh:
        data = tlib.load(fh)
    urls_map = data.get("project", {}).get("urls", {})
    return urls_map.get("Homepage")
def cli_entry_pyproject():
    homepage_url = load_homepage_from_pyproject("pyproject.toml")
    if homepage_url:
        print(homepage_url)
    else:
        print("Homepage URL not found")

Solution 2: query installed metadata via importlib.metadata

If the package is already installed, you don’t need access to pyproject.toml. Retrieve the project URLs from the distribution metadata.

from importlib import metadata as pkg_meta
def fetch_project_urls(dist_name: str):
    meta = pkg_meta.metadata(dist_name)
    return meta.get_all("Project-URL")
def cli_entry_installed():
    urls = fetch_project_urls("spam-eggs")
    if urls:
        for item in urls:
            print(item)
    else:
        print("No Project-URL entries found")

Why this matters

Embedding metadata lookups directly into your entry points keeps your CLI self-describing without duplicating values across code and configuration. When the documentation site, repository, or issue tracker changes, you update a single source of truth and the CLI reflects it immediately. This also avoids brittle parsing of ad-hoc files or relying on non-standard layouts. As a bonus, the approach is straightforward even though it might not be immediately obvious from the documentation; a small, robust snippet is all that’s needed.

Practical takeaways

Choose the path that matches your runtime. If your tool runs inside the project tree, parse pyproject.toml and directly access [project.urls]. If it runs against an installed distribution, use importlib.metadata to obtain the project’s URLs. Keep the retrieval logic minimal and let the packaging metadata be the single source of truth.

The article is based on a question from StackOverflow by bad_coder and an answer by scr.