setuptools:パッケージデータフォルダーの場所


94

私はsetuptoolsを使用してpythonパッケージを配布しています。次に、追加のデータファイルを配布する必要があります。

setuptoolsのドキュメントから収集したものから、データファイルをパッケージディレクトリ内に置く必要があります。ただし、ルートディレクトリのサブディレクトリ内にデータファイルを配置したいのですが。

私が避けたいこと:

/ #root
|- src/
|  |- mypackage/
|  |  |- data/
|  |  |  |- resource1
|  |  |  |- [...]
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

代わりにしたいもの:

/ #root
|- data/
|  |- resource1
|  |- [...]
|- src/
|  |- mypackage/
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

必須ではないので、私はサブディレクトリをたくさん持つことに抵抗があります。理由を見つけることができません。なぜ/ have /を使って、ファイルをパッケージディレクトリ内に配置しますか。非常に多くのネストされたサブディレクトリIMHOを操作するのも面倒です。または、この制限を正当化する正当な理由はありますか?


8
私は、リソース(ドキュメント、画像など)を配布するには「DATA_FILES」を使用することについて同様の質問を:stackoverflow.com/questions/5192386/...を ...と(2)の応答は、両方の代わりに「package_data」を使用すると述べました。現在、パッケージデータを使用していますが、データとドキュメントをパッケージ内に配置する必要があることを意味します。つまり、ソースコードに混在させる必要があります。私はこれが嫌いです。ソースをgrepすると、検索しているクラス定義だけでなく、それらが私のRST、HTML、および中間ファイル内にある何十もの言及も見つかります。:-(
ジョナサンハートレー

2
@JonathanHartleyはこの応答が非常に遅いことを知っていますが__init__.py、ファイルが空白であっても、ファイルを追加することで任意のディレクトリを「パッケージ」にすることができます。したがって、データディレクトリを空の__init__.pyファイルで分離して、パッケージのように見せることができます。ソースツリー内のgrepがgrepを取得しないようにする必要がありますが、Pythonとそのビルドツールによってパッケージとして認識されます。
dhj 2014

@dhj面白いアイデア、ありがとう。
Jonathan Hartley

4
@dhjそのアプローチの唯一の問題は、pythonが 'data'というパッケージをインストールしたと思っていることです。インストールした別のパッケージが同じ方法でデータをパッケージ化しようとした場合、2つの競合する「データ」パッケージがインストールされます。
つま先は

回答:


111

オプション1:パッケージデータとしてインストールする

Pythonパッケージのルート内にデータファイルを配置する主な利点は、ファイルがユーザーのシステム(Windows、Mac、Linux、一部のモバイルプラットフォーム、またはEgg内など)のどこに存在するかを気にする必要がないことです。dataどこにどのようにインストールされているかに関係なく、Pythonパッケージルートからの相対ディレクトリをいつでも見つけることができます。

たとえば、次のようなプロジェクトレイアウトがあるとします。

project/
    foo/
        __init__.py
        data/
            resource1/
                foo.txt

関数を追加し__init__.pyて、データファイルへの絶対パスを見つけることができます。

import os

_ROOT = os.path.abspath(os.path.dirname(__file__))
def get_data(path):
    return os.path.join(_ROOT, 'data', path)

print get_data('resource1/foo.txt')

出力:

/Users/pat/project/foo/data/resource1/foo.txt

プロジェクトが卵としてインストールされた後、パスdataは変更されますが、コードを変更する必要はありません。

/Users/pat/virtenv/foo/lib/python2.6/site-packages/foo-0.0.0-py2.6.egg/foo/data/resource1/foo.txt

オプション2:固定場所にインストールする

別の方法は、データをPythonパッケージの外部に配置し、次のいずれかを行うことです。

  1. 場所持っているdata設定ファイル経由で渡さを、コマンドライン引数または
  2. 場所をPythonコードに埋め込みます。

プロジェクトの配布を計画している場合、これはあまり望ましくありません。これを本当に実行したい場合dataは、タプルのリストを渡してファイルの各グループの宛先を指定することにより、ターゲットシステムの好きな場所にインストールできます。

from setuptools import setup
setup(
    ...
    data_files=[
        ('/var/data1', ['data/foo.txt']),
        ('/var/data2', ['data/bar.txt'])
        ]
    )

更新:Pythonファイルを再帰的にgrepするシェル関数の例:

atlas% function grep_py { find . -name '*.py' -exec grep -Hn $* {} \; }
atlas% grep_py ": \["
./setup.py:9:    package_data={'foo': ['data/resource1/foo.txt']}

7
状況を理解するのを手伝ってくれてありがとう。ですから、あなた(そして他のすべての人)が示唆するように、package_dataを使用して実行できてうれしいです。ただし、パッケージソースディレクトリ内にデータとドキュメントを配置するのが不便で面倒だと思うのは私だけですか?(たとえば、私のソースをgrepすると、ドキュメントから数十の不要なヒットが返されます。使用するたびに、 '-exclude-dir' paramsをgrepに追加できます。インポートなどを壊さずに、パッケージディレクトリ内に「src」サブディレクトリを含めることなどが可能
Jonathan Hartley

通常、パッケージに必要なデータファイルのみをパッケージディレクトリに配置します。私はドキュメントをとしてインストールしdata_filesます。また、Python以外のファイルを無視するためのgrepのシェルエイリアスを考え出すこともできますgrep_py
samplebias

ちょっとサンプルバイアス。アップデートありがとうございます。ただし、テキストエディターのファイル内検索からctagsからawk まで、grepだけではありません。プロジェクトを再編成して、ドキュメントをdata_filesに配置し、どのように機能するかを確認します。すぐに戻って... :-)
ジョナサンハートレー

...それで問題ないようです。私を正しい軌道に乗せてくれてありがとう。+50の評判ポイントはおいしいですか?
ジョナサンハートレー

ありがとう!聞いてよかった、うまくいったことをうれしく思い、あなたは進歩しています!
samplebias 2011年

13

私はあなたが次の構造を維持することを可能にする良い妥協点を見つけたと思います:

/ #root
|- data/
|  |- resource1
|  |- [...]
|- src/
|  |- mypackage/
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

samplebiasの回答で説明されている問題を回避するには、データをpackage_dataとしてインストールする必要がありますが、ファイル構造を維持するには、setup.pyに追加する必要があります。

try:
    os.symlink('../../data', 'src/mypackage/data')
    setup(
        ...
        package_data = {'mypackage': ['data/*']}
        ...
    )
finally:
    os.unlink('src/mypackage/data')

このようにして、「ジャストインタイム」で適切な構造を作成し、ソースツリーを整理して管理します。

コード内でそのようなデータファイルにアクセスするには、次のコードを使用するだけです。

data = resource_filename(Requirement.parse("main_package"), 'mypackage/data')

コードで 'mypackage'を指定する必要はまだありません。データがこのモジュールでは必要ないためですが、妥協案だと思います。


-4

基本的に、引数として* data_files *をsetup()に与えることができると思います。


うーん... distutilsのドキュメントにあることがわかりますが、setuptoolsのドキュメントにはありません。とにかく、どうすれば最終的にそれにアクセスできますか?
phant0m 2010

data_filesは、複数のパッケージ間で共有されるデータにのみ使用する必要があると思います。たとえば、PyPIからpip installした場合、data_filesにリストされているファイルは、メインのPythonインストールディレクトリの直下のディレクトリにインストールされます。(つまり、Python27 / Lib / site-packages / mypackageにはありませんが、 'Python27 / Lib'と並行しています)
Jonathan Hartley
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.