2025, Nov 06 21:01
Два способа получить URL из [project.urls] в entry point
Показываем, как в Python-CLI получить URL из [project.urls] в pyproject.toml: через tomllib по исходникам и через importlib.metadata по установленному пакету.
Как получить значение из [project.urls] в pyproject.toml во время выполнения — прямо внутри entry point? Это частый сценарий, когда CLI должен показывать метаданные пакета, например ссылку на Homepage, не пришивая её в код. Ниже — краткая инструкция по двум рабочим подходам, которые опираются только на возможности стандартной библиотеки, доступные в экосистеме упаковки Python.
Постановка задачи
У вас есть пакет, настроенный через pyproject.toml, и скрипт, опубликованный как entry point. Цель — получить URL, соответствующий ключу Homepage в разделе [project.urls], из функции, на которую указывает 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"
Что на самом деле происходит
Во время выполнения возможны два сценария: либо у вас есть доступ к дереву исходников проекта, включая pyproject.toml, либо у вас есть только установленный пакет. В первом случае можно напрямую разобрать pyproject.toml и прочитать таблицу [project.urls]. Во втором — запросить метаданные установленного дистрибутива и забрать URL-адреса проекта, которые предоставляет менеджер пакетов.
Решение 1: читаем pyproject.toml с помощью tomllib
Если CLI запускается в окружении, где доступен файл pyproject.toml проекта, разберите его и возьмите значение Homepage напрямую из соответствующего словаря.
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")
Решение 2: получаем метаданные установленного пакета через importlib.metadata
Если пакет уже установлен, доступ к pyproject.toml не нужен. Получите URL-адреса проекта из метаданных дистрибутива.
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")
Почему это важно
Встраивая получение метаданных прямо в entry points, вы делаете CLI самодокументируемым и избегаете дублирования значений между кодом и конфигурацией. Когда меняется сайт документации, репозиторий или трекер задач, достаточно обновить единственный источник правды — и CLI сразу это подхватит. Это также избавляет от хрупкого парсинга произвольных файлов и зависимости от нестандартных структур. Плюс, подход остаётся простым, даже если из документации это неочевидно: нужен лишь небольшой, надёжный фрагмент кода.
Практические выводы
Выбирайте путь, который соответствует среде выполнения. Если инструмент запускается внутри дерева проекта, разбирайте pyproject.toml и обращайтесь напрямую к [project.urls]. Если работаете с установленным дистрибутивом, используйте importlib.metadata, чтобы получить URL-адреса проекта. Держите логику извлечения минимальной и полагайтесь на метаданные упаковки как на единственный источник истины.