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

Setuptools: расположение папки данных пакета

Я использую setuptools для распространения моего пакета python. Теперь мне нужно распространять дополнительные файлы данных.

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

Чего я бы хотел избежать:

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

Что я хотел бы использовать вместо этого:

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

Я просто не чувствую себя комфортно, имея столько подкаталогов, если это не существенно. Я не могу найти причину, почему я/имею/помещаю файлы в каталог пакета. Также громоздко работать со множеством вложенных подкаталогов IMHO. Или есть веская причина, которая оправдывала бы это ограничение?

4b9b3361

Ответ 1

Вариант 1: Установить как данные пакета

Основное преимущество размещения файлов данных в корне вашего пакета Python заключается в том, что он позволяет вам не беспокоиться о том, где будут жить файлы на системы, которая может быть Windows, Mac, Linux, некоторой мобильной платформы или внутри Яйца. Ты можешь всегда находите каталог 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, а затем либо:

  • Проложите местоположение data через файл конфигурации, аргументы командной строки или
  • Вставьте местоположение в свой код Python.

Это гораздо менее желательно, если вы планируете распространять свой проект. Если вы действительно хотите это сделать, вы можете установить data везде, где захотите, в целевой системе, указав место назначения для каждой группы файлов, перейдя в список кортежей:

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

Обновлено: пример функции оболочки для рекурсивного grep файла Python:

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

Ответ 2

Думаю, я нашел хороший компромисс, который позволит вам сохранить следующую структуру:

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

Вам следует установить данные как package_data, чтобы избежать проблем, описанных в ответе на примере samplebias, но для того, чтобы сохранить файловую структуру, вы должны добавить ее в файл 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", поскольку данные могут не иметь ничего общего с этим модулем, но я думаю, это хороший компромисс.

Ответ 3

Я использую setuptools для создания собственных пакетов ОС, таких как RPM и DEB. Я использую макет проекта.

<project>/
        lib/      -> .../lib/pythonX/site-packages/
        bin/      -> .../bin/
        etc/      -> /etc/
        doc/
           man/   -> .../man/man1/
           share/ -> .../share/doc/<project>/

В моем файле setup.py выполняется соответствующее сопоставление, как указано выше. Я считаю, что этот макет идеален для python. Выпущенные пакеты могут быть перемещены, но по умолчанию они будут находиться под /usr/local/.

Ответ 4

Я думаю, что вы можете в принципе дать что-нибудь как аргумент * data_files * для setup().