У тому числі не-Python-файли з setup.py


200

Як змусити setup.pyвключити файл, який не входить до коду? (Зокрема, це файл ліцензії, але це може бути будь-яка інша річ.)

Я хочу мати можливість контролювати розташування файлу. У оригінальній папці джерела файл знаходиться в корені пакета. (тобто на тому ж рівні, що і найвищий __init__.py.) Я хочу, щоб він залишався саме там, коли встановлений пакет, незалежно від операційної системи. Як це зробити?


як ти це робиш на даний момент? попереднє запитання вказує на те, що ви знайомі з тим, як додати файл ліцензії, і який у вас код "не працює"?
SilentGhost

2
data_files = [('', ['lgpl2.1_license.txt',]),]поміщає його в папку Python26.
Рам Рахум

Після деяких негативних відгуків я знову прочитав ваше запитання і зрозумів, чого мені не вистачає. Я оновив свою відповідь, щоб надати нехарактерне рішення вашого питання, яке не потребує додаткових модулів (наприклад, setuptools або distribute).
Еван Плейс

Дякую, Еване. Однак я повністю в порядку з використанням setuptools, оскільки це так поширено.
Рам Рахум

Відповіді:


224

Мабуть, найкращий спосіб зробити це - використовувати 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']},
include_package_data=True,

package_dataце dictназви пакетів (порожні = всі пакунки) до списку шаблонів (можуть включати глобуси). Наприклад, якщо ви хочете вказати лише файли в своєму пакеті, ви також можете це зробити:

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

Рішення тут, безумовно, не перейменувати ваші не- pyфайли з .pyрозширенням.

Дивіться презентацію Іана Бікінга для отримання додаткової інформації.

ОНОВЛЕННЯ: Ще один [кращий] підхід

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

Після написання цієї відповіді я виявив, що використання, MANIFEST.inяк правило, менш розчаровує підхід, щоб просто переконатися, що у розповсюдженні джерела ( tar.gz) є потрібні вам файли.

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

include requirements.txt
recursive-include data *

Проте, для того , щоб ці файли , які будуть скопійовані під час установки в папку пакета всередині сайту-пакетів, вам необхідно надати include_package_data=Trueв setup()функції. Див. Розділ Додавання файлів без коду для отримання додаткової інформації.


5
package_data також доступний для чистих сценаріїв налаштування distutils з Python 2.3.
Ерік Арауджо

15
Ця відповідь виглядає розумною, але не працює для мене. Оскільки package_data є сумнівно ненадійною (вимагає узгодження MANIFEST.in та setup.py як для додавання файлів у sdist, так і для встановлення їх як окремі кроки), а автор цієї відповіді зазначає, що "не перевірено", чи може хто ще підтвердьте, чи працює він для них? Мій файл ЛІЦЕНЗІЇ включений до списку sdist, але не встановлюється, коли я запускаю "python setup.py install" ні "pip install Package"
Джонатан Хартлі,

11
Презентація Ian Bicking показує лише, як встановити дані пакета для файлів, які знаходяться в пакеті. Мій файл ЛІЦЕНЗІЇ знаходиться на найвищому рівні мого проекту, тобто не міститься в будь-яких пакунках. Чи можу я все-таки використовувати пакет_дані? Використання data_files - це нестартер, оскільки він розміщує файли в загальносистемному місці. не пов’язаний з моїм проектом, і що ще гірше, місце розташування змінюється залежно від того, запускаю "setup.py install" або "pip install" від того самого sdist.
Джонатан Хартлі

8
Я здогадуюсь, що причина, що вона не працює для мене, полягає в тому, що файл не знаходиться в жодному пакеті - це файл LICENSE у верхньому рівні сховища, а отже, його неможливо встановити за допомогою 'package_data'
Джонатан Хартлі

7
Ця відповідь для мене не працює. Додаткові файли не потрапляють у
тарбол

44

Щоб виконати те, що ви описуєте, потрібно зробити два кроки ...

  • Файл потрібно додати до вихідного коду
  • setup.py потрібно змінити, щоб встановити файл даних до вихідного шляху

Крок 1. Щоб додати файл до вихідного тарболу, включіть його в МАНІФЕСТ

Створіть МАНІФЕСТ шаблон у папці, що містить 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, щоб відповідати джерелу установки dir ...

Витягніть інформацію про встановлення dir з distutils за допомогою:

from distutils.command.install import INSTALL_SCHEMES

Змініть дір ​​встановлення даних, щоб він відповідав джерелу встановлення джерела:

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

І додайте файл даних та місце розташування до setup ():

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

Примітка. Наведені вище дії повинні виконати саме те, що ви описали стандартно, не вимагаючи бібліотек розширень.


10
МАНІФЕСТ лише файли управління, що входять у вихідний тарбол (створений sdist). Файли, перелічені там, не будуть встановлені.
Девід Курнопе

@David Я не усвідомлював, як далеко я був у своєму першому підході. Я оновив відповідь як правильну, щоб виконати те, що запитував, не вимагаючи додаткових сторонніх бібліотек.
Еван Плейс

3
@ Éric Якась конкретна причина, чому? і чи є у вас життєздатна альтернатива інсталятора, яка не потребує сторонніх пакетів (наприклад, setup_tools) для роботи. Я вибрав distutils над setuptools, оскільки він входить до ванільної установки python, і я будував модулі для PYPI. Має бути кращий спосіб зробити це зараз, використовуючи distutils2, але я пізніше не торкався python, тому не знав би як. Оскільки ви, здається, знаєте інформацію про distutils2, я думаю, що іншим з нас було б корисно мати відповідну альтернативу distutils2.
Еван Плейс

6
Як було зазначено в інших потоках package_data, не працює, якщо файл не знаходиться в пакеті.
Gringo Suave

2
@ ÉricAraujo: Це не погана ідея використовувати це рішення, як немає іншого способу. Це поганий дизайн distutils - це правда. Але це фактично публічний API, який ніколи не зміниться, оскільки він порушить багато речей. Будемо сподіватися, що distutils2 забезпечить кращі рекомендовані способи.
anatoly techtonik


7

Я хотів написати коментар до одного із запитань, але мені недостатньо репутації для цього

Ось що для мене спрацювало (придумав це після посилання на документи):

package_data={
    'mypkg': ['../*.txt']
},

include_package_data: False

Останній рядок був, як не дивно, також для мене вирішальним (ви також можете опустити цей аргумент ключового слова - він працює так само).

Для цього потрібно копіювати всі текстові файли у верхньому або кореневому каталозі (один рівень вгору від пакета mypkg ви хочете поширити).

Сподіваюсь, це допомагає!


Я шукав спосіб, щоб не треба створити MANIFEST.in, це працювало для мене. Останній рядок також був для мене вирішальним. Мої рядки булиinclude_package_data=False, package_data={ "": ["../CHANGELOG.md"] },
Мендак

7

Крок 1: створітьMANIFEST.in файл у тій же папці з setup.py

Крок 2: включіть відносний шлях до файлів, які ви хочете додатиMANIFEST.in

include README.rst
include docs/*.txt
include funniest/data.json

Крок 3: встановіть include_package_data=Trueу setup()функції копіювання цих файлів на сайт-пакет

Довідка тут.


6

Це 2019 рік, і ось що працює - незважаючи на поради тут і там, те, що я знайшов в Інтернеті на півдорозі, задокументовано, використовує setuptools_scm, передається як варіанти дляsetuptools.setup . Сюди ввійдуть будь-які файли даних, які розміщені на вашому VCS, будь то git чи будь-який інший, до колесного пакету, і змусять "встановити піп" з сховища git, щоб принести ці файли разом.

Отже, я щойно додав ці два рядки до виклику установки на "setup.py". Ніяких додаткових встановлень або імпорту не потрібно:

    setup_requires=['setuptools_scm'],
    include_package_data=True,

Не потрібно вручну перелічувати package_data або у файлі MANIFEST.in - якщо він виконаний у версії, він включається до пакету. Документи про "setuptools_scm" роблять акцент на створенні номера версії з позиції фіксації та ігнорують дійсно важливу частину додавання файлів даних. (Мене не хвилює менше, чи мій файл проміжного колеса буде названий "* 0.2.2.dev45 + g3495a1f" чи використовуватиме жорстко кодований номер версії "0.3.0dev0", який я набрав - але важливі файли для програми залишаю робота позаду дещо важлива)


5

У setup.py під час установки (:

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

1
Це насправді нічого не робить для досягнення мети ОП. Що б ви не писали package_data, це не вплине на те, що setup.py installробить, якщо ви не змінили команду install. Якщо ці файли не містяться в каталозі пакунків, чого зазвичай потрібно уникати.
wvxvw

3

Ось простіша відповідь, яка працювала на мене.

По-перше, за коментарем Python Dev, описаним вище, налаштування настройок не потрібно:

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']},
)

1
Поскаржитися, що каталог pkgameне існує
Ентоні Конг

1

Мені просто хотілося дізнатися, що я працював з Python 2.7 на Centos 6. Додавання package_data або data_files, як було сказано вище, для мене не працювало. Я додав MANIFEST.IN з потрібними файлами, які помістили непітонські файли в тарбол, але не встановив їх на цільовій машині через RPM.

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

from setuptools import setup


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

файл - 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

-12

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


7
Дивіться мій пост. Це не повинно бути негарним. Просто важко знайти хороший приклад в мережі, тому що хорошу документацію для встановлення пакунків важко знайти.
Еван Плейс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.