プロジェクトのパッケージングと配布¶
Page Status: | Complete |
---|---|
Last Reviewed: | 2015-09-08 |
このセクションでは、独自の Python プロジェクトを設定、パッケージ、配布する方法の基本を説明する。パッケージのインストール のページの内容は既に熟知していることを前提とする。
このセクションは Python プロジェクト開発のベストプラクティス全体を網羅するものでは ない 。例えば、バージョン管理、文書化、テストのためのガイダンスや推奨ツールは提供しない。
詳細なリファレンスは setuptools ドキュメントの Building and Distributing Packages を見よ。ただしそこにあるいくつかの勧告は内容が古くなっているかもしれない。不整合な点があれば、Python Packaging User Guide の方を選択せよ。
Contents
パッケージングと配布の要件¶
まず、パッケージインストールの要件 を満たしていることを確認する。
“twine” をインストール [1]:
pip install twine
これはプロジェクトの distribution を PyPI にアップロードするために必要だ(以下 を参照)。
プロジェクトの設定¶
初期ファイル¶
setup.py¶
最も重要なファイルは “setup.py” だ。これはプロジェクトのルートディレクトリに置かれる。サンプルは PyPA sample project の setup.py を見よ。
“setup.py” は主に 2 つの機能を提供する:
- プロジェクトのさまざまな側面の設定。
setup.py
の第一の特徴は、グローバル関数setup()
の単一の呼び出しを含むことだ。この関数に渡すキーワード引数によって、プロジェクトの詳細が定義される。最も重要な引数群は 以下のセクション で説明する。 - パッケージングタスクに関連するさまざまなコマンドを実行するコマンドラインインターフェース。コマンドの一覧を得るには、
python setup.py --help-commands
を実行する。
setup.cfg¶
“setup.cfg” は setup.py
コマンドのデフォルトオプションを含む ini
ファイルだ。サンプルは PyPA sample project の setup.cfg を見よ。
README.rst¶
全てのプロジェクトはその目的を記した readme ファイルを含むべきだ。最も一般的なフォーマットは reStructuredText で、拡張子 “rst” を持つが、これは必須事項ではない。
サンプルは PyPA sample project の README.rst を見よ。
MANIFEST.in¶
“MANIFEST.in” は python setup.py sdist (or bdist_wheel)
が自動ではパッケージに含めないファイルを追加したい場合に必要だ。デフォルトでパッケージに含まれるファイルのリストは、distutils ドキュメントの
Specifying the files to distribute
を見よ。
サンプルは PyPA sample project の MANIFEST.in を見よ。
MANIFEST.in
ファイルの記述の詳細は、distutils ドキュメントの The MANIFEST.in template
を見よ。
<your package>¶
これは必須ではないが、プロジェクト内の Python モジュールとパッケージはプロジェクトと同 名 もしくは非常に似た名前の単一トップレベルパッケージ以下に置くのが最も一般的なやり方だ。
サンプルは PyPA sample project に含まれる sample パッケージを見よ。
setup() の引数¶
前述の通り、 setup.py
の第一の特徴はグローバル関数 setup()
への単一の呼び出しを含むことだ。この関数へのキーワード引数によってプロジェクトの詳細が定義される。
最も重要な引数群を以下で説明する。各コード片は PyPA sample project に含まれる setup.py からの引用だ。
version¶
version='1.2.0',
これはプロジェクトの現在のバージョンだ。これによってユーザは最新版をインストールしているか判断でき、またユーザ自身のソフトウェアがどのバージョンに対してテスト済みかを示せる。
プロジェクトを公開すると、PyPI 上では各リリースについてバージョンが表示される。
バージョン番号を使ってユーザに互換性情報を伝える方法の詳細は、 Versioning scheme の選択 を見よ。
プロジェクトコード自体が実行時にバージョン番号へのアクセスを必要とする場合、最も単純な方法は setup.py
とコードの両方にバージョン番号を書くことだ。値の重複を避けたいのであれば、方法はいくつかある。追加トピックの「プロジェクトバージョンの単一ソース化 」を見よ。
description¶
description='A sample Python project',
long_description=long_description,
プロジェクトの短い説明と長い説明だ。プロジェクトを公開すると、 PyPI 上でこれらの値が表示される。
author¶
author='The Python Packaging Authority',
author_email='pypa-dev@googlegroups.com',
作者に関する情報を書く。
classifiers¶
classifiers=[
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# Indicate who your project is intended for
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
# Pick your license as you wish (should match "license" above)
'License :: OSI Approved :: MIT License',
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
],
プロジェクトの分類に使われる値のリストを書く。完全なリストは https://pypi.python.org/pypi?%3Aaction=list_classifiers を見よ。
packages¶
packages=find_packages(exclude=['contrib', 'docs', 'tests*']),
プロジェクトに含まれる パッケージ のリストを得るために必要となる。手動でリストを書いてもよいが、
setuptools.find_packages
を使うと自動で探してくれる。 exclude
キーワード引数を使うことで、リリース/インストールしたくないパッケージを除外できる。
install_requires¶
install_requires=['peppercorn'],
“install_requires” は、プロジェクトの実行のために最小限必要な依存関係を指定するのに使う。pip がプロジェクトをインストールするとき、この指定に従って依存パッケージがインストールされる。
“install_requires” の使用については、install_requires vs Requirements files により詳しい情報がある。
package_data¶
package_data={
'sample': ['package_data.dat'],
},
パッケージ に追加のファイルをインストールしなければならないことがしばしばある。これらはパッケージの実装に深く関わるデータだったり、パッケージを使うプログラマの関心を引くようなドキュメントを含むテキストファイルだったりする。これらのファイルは “package data” と呼ばれる。
“package_data” の値はパッケージ名から相対パス名群へのマッピングであり、指定されたファイルがパッケージへコピーされる。パスはパッケージを含むディレクトリからの相対パスとして解釈される。
詳しくは、 setuptools ドキュメント の Including Data Files を見よ。
data_files¶
data_files=[('my_data', ['data/data_file'])],
ほとんどの場合は package_data 設定で事足りるが、場合によっては
パッケージ の 外 にデータファイルを置く必要があるかもしれない。 data_files
ディレクティブはこれを可能にする。
シーケンス内の各 (directory, files) ペアでインストール先ディレクトリとそこに置くファイル群を指定する。ディレクトリが相対パスの場合、
installation prefix (pure-Python distribution なら Python の sys.prefix, 拡張モジュールを含むなら
sys.exec_prefix) からの相対パスとして解釈される。各ファイル名はプロジェクトの source distribution のトップにある setup.py
からの相対パスとして解釈される。
詳しくは、distutils の Installing Additional Files セクションを見よ。
注釈
setuptools は “data_files” に絶対パスを許しており、 sdist からのインストール時は、pip はそれを絶対パスのまま扱う。しかし wheel distribution からのインストール時はそうではない。Wheels は絶対パスをサポートしておらず、”site-packages” からの相対パスへのインストールとなる。この件に関する議論は wheel Issue #92 を見よ。
scripts¶
setup()
は、予め作成されたスクリプトをインストールするための
scripts
キーワードをサポートしている。しかし、プラットフォーム間の互換性のために推奨されるアプローチは console_scripts エントリポイントを使うことだ(下記参照)。
entry_points¶
entry_points={
...
},
このキーワードを使うと、プロジェクトまたは依存パッケージにより定義される名前付きエントリポイントとしてプロジェクトが提供するプラグインを指定できる。
詳しくは、setuptools ドキュメントの Dynamic Discovery of Services and Plugins セクションを見よ。
最もよく使われるエントリポイントは “console_scripts” だ(下記参照)。
console_scripts¶
entry_points={
'console_scripts': [
'sample=sample:main',
],
},
スクリプトインターフェースを登録するには、”console_script” エントリポイント を使う。これらのインターフェースを実際のスクリプトに変換する作業はツールチェインが行ってくれる。[2] スクリプトは distribution のインストール中に生成される。
詳しくは、 setuptools ドキュメント の Automatic Script Creation を見よ。
Versioning scheme の選択¶
相互運用性のための標準準拠¶
個々の Python プロジェクトは固有のニーズに基づいて異なる versioning
scheme を採用してよいが、それら全ては PEP 440 で指定された
public version scheme に適合していなければならない。これは pip
や setuptools
のようなツール/
ライブラリのサポートを得るためだ。
標準準拠バージョン番号の例をいくつか示す:
1.2.0.dev1 # Development release
1.2.0a1 # Alpha Release
1.2.0b1 # Beta Release
1.2.0rc1 # Release Candidate
1.2.0 # Final Release
1.2.0.post1 # Post Release
15.10 # Date based release
23 # Serial release
バージョン番号を付けるアプローチには歴史的なバリエーションがあり、これらによりよく対応するため、PEP 440 は包括的な バージョン正規化 手法も定義している。これは個々のバージョン番号の様々な書式を標準化された正規形にマップするものだ。
Scheme の選択肢¶
Semantic versioning (推奨)¶
新規プロジェクトでは、 Semantic Versioning に基づく versioning scheme を推奨する。ただし、プレリリースとビルドメタデータを扱う際は異なるアプローチが採用されている。
Semantic versioning の本質は MAJOR.MINOR.MAINTENANCE の 3 パートからなる番号付けであり、プロジェクト作者は以下の場合にそれぞれの番号をインクリメントする:
- MAJOR バージョンは、非互換な API 変更を行ったとき。
- MINOR バージョンは、後方互換性のある機能追加を行ったとき。
- MAINTENANCE バージョンは、後方互換性のあるバグ修正を行ったとき。
プロジェクト作者がこのアプローチを採用していれば、ユーザは
“compatible release” specifier を利用できる。例えば
name ~= X.Y
とすることで、少なくともリリース X.Y が必要だが、後続のリリースのうち MAJOR バージョンが一致する任意のものを許す、という指定ができる。
Semantic versioning を採用する Python プロジェクトは、 Semantic Versioning 2.0.0 specification の 1-8 項に従うべきだ。
Date based versioning¶
Semantic versioning は全てのプロジェクトに適した選択肢というわけではない。例えば、定期的な日時ベースのリリースサイクルを持つものや、機能を削除するまでのリリース数を警告として提示する機能廃止プロセスを持つものには適さない。
Date based versioning の主な利点は、特定リリースの基本機能セットがどの程度古いものかがバージョン番号を見ただけですぐわかることだ。
典型的な Date based プロジェクトのバージョン番号は YEAR.MONTH の形だ
(例えば、 12.04
, 15.10
)。
Serial versioning¶
これは最も単純な versioning scheme であり、リリースごとにインクリメントされる単一の番号から成る。
Serial versioning は開発者にとっては管理が非常に容易だが、エンドユーザにとっては最も追跡しにくいものだ。なぜなら、serial version number は API の後方互換性に関する情報をほとんど、または全く伝えないからだ。
Hybrid schemes¶
上で挙げたものを組み合わせることも考えられる。例えば、date based versioning と serial versioning を組み合わせて YEAR.SERIAL という方式を作ることもできる。これはおおよそのリリース時期が容易にわかるが、年内の特定のリリースサイクルでコミットするわけではない。
Pre-release versioning¶
基本となる versioning scheme がどうであれ、ある最終リリースに対するプレリリースは以下のように公開される:
- 0 以上の dev リリース (”.devN” サフィックスで示す)
- 0 以上の alpha リリース (”.aN” サフィックスで示す)
- 0 以上の beta リリース (”.bN” サフィックスで示す)
- 0 以上の release candidates (”.rcN” サフィックスで示す)
pip
とその他のモダンな Python パッケージインストーラは、依存パッケージをインストールする際はデフォルトでプレリリースを無視する。
Local version identifiers¶
Public version identifiers は、 PyPI 経由での配布をサポートするために設計されたものだ。Python のソフトウェア配布ツールは、local version identifier の概念もサポートしている。これは公開予定のないローカル開発ビルドや、再配布者によりメンテナンスされる修正リリースを識別するのに使われる。
Local version identifier は
<public version identifier>+<local version label>
の形になる。例えば:
1.2.0.dev1+hg.5.b11e5e6f0b0b # 5th VCS commmit since 1.2.0.dev1 release
1.2.1+fedora.4 # Package with downstream Fedora patches applied
「開発モード」での作業¶
必須ではないが、作業中のプロジェクトを “editable” または “develop” と呼ばれるモードでローカルにインストールするのが一般的だ。これにより、インストールしたプロジェクトをそのまま編集できる。
今プロジェクトのルートディレクトリにいるとしよう。以下を実行する:
pip install -e .
いくぶん暗号的だが、 -e
は --editable
の短縮形で、 .
はカレントディレクトリを指す。つまり、カレントディレクトリ(プロジェクト)を
editable モードでインストールするという意味だ。これは
“install_requires” で宣言された依存パッケージ、および
“console_scripts” で宣言されたスクリプトも全てインストールする。このときインストールされる依存パッケージは editable モードにはならない。
依存パッケージも editable モードでインストールしたいというのはよくあることだ。例えば、プロジェクトが “foo” と “bar” を必要としているが、 “bar” は VCS から editable モードでインストールしたいとしよう。その場合、requirements ファイルは以下のように書ける:
-e .
-e git+https://somerepo/bar.git#egg=bar
1 行目はプロジェクトと依存パッケージ全てをインストールすると宣言している。2 行目は依存パッケージ “bar” を PyPI からではなく VCS から取得するようにオーバーライドしている。Requirements ファイルの詳細は、pip ドキュメントの Requirements File セクションを見よ。VCS インストールの詳細は、pip ドキュメントの VCS Support セクションを見よ。
最後に、依存パッケージを何もインストールしたくないなら、以下を実行する:
pip install -e . --no-deps
詳しくは、 setuptools ドキュメント の Development Mode を見よ。
プロジェクトのパッケージング¶
プロジェクトを PyPI のような Package Index からインストール可能にするには、プロジェクトの Distribution (パッケージ)を作る必要がある。
Source Distributions¶
最低でも、Source Distribution は作る必要がある:
python setup.py sdist
“Source distribution” はビルドされていない(つまり、Built
Distribution ではない)。これを pip でインストールする際はビルドのステップが必要だ。たとえ distribution が pure Python (一切の拡張を含まない)であっても、 setup.py
からインストールメタデータをビルドするステップが必要となる。
Wheels¶
プロジェクトの wheel も作るべきだ。Wheel は ビルド済みパッケー ジ であり、インストールに「ビルド」プロセスを必要としない。Wheel があると、エンドユーザは source distribution よりずっと高速にインストールができる。
プロジェクトが pure Python (一切のコンパイル済み拡張を含まない)で、 Python 2 と 3 の両方をネイティブにサポートするなら、“Universal Wheel” (以下のセクションを参照) と呼ばれるものを作ることになる。
プロジェクトが pure Python で、Python 2 と 3 の片方しかネイティブにサポートしないなら、“Pure Python Wheel (以下のセクションを参照) を作ることになる。
プロジェクトがコンパイル済み拡張を含むなら、“Platform Wheel” (以 下のセクションを参照) と呼ばれるものを作ることになる。
Universal Wheels¶
“Universal Wheels” は pure Python (一切のコンパイル済み拡張を含まない) かつ Python 2 と 3 をサポートする wheels だ。この wheel はどの環境でも pip でインストールできる。
Universal Wheel をビルドするには:
python setup.py bdist_wheel --universal
“setup.cfg” で --universal
フラグを恒久的に設定することもできる(サンプル: sampleproject/setup.cfg)
[bdist_wheel]
universal=1
--universal
設定は以下の場合のみ使うこと:
- プロジェクトが一切の修正なしで(つまり、2to3 を必要とせず) Python 2 と 3 で動く
- プロジェクトが C 拡張を一切含まない。
今のところ、 bdist_whell
はこの設定が不適切に使われていても警告を出さないので注意。
プロジェクトがオプションの C 拡張を含むなら、universal wheel を公開することは勧められない。というのは、pip は source installation より wheel を優先するため、拡張をビルドしなくなるからだ。
Pure Python Wheels¶
“Universal” でない “Pure Python Wheels” は、pure Python (一切のコンパイル済み拡張を含まない)かつ Python 2 と 3 の片方しかネイティブにサポートしない whells だ。
この wheel をビルドするには:
python setup.py bdist_wheel
bdist_wheel はコードが pure Python であることを検出し、ビルドに使ったのと同じメジャーバージョン (Python 2 または Python 3)の Python 環境で使えるように名付けられた wheel を作る。Wheelファイルの命名の詳細は、 PEP 425 を見よ。
コードが Python 2 と 3 の両方をサポートするが、それが異なったコードによる(例えば、 “2to3”
を使っている)場合は、 setup.py bdist_wheel
を 2 回(Python 2, 3 用に 1 回ずつ)実行できる。これでそれぞれのバージョン用の wheels が生成される。
Platform Wheels¶
“Platform Wheels” は Linux, OSX, Windows といったプラットフォーム固有の wheels だ。これは普通、コンパイル済み拡張を含むためにそうなっている。
この wheel をビルドするには:
python setup.py bdist_wheel
bdist_wheel はコードが pure Python でないことを検出し、ビルドされたプラットフォームでのみ使えるように名付けられた wheel を作る。Wheel ファイルの命名の詳細は、PEP 425 を見よ。
PyPI へのプロジェクトのアップロード¶
注釈
メインの PyPI リポジトリへリリースする前に、 PyPI テストサイト で練習することを勧める。このテストサイトは半定期的にクリーンアップされる。テストサイトを使うための設定については、 この説明 を見よ。
Distribution を作るコマンドを実行すると、プロジェクトのルートディレクトリ下に新規ディレクトリ dist/ が作られる。ここにアップロードすべき distribution ファイルがある。
アカウント作成¶
まず、PyPI のユーザアカウントが必要だ。これには 2 つの方法がある:
- PyPI ウェブサイトのフォームを使って 手動でアカウントを作る。
- (非推奨): 最初のプロジェクトを登録するついでにアカウントを作る (セキュリティ上の理由で推奨されない。次のセクションの方法 #3 を見よ)。
方法 #1 (フォーム)でアカウントを作った場合、 ~/.pypirc
ファイルを以下のように書く必要がある:
[distutils] index-servers=pypi [pypi] repository = https://upload.pypi.org/legacy/ username = <username> password = <password>
パスワード行は省略してもよい。twine に -p PASSWORD
引数を渡すか、単に要求されたときにパスワードを入力すればよい。
プロジェクトの登録¶
次に、これが最初のリリースの場合、アップロードする前にプロジェクトを明示的に登録する必要がある(今のところ)。
これには 3 つの方法がある:
- PyPI ウェブサイトのフォーム を使い、ローカルのプロジェクトツリーの
myproject.egg-info/PKG-INFO
にあるPKG-INFO
をアップロードする。このファイルまたはディレクトリがない場合は、python setup.py egg_info
を実行すれば生成される。 twine register dist/mypkg.whl
を実行すると、twine が指定されたファイル内のパッケージメタデータに基づいてプロジェクトを登録する。twine が正しく動くために、予め~/.pypirc
を適切に設定しておかなければならない。- (非推奨):
python setup.py register
を実行する。まだユーザアカウントがない場合、ウィザードが作成してくれる。ここでこのアプローチを説明するのは他のガイドで言及されているからだが、推奨はしない。なぜなら、Python のバージョンによっては平文の HTTP, または検証されていない HTTPS 接続を使う可能性があり、その場合ユーザ名とパスワードが傍受できてしまうからだ。
Distributions のアップロード¶
ついに、PyPI へ distributions をアップロードできるようになった。
これには 2 つの方法がある:
twine を使う:
twine upload dist/*
twine を使う最大の理由は、
python setup.py upload
(以下の方法 #2) はファイルを平文でアップロードすることだ。これだと MITM 攻撃でユーザ名とパスワードが盗まれうる。twine は検証された TLS 接続のみを使って PyPI へのアップロードを行い、認証情報を盗難から守る。次に、twine を使うと distribution ファイルを事前に作っておくことができる。
python setup.py upload
では、同じコマンド呼び出しで作ったものしかアップロードできない。これだと、PyPI へのアップロード前にそのファイルをテストして正しく動くことを保証することができない。最後に、twine を使うと、事前にファイルに署名し、その .asc ファイルをコマンドラインで渡せる (
twine upload twine-1.0.1.tar.gz twine-1.0.1.tar.gz.asc
)。これにより、パスフレーズを gpg 以外に対して入力していないことを保証できる(あなた が直接gpg --detach-sign -a <filename>
を実行するのだから)。(非推奨): setuptools を使う:
python setup.py sdist bdist_wheel upload
ここでこのアプローチを説明するのは他のガイドで言及されているからだが、推奨はしない。なぜなら、Python のバージョンによっては平文の HTTP, または検証されていない HTTPS 接続を使う可能性があり、その場合ユーザ名とパスワードが傍受できてしまうからだ。
[1] | プラットフォームによっては、root または管理者権限が必要かもしれない。pip は現在、 ユーザ単位のインストールをデフォルト とする ことでこの状況を変えることを検討している。 |
[2] | 具体的には、”console_script” アプローチを使うと Windows 上で
.exe ファイルを生成できる。これが必要なのは Windows が
.exe ファイルを特別扱いするためだ。 PATHEXT や
Python Launcher for Windows のようなスクリプト実行機能は多くのケースで利用できるが、全てではない。 |