Setuptools: расположение папки данных пакета
Я использую setuptools для распространения моего пакета python. Теперь мне нужно распространять дополнительные файлы данных.
Из того, что я собрал из документации setuptools, мне нужно иметь файлы данных внутри каталога пакета. Тем не менее, я предпочел бы, чтобы мои файлы данных находились внутри подкаталога в корневом каталоге.
Чего я бы хотел избежать:
/ #root
|- src/
| |- mypackage/
| | |- data/
| | | |- resource1
| | | |- [...]
| | |- __init__.py
| | |- [...]
|- setup.py
Что я хотел бы использовать вместо этого:
/ #root
|- data/
| |- resource1
| |- [...]
|- src/
| |- mypackage/
| | |- __init__.py
| | |- [...]
|- setup.py
Я просто не чувствую себя комфортно, имея столько подкаталогов, если это не существенно. Я не могу найти причину, почему я/имею/помещаю файлы в каталог пакета. Также громоздко работать со множеством вложенных подкаталогов IMHO. Или есть веская причина, которая оправдывала бы это ограничение?
Ответы
Ответ 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().