Включение файлов, отличных от Python, с помощью setup.py

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

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

Ответ 1

Вероятно, лучший способ сделать это - использовать директиву setuptools package_data. Это означает использование setuptools (или distribute) вместо distutils, но это очень плавное обновление.

Вот полный (но непроверенный) пример:

from setuptools import setup, find_packages

setup(
    name='your_project_name',
    version='0.1',
    description='A description.',
    packages=find_packages(exclude=['ez_setup', 'tests', 'tests.*']),
    package_data={'': ['license.txt']},
    include_package_data=True,
    install_requires=[],
)

Обратите внимание на конкретную строку, которая здесь критическая:

package_data={'': ['license.txt']}

Это dict имен пакетов (empty = all packages) в список шаблонов (может включать в себя глобусы). Например, если вы хотите указывать только файлы внутри своего пакета, вы также можете это сделать:

package_data={'yourpackage': ['*.txt', 'path/to/resources/*.txt']}

Решение здесь, безусловно, не должно переименовывать ваши файлы не py с расширением .py.

Подробнее см. презентация Ian Bicking.

UPDATE: другой подход [лучше]

Другой подход, который хорошо работает, если вы просто хотите контролировать содержимое исходного дистрибутива (sdist) и иметь файлы за пределами пакета (например, каталог верхнего уровня), заключается в добавлении файла MANIFEST.in. См. документацию Python для формата этого файла.

С момента написания этого ответа я обнаружил, что использование MANIFEST.in обычно менее расстраивает подход, чтобы убедиться, что ваш исходный дистрибутив (tar.gz) имеет нужные вам файлы.

Например, если вы хотите включить requirements.txt из верхнего уровня, рекурсивно включить каталог "данные" верхнего уровня:

include requirements.txt
recursive-include data *

Ответ 2

Чтобы выполнить то, что вы описываете, выполните два шага...

  • Файл должен быть добавлен в исходный архив
  • setup.py необходимо изменить, чтобы установить файл данных в исходный путь

Шаг 1: Чтобы добавить файл в исходный архив, включите его в MANIFEST

Создайте шаблон MANIFEST в папке, содержащей setup.py

MANIFEST - это в основном текстовый файл со списком всех файлов, которые будут включены в исходный архив.

Вот как выглядит MANIFEST для моего проекта:

  • CHANGELOG.txt
  • INSTALL.txt
  • LICENSE.TXT
  • pypreprocessor.py
  • README.txt
  • setup.py
  • test.py
  • todo.txt

Примечание. Хотя sdist делает автоматически добавляет файлы, я предпочитаю явно указывать их, а не предсказывая, что он делает и не делает.

Шаг 2. Чтобы установить файл данных в исходную папку, измените setup.py

Поскольку вы хотите добавить файл данных (LICENSE.txt) в папку установки источника, вам необходимо изменить путь установки данных, чтобы он соответствовал пути установки источника. Это необходимо, потому что по умолчанию файлы данных устанавливаются в другое место, кроме исходных файлов.

Чтобы изменить каталог установки данных в соответствии с исходной установкой dir...

Извлеките информацию об установочном каталоге из distutils с помощью:

from distutils.command.install import INSTALL_SCHEMES

Измените каталог установки данных в соответствии с исходным каталогом установки:

for scheme in INSTALL_SCHEMES.values():
    scheme['data'] = scheme['purelib']

И добавьте файл данных и местоположение в setup():

data_files=[('', ['LICENSE.txt'])]

Примечание. Вышеупомянутые шаги должны выполнять именно то, что вы описали стандартным образом, не требуя каких-либо библиотек расширений.

Ответ 3

В setup.py при настройке (:

setup(
   name = 'foo library'
   ...
  package_data={
   'foolibrary.folderA': ['*'],     # All files from folder A
   'foolibrary.folderB': ['*.txt']  #All text files from folder B
   },

Ответ 4

Вот более простой ответ, который сработал у меня.

Во-первых, за комментарий Python Dev выше, setuptools не требуется:

package_data is also available to pure distutils setup scripts 
since 2.3. – Éric Araujo

Это здорово, потому что установка требования setuptools на ваш пакет означает, что вам также придется его установить. Короче говоря:

from distutils.core import setup

setup(
    # ...snip...
    packages          = ['pkgname'],
    package_data      = {'pkgname': ['license.txt']},
)

Ответ 5

Я просто хотел следить за тем, что я нашел, работая с Python 2.7 на Centos 6. Добавление пакетов_данных или data_files, как указано выше, не помогло мне. Я добавил MANIFEST.IN с файлами, которые я хотел, которые помещали файлы, отличные от python, в tarball, но не устанавливали их на целевой машине через RPM.

В конце концов, я смог получить файлы в своем решении, используя "параметры" в setup/setuptools. Файлы параметров позволяют изменять различные разделы файла spec из файла setup.py. Как следует.

from setuptools import setup


setup(
    name='theProjectName',
    version='1',
    packages=['thePackage'],
    url='',
    license='',
    author='me',
    author_email='[email protected]',
    description='',
    options={'bdist_rpm': {'install_script': 'filewithinstallcommands'}},
)

file - MANIFEST.in:

include license.txt

file - filewithinstallcommands:

mkdir -p $RPM_BUILD_ROOT/pathtoinstall/
#this line installs your python files
python setup.py install -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES
#install license.txt into /pathtoinstall folder
install -m 700 license.txt $RPM_BUILD_ROOT/pathtoinstall/
echo /pathtoinstall/license.txt >> INSTALLED_FILES

Ответ 6

создайте MANIFEST.in в корне проекта с помощью recursive-include в требуемый каталог или include с именем файла.

include LICENSE
include README.rst
recursive-include package/static *
recursive-include package/templates *

документация можно найти здесь

Ответ 7

Выяснилось обходное решение: я переименовал my lgpl2.1_license.txt в lgpl2.1_license.txt.py и поместил несколько тройных цитат вокруг текста. Теперь мне не нужно использовать параметр data_files или не указывать абсолютные пути. Я думаю, что сделать его модулем Python уродливо, но я считаю его менее уродливым, чем указание абсолютных путей.