Spec-Zone.ru › Python 3.11

Написание скрипта настройки

Примечание

Этот документ хранится только до тех пор, пока документация 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, т. е. с использованием разделителя слеш. 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, вы можете воспользоваться тем фактом, что файлы заголовков устанавливаются в согласованном формате командой install_headers Distutils. Например, файлы заголовков 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 — список файлов, от которых зависит расширение (например, файлы заголовков). Команда сборки вызовет компилятор на исходных файлах для перестроения расширения, если какой-либо из этих файлов был изменен с момента предыдущей сборки.

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); то есть ожидается, что файлы являются частью пакета в исходных каталогах. Они также могут содержать шаблоны подстановок.

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

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

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 в случае отсутствия шаблона. См. Указание файлов для распространения.

END_OF_DOCUMENT_MARKER

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 — текст, указывающий лицензию, охватывающую пакет, если лицензия не выбрана из классификаторов «Лицензия» Trove. См. поле Classifier. Обратите внимание, что существует опция дистрибуции licence, которая устарела, но все еще действует как псевдоним для license.
  6. Это поле должно быть списком.
  7. Список допустимых классификаторов приведен на PyPI.
  8. Для обеспечения обратной совместимости это поле также принимает строку. Если вы передаете строку через запятую 'foo, bar', она будет преобразована в ['foo', 'bar']. В противном случае она будет преобразована в список из одной строки.
‘короткая строка’

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

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

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

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

См. ниже.

Кодирование информации о версии само по себе является искусством. Пакеты Python обычно придерживаются формата версии major.minor[.patch][sub]. Значение «major» равно 0 для начальных, экспериментальных выпусков программного обеспечения. Оно увеличивается для релизов, представляющих значительные вехи в пакете. Значение «minor» увеличивается, когда добавляются важные новые функции в пакет. Значение «patch» увеличивается при выпуске исправлений ошибок. Дополнительная информация о версии иногда используется для указания суб-выпусков. Это «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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/distutils/setupscript.html

Spec-Zone.ru

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