Pythonパッケージのビルドについて学ぶ#

Image showing the progression of creating a Python package, building it and then publishing to PyPI and conda-forge. You take your code and turn it into distribution files (sdist and wheel) that PyPI accepts. Then there is an arrow towards the PyPI repository where ou publish both distributions. From PyPI if you create a conda-forge recipe you can then publish to conda-forge.

Once you have published both package distributions (the source distribution and the wheel) to PyPI, you can then publish to conda-forge. The conda-forge requires an source distribution on PyPI in order to build your package on conda-forge. You do not need to rebuild your package to publish to conda-forge.#

PythonパッケージをPyPI(またはcondaチャンネル)に公開するには、ビルドする必要があります。ビルドプロセスは、あなたのコードとメタデータをPyPIにアップロードできる配布フォーマットに整理し、その後ユーザーがダウンロードしてインストールできるようにします。 注意: conda-forgeが適切にパッケージを自動ビルドするためには、sdistをPyPIに公開する必要があります。

Pythonパッケージのビルドとは何ですか?#

Pythonパッケージを公開 し、誰でも簡単にインストールできるようにするには、まずそれをビルドする必要があります。

しかし、Pythonのパッケージを作るとは何ですか?

上の図のように, Pythonパッケージをビルドするとき、ソースファイルをディストリビューションパッケージと呼ばれるものに変換します。 配布パッケージには、あなたのソースコードとパッケージのメタデータが、 Python Package Index が要求する形式で含まれています。

注釈

Pythonや他の言語では、パッケージという言葉は様々な意味で使われています。 このページでは、 Python Packaging Authority の慣例に合わせ、ビルドステップの成果物を 配布パッケージ と呼ぶことにします。

あなたのコード、ドキュメント、テスト、メタデータをpipとPyPIの両方が使える形式に整理し、フォーマットするこのプロセスは、ビルドステップと呼ばれます。

プロジェクトのメタデータとPyPI#

ビルドツールとPyPIの両方があなたのパッケージを説明し理解するために使うメタデータは、一般的に pyproject.tomlファイル に格納されます。 このメタデータはいくつかの目的で使用されます:

  1. パッケージのビルドに使用するツール(pip、 pypa's Build 、またはpoetry、PDM、Hatchのようなエンドツーエンドツール)があなたのパッケージのビルド方法を理解するのに役立ちます。ビルドツールに提供される情報には以下のものがあります:

  • pyproject.tomlファイルの [build-system] テーブルは、sdistとwheelディストリビューションの作成に使用したい ビルドバックエンドツール をpipに伝えます。

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
  • また、プロジェクトテーブルの dependencies セクションは、ビルドツールと PyPI にプロジェクトが必要とする依存関係を伝えます。

dependencies = [
    "numpy",
    "geopandas",
]
  1. ビルドツールがパッケージ配布ファイル(PyPIで公開するファイル)を作成するとき、PyPIが読み込んでユーザがあなたのパッケージを見つけるのに役立つMETADATAファイルも作成します。 例えば:

  • pyproject.tomlファイルの [project] テーブルの classifiers = セクションは、PyPIのユーザが特定のライセンスを含むパッケージや特定のバージョンのpythonをサポートするパッケージをフィルタリングするための情報を提供します。

classifiers = [
    # How mature is this project? Common values are
    "Development Status :: 4 - Beta",

    # Indicate who your project is intended for
    "Intended Audience :: Developers",
    "Topic :: Software Development :: Build Tools",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3 :: Only",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
]

メタデータのsetup.pyとsetup.cfgはどうなったのですか?

プロジェクトのメタデータは、以前は setup.py ファイルか setup.cfg ファイルに保存されていました。パッケージのメタデータを保存するために現在推奨されている方法は、pyproject.tomlファイルを使用することです。 pyproject.tomlファイルについての詳細はこちらです。

例 - xclim#

When you publish to PyPI, you will notice that each package has metadata listed. Let's have a look at xclim, one of our pyOpenSci packages. Notice that on the PyPI landing page you see some metadata about the package including python, maintainer information and more. PyPI is able to populate this metadata because it was defined using correct syntax and classifiers by Xclim's maintainers, pyproject.toml file. This metadata when the xclim package is built, is translated into a distribution file that allows PyPI to read the metadata and print it out on their website.

xclimパッケージのPyPI左サイドバーの画像です。一番上のセクションにはClassifierとあります。その下に、開発状況、対象読者、ライセンス、自然言語、オペレーティングシステム、プログラミング言語、トピックなどの項目があります。 これらの各セクションの下には、さまざまな分類オプションがあります。 " width="300px">

pyproject.tomlにclassifierセクションを追加してパッケージがビルドされると、ビルドツールはメタデータをPyPIが理解できる形式に整理し、PyPIのランディングページに表示します。 これらの分類子により、ユーザはサポートするpythonのバージョンやカテゴリなどでパッケージをソートすることもできます。#

Graphic showing the high level packaging workflow. On the left you see a graphic with code, metadata and tests in it. Those items all go into your package. Documentation and data are below that box because they aren't normally published in your packaging wheel distribution. An arrow to the right takes you to a build distribution files box. That box leads you to either publishing to TestPyPI or the real PyPI. From PyPI you can then connect to conda-forge for an automated build that sends distributions from PyPI to conda-forge.

PythonパッケージをPyPI(またはConda)に公開するには、ビルドする必要があります。ビルドプロセスは、あなたのコードとメタデータをPyPIにアップロードできる配布フォーマットに整理し、その後ユーザーがダウンロードしてインストールできるようにします。 注意: conda-forgeが適切にパッケージを自動ビルドするためには、sdistをPyPIに公開する必要があります。#

This screenshot shows the metadata on PyPI for the xclim package. On it you can see the name of the license, the author and maintainer names keywords associated with the package and the base python version it requires which is 3.8.

xclimパッケージのメタデータを示すPyPIのスクリーンショット。#


Here you see the maintainer metadata as it is displayed on PyPI. For xclim there are three maintainers listed with their profile pictures and github user names to the right.

PyPI に表示されている xclim パッケージのメンテナ名と GitHub ユーザ名。 この情報はpyproject.tomlに記録され、ビルドツールで処理され、パッケージのsdistとwheelディストリビューションに保存されます。#

PyPIやPipが期待する配布フォーマットを作るには?#

理論的には、PyPIが望むようにコードを整理する独自のスクリプトを作成することができます。 しかし、データフレーム用のPandasや配列用のNumpyのような既知の構造を扱うパッケージがあるように、パッケージのビルド配布ファイルの作成を支援するパッケージやツールがあります。

注釈

パッケージングツールには、パッケージングプロセス全体を支援するものもあれば、プロセスの1ステップだけを支援するものもあります。 例えばsetuptoolsはよく使われるビルドバックエンドで、sdistやwheelの作成に使うことができます。 一方、Hatch、PDM、Poetry、flitのようなツールは、パッケージングプロセスの他の部分を支援します。

これは、パッケージングエコシステムに混乱と複雑さをもたらす可能性がありますが、ほとんどの場合、各ツールは同じ配布出力を提供します(ほとんどのユーザーが気にしないような小さな違いはあります)。 これらのツールの詳細については、このページを参照してください。

以下では、PyPIが公開することを期待している2つの配布ファイル、sdistとwheelについて学びます。 sdistとwheelです。それぞれの構造と、どのようなファイルがあるのかについて学びます。

PythonパッケージをPyPIに公開するために作成する必要がある配布ファイルは、ソース配布(sdist)とwheelの2つです。 sdistにはパッケージの生のソースコードが含まれています。 wheel(.whl)には、ビルド/コンパイルされたファイルが含まれており、誰のコンピュータにも直接インストールすることができます。

両ディストリビューションの詳細は以下の通りです。

注釈

もし、あなたのパッケージが追加のビルド/コンパイルステップのない純粋なpythonパッケージであれば、sdistとwheelのディストリビューションは似たような内容になるでしょう。 しかし、もしあなたのパッケージが他の言語での拡張機能を持っていたり、ビルドがより複雑であったりする場合、2つのディストリビューションは大きく異なるでしょう。

また、このセクションではcondaのビルドワークフローについては触れないことに注意してください。 condaのビルドについてはこちらで詳しく説明しています

What is a source distribution (sdist)#

ソースファイル は、パッケージをビルドするために必要な、ビルドされていないファイルです。 これらは、GitHubやあなたがコードを管理するために使っているプラットフォームに保存する "raw / as-is" ファイルです。

Source Distributions(S + Dist)はsdistと呼ばれます。その名の通り、SDISTにはソースコードが含まれています; ビルドもコンパイルもされていません。 したがって、ユーザーがpipを使ってソースディストリビューションをインストールする場合、pipは最初にビルドステップを実行する必要があります。 このため、ソース・ディストリビューションを、(プロジェクトの依存関係を除いた)ホイールのビルドに必要なすべてを含む圧縮アーカイブとして、ネットワークアクセスなしで定義することができます。

Sdist は通常、 .tar.gz アーカイブ (しばしば "tarball" と呼ばれます) として保存されます。 そのため、ユーザーが pip を使用してソースディストリビューションをインストールする場合、pip は最初にビルドステップを実行する必要があります。

以下はstravalib Pythonパッケージのsdistの例です:

stravalib-1.1.0.post2-SDist.tar.gz file contents

├─ 📂 stravalib
│  ├─ tests
│  │  ├─ integration
│  │  │  ├─ __init__.py
│  │  │  ├─ conftest.py
│  │  │  ├─ strava_api_stub.py
│  │  │  └─ test_client.py
│  │  ├─ unit
│  │  │  ├─ __init__.py
│  │  │  ├─ test_attributes.py
│  │  │  ├─ ...
│  │  ├─ __init__.py
│  │  ├─ auth_responder.py
│  │  └─ test.ini-example
│  ├─ util
│  │  ├─ __init__.py
│  │  └─ limiter.py
│  ├─ __init__.py
│  ├─ _version.py
│  ├─ _version_generated.py
│  ├─ attributes.py
│  ├─ ...
├─ stravalib.egg-info
│  ├─ PKG-INFO
│  ├─ SOURCES.txt
│  ├─ dependency_links.txt
│  ├─ requires.txt
│  └─ top_level.txt
├─ CODE_OF_CONDUCT.md
├─ CONTRIBUTING.md
├─ LICENSE.txt
├─ MANIFEST.in
├─ Makefile
├─ PKG-INFO
├─ README.md
├─ CHANGELOG.md
├─ environment.yml
├─ pyproject.toml
├─ requirements-build.txt
├─ requirements.txt
└─ setup.cfg

GitHubアーカイブとsdistの比較

GitHub でリリースを作成すると、GitHub リポジトリ内のすべてのファイルを含む git archive が作成されます。これらのファイルはsdistと似ているが、これら2つのアーカイブは同じではない。sdistには、メタデータ・ディレクトリーや、 setuptools_scmhatch_vcs を使う場合はバージョンを保存するファイルなど、他にもいくつかの項目が含まれています。

What is a Python wheel (whl):#

ホイールファイルはZIP形式のアーカイブで、ファイル名は特定のフォーマット(下記)に従い、拡張子は .whl です。 .whl アーカイブには、プロジェクトのpyproject.tomlファイルから生成されたメタデータを含む特定のファイル群が含まれています。 pyproject.tomlや、ソース配布物に含まれる可能性のあるその他のファイルは、ビルドされた配布物であるため、wheelには含まれません。

wheel(.whl)は、ビルドされたバイナリーディストリビューションです。 バイナリファイル は、ビルド/コンパイルされたソースファイルです。 これらのファイルはすぐにインストールできます。 wheel (.whl) は、パッケージを直接インストールするために必要な すべてのファイルを含む zip ファイルです。 wheelに含まれるファイルはすべてバイナリで、これはコードがすでにコンパイル/ビルドされていることを意味します。 wheelの取り付けがより迅速に - 特にビルド・ステップが必要なパッケージの場合はそうなります。

ホイールには、setup.cfgpyproject.toml のようなパッケージの設定ファイルは含まれていません。 このディストリビューションはすでにビルドされていますので、すぐにインストールできます。

ビルドされているため、純粋な Python プロジェクトでは wheel ファイルのインストールが速くなり、マシン間で一貫したインストールができるようになります。

Tip

ウィールは、パッケージがより複雑なビルドをサポートするために setup.py ファイルを必要とする場合にも便利です。 この場合、wheelバンドルのファイルはあらかじめビルドされているので、インストールするユーザはインストール時に悪意のあるコードインジェクションを心配する必要がありません。

wheelのファイル名には、パッケージに関する重要なメタデータが含まれています。

例: stravalib-1.1.0.post2-py3-none.whl

  • 名前: stravalib

  • version: 1.1.0

  • ビルド番号: 2 (post2) (read more about post here)

  • py3: Python 3.x をサポート

  • none: オペレーティングシステムに依存しない (Windows、Mac、Linuxで動作)

  • any: あらゆるコンピュータ・プロセッサ/アーキテクチャで動作

ホイールファイルを解凍 (unzipped) するとどのように見えるか:

stravalib-1.1.0.post2-py3-none.whl file contents:

├─ 📂 stravalib
│  ├─ tests
│  │  ├─ functional
│  │  │  ├─ __init__.py
│  │  │  ├─ test_client.py
│  │  ├─ unit
│  │  │  ├─ __init__.py
│  │  │  ├─ test_attributes.py
│  │  ├─ __init__.py
│  │  ├─ auth_responder.py
│  │  └─ test.ini-example
│  ├─ util
│  │  ├─ __init__.py
│  │  └─ limiter.py
│  ├─ __init__.py
│  ├─ _version.py
│  ├─ _version_generated.py
│  ├─ attributes.py
│  ├─ client.py
└─ stravalib-1.1.0.post2.dist-info  # Package metadata are stored here
   ├─ LICENSE.txt
   ├─ METADATA
   ├─ RECORD
   ├─ WHEEL
   └─ top_level.txt