概要
- 自作したパッケージをTestPyPI/PyPIに公開する方法を紹介します。
- パッケージの作成とTestPyPI/PyPIへの公開はPoetryを使用します。
注意事項
- 本記事は2025/02/24時点の情報です。最新情報とは異なる場合があります。記載内容と異なる場合は公式の最新情報を確認してくだい。
- Poetryのver2.0.0でPEP621対応がサポートされ、pyproject.tomlは
[project]
セクションでプロジェクト情報を管理するようになりました。1
ver2.0.0より前のバージョンでは[tool.poetry]
セクションで管理する仕様のため利用状況に合わせてpyproject.tomlの作成が必要になります。
- 本記事では両方の記法を紹介しますが、最新版では仕様が変わる可能性があるため、事前に動作確認(TestPyPIへの公開)をすることを推奨します。
各種情報
Poetryのバージョン
$ poetry --version
Poetry (version 2.1.0)
プロジェクト情報
下記リポジトリをPyPIに公開します。
github.com
プロジェクトについて簡単に説明すると、Python系のドキュメントで使用されているmkdocsの拡張機能です。mkdocs-macros-pluginを使用していくつか拡張機能を追加しています。
フォルダ構成
基本構成は下記の通りです。詳細はここでは記載しませんが、Python、JavaScript(Node.js も含む)の構成になっています。
mkdocs-macros-utils $ tree -L 1
.
├── LICENCE
├── README.md
├── README_PyPI.md
├── coverage
├── docs
├── htmlcov
├── jest.config.js
├── mkdocs.yml
├── mkdocs_macros_utils
│ ├── __init__.py
│ ├── __pycache__
│ ├── debug_logger.py
│ ├── gist_codeblock.py
│ ├── link_card.py
│ ├── static
│ └── x_twitter_card.py
├── node_modules
├── overrides
├── package-lock.json
├── package.json
├── poetry.lock
├── pyproject.toml
├── requirements-dev.txt
├── requirements.txt
├── scripts
├── site
└── tests
├── __pycache__
├── js
│ ├── setup.js
│ └── x-twitter-widget.test.js
└── python
├── __init__.py
├── __pycache__
├── conftest.py
└── mkdocs_macros_utils
設定ファイル(pyproject.toml)
poetry version(>=2.0.0)の場合
- Poetryのver2.0.0でサポートされたPEP621の構成2は下記の通りです(
poetry new
コマンド実行時の構成です。)
[project.urls]
は必須ではありませんが、追加するとPyPI側にも反映されます。
# For poetry version(>=2.0.0)
[project]
name = "mkdocs-macros-utils"
version = "0.0.7"
description = "mkdocs-macros-utils is a mkdocs-macros-plugin based project that provides macros to extend cards, code blocks, etc, in MkDocs documents."
authors = [
{name = "7rikazhexde", email = "33836132+7rikazhexde@users.noreply.github.com"}
]
license = {text = "MIT"}
readme = "README_PyPI.md"
requires-python = ">=3.10,<4.0"
dependencies = [
"mkdocs-macros-plugin>=1.3.7,<2.0.0",
"mkdocs-material>=9.6.1,<10.0.0",
"requests>=2.25.0",
"jinja2>=3.0.0",
"pygments>=2.19.1",
]
[project.optional-dependencies]
dev = [
"pytest>=8.3.4",
"mypy>=1.14.1",
"ruff>=0.9.4",
"pre-commit>=4.1.0",
"pytest-cov>=6.0.0",
"pytest-mock>=3.14.0",
"pytest-xdist>=3.6.1",
"taskipy>=1.14.1",
]
[project.urls]
homepage = "https://github.com/7rikazhexde/mkdocs-macros-utils"
repository = "https://github.com/7rikazhexde/mkdocs-macros-utils"
documentation = "https://7rikazhexde.github.io/mkdocs-macros-utils/"
# Project setup for Poetry
[tool.poetry]
# Operating modes
packages = [
{ include = "mkdocs_macros_utils" }
]
# Build system configuration
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
# Task runner configuration
[tool.taskipy.tasks]
test_coverage_verbose = "pytest -s -vv --cov=mkdocs_macros_utils --cov-branch --cov-report term-missing --cov-report html"
test_html_report = "pytest --html=htmlcov/report_page.html"
test_ci_xml = "python scripts/run_tests.py --report xml"
test_ci_term = "python scripts/run_tests.py --report term"
test_coverage = "pytest --cov=mkdocs_macros_utils --cov-branch --cov-report=term-missing --cov-report=html"
# Type checking configuration
[tool.mypy]
files = ["mkdocs_macros_utils", "tests"]
explicit_package_bases = true
python_version = "3.12"
show_error_context = true
show_column_numbers = true
ignore_missing_imports = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unused_ignores = true
warn_redundant_casts = true
# Overrides mypy ignore import settings
[[tool.mypy.overrides]]
module = ["mkdocs.*","mkdocs_macros.*","jinja2.*","ruamel.*","pygments.*"]
ignore_missing_imports = true
# Test configuration
[tool.pytest.ini_options]
testpaths = ["tests/python"]
poetry version(<2.0.0)の場合
- Poetryのver2.0.0より前のVertsionでは
[tool.poetry]
で作成します3。
- プロジェクトのURLなどは
[tool.poetry]
に含めます。
# For poetry version(<2.0.0)
[tool.poetry]
name = "mkdocs-macros-utils"
version = "0.0.7"
description = "mkdocs-macros-utils is a mkdocs-macros-plugin based project that provides macros to extend cards, code blocks, etc, in MkDocs documents."
authors = ["7rikazhexde <33836132+7rikazhexde@users.noreply.github.com>"]
packages = [
{ include = "mkdocs_macros_utils" }
]
readme = "README_PyPI.md"
homepage = "https://github.com/7rikazhexde/mkdocs-macros-utils"
repository = "https://github.com/7rikazhexde/mkdocs-macros-utils"
documentation = "https://7rikazhexde.github.io/mkdocs-macros-utils/"
[tool.poetry.dependencies]
python = ">=3.10,<4.0"
mkdocs-macros-plugin = ">=1.3.7,<2.0.0"
mkdocs-material = ">=9.6.1,<10.0.0"
requests = ">=2.25.0"
jinja2 = ">=3.0.0"
pygments = ">=2.19.1"
# Development dependencies - these are not included in the final package
[tool.poetry.group.dev.dependencies]
pytest = "^8.3.4"
mypy = "^1.14.1"
ruff = "^0.9.4"
pre-commit = "^4.1.0"
pytest-cov = "^6.0.0"
pytest-mock = "^3.14.0"
pytest-xdist = "^3.6.1"
taskipy = "^1.14.1"
# Build system configuration(「For poetry version(>=2.0.0)」と同じ)
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
# Task runner configuration(「For poetry version(>=2.0.0)」と同じ)
[tool.taskipy.tasks]
test_coverage_verbose = "pytest -s -vv --cov=mkdocs_macros_utils --cov-branch --cov-report term-missing --cov-report html"
test_html_report = "pytest --html=htmlcov/report_page.html"
test_ci_xml = "python scripts/run_tests.py --report xml"
test_ci_term = "python scripts/run_tests.py --report term"
test_coverage = "pytest --cov=mkdocs_macros_utils --cov-branch --cov-report=term-missing --cov-report=html"
# Type checking configuration(「For poetry version(>=2.0.0)」と同じ)
[tool.mypy]
files = ["mkdocs_macros_utils", "tests"]
explicit_package_bases = true
python_version = "3.12"
show_error_context = true
show_column_numbers = true
ignore_missing_imports = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unused_ignores = true
warn_redundant_casts = true
# Overrides mypy ignore import settings(「For poetry version(>=2.0.0)」と同じ)
[[tool.mypy.overrides]]
module = ["mkdocs.*","mkdocs_macros.*","jinja2.*","ruamel.*","pygments.*"]
ignore_missing_imports = true
# Test configuration(「For poetry version(>=2.0.0)」と同じ)
[tool.pytest.ini_options]
testpaths = ["tests/python"]
パッケージの公開手順
以下の手順で実行します。
- 公開設定
- TestPyPIソースへの公開
- TestPyPIソースからのパッケージインストール
- PyPIソースへの公開
- PyPIソースからのパッケージインストール
関連ドキュメントは下記です。
packaging.python.org
python-poetry.org
以降はそれぞれの内容について記載します。
公開設定
Pythonのパッケージ管理では、パッケージの公開先としてPyPI(本番環境)とTestPyPI(テスト環境)が存在します。
まず、TestPyPIで基本動作を確認し、問題がなければ、PyPIに公開する手順で実施します。
PyPI(本番環境)とTestPyPI(テスト環境)への公開では、アカウント登録とAPIトークンの作成、そして、poetryに設定する必要になります。
未実施の場合は以下の記事を参考に実施します。
packaging.python.org
test.pypi.org
トークン取得後は以下Poetryの資格情報のドキュメントを参考に設定します。
python-poetry.org
TestPyPI向けの設定
poetry config pypi-token.testpypi <your-testpypi-token>
poetry config pypi-token.pypi <your-pypi-token>
設定された情報はauth.toml
から確認できます。
# For WSL: $HOME/.config/pypoetry/auth.toml
[pypi-token]
testpypi = "<your-testpypi-toke>"
pypi = "<your-pypi-token>"
公開先情報の登録
Poetryでは以下の公式ドキュメント記載の通り、index API(Legacy Upload API)を使用してパッケージの公開処理を行います。
その際、poetryのconfig情報に公開先情報を設定する必要があります。設定していない場合は、公開処理のpoetry publish
コマンド実行時にエラーになります。
python-poetry.org
Poetry treats repositories to which you publish packages as user specific and not project specific configuration unlike package sources. Poetry, today, only supports the Legacy Upload API when publishing your project.
設定方法は下記の通りです。
TestPyPI向けの設定
poetry config repositories.testpypi https://test.pypi.org/legacy/
poetry config repositories.pypi https://upload.pypi.org/legacy/
設定された情報はconfig.toml
から確認できます。
# For WSL: $HOME/.config/pypoetry/config.toml
[repositories.testpypi]
url = "https://test.pypi.org/legacy/"
[repositories.pypi]
url = "https://upload.pypi.org/legacy/"
TestPyPIソースへの公開
まず、バージョンはprojectのversionキーの値に基づき作成/管理されます。
[project]
name = "mkdocs-macros-utils"
version = "0.0.7" # この値
以下のコマンドを実行してパッケージをビルドします。ビルドが成功するとwhl
ファイルとtar
ファイルが作成されます。(version = "0.0.7"
の値を元に作成されています。)
詳細は以下のドキュメントを確認ください。
packaging.python.org
$ poetry build
Building mkdocs-macros-utils (0.0.7)
- Building sdist
- Built mkdocs_macros_utils-0.0.7.tar.gz
- Building wheel
- Built mkdocs_macros_utils-0.0.7-py3-none-any.whl
testpypiに公開する場合は、パッケージを登録するリポジトリ (デフォルトはpypi)を指定して実行します。 その際、config
コマンドで設定したリポジトリ名と一致する必要があるので注意が必要です。
poetry publish --repository testpypi
その後、mkdocs-macros-utilsのtestpipyを確認すると実際に公開されていることを確認できます。
TestPyPIソースからのパッケージインストール
まず、poetryのドキュメントに以下の記載があります。
python-poetry.org
By default, Poetry discovers and installs packages from PyPI. But, you want to install a dependency to your project for a simple API repository? Let’s do it.
First, configure the package source as a supplemental (or explicit) package source to your project.
つまり、TestPyPIからパッケージをインストールするためには、インストール元の情報をpyproject.toml
にソースとして設定する必要があります。
そこで、次のコマンドを実行してpyproject.toml
にtestpypiのソース情報を設定します。
poetry source add --priority=supplemental testpypi https://pypi.example.org/simple/
実行すると、pyproject.toml
に以下の情報が追記されます。
[[tool.poetry.source]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
priority = "supplemental"
なお、パッケージのインストールは、poetry add
コマンドを使用しますが、デフォルトではPyPIソースを参照します。これは以下の記載から確認できます。
By default, if you have not configured any primary source, Poetry is configured to use the Python ecosystem’s canonical package index PyPI.
そして、PyPIソースの優先順位は--priority
オプションで設定されます。
--priority
オプションは値として、primary
とsupplemental
,explict
が指定可能でそれぞれ以下の意味を持ちます。
priority値 |
意味 |
動作 |
使用例 |
primary |
主要ソース |
- デフォルトのPyPIソースを無効化 - 依存パッケージもこのソースから探す - priorityを指定しない場合のデフォルト値 |
プライベートリポジトリを主要なパッケージソースとして使用する場合 |
supplemental |
補完ソース |
- PyPIソースは無効化されない - 他のソースで見つからない場合のみ使用 - --source オプションで明示的に指定可能 |
TestPyPIからの特定パッケージのインストールと、PyPIからの依存パッケージのインストールを併用する場合 |
explicit |
明示的ソース |
- パッケージ設定で明示的に指定された場合のみ使用 - --source オプションでの指定が必要 |
PyTorchのGPUパッケージなど、特定のパッケージを特定のソースからのみ取得する場合 |
関連情報
python-poetry.org
If priority
is undefined, the source is considered a primary source, which disables the implicit PyPI source and takes precedence over supplemental sources.
Package sources are considered in the following order:
- primary sources or implicit PyPI (if there are no primary sources),
- supplemental sources.
ここで、testpypiソースからパッケージをインストールする場合のポイントとして、依存パッケージのインストールがあります。
パッケージ管理について、パッケージはtestpypiとpypiで公開されていると説明しましたが、公開対象パッケージが依存パッケージを含む場合、依存パッケージがtestpypiソースで公開されているかどうかは各プロジェクトに依存しますが、大抵の場合は公開されていません。
これは検索すれば確認できます。また、これは他のパッケージでも同様で、例えばパッケージ更新(poetry update
)する場合でも公開されていなければエラーになります。
しかし、実際には動作確認として、テスト用にtestpypiに公開したパッケージを問題なくインストールできるか確認したいわけです。
その場合にどうすればよいかですが、上記記載の通り、--priority=supplemental
でソースを登録することで、一時ソースとしてpypiからインストールされるようになるため、依存パッケージを含む自作パッケージをインストールすることができるようになります。
注意点として、testpypiからインストールする場合には、--sorce
オプションを指定して取得します。
poetry add --source testpypi mkdocs-macros-utils
以上で、testpipyからのインストールが成功すれば、testpypiでも一連の動作確認ができたことになるので、本番環境(PyPI)での公開を行います。
基本的にはTestPyPIソースへの公開手順と同じですが、事前にpoetry remove
コマンドでtestpipyで追加した自作パッケージ(mkdocs-macros-utils)とビルドファイル(distフォルダ)を削除します。
poetry remove mkdocs-macros-utils
そして、poetry build
コマンドでパッケージをビルドします。
$ poetry build
Building mkdocs-macros-utils (0.0.7)
- Building sdist
- Built mkdocs_macros_utils-0.0.7.tar.gz
- Building wheel
- Built mkdocs_macros_utils-0.0.7-py3-none-any.whl
その後、configコマンドで設定したリポジトリ名(pypi
)を指定してPyPIに公開します。
poetry publish --repository pypi
また、ビルドと公開手順をまとめて指定することも可能であり、以下コマンドで実行できます。
poetry publish --build --repository pypi
なお、もし誤ってpublishコマンドを実行したとしても同じバージョンがリリースされている場合は400エラーとなり失敗するため、誤って公開されることはありません。
$ poetry publish --build --repository pypi
Building mkdocs-macros-utils (0.0.7)
- Building sdist
- Built mkdocs_macros_utils-0.0.7.tar.gz
- Building wheel
- Built mkdocs_macros_utils-0.0.7-py3-none-any.whl
Publishing mkdocs-macros-utils (0.0.7) to PyPI
- Uploading mkdocs_macros_utils-0.0.7-py3-none-any.whl FAILED
HTTP Error 400: File already exists ('mkdocs_macros_utils-0.0.7-py3-none-any.whl', with blake2_256 hash '70ebb1d95f8bb5c724455d1fcbfeba701c7db49b54bb6606259874fd5d847f60'). See https://pypi.org/help/#file-name-reuse for more information. | b"<html>\n <head>\n <title>400 File already exists ('mkdocs_macros_utils-0.0.7-py3-none-any.whl', with blake2_256 hash '70ebb1d95f8bb5c724455d1fcbfeba701c7db49b54bb6606259874fd5d847f60'). See https://pypi.org/help/#file-name-reuse for more information.
その後、mkdocs-macros-utilsのpipyを確認すると実際に公開されていることを確認できます。
PyPIソースからのパッケージインストール
poetry add
コマンドで追加します。
インストール時の動作を確認する場合は、verbose
オプション(-v
:通常出力,-vv
:詳細出力,-vvv
:デバッグ出力)を指定することで、詳細を確認できます。
poetry add mkdocs-macros-utils -vvv
まとめ
- 自作したパッケージをPoetryを使用して、TestPyPI/PyPIに公開する方法を紹介しました。
- 私はmkdocs-macros-utils以外にも自作のコードをGitHubでリポジトリ公開していますが、より多くのユーザーに使用してもらう場合にはPyPIでの公開が重要であると考えています。
- 公開手順は非常に簡単で公式ドキュメントを見れば必要な情報は記載されているので、参照すれば問題なく公開できました。
- TestPyPIからのパッケージのインストールでは、いくつかの設定が必要ですが、正しく設定すれば問題なく動作確認できます。
- テスト環境で事前に動作検証ができることは安心感を持てます。今後もうまく活用して、他のプロジェクトをPyPIに公開していきたいと思いました。
以上です。