uvでPythonパッケージを公開する

Python

AGEFreighterを公開するにあたってTest PyPIから本番に移行し、それに伴っていくつかファイルをちゃんと作る必要もあったので、備忘録を兼ねてまとめておく。

環境整備

まずuvで以下の準備をする。

uv init agefreighter
cd agefreighter
uv venv
source .venv/bin/activate

Pythonのバージョンを指定する場合は、以下。

uv init agefreighter -p 3.10.0

これで、以下の状態になる。

.
├── README.md
├── hello.py
└── pyproject.toml

hello.pyは不要なので削除する。

毎回、sourceコマンドを実行するのが面倒な場合は、こちらのエントリーでも見てください。

コードと関連ファイル

age_freighter.pyとテストコードであるtest_agefreighter.py、テストデータを入れる。

.
├── README.md
├── data
│   ├── actorfilms.csv
│   ├── cities.csv
│   ├── countries.csv
│   └── edges.csv
├── pyproject.toml
├── src
│   └── agefreighter
│       ├── __init__.py
│       └── agefreighter.py
├── tests
│   └── test_agefreighter.py
└── uv.lock

src/agefreighter/__init__.pyの中身は以下の通り。これが無いとパッケージを見つけてくれない。

from .agefreighter import AgeFreighter

tests/test_agefreighter.pyを実行すると、あれやこれやのパッケージが無いと言われるので、逐一、uv addする。

uv add pandas

pyproject.tomlは以下の通り。dependenciesはuv addした際に更新されるので特に問題はないかと。build-systemとhatchに関する設定を追加してある。

[project]
name = "agefreighter"
authors = [
    {name = "Rio Fujita", email = "rifujita@microsoft.com"},
]
version = "0.3.0"
license = {file = "LICENSE"}
description = "AgeFreighter is a Python package that helps you to create a graph database using Azure Database for PostgreSQL."
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
    "asyncio>=3.4.3",
    "networkx>=3.4.2",
    "numpy>=2.1.3",
    "pandas>=2.2.3",
    "psycopg>=3.2.3",
    "psycopg-pool>=3.2.4",
    "pyarrow>=18.1.0",
    "resource>=0.2.1",
    "typing-extensions>=4.12.2",
    "neo4j>=5.27.0",
]

[tool.uv.workspace]
members = ["agefreighter"]

[project.urls]
Homepage = "https://github.com/rioriost/agefreighter"
Issues = "https://github.com/rioriost/agefreighter/issues"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.sdist]
include = [
  "src/agefreighter/*.py",
  "/tests",
]
exclude = [
  "uv.lock",
  "/data/*",
  "dist/.DS_Store",
]

[tool.hatch.build.targets.wheel]
packages = ["src/agefreighter"]

LICENSEファイルを追加する。中身はMITにしてある。ダミーデータを生成するスクリプトも追加。README.mdはGitHub Copilotにお願いすると良い感じのテンプレートを教えてくれるので、それを編集。

.
├── LICENSE
├── README.md
├── data
│   ├── actorfilms.csv
│   ├── cities.csv
│   ├── countries.csv
│   └── edges.csv
├── pyproject.toml
├── src
│   └── agefreighter
│       ├── __init__.py
│       └── agefreighter.py
├── tests
│   ├── dummy_generator.py
│   └── test_agefreighter.py
└── uv.lock

5 directories, 12 files

ビルド

ビルドサブコマンドを実行する。

uv build

すると、distsディレクトリにファイルが生成される。


├── LICENSE
├── README.md
├── data
│   ├── actorfilms.csv
│   ├── cities.csv
│   ├── countries.csv
│   └── edges.csv
├── dist
│   ├── agefreighter-0.3.0-py3-none-any.whl
│   └── agefreighter-0.3.0.tar.gz
├── pyproject.toml
├── src
│   └── agefreighter
│       └── agefreighter.py
├── tests
│   ├── dummy_generator.py
│   └── test_agefreighter.py
└── uv.lock

公開の準備

pypi.orgでアカウントを作成したら、[アカウント設定]→[APIトークン]で[APIトークンの追加]。生成されたトークンを、.zprofile等に環境変数として入れておくでも、パスワードマネージャに保存するでも、お好きなように。

export PYPI_TOKEN='pypi-xxxxxxx'

公開

publishサブコマンドで公開。

uv publish --token=$PYPI_TOKEN

まとめ

uvを使うと簡単。