Подтвердить что ты не робот

Как добавить данные пакета рекурсивно в Python setup.py?

У меня есть новая библиотека, которая должна включать множество подпапок небольших файлов данных, и я пытаюсь добавить их в качестве данных пакета. Представь, что у меня есть моя библиотека так:

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

Я хочу добавить все данные во все подпапки через setup.py, но мне кажется, что мне нужно вручную войти в каждую подпапку (их около 100) и добавить файл инициализации.py. Кроме того, setup.py найдет эти файлы рекурсивно или мне нужно вручную добавить все эти файлы в setup.py, например:

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

Я могу сделать это с помощью сценария, но, похоже, супер боль. Как я могу добиться этого в setup.py?

PS иерархия этих папок важна, потому что это база данных файлов материалов, и мы хотим, чтобы дерево файлов было сохранено, когда мы представляем их в графическом интерфейсе пользователю, поэтому было бы в наших интересах сохранить целостность этой файловой структуры.,

4b9b3361

Ответ 1

  1. Используйте Setuptools вместо distutils.
  2. Используйте файлы данных вместо данных пакета. Это не требует __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()
    

Ответ 2

Проблема с ответом 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, вы увидите, что ваши дополнительные файлы перечислены (как отслеживается с пакетом).

Ответ 3

Если у вас нет проблем с получением вашего файла setup.py dirty use distutils.dir_util.copy_tree.
Вся проблема заключается в том, как исключить из нее файлы.
Вот код:

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

__packagename__ = '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. Подробнее о copy_tree() модуле distutils можно найти здесь.

Ответ 4

Я могу предложить небольшой код для добавления data_files в setup():

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,
)

Ответ 5

Используйте glob, чтобы выбрать все подпапки в вашем setup.py

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

Ответ 6

Мне удалось скопировать файлы с помощью регулярных выражений:

package_data={'example', ['assets/**/*']}