web-dev-qa-db-ja.com

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

Setuptoolsを使用してpythonパッケージを配布します。ここで、追加のデータファイルを配布する必要があります。

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

私が避けたいこと:

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

代わりに私が持ちたいもの:

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

必要でない場合、あまり多くのサブディレクトリを作成することに不安を感じるだけです。パッケージディレクトリ内にファイルを/ have /配置する理由、理由を見つけることができません。また、非常に多くのネストされたサブディレクトリIMHOで作業するのは面倒です。または、この制限を正当化する正当な理由はありますか?

79
phant0m

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

Pythonパッケージのルート内にデータファイルを配置することの主な利点は、Windows、Mac、Linuxなどのユーザーのシステム上でファイルがどこにあるか心配することを回避できることです。モバイルプラットフォーム、またはEgg内。ディレクトリのインストール場所や方法に関係なく、Pythonパッケージルートに関連するディレクトリdataを常に見つけることができます。

たとえば、次のようなプロジェクトレイアウトがある場合:

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

プロジェクトをEggとしてインストールすると、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'])
        ]
    )

更新:grep Python files:

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

私はあなたが次の構造を維持できるようにする良い妥協案を見つけたと思います:

_/ #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」を指定する必要はありませんが、良い妥協案だと思います。

11
polvoazul