Я использую setuptools для распространения моего пакета python. Теперь мне нужно распространить дополнительные файлы данных.
Из того, что я собрал из документации setuptools, мне нужно, чтобы мои файлы данных находились внутри каталога пакета. Однако я бы предпочел, чтобы мои файлы данных находились в подкаталоге корневого каталога.
Чего бы я хотел избежать:
/ #root
|- src/
| |- mypackage/
| | |- data/
| | | |- resource1
| | | |- [...]
| | |- __init__.py
| | |- [...]
|- setup.py
Вместо этого я бы хотел:
/ #root
|- data/
| |- resource1
| |- [...]
|- src/
| |- mypackage/
| | |- __init__.py
| | |- [...]
|- setup.py
Мне просто неудобно иметь такое количество подкаталогов, если это не важно. Я не могу найти причину, по которой я / должен / помещать файлы в каталог пакета. Также неудобно работать с таким количеством вложенных подкаталогов IMHO. Или есть веская причина, оправдывающая это ограничение?
python
setuptools
phant0m
источник
источник
__init__.py
файл, даже если этот файл пустой. Таким образом, вы можете сохранить каталог данных отдельно от пустого__init__.py
файла, чтобы он выглядел как пакет. Это должно удерживать grep от вашего исходного дерева от их сбора, но он все равно будет распознаваться как пакет python и его инструментами сборки.Ответы:
Вариант 1. Установить как данные пакета
Основное преимущество размещения файлов данных в корне вашего пакета Python заключается в том, что это позволяет вам не беспокоиться о том, где файлы будут находиться в системе пользователя, которая может быть Windows, Mac, Linux, какой-либо мобильной платформой или внутри Egg. Вы всегда можете найти каталог
data
относительно корня вашего пакета Python, независимо от того, где и как он установлен.Например, если у меня такой макет проекта:
Вы можете добавить функцию для
__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')
Выходы:
После того, как проект будет установлен как 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, а затем либо:
data
через файл конфигурации, аргументы командной строки илиЭто гораздо менее желательно, если вы планируете распространять свой проект. Если вы действительно хотите это сделать, вы можете установить его в
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']}
источник
data_files
. Кроме того, вы можете придумать псевдоним оболочки для grep, чтобы игнорировать файлы, отличные от Python, напримерgrep_py
.Думаю, я нашел хороший компромисс, который позволит вам сохранить следующую структуру:
/ #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 в коде, поскольку данные не могут иметь ничего общего с этим модулем, но я думаю, что это хороший компромисс.
источник
Я думаю, что вы можете в принципе указать что угодно в качестве аргумента * data_files * для setup () .
источник