MANIFEST.in игнорируется при установке «python setup.py» - файлы данных не установлены?


89

Вот мой урезанный скрипт setup.py с удаленным не-кодовым материалом:

#!/usr/bin/env python

from distutils.core import setup
from whyteboard.misc import meta


setup(
    name = 'Whyteboard',
    version = meta.version,

    packages = ['whyteboard', 'whyteboard.gui', 'whyteboard.lib', 'whyteboard.lib.pubsub',
                'whyteboard.lib.pubsub.core', 'whyteboard.lib.pubsub.utils', 'whyteboard.misc'],

    py_modules = ['whyteboard'],
    scripts = ['whyteboard.py'],
)

MANIFEST.in:

include *.txt
include whyteboard-help/*.*
recursive-include locale *.mo
recursive-include images *.png

Когда я запускаю «python setup.py install sdist», я получаю красивый .tar.gz с корневой папкой «whyteboard-0.41» с папками locale / images / и whyteboard-help / внутри. Здесь также есть мой скрипт whyteboard.py, который запускает мою программу из исходного пакета whyteboard.

Так:

whyteboard/
 ├── locale/
 ├── images
 ├── whyteboard-help/
 ├── whyteboard/
 │  ├── __init__.py
 │  └── other packages etc
 ├── whyteboard.py
 ├── README
 ├── setup.py
 └── CHANGELOG

Это отражает исходный код моей программы, все так и должно быть, и это правильно.

Однако, когда я запускаю «python setup.py install», ни один из моих файлов данных не записывается - только исходный пакет «whyteboard», а файл whyteboard.py помещается в /usr/local/lib/python2.6/dist-packages/ .

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

Как я могу получить "установку" для создания этой структуры каталогов? Насколько я могу судить, он игнорирует мой файл манифеста.


Ответы:


30

Некоторые примечания в дополнение к ответу Неда (который касается основной проблемы):

Distutils не устанавливает пакеты и модули Python в подкаталог для каждого проекта внутри site-packages(или dist-packagesв Debian / Ubuntu): они устанавливаются непосредственно в site-packages, как вы видели. Таким образом, содержащий whyteboard-xxкаталог в вашем sdist не будет существовать в окончательно установленной форме.

Одним из следствий этого является то, что вы должны быть осторожны, чтобы указать свое имя data_filesтаким образом, чтобы прояснить, к какому проекту они принадлежат, потому что эти файлы / каталоги устанавливаются непосредственно в глобальный site-packagesкаталог, а не внутри какого-либо содержащего whyteboardкаталога.

Или вы могли бы вместо того, чтобы сделать данные package_dataо whyteboardпакете (что означает , что он должен жить внутри этого пакета, то есть рядом с необходимыми __init__.py), и тогда это не проблема.

Наконец, нет смысла иметь и whyteboard.pyмодуль, py_modulesи whyteboard/__init__.pyпакет packages. Эти два являются взаимоисключающими, и если у вас есть оба, whyteboard.pyмодуль будет проигнорирован при импорте в пользу пакета с тем же именем.

Если whyteboard.pyэто просто сценарий и не предназначен для импорта, вам следует использовать для него параметр сценариев и удалить его из py_modules.


1
Это неудачно. Мне не нравится идея иметь данные пакета - для меня более разумно, чтобы эти ресурсы находились вне исходного каталога. Также мне не нравится, что имена каталогов должны начинаться с имени программы (хотя я уже делаю это для файлов помощи). Хм ..
Стивен Спроут

67

MANIFEST.inсообщает Distutils, какие файлы следует включить в исходный дистрибутив, но не влияет напрямую на то, какие файлы устанавливаются. Для этого вам необходимо включить в файл соответствующие файлы setup.py, как правило, либо как данные пакета, либо как дополнительные файлы .


Я попытался добавить список данных пакета, но ни один из указанных мной файлов не использовался. Я не был уверен, были ли установлены местоположения файлов относительно общей установки пакета. Во всяком случае, он все еще записывал мои файлы в неправильную структуру каталогов, как я ожидал.
Стивен Спроут,

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

4
Это работает для меня: дублирование моих записей MANIFEST.in внутри data_packages setup.py заставляет все работать. Спасибо, Нед - я годами не мог понять этого момента. Надеюсь, теперь мой опыт distutils / setuptools / distribute станет более понятным.
Джонатан Хартли

7
Имеет ли смысл такая конструкция, позволяющая включать в пакет файлы, которые не будут установлены? Когда это будет использовано?
Роджер Даль

28

Я не мог понять, почему мой MANIFEST.inфайл игнорировался при запуске python setup.py install- оказывается, include_package_data=Trueпроблема решается. Эта package_dataопция на самом деле не требуется.


хороший улов, почему include_package_data=Trueне значение по умолчанию?
лян

9

Вам следует использовать setuptools:

#!/usr/bin/env python

from setuptools import setup, find_packages
from whyteboard.misc import meta


setup(
  name = 'Whyteboard',
  version = meta.version,

  packages = find_packages(),
  include_package_data=True,

  py_modules = ['whyteboard'],
  scripts = ['whyteboard.py'],
)

На самом деле файл МАНИФЕСТА не используется для выполнения работы, но он включает все необходимые файлы.


Это сработало для меня с помощью setuptools . Я создаю пакет Debian и вижу, что мои файлы glade, перечисленные в package_dataсловаре, появляются в нужном месте только после добавления include_package_data=Tru.
mlt

8

Запустив python 2.6.1 в Mac OSX, мне не повезло, кроме использования параметра data_files в setup.py. Все с MANIFEST.in просто приводило к тому, что файлы включались в пакет dist, но никогда не устанавливались. Я проверил некоторые другие пакеты, и они действительно использовали data_files для указания дополнительных файлов.

Я создал небольшую функцию, которая помогает перечислить все файлы из дерева каталогов в

(target_dir, [список файлов]) ожидаемый формат data_files:

def gen_data_files(*dirs):
    results = []

    for src_dir in dirs:
        for root,dirs,files in os.walk(src_dir):
            results.append((root, map(lambda f:root + "/" + f, files)))
    return results

Теперь я могу просто вызвать это внутри своего вызова настройки:

setup(... data_files = gen_data_files("docs", "lib") ...

И все в этих деревьях устанавливается.


11
Это здорово, но где его установить? Для меня, когда я использую «pip install», мои файлы data_files попадают в корень моего virtualenv (то есть в один каталог, общий для всех пакетов virtualenv). Если я использую «setup.py install», тогда мои файлы data_files попадают в «site- пакеты / <мой пакет> .egg / ". Если файлы представляют собой данные, необходимые во время выполнения, то ни в том, ни в другом случае для моего кода нетривиально найти эти файлы, и, конечно, мне нужно искать в обоих каталогах во время выполнения. Если файлы являются моим файлом ЛИЦЕНЗИИ, то ни в том, ни в другом случае мои пользователи не могут получить ЛИЦЕНЗИЮ из моего источника. Озадачен.
Джонатан Хартли,

3

Минимальный опубликованный исполняемый пример

Ключевой вывод: MANIFEST.inработал только у меня, package_dataне работал .

Проверено на Ubuntu 19.10, Python 3.7.5, wheel == 0.32.3, setuptools == 41.1.0, twine == 3.1.1.

Как конечные пользователи используют пакет из https://pypi.org/project/python-sample-package-with-data/ :

python3 -m pip install --user python-sample-package-with-data
python-sample-package-with-data

Ожидаемый результат:

hello data

Как его публикуют сопровождающие:

# One time setup.
python3 -m pip install --user setuptools wheel twine

# Every time you want to publish.
python setup.py sdist bdist_wheel
twine upload dist/*
rm -rf build dist *.egg-info

Фактические файлы:

MANIFEST.in

# Or else pip install cannot find README.md on the setup.py under certain conditions.
include README.md

# This actually adds the data file.
include python_sample_package_with_data/mydata.txt

Python-образец-пакет-с-данными

#!/usr/bin/env python3

import python_sample_package_with_data

print(python_sample_package_with_data.get_data(), end='')

python_sample_package_with_data / __ init__.py

try:
    import importlib.resources as importlib_resources
except ImportError:
    # In PY<3.7 fall-back to backported `importlib_resources`.
    import importlib_resources

def get_data():
    return importlib_resources.read_text(__name__, 'mydata.txt')

python_sample_package_with_data / mydata.txt

hello data

setup.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from setuptools import setup, find_packages

from os import path
this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, 'README.md')) as f:
    long_description = f.read()

setup(
    name='python-sample-package-with-data',
    version='0.0.3',
    description='My short description',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='https://github.com/cirosantilli/python-sample-package-with-data',
    author='Ciro Santilli',
    author_email='ciro.santilli.contact@gmail.com',
    packages=find_packages(),
    include_package_data=True,
    scripts=['python-sample-package-with-data'],
)

Библиография:

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.