Spec-Zone.ru › Python 3.8

Написание скрипта установки

Примечание

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

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

Вот несколько более сложный пример, за которым мы будем следить в следующих нескольких разделах: собственный скрипт установки Distutils. (Помните, что хотя 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-модулей по пакетам, а не по модулям. Это важно, поскольку Distutils состоит из нескольких десятков модулей, разделенных (пока) на два пакета; явный список каждого модуля было бы утомительно генерировать и сложно поддерживать. Для получения дополнительной информации о дополнительных метаданных см. раздел Дополнительные метаданные.

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

Конечно, это относится только к именам путей, предоставленным функциям 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 обработать (создать, распространить, установить и т. д.) все чисто Python-модули, найденные в каждом пакете, упомянутом в списке packages. Для этого, конечно, должна быть взаимосвязь между именами пакетов и каталогами в файловой системе. По умолчанию соответствие является наиболее очевидным, т. е. пакет distutils находится в каталоге distutils относительно корня распределения. Таким образом, когда вы указываете packages = ['foo'] в своём скрипте установки, вы гарантируете, что Distutils найдёт файл 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'], вы сообщаете Distutils искать lib/__init__.py и lib/bar/__init__.py. (Помните, что хотя package_dir применяется рекурсивно, вы должны явно указать все пакеты в packages: Distutils не будут рекурсивно сканировать вашу структуру каталогов в поисках любого каталога с файлом __init__.py)

2.2. Перечисление отдельных модулей

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

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

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

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

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

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

#include <Numerical/arrayobject.h>

Однако, если вы должны поместить директорию включения Numerical прямо в свой путь поиска заголовков, вы можете найти эту директорию с помощью модуля 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'])

эквивалентно наличию этого вверху каждого файла исходного кода C:

#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 — это логическое значение; если оно истинно, ошибка построения в расширении не прервёт процесс построения, а вместо этого просто не установит вызвавшее ошибку расширение.

Опция extra_objects — это список файлов объектного кода, которые должны быть переданы линкеру. Эти файлы не должны иметь расширений, так как используется стандартное расширение для компилятора.

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

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

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

END_OF_DOCUMENT_MARKER

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

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

  1. Требовать пакеты или модули.
  2. Предоставлять пакеты или модули.
  3. Устаревать пакеты или модули.

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

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

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

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

<    >    ==
<=   >=   !=

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

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

Выражение requires

Описание

==1.0

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

>1.0, !=1.5.1, <2.0

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

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

Примеры:

Выражение provides

Описание

mypkg

Предоставляем mypkg, используя версию дистрибутива

mypkg (1.1)

Предоставляем mypkg версии 1.1, независимо от версии дистрибутива

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Каталог должен быть относительным путём. Он интерпретируется относительно префикса установки (Python’s sys.prefix для системных установок; site.USER_BASE для пользовательских установок). Distutils позволяет сделать каталог абсолютным путём установки, но это не рекомендуется, поскольку это несовместимо с форматом упаковки колес (wheel). Никакая информация о каталоге из файлов не используется для определения конечного расположения установленного файла; используется только имя файла.

Вы можете указать опции 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 (см. http://docutils.sourceforge.net/).

‘список строк’

См. ниже.

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

0.1.0

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

1.0.1a2

второй альфа-выпуск первой версии исправления 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) терпит неудачу.

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/distutils/setupscript.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API