setuptools: расположение папки с данными пакета - PullRequest
76 голосов
/ 23 декабря 2010

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

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

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

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

Что бы я хотел вместо этого:

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

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

Ответы [ 3 ]

98 голосов
/ 24 марта 2011

Вариант 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

После того, как проект установлен как 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. Embed theрасположение в вашем коде Python.

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

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

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

atlas% function grep_py { find . -name '*.py' -exec grep -Hn $* {} \; }
atlas% grep_py ": \["
./setup.py:9:    package_data={'foo': ['data/resource1/foo.txt']}
8 голосов
/ 23 октября 2014

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

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

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

0 голосов
/ 23 декабря 2010

Я думаю, что в качестве аргумента * data_files * можно в принципе setup () .

.
...