はじめに
サァン!!! nikkieです。
Pythonのパッケージに.py
以外のファイルを含める設定について先日アウトプットしました。
知ったことを自作パッケージに適用しようとしたところ、ほかの設定方法もあることが分かりました。
深まった理解を元にアウトプットします。
※タイトルのリソースファイルは、setuptoolsのドキュメントではデータファイルと理解しています。
用語の揺れがありますが、「リソースファイル」と「データファイル」、同じものを指すとして使っていきます。
目次
- はじめに
- 目次
- 結論
- 経緯:include_package_data=TrueとMANIFEST.inを使わなくても、パッケージングできてんじゃん!(package_data)
- setuptoolsのUser guide 「Data Files Support」
- 設定例
- 終わりに
結論
指定方法3つは、以下に端的なまとめがあります
include_package_data
- これはフラグ(TrueまたはFalse)
- MANIFEST.inまたはバージョン管理システムプラグインと合わせて使う(
include_package_data
単体では機能しない)
package_data
- 含めるデータファイルのパターンを辞書で指定する
- MANIFEST.inやバージョン管理システムプラグインがなくても
package_data
単体で機能する
exclude_package_data
- 含め ない データファイルのパターンを辞書で指定する
- 利用例:
include_package_data=True
とセットで使う package_data
と一緒に使った場合はexclude_package_data
が優先される
この記事ではinclude_package_data
とpackage_data
を扱います
経緯:include_package_data=True
とMANIFEST.inを使わなくても、パッケージングできてんじゃん!(package_data)
include_package_data=True
とMANIFEST.inが必要と学んだnikkie氏。
過去に書いていたsetup.pyにも適用しようと思い立ちます。
https://github.com/ftnext/bring-script-more-users/blob/bringscript0.1.0/bringscript/setup.py
このsetup.pyはPyCon APAC 2020のワークショップの自作ヘルパーライブラリのものです1。
テンプレートエンジンを使ってスキャフォールディングするライブラリを作りました。
テンプレートファイルは.py
ではないので、データファイルです。
ワークショップ中にテンプレートファイルが見つからないエラーが報告されています。
「これってsetup.pyでデータファイルの設定ができていなかったからなのかな」と小さな心残りとなりました。
このたび自信を持ってinclude_package_data=True
とMANIFEST.inで設定できそうなので、このsetup.pyに立ち戻りました。
すると、データファイルがインストールされない事象は手元では再現しないんですよね(macOSやDockerのpythonイメージを動かして検証)。
MANIFEST.inは置けてないですし、include_package_data=True
も指定していない のですが、以下の設定がありました。
setup( ..., package_data={"bringscript": ["templates/*/*.jinja"]}, )
「このpackage_data
って何よ? include_package_data=True
と何が違うのよ?」というのが今回の記事の出発点です。
setuptoolsのUser guide 「Data Files Support」
パッケージングでデータファイルをサポートする方法3つが紹介されるページです。
include_package_data
- setup関数で
include_package_data=True
を指定 - MANIFEST.inにデータファイルを指定する
- パージョン管理システムプラグインを代わりに使ってもよい(nikkie素振り材料)
include_package_data=True
が意味するのは、パッケージディレクトリにある.py
でないすべてのファイルをデータファイルとみなすということのようです2。
だから、TrueまたはFalseというフラグなんですねー(みなすか、みなさないか)。
Trueでみなす指定をした上で、具体的なデータファイルはMANIFEST.in(やバージョン管理プラグイン)で指定します
package_data
include_package_data
よりもきめ細やかにデータファイルの制御をするのがpackage_data
!3
ここには辞書を指定します。
例:{"mypkg": ["*.txt"]}
- キー:パッケージ名
- 空文字列は全てのパッケージを意味する(複数のパッケージがあるときの例より)
- 値:データファイルのパターン(文字列)のリスト
package_data
を使って指定したデータファイルはMANIFEST.inを必要としません(バージョン管理システムプラグインも必要としないそうです)。
これが、PyCon APAC 2020 自作ライブラリのsetup.pyの指定だったというわけですね!(謎は全て解けた!)
設定例
パッケージ構造
project_root_directory ├── setup.py ├── MANIFEST.in # include_package_dataで必要、package_dataでは不要 └── mypkg ├── __init__.py ├── data1.rst ├── data2.rst ├── data1.txt └── data2.txt
include_package_data
(※先日のエントリと同様の例です)
setup.py
from setuptools import setup, find_packages setup( # ..., packages=find_packages(), include_package_data=True )
MANIFEST.in
include mypkg/*.txt include mypkg/*.rst
package_data
setup.py
from setuptools import setup, find_packages setup( # ..., packages=find_packages(), package_data={"mypkg": ["*.txt", "*.rst"]} )
(MANIFEST.inは不要です)
終わりに
パッケージのリソースファイルまわりのアウトプットでした。
設定に使う組み合わせ例です:
- setupの
include_package_data=True
と、MANIFEST.inファイル - setupの
package_data
のみ
ここで取り上げた2020年のヘルパーライブラリでは、ぶっちゃけよく分からずにpackage_data
と書いていました(きっとStackOverflowか何かから拾ってきたのです)。
include_package_data=True
とMANIFEST.inを知って立ち返ったところ疑問にぶつかり、ドキュメントに当たる中でpackage_data
でも指定できることを知りました。
include_package_data
はフラグなので具体的なファイルの指定が必要で、package_data
は具体的なファイルの指定込みと理解し、しっくり来ています🙌
- ワークショップのリポジトリです ↩
-
package_dataの項より。「By default,
include_package_data
considers all non.py
files found inside the package directory (src/mypkg
in this case) as data files,」↩ -
package_dataの項より。「If you want finer-grained control over what files are included, then you can also use the
package_data
keyword.」↩