はじめに
サァン!!! 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_dataconsiders all non.pyfiles found inside the package directory (src/mypkgin 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_datakeyword.」↩