web-dev-qa-db-ja.com

Python setup.py?でパッケージデータを再帰的に追加する方法

私は小さなデータファイルのサブフォルダをたくさん含まなければならない新しいライブラリを持っています。そしてそれらをパッケージデータとして追加しようとしています。私のライブラリがあると想像してください:

 library
    - foo.py
    - bar.py
 data
   subfolderA
      subfolderA1
      subfolderA2
   subfolderB
      subfolderB1 
      ...

Setup.pyを使用してすべてのサブフォルダーにすべてのデータを追加したいのですが、すべてのサブフォルダー(100個程度)に手動で移動してinitを追加する必要があるようです。 pyファイル。さらに、setup.pyはこれらのファイルを再帰的に検索しますか、または次のようにsetup.pyにこれらすべてを手動で追加する必要がありますか?

package_data={
  'mypackage.data.folderA': ['*'],
  'mypackage.data.folderA.subfolderA1': ['*'],
  'mypackage.data.folderA.subfolderA2': ['*']
   },

スクリプトを使用してこれを実行できますが、非常に苦痛のようです。 setup.pyでこれを達成するにはどうすればよいですか?

PS、これらのフォルダーの階層は重要です。これはマテリアルファイルのデータベースであり、ユーザーにGUIで表示するときにファイルツリーを保持する必要があるため、このファイル構造をそのまま保持することの利点です。

38
  1. Distutilsの代わりに Setuptools を使用します。
  2. パッケージデータの代わりに data files を使用します。これらは__init__.pyを必要としません。
  3. 文字どおりに記述する代わりに、標準のPythonコードを使用して、ファイルとディレクトリのリストを生成します。

    data_files = []
    directories = glob.glob('data/subfolder?/subfolder??/')
    for directory in directories:
        files = glob.glob(directory+'*')
        data_files.append((directory, files))
    # then pass data_files to setup()
    
25
Kevin

globの答えの問題は、それだけのことをしているということです。つまり完全に再帰的ではありません。 copy_tree回答の問題は、コピーされたファイルがアンインストール時に残されることです。

適切な解決策は、セットアップ呼び出しでpackage_dataパラメーターを設定できるようにする再帰的な解決策です。

これを行うためのこの小さなメソッドを書きました:

import os

def package_files(directory):
    paths = []
    for (path, directories, filenames) in os.walk(directory):
        for filename in filenames:
            paths.append(os.path.join('..', path, filename))
    return paths

extra_files = package_files('path_to/extra_files_dir')

setup(
    ...
    packages = ['package_name'],
    package_data={'': extra_files},
    ....
)

pip uninstall package_nameを実行すると、追加のファイルが一覧表示されます(パッケージで追跡されます)。

33
Sandy Chapman

Setup.pyコードをダーティにすることに問題がない場合は、_distutils.dir_util.copy_tree_を使用します。
全体の問題は、そこからファイルを除外する方法です。
以下にコードを示します。

_import os.path
from distutils import dir_util
from distutils import sysconfig
from distutils.core import setup

__package= 'x' 
setup(
    name = __packagename__,
    packages = [__packagename__],
)

destination_path = sysconfig.get_python_lib()
package_path = os.path.join(destination_path, __packagename__)

dir_util.copy_tree(__packagename__, package_path, update=1, preserve_mode=0)
_

注意事項

  • このコードは、ソースコードを宛先パスに再帰的にコピーします。
  • 同じsetup(...)を使用できますが、copy_tree()を使用して、インストールのパスに必要なディレクトリを拡張できます。
  • Distutilインストールのデフォルトパスは [〜#〜] api [〜#〜] にあります。
  • Distutilsのcopy_tree()モジュールの詳細については、 here を参照してください。
  • 4
    Heartagramir

    Globを使用して、setup.py内のすべてのサブフォルダーを選択します

    ...
    packages=['your_package'],
    package_data={'your_package': ['data/**/*']},
    ...
    
    2
    gbonetti

    Setup()でdata_filesを追加する小さなコードを提案できます。

    data_files = []
    
    start_point = os.path.join(__pkgname__, 'static')
    for root, dirs, files in os.walk(start_point):
        root_files = [os.path.join(root, i) for i in files]
        data_files.append((root, root_files))
    
    start_point = os.path.join(__pkgname__, 'templates')
    for root, dirs, files in os.walk(start_point):
        root_files = [os.path.join(root, i) for i in files]
        data_files.append((root, root_files))
    
    setup(
        name = __pkgname__,
        description = __description__,
        version = __version__,
        long_description = README,
        ...
        data_files = data_files,
    )
    
    2
    Stan