2. Написание сценария установки

Примечание

Этот документ будет храниться только до тех пор, пока в документации setuptools по адресу https://setuptools.readthedocs.io/en/latest/setuptools.html самостоятельно не будет представлена вся соответствующая информация, которая в настоящее время включена в этот документ.

Установочный скрипт является центром всей деятельности по созданию, распространению и установке модулей с использованием Distutils. Основная цель установочного скрипта - описать распространение вашего модуля в Distutils, чтобы различные команды, работающие с вашими модулями, выполнялись правильно. Как мы видели в разделе Простой пример выше, сценарий установки состоит в основном из вызова setup(), а большая часть информации, передаваемой в дистрибутивы разработчиком модуля, передается в виде аргументов ключевого слова setup().

Вот немного более сложный пример, которому мы будем следовать в следующих двух разделах: собственный сценарий установки Distutils. (Имейте в виду, что, хотя дистрибутивы включены в состав Python 1.6 и более поздних версий, они также существуют независимо, так что пользователи Python 1.5.2 могут использовать их для установки других дистрибутивов модулей. Собственный установочный скрипт Distutils, показанный здесь, используется для установки пакета в Python 1.5.2.)

#!/usr/bin/env python

from distutils.core import setup

setup(name='Distutils',
      version='1.0',
      description='Python Distribution Utilities',
      author='Greg Ward',
      author_email='gward@python.net',
      url='https://www.python.org/sigs/distutils-sig/',
      packages=['distutils', 'distutils.command'],
     )

Есть только два отличия между этим и обычным однофайловым дистрибутивом, представленным в разделе Простой пример: больше метаданных и спецификация модулей на чистом Python по пакетам, а не по модулям. Это важно, поскольку дистрибутивы состоят из пары десятков модулей, разделенных (пока) на два пакета; создание явного списка каждого модуля было бы утомительным и сложным в обслуживании. Для получения дополнительной информации о дополнительных метаданных смотрите раздел Дополнительные метаданные.

Обратите внимание, что любые пути к файлам или каталогам, указанные в сценарии установки, должны быть написаны с использованием соглашения Unix, т.е. через косую черту. Дистрибутивы позаботятся о преобразовании этого не зависящего от платформы представления в то, что подходит для вашей текущей платформы, прежде чем фактически использовать путь. Это делает ваш установочный скрипт переносимым в разные операционные системы, что, конечно же, является одной из основных целей дистрибутива. В связи с этим все пути в этом документе разделены косой чертой.

Это, конечно, относится только к путевым именам, присвоенным функциям Distutils. Если вы, например, используете стандартные функции Python, такие как glob.glob() или os.listdir() для указания файлов, вам следует быть осторожным при написании переносимого кода вместо жесткого кодирования разделителей путей:

glob.glob(os.path.join('mydir', 'subdir', '*.html'))
os.listdir(os.path.join('mydir', 'subdir'))

2.1. Перечисление целых пакетов

Параметр packages указывает Distutils обрабатывать (создавать, распространять, устанавливать и т.д.) все модули pure Python, найденные в каждом пакете, упомянутом в списке packages. Для этого, конечно, должно быть соответствие между именами пакетов и каталогами в файловой системе. Соответствие по умолчанию является наиболее очевидным, т.е. пакет distutils находится в каталоге distutils относительно корневого каталога дистрибутива. Таким образом, когда вы говорите packages = ['foo'] в своем сценарии установки, вы обещаете, что дистрибутивы найдут файл foo/__init__.py (который в вашей системе может быть написан по-другому, но вы поняли идею), относящийся к каталогу, в котором находится ваш сценарий установки. Если вы нарушите это обещание, Distutils выдаст предупреждение, но все равно обработает поврежденный пакет.

Если вы используете другое соглашение для размещения своего исходного каталога, это не проблема: вам просто нужно указать параметр package_dir, чтобы сообщить Distutils о вашем соглашении. Например, предположим, что вы храните все исходные тексты Python в lib, так что модули в «корневом пакете» (т.е. вообще не в каком-либо пакете) находятся в lib, модули в foo пакете находятся в lib/foo и так далее. Тогда вы бы поставили

package_dir = {'': 'lib'}

в вашем сценарии установки. Ключами к этому справочнику являются имена пакетов, а пустое имя пакета означает корневой пакет. Значения - это имена каталогов, относящихся к корневому каталогу вашего дистрибутива. В этом случае, когда вы говорите packages = ['foo'], вы обещаете, что файл lib/foo/__init__.py существует.

Другое возможное соглашение заключается в том, чтобы поместить пакет foo прямо в lib, пакет foo.bar - в lib/bar и т.д. Это может быть записано в сценарии установки следующим образом

package_dir = {'foo': 'lib'}

Запись package: dir в словаре package_dir неявно применяется ко всем пакетам, указанным ниже package, поэтому здесь автоматически обрабатывается вариант foo.bar. В этом примере значение packages = ['foo', 'foo.bar'] указывает дистрибутивам на поиск lib/__init__.py и lib/bar/__init__.py. (Имейте в виду, что, хотя package_dir применяется рекурсивно, вы должны явно перечислить все пакеты в packages: дистрибутивы не будут рекурсивно сканировать ваше дерево исходных текстов в поисках любого каталога с файлом __init__.py.)

2.2. Список отдельных модулей

Для небольшого дистрибутива модулей вы можете предпочесть перечислять все модули, а не перечислять пакеты - особенно в случае с одним модулем, который входит в «корневой пакет» (т.е. вообще без пакета). Этот простейший случай был показан в разделе Простой пример; вот несколько более сложный пример:

py_modules = ['mod1', 'pkg.mod2']

Здесь описаны два модуля, один из которых находится в пакете «root», другой - в пакете pkg. Опять же, расположение пакетов/каталогов по умолчанию подразумевает, что эти два модуля можно найти в mod1.py и pkg/mod2.py, и что pkg/__init__.py также существует. И опять же, вы можете переопределить соответствие пакета/каталога, используя опцию package_dir.

2.3. Описание модулей расширения

Точно так же, как написание модулей расширения Python немного сложнее, чем написание модулей на чистом Python, описать их в дистрибутивах немного сложнее. В отличие от чистых модулей, недостаточно просто перечислить модули или пакеты и ожидать, что дистрибутивы сами найдут нужные файлы; вы должны указать имя расширения, исходный файл (ы) и любые требования к компиляции/компоновке (включая каталоги, библиотеки для создания ссылок и т.д.).

Все это делается с помощью другого ключевого аргумента setup(), параметра ext_modules. ext_modules - это просто список Extension экземпляров, каждый из которых описывает отдельный модуль расширения. Предположим, что ваш дистрибутив включает в себя одно расширение, называемое foo и реализованное с помощью foo.c. Если не требуется никаких дополнительных инструкций для компилятора/компоновщика, описать это расширение довольно просто:

Extension('foo', ['foo.c'])

Класс Extension может быть импортирован из distutils.core вместе с setup(). Таким образом, сценарий установки для дистрибутива модуля, который содержит только это расширение и ничего больше, может быть:

from distutils.core import setup, Extension
setup(name='foo',
      version='1.0',
      ext_modules=[Extension('foo', ['foo.c'])],
      )

Класс Extension (фактически, базовый механизм создания расширений, реализованный командой build_ext) обеспечивает большую гибкость при описании расширений Python, что объясняется в следующих разделах.

2.3.1. Имена расширений и пакеты

Первым аргументом конструктора Extension всегда является имя расширения, включая любые имена пакетов. Например,

Extension('foo', ['src/foo1.c', 'src/foo2.c'])

описывает расширение, которое находится в корневом пакете, в то время как

Extension('pkg.foo', ['src/foo1.c', 'src/foo2.c'])

описывает одно и то же расширение в пакете pkg. Исходные файлы и результирующий объектный код в обоих случаях идентичны; единственное различие заключается в том, где в файловой системе (и, следовательно, в иерархии пространства имен Python) находится результирующее расширение.

Если у вас есть несколько расширений в одном пакете (или все они находятся в одном базовом пакете), используйте ключевое слово ext_package в качестве аргумента setup(). Например,

setup(...,
      ext_package='pkg',
      ext_modules=[Extension('foo', ['foo.c']),
                   Extension('subpkg.bar', ['bar.c'])],
     )

будет скомпилирован foo.c с расширением pkg.foo, а bar.c - с расширением pkg.subpkg.bar.

2.3.2. Исходные файлы расширений

Вторым аргументом конструктора Extension является список исходных файлов. Поскольку дистрибутивы в настоящее время поддерживают только расширения C, C++ и Objective-C, обычно это исходные файлы C/C++/Objective-C. (Обязательно используйте соответствующие расширения, чтобы различать исходные файлы C++: .cc и .cpp, похоже, распознаются как компиляторами Unix, так и Windows.)

Однако вы также можете включить в список файлы интерфейса SWIG (.i); команда build_ext знает, как обращаться с расширениями SWIG: она запустит SWIG для файла интерфейса и скомпилирует полученный файл C/C++ с вашим расширением.

Несмотря на это предупреждение, параметры SWIG в настоящее время могут быть переданы следующим образом:

setup(...,
      ext_modules=[Extension('_foo', ['foo.i'],
                             swig_opts=['-modern', '-I../include'])],
      py_modules=['foo'],
     )

Или в командной строке, подобной этой:

> python setup.py build_ext --swig-opts="-modern -I../include"

На некоторых платформах вы можете включать файлы, не являющиеся исходными кодами, которые обрабатываются компилятором и включаются в ваше расширение. В настоящее время это означает только текстовые файлы сообщений Windows (.mc) и файлы определений ресурсов (.rc) для Visual C++. Они будут скомпилированы в двоичные файлы ресурсов (.res) и связаны с исполняемым файлом.

2.3.3. Параметры препроцессора

Три необязательных аргумента для Extension помогут, если вам нужно указать каталоги включения для поиска или макросы препроцессора для определения/отмены определения: include_dirs, define_macros, и undef_macros.

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

Extension('foo', ['foo.c'], include_dirs=['include'])

Вы можете указать там абсолютные каталоги; если вы знаете, что ваше расширение будет создано только в Unix-системах с X11R6, установленным на /usr, вам может сойти с рук

Extension('foo', ['foo.c'], include_dirs=['/usr/include/X11'])

Вам следует избегать такого рода непереносимого использования, если вы планируете распространять свой код: вероятно, лучше написать код на C следующим образом

#include <X11/Xlib.h>

Если вам нужно включить заголовочные файлы из какого-либо другого расширения Python, вы можете воспользоваться тем фактом, что заголовочные файлы устанавливаются согласованным образом с помощью команды Distutils install_headers. Например, числовые заголовочные файлы Python устанавливаются (при стандартной установке Unix) в /usr/local/include/python1.5/Numerical. (Точное расположение будет отличаться в зависимости от вашей платформы и установки Python.) Поскольку каталог Python include—/usr/local/include/python1.5 в данном случае— всегда включается в путь поиска при создании расширений Python, лучшим подходом является написание кода на C следующим образом

#include <Numerical/arrayobject.h>

Однако, если вам необходимо поместить каталог Numerical include прямо в путь поиска в заголовке, вы можете найти этот каталог с помощью модуля Distutils distutils.sysconfig:

from distutils.sysconfig import get_python_inc
incdir = os.path.join(get_python_inc(plat_specific=1), 'Numerical')
setup(...,
      Extension(..., include_dirs=[incdir]),
      )

Несмотря на то, что это довольно портативно - оно будет работать на любой установке Python, независимо от платформы, - вероятно, проще просто написать свой код на C разумным способом.

Вы можете определять и отменять определение макросов препроцессора с помощью параметров define_macros и undef_macros. define_macros принимает список (name, value) кортежей, где name - это имя определяемого макроса (строка), а value - его значение: либо строка, либо None. (Определение макроса FOO в None эквивалентно простому #define FOO в вашем исходном коде на C: в большинстве компиляторов при этом FOO устанавливается в строку 1.) undef_macros - это просто список макросов, которые нужно отменить.

Например:

Extension(...,
          define_macros=[('NDEBUG', '1'),
                         ('HAVE_STRFTIME', None)],
          undef_macros=['HAVE_FOO', 'HAVE_BAR'])

это эквивалентно тому, что это находится в верхней части каждого исходного файла на языке Си:

#define NDEBUG 1
#define HAVE_STRFTIME
#undef HAVE_FOO
#undef HAVE_BAR

2.3.4. Параметры библиотеки

Вы также можете указать библиотеки, на которые следует ссылаться при создании вашего расширения, и каталоги для поиска этих библиотек. Параметр libraries - это список библиотек, на которые можно установить ссылки, library_dirs - это список каталогов для поиска библиотек во время создания ссылок, а runtime_library_dirs - это список каталогов для поиска общих (динамически загружаемых) библиотек библиотеки во время выполнения.

Например, если вам нужно установить связь с библиотеками, которые, как известно, находятся в пути поиска стандартной библиотеки в целевых системах

Extension(...,
          libraries=['gdbm', 'readline'])

Если вам нужно установить связь с библиотеками, расположенными в нестандартном месте, вам придется указать это местоположение в library_dirs:

Extension(...,
          library_dirs=['/usr/X11R6/lib'],
          libraries=['X11', 'Xt'])

(Опять же, такого рода непереносимых конструкций следует избегать, если вы собираетесь распространять свой код.)

2.3.5. Другие варианты

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

Параметр optional имеет логическое значение; если оно равно true, сбой сборки в расширении не приведет к прерыванию процесса сборки, а вместо этого просто не установит сбойное расширение.

Параметр extra_objects представляет собой список объектных файлов, которые должны быть переданы компоновщику. Эти файлы не должны иметь расширений, поскольку используется расширение по умолчанию для компилятора.

extra_compile_args и extra_link_args могут использоваться для указания дополнительных параметров командной строки для соответствующих командных строк компилятора и компоновщика.

export_symbols полезен только в Windows. Он может содержать список символов (функций или переменных), которые необходимо экспортировать. Эта опция не требуется при создании скомпилированных расширений: Distutils автоматически добавит initmodule в список экспортируемых символов.

Параметр depends - это список файлов, от которых зависит расширение (например, заголовочные файлы). Команда build вызовет компилятор в исходных текстах для перестройки расширения, если что-либо в этих файлах было изменено с момента предыдущей сборки.

2.4. Взаимосвязи между дистрибутивами и пакетами

Дистрибутив может быть связан с пакетами тремя конкретными способами:

  1. Для этого могут потребоваться пакеты или модули.

  2. Он может предоставлять пакеты или модули.

  3. Это могут быть устаревшие пакеты или модули.

Эти связи могут быть заданы с помощью ключевых слов-аргументов функции distutils.core.setup().

Зависимости от других модулей и пакетов Python можно указать, указав в аргументе ключевого слова requires значение setup(). Значение должно быть списком строк. Каждая строка указывает необходимый пакет и, при необходимости, какие версии являются достаточными.

Чтобы указать, что требуется какая-либо версия модуля или пакета, строка должна полностью состоять из имени модуля или пакета. В качестве примеров можно привести 'mymodule' и 'xml.parsers.expat'.

Если требуются конкретные версии, в круглых скобках может быть указана последовательность определителей. Каждый определитель может состоять из оператора сравнения и номера версии. Допустимыми операторами сравнения являются:

<    >    ==
<=   >=   !=

Их можно объединить, используя несколько квалификаторов, разделенных запятыми (и необязательными пробелами). В этом случае все квалификаторы должны совпадать; для объединения оценок используется логическое И.

Давайте рассмотрим несколько примеров:

Требует выражения

Объяснение

==1.0

Совместима только версия 1.0

>1.0, !=1.5.1, <2.0

Любая версия после 1.0 и до 2.0 совместима, за исключением 1.5.1

Теперь, когда мы можем указывать зависимости, нам также нужно иметь возможность указать, что мы предоставляем, чего могут требовать другие дистрибутивы. Это делается с помощью ключевого слова provides в качестве аргумента setup(). Значение этого ключевого слова представляет собой список строк, каждая из которых содержит название модуля или пакета Python и необязательно указывает версию. Если версия не указана, предполагается, что она соответствует версии дистрибутива.

Вот несколько примеров:

Обеспечивает выражение

Объяснение

mypkg

Укажите mypkg, используя распространяемую версию

mypkg (1.1)

Укажите mypkg версию 1.1, независимо от версии дистрибутива

Пакет может объявить, что он устаревает для других пакетов, используя аргумент ключевого слова obsoletes. Значение этого параметра аналогично значению ключевого слова requires: список строк, содержащих спецификации модуля или пакета. Каждый спецификатор состоит из имени модуля или пакета, за которым, при необходимости, следует один или несколько указателей версии. Указатели версии указаны в круглых скобках после имени модуля или пакета.

Версии, указанные в квалификаторах, являются устаревшими для описываемого дистрибутива. Если квалификаторы не указаны, все версии названного модуля или пакета считаются устаревшими.

2.5. Установка скриптов

До сих пор мы имели дело с чистыми и не совсем чистыми модулями Python, которые обычно не запускаются сами по себе, а импортируются скриптами.

Скрипты - это файлы, содержащие исходный код Python, предназначенные для запуска из командной строки. Скрипты не требуют наличия дистрибутивов для выполнения чего-либо очень сложного. Единственная полезная особенность заключается в том, что если первая строка скрипта начинается с #! и содержит слово «python», то утилита Distutils настроит первую строку так, чтобы она указывала на текущее местоположение интерпретатора. По умолчанию она заменяется на текущее местоположение интерпретатора. Параметр --executable (или -e) позволит явно переопределить путь интерпретатора.

Параметр scripts - это просто список файлов, которые будут обрабатываться таким образом. Из сценария установки PyXML:

setup(...,
      scripts=['scripts/xmlproc_parse', 'scripts/xmlproc_val']
      )

Изменено в версии 3.1: Все скрипты также будут добавлены в файл MANIFEST, если шаблон не указан. Смотрите Указание файлов для распространения.

2.6. Установка данных пакета

Часто в пакет требуется установить дополнительные файлы. Эти файлы часто представляют собой данные, тесно связанные с реализацией пакета, или текстовые файлы, содержащие документацию, которая может представлять интерес для программистов, использующих пакет. Эти файлы называются package data.

Данные пакета могут быть добавлены к пакетам с помощью ключевого слова package_data в качестве аргумента функции setup(). Значение должно быть отображением имени пакета в список относительных путей, которые должны быть скопированы в пакет. Пути интерпретируются как относящиеся к каталогу, содержащему пакет (при необходимости используется информация из сопоставления package_dir); то есть ожидается, что файлы будут частью пакета в исходных каталогах. Они также могут содержать шаблоны глобальных объектов.

Имена путей могут содержать части каталогов; все необходимые каталоги будут созданы в процессе установки.

Например, если пакет должен содержать подкаталог с несколькими файлами данных, файлы могут быть расположены в дереве исходного кода следующим образом:

setup.py
src/
    mypkg/
        __init__.py
        module.py
        data/
            tables.dat
            spoons.dat
            forks.dat

Соответствующий вызов setup() может быть:

setup(...,
      packages=['mypkg'],
      package_dir={'mypkg': 'src/mypkg'},
      package_data={'mypkg': ['data/*.dat']},
      )

Изменено в версии 3.1: Все файлы, соответствующие package_data, будут добавлены в файл MANIFEST, если шаблон не указан. Смотрите Указание файлов для распространения.

2.7. Установка дополнительных файлов

Параметр data_files можно использовать для указания дополнительных файлов, необходимых для распространения модуля: файлов конфигурации, каталогов сообщений, файлов данных, всего, что не входит в предыдущие категории.

data_files задает последовательность пар (каталог, файлы) следующим образом:

setup(...,
      data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
                  ('config', ['cfg/data.cfg'])],
     )

Каждая пара (каталог, файлы) в последовательности указывает каталог установки и файлы, которые будут в него установлены.

Каждое имя файла в files интерпретируется относительно скрипта setup.py в верхней части исходного кода дистрибутива пакета. Обратите внимание, что вы можете указать каталог, в который будут установлены файлы данных, но сами файлы данных переименовывать нельзя.

Путь к каталогу * должен быть относительным. Он интерпретируется относительно префикса установки (sys.prefix в Python для системных установок; site.USER_BASE для пользовательских установок). В Distutils в качестве абсолютного пути установки используется directory, но это не рекомендуется, поскольку это несовместимо с форматом упаковки wheel. Информация о каталоге из files не используется для определения конечного местоположения установленного файла; используется только имя файла.

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

Изменено в версии 3.1: Все файлы, соответствующие data_files, будут добавлены в файл MANIFEST, если шаблон не указан. Смотрите Указание файлов для распространения.

2.8. Дополнительные метаданные

Сценарий установки может содержать дополнительные метаданные, помимо имени и версии. Эта информация включает:

Метаданные

Описание

Ценность

Записи

name

название пакета

короткая строка

(1)

version

версия этого выпуска

короткая строка

(1)(2)

author

имя автора пакета

короткая строка

(3)

author_email

адрес электронной почты автора пакета

адрес электронной почты

(3)

maintainer

имя сопровождающего пакета

короткая строка

(3)

maintainer_email

адрес электронной почты сопровождающего пакета

адрес электронной почты

(3)

url

домашняя страница пакета

URL-адрес

(1)

description

краткое, обобщающее описание пакета

короткая строка

long_description

более подробное описание упаковки

длинная строка

(4)

download_url

место, где можно загрузить пакет

URL-адрес

classifiers

список классификаторов

список строк

(6)(7)

platforms

список платформ

список строк

(6)(8)

keywords

список ключевых слов

список строк

(6)(8)

license

лицензия на пакет услуг

короткая строка

(5)

Записи:

  1. Эти поля обязательны для заполнения.

  2. Рекомендуется, чтобы версии имели вид major.minor[.patch[.sub]].

  3. Должен быть указан либо автор, либо сопровождающий. Если указан сопровождающий, в distutils он указан как автор в PKG-INFO.

  4. Поле long_description используется PyPI при публикации пакета для создания страницы проекта.

  5. Поле license представляет собой текст, указывающий на лицензию, охватывающую пакет, если лицензия не является выборкой из классификаторов «Лицензия». Смотрите поле Classifier. Обратите внимание, что существует параметр распространения licence, который устарел, но по-прежнему используется как псевдоним для license.

  6. Это поле должно быть списком.

  7. Допустимые классификаторы перечислены в PyPI.

  8. Для сохранения обратной совместимости это поле также принимает строку. Если вы введете строку, разделенную запятой 'foo, bar', она будет преобразована в ['foo', 'bar'], в противном случае она будет преобразована в список из одной строки.

«короткая строка»

Одна строка текста, не более 200 символов.

«длинная строка»

Несколько строк обычного текста в формате reStructuredText (см. https://docutils.sourceforge.io/).

«список строк»

Смотреть ниже.

Кодирование информации о версии - это искусство само по себе. Пакеты Python обычно соответствуют формату версии major.minor[.patch][sub]. Для начальных, экспериментальных выпусков программного обеспечения значение major равно 0. Оно увеличивается для выпусков, которые представляют собой основные этапы в разработке пакета. Количество исправлений увеличивается, когда в пакет добавляются важные новые функции. Количество исправлений увеличивается, когда выпускаются версии с исправлениями ошибок. Иногда для обозначения дополнительных версий используется дополнительная информация об обучающей версии. Это «a1,a2,…,aN» (для альфа-версий, в которых функциональность и API могут меняться), «b1,b2,…,bN» (для бета-версий, в которых исправляются только ошибки) и «pr1,pr2,…,prN» (для финального предварительного релиза тестирование). Вот несколько примеров:

0.1.0

первый, экспериментальный выпуск пакета

1.0.1а2

второй альфа-релиз первого патча версии 1.0

classifiers должно быть указано в списке:

setup(...,
      classifiers=[
          'Development Status :: 4 - Beta',
          'Environment :: Console',
          'Environment :: Web Environment',
          'Intended Audience :: End Users/Desktop',
          'Intended Audience :: Developers',
          'Intended Audience :: System Administrators',
          'License :: OSI Approved :: Python Software Foundation License',
          'Operating System :: MacOS :: MacOS X',
          'Operating System :: Microsoft :: Windows',
          'Operating System :: POSIX',
          'Programming Language :: Python',
          'Topic :: Communications :: Email',
          'Topic :: Office/Business',
          'Topic :: Software Development :: Bug Tracking',
          ],
      )

Изменено в версии 3.7: setup теперь предупреждает, когда поля classifiers, keywords или platforms не указаны в виде списка или строки.

2.9. Отладка сценария установки

Иногда что-то идет не так, и сценарий установки выполняет не то, что хочет разработчик.

Distutils перехватывает все исключения при запуске сценария установки и выводит простое сообщение об ошибке перед завершением работы сценария. Причина такого поведения заключается в том, чтобы не вводить в заблуждение администраторов, которые плохо разбираются в Python и пытаются установить пакет. Если они получают большую и длинную обратную связь из недр Distutils, они могут подумать, что пакет или установка Python нарушены, потому что они не читают до конца и не видят, что это проблема с правами доступа.

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

Вернуться на верх