setupscript.md
1> **Источник:** https://python-all.ru/3.0/distutils/setupscript.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Написание скрипта установки89The setup script is the centre of all activity in building, distributing, and installing modules using the Distutils. The main purpose of the setup script is to describe your module distribution to the Distutils, so that the various commands that operate on your modules do the right thing. As we saw in section [*A Simple Example*](https://python-all.ru/3.0/distutils/introduction.html#distutils-simple-example) above, the setup script consists mainly of a call to `setup()`, and most information supplied to the Distutils by the module developer is supplied as keyword arguments to `setup()`.1011Вот немного более сложный пример, который мы будем рассматривать в следующих нескольких разделах: собственный сценарий установки Distutils. (Имейте в виду, что хотя Distutils входят в состав Python 1.6 и более поздних версий, они также существуют независимо, чтобы пользователи Python 1.5.2 могли использовать их для установки других дистрибутивов модулей. Собственный сценарий установки Distutils, показанный здесь, используется для установки пакета в Python 1.5.2.)1213```python14#!/usr/bin/env python1516from distutils.core import setup1718setup(name='Distutils',19 version='1.0',20 description='Python Distribution Utilities',21 author='Greg Ward',22 author_email='gward@python.net',23 url='http://www.python.org/sigs/distutils-sig/',24 packages=['distutils', 'distutils.command'],25 )26```2728Есть только два отличия от тривиального однофайлового дистрибутива, представленного в разделе [*A Simple Example*](https://python-all.ru/3.0/distutils/introduction.html#distutils-simple-example): больше метаданных и указание чистых модулей Python по пакетам, а не по модулям. Это важно, поскольку Distutils состоят из нескольких десятков модулей, разбитых (пока) на два пакета; явный список всех модулей было бы утомительно составлять и сложно поддерживать. Дополнительную информацию о метаданных см. в разделе [*Additional meta-data*](https://python-all.ru/3.0/distutils/setupscript.html#meta-data).2930Обратите внимание: любые пути (к файлам или каталогам), указанные в сценарии установки, должны записываться в стиле Unix, то есть с разделителем-слешем. Distutils позаботится о преобразовании этого платформонезависимого представления в то, что подходит для вашей текущей платформы, перед фактическим использованием пути. Это делает ваш сценарий установки переносимым между операционными системами, что, конечно, является одной из главных целей Distutils. В этом духе все пути в данном документе записываются через слеш.3132This, of course, only applies to pathnames given to Distutils functions. If you, for example, use standard Python functions such as [`glob.glob()`](https://python-all.ru/3.0/library/glob.html#glob.glob) or [`os.listdir()`](https://python-all.ru/3.0/library/os.html#os.listdir) to specify files, you should be careful to write portable code instead of hardcoding path separators:3334```python35glob.glob(os.path.join('mydir', 'subdir', '*.html'))36os.listdir(os.path.join('mydir', 'subdir'))37```3839## Перечисление целых пакетов4041Параметр *packages* указывает Distutils обработать (собрать, распространить, установить и т.д.) все чистые модули Python, найденные в каждом пакете, указанном в списке *packages*. Для этого, разумеется, необходимо, чтобы имена пакетов соответствовали каталогам в файловой системе. По умолчанию это соответствие наиболее очевидное: пакет [`distutils`](https://python-all.ru/3.0/library/distutils.html#module-distutils) находится в каталоге `distutils` относительно корня дистрибутива. Таким образом, когда в установочном скрипте вы указываете `packages = ['foo']`, вы гарантируете, что Distutils найдет файл `foo/__init__.py` (на вашей системе он может называться иначе, но суть ясна) относительно каталога, где находится ваш установочный скрипт. Если вы нарушите это обещание, Distutils выдаст предупреждение, но всё равно обработает этот «сломанный» пакет.4243Если структура исходного каталога отличается от стандартной, это не проблема: достаточно указать параметр *package\_dir*, чтобы сообщить Distutils о своей структуре. Например, весь исходный код на Python находится в каталоге `lib`, так что модули «корневого пакета» (т.е. не входящие ни в один пакет) располагаются в `lib`, модули пакета `foo` – в `lib/foo` и так далее. Тогда нужно указать4445```python46package_dir = {'': 'lib'}47```4849в ваш скрипт установки. Ключи этого словаря – имена пакетов, а пустое имя пакета означает корневой пакет. Значения – имена каталогов относительно корня дистрибутива. В этом случае, когда указано `packages = ['foo']`, вы обещаете, что существует файл `lib/foo/__init__.py`.5051Другое возможное соглашение – поместить пакет `foo` прямо в `lib`, пакет `foo.bar` – в `lib/bar` и т.д. В скрипте установки это будет записано как5253```python54package_dir = {'foo': 'lib'}55```5657Запись `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`.)5859## Перечисление отдельных модулей6061Для небольшого дистрибутива модулей может быть удобнее перечислить все модули, а не пакеты – особенно случай одного модуля, который находится в «корневом пакете» (то есть вообще без пакета). Этот простейший случай был показан в разделе [*Простой пример*](https://python-all.ru/3.0/distutils/introduction.html#distutils-simple-example); вот немного более сложный пример:6263```python64py_modules = ['mod1', 'pkg.mod2']65```6667Здесь описаны два модуля: один в «корневом» пакете, другой в пакете `pkg`. Опять же, стандартное соответствие пакетов и каталогов подразумевает, что эти модули находятся в `mod1.py` и `pkg/mod2.py`, а также существует `pkg/__init__.py`. И снова соответствие пакетов и каталогов можно изменить с помощью параметра *package\_dir*.6869## Описание модулей расширения7071Так же как написание модулей расширения Python немного сложнее, чем написание чистых модулей Python, их описание для Distutils тоже немного сложнее. В отличие от чистых модулей, недостаточно просто перечислить модули или пакеты и ожидать, что Distutils сам найдёт нужные файлы; необходимо указать имя расширения, исходные файлы и любые требования к компиляции/компоновке (каталоги включения, библиотеки для компоновки и т.д.).7273Всё это делается через ещё один именованный аргумент `setup()`, параметр *ext\_modules*. *ext\_modules* – это просто список экземпляров `Extension`, каждый из которых описывает один модуль-расширение. Предположим, ваш дистрибутив содержит одно расширение с именем `foo`, реализованное в файле `foo.c`. Если компилятору/компоновщику не нужны дополнительные указания, описание этого расширения будет совсем простым:7475```python76Extension('foo', ['foo.c'])77```7879Класс `Extension` можно импортировать из [`distutils.core`](https://python-all.ru/3.0/distutils/apiref.html#module-distutils.core) вместе с `setup()`. Таким образом, скрипт установки для дистрибутива, содержащего только это одно расширение и ничего больше, может выглядеть так:8081```python82from distutils.core import setup, Extension83setup(name='foo',84 version='1.0',85 ext_modules=[Extension('foo', ['foo.c'])],86 )87```8889Класс `Extension` (фактически, лежащая в его основе механика сборки расширений, реализованная командой **build\_ext**) поддерживает большую гибкость при описании расширений Python, что объясняется в следующих разделах.9091### Имена расширений и пакеты9293Первый аргумент конструктора `Extension` – это всегда имя расширения, включая имена пакетов. Например,9495```python96Extension('foo', ['src/foo1.c', 'src/foo2.c'])97```9899описывает расширение, находящееся в корневом пакете, тогда как100101```python102Extension('pkg.foo', ['src/foo1.c', 'src/foo2.c'])103```104105описывает то же расширение в пакете `pkg`. Исходные файлы и результирующий объектный код в обоих случаях идентичны; разница лишь в том, где в файловой системе (а следовательно, и в иерархии пространства имён Python) окажется результирующее расширение.106107Если несколько расширений находятся в одном пакете (или все в одном базовом пакете), используйте именованный аргумент *ext\_package* функции `setup()`. Например,108109```python110setup(...,111 ext_package='pkg',112 ext_modules=[Extension('foo', ['foo.c']),113 Extension('subpkg.bar', ['bar.c'])],114 )115```116117скомпилирует `foo.c` в расширение `pkg.foo`, а `bar.c` – в `pkg.subpkg.bar`.118119### Исходные файлы расширений120121Второй аргумент конструктора `Extension` – это список исходных файлов. Поскольку Distutils на данный момент поддерживает только расширения на C, C++ и Objective-C, это обычно исходные файлы на C/C++/Objective-C. (Обязательно используйте соответствующие расширения, чтобы различать файлы C++: `.cc` и `.cpp`, по-видимому, распознаются компиляторами как Unix, так и Windows.)122123Однако в список можно также включать файлы интерфейсов SWIG (`.i`); команда **build\_ext** умеет работать с расширениями SWIG: она запустит SWIG на файле интерфейса и скомпилирует полученный C/C++-файл в ваше расширение.124125**\*\*** Поддержка SWIG грубовата и в основном не тестировалась! **\*\***126127Несмотря на это предупреждение, опции для SWIG в настоящее время можно передавать так:128129```python130setup(...,131 ext_modules=[Extension('_foo', ['foo.i'],132 swig_opts=['-modern', '-I../include'])],133 py_modules=['foo'],134 )135```136137Или в командной строке так:138139```python140> python setup.py build_ext --swig-opts="-modern -I../include"141```142143На некоторых платформах можно включать в расширение неисходные файлы, которые обрабатываются компилятором. В настоящее время это касается файлов сообщений Windows (`.mc`) и файлов определения ресурсов (`.rc`) для Visual C++. Они будут скомпилированы в двоичные ресурсные файлы (`.res`) и подключатся к исполняемому файлу.144145### Опции препроцессора146147Три необязательных аргумента `Extension` помогут, если нужно указать каталоги для поиска включаемых файлов или макросы препроцессора для определения/отмены: `include_dirs`, `define_macros` и `undef_macros`.148149Например, если вашему расширению требуются заголовочные файлы из каталога `include` в корне дистрибутива, используйте опцию `include_dirs`:150151```python152Extension('foo', ['foo.c'], include_dirs=['include'])153```154155Там можно указывать абсолютные пути; если вы знаете, что ваше расширение будет собираться только в Unix-системах с установленным X11R6 в `/usr`, можно обойтись156157```python158Extension('foo', ['foo.c'], include_dirs=['/usr/include/X11'])159```160161Следует избегать такого непереносимого использования, если вы планируете распространять свой код: вероятно, лучше написать код на C так:162163```python164#include <X11/Xlib.h>165```166167Если вам нужно включить заголовочные файлы из другого расширения Python, можно воспользоваться тем, что заголовочные файлы устанавливаются единообразно командой **install\_header** из Distutils. Например, заголовочные файлы Numerical Python устанавливаются (в стандартной установке Unix) в `/usr/local/include/python1.5/Numerical`. (Точное расположение зависит от вашей платформы и установки Python.) Поскольку каталог включения Python – в данном случае `/usr/local/include/python1.5` – всегда включён в путь поиска при сборке расширений Python, лучше всего писать код на C так:168169```python170#include <Numerical/arrayobject.h>171```172173Если же необходимо поместить каталог include `Numerical` прямо в путь поиска заголовков, то этот каталог можно найти с помощью модуля Distutils [`distutils.sysconfig`](https://python-all.ru/3.0/distutils/apiref.html#module-distutils.sysconfig):174175```python176from distutils.sysconfig import get_python_inc177incdir = os.path.join(get_python_inc(plat_specific=1), 'Numerical')178setup(...,179 Extension(..., include_dirs=[incdir]),180 )181```182183Несмотря на то, что это вполне переносимо – будет работать в любой установке Python, независимо от платформы, – вероятно, проще просто написать код на C разумным способом.184185Можно определять и отменять макросы препроцессора с помощью опций `define_macros` и `undef_macros`. `define_macros` принимает список кортежей `(name, value)`, где `name` – имя определяемого макроса (строка), а `value` – его значение: строка или `None`. (Определение макроса `FOO` как `None` эквивалентно голому `#define FOO` в C-исходнике: для большинства компиляторов это устанавливает `FOO` в строку `1`.) `undef_macros` – это просто список макросов, которые нужно отменить.186187Например:188189```python190Extension(...,191 define_macros=[('NDEBUG', '1'),192 ('HAVE_STRFTIME', None)],193 undef_macros=['HAVE_FOO', 'HAVE_BAR'])194```195196is the equivalent of having this at the top of every C source file:197198```python199#define NDEBUG 1200#define HAVE_STRFTIME201#undef HAVE_FOO202#undef HAVE_BAR203```204205### Опции библиотек206207Также можно указать библиотеки, с которыми нужно линковать расширение, и каталоги для поиска этих библиотек. Опция `libraries` – это список библиотек для линковки, `library_dirs` – список каталогов для поиска библиотек на этапе линковки, а `runtime_library_dirs` – список каталогов для поиска разделяемых (динамически загружаемых) библиотек во время выполнения.208209Например, если требуется скомпоновать расширение с библиотеками, которые заведомо находятся в стандартном пути поиска библиотек в целевых системах,210211```python212Extension(...,213 libraries=['_gdbm', 'readline'])214```215216Если нужно линковаться с библиотеками в нестандартном расположении, придётся указать это расположение в `library_dirs`:217218```python219Extension(...,220 library_dirs=['/usr/X11R6/lib'],221 libraries=['X11', 'Xt'])222```223224(Повторим: подобные непереносимые конструкции следует избегать, если планируется распространять свой код.)225226**\*\*** Следует упомянуть библиотеки clib здесь или где-нибудь ещё! **\*\***227228### Другие варианты229230Существуют и другие опции, которые можно использовать для обработки особых случаев.231232Параметр *extra\_objects* – это список объектных файлов, передаваемых компоновщику. Эти файлы не должны иметь расширений, так как используется расширение по умолчанию для компилятора.233234Параметры *extra\_compile\_args* и *extra\_link\_args* можно использовать для указания дополнительных параметров командной строки для компилятора и компоновщика соответственно.235236Параметр *export\_symbols* полезен только в Windows. Он может содержать список символов (функций или переменных), которые нужно экспортировать. Этот параметр не требуется при сборке скомпилированных расширений: Distutils автоматически добавит `initmodule` в список экспортируемых символов.237238## Отношения между дистрибутивами и пакетами239240Дистрибутив может относиться к пакетам тремя определёнными способами:2412421. Он может требовать пакеты или модули.2432. Он может предоставлять пакеты или модули.2443. Он может заменять (делать устаревшими) пакеты или модули.245246Эти зависимости можно указать с помощью именованных аргументов функции [`distutils.core.setup()`](https://python-all.ru/3.0/distutils/apiref.html#distutils.core.setup).247248Зависимости от других модулей и пакетов Python можно указать, передав *requires* в качестве именованного аргумента функции `setup()`. Значением должен быть список строк. Каждая строка задает требуемый пакет и, опционально, подходящие версии.249250Чтобы указать, что требуется любая версия модуля или пакета, строка должна состоять только из имени модуля или пакета. Примеры: `'mymodule'` и `'xml.parsers.expat'`.251252Если требуются конкретные версии, можно указать последовательность квалификаторов в скобках. Каждый квалификатор может состоять из оператора сравнения и номера версии. Допустимые операторы сравнения:253254```python255< > ==256<= >= !=257```258259Их можно комбинировать, используя несколько квалификаторов, разделённых запятыми (и необязательными пробелами). В этом случае все квалификаторы должны совпадать; используется логическое И для объединения результатов.260261Рассмотрим несколько примеров:262263| Выражение Requires | Пояснение |264| --- | --- |265| `==1.0` | Совместима только версия `1.0` |266| `>1.0, !=1.5.1, <2.0` | Любая версия после `1.0` и до `2.0` совместима, за исключением `1.5.1` |267268Теперь, когда мы можем указывать зависимости, нужно также уметь указывать, что мы предоставляем, чтобы другие дистрибутивы могли на это ссылаться. Для этого используется именованный аргумент *provides* функции `setup()`. Значением этого аргумента является список строк, каждая из которых задает имя модуля или пакета Python и, опционально, версию. Если версия не указана, считается, что она соответствует версии дистрибутива.269270Несколько примеров:271272| Выражение Provides | Пояснение |273| --- | --- |274| `mypkg` | Предоставляет `mypkg`, используя версию дистрибутива |275| `mypkg (1.1)` | Предоставляет `mypkg` версии 1.1, независимо от версии дистрибутива |276277Пакет может объявлять, что он заменяет (делает устаревшими) другие пакеты, с помощью именованного аргумента *obsoletes*. Его значение аналогично значению аргумента *requires*: список строк, задающих спецификаторы модуля или пакета. Каждый спецификатор состоит из имени модуля или пакета, за которым необязательно следуют один или несколько квалификаторов версии. Версионные квалификаторы указываются в скобках после имени модуля или пакета.278279Версии, указанные квалификаторами, считаются заменяемыми (устаревшими) данным дистрибутивом. Если квалификаторы не указаны, считаются устаревшими все версии указанного модуля или пакета.280281## Установка скриптов282283До сих пор мы имели дело с чистыми и нечистыми модулями Python, которые обычно не запускаются сами по себе, а импортируются скриптами.284285Скрипты – это файлы, содержащие исходный код Python, предназначенные для запуска из командной строки. Скрипты не требуют от Distutils ничего очень сложного. Единственная интересная особенность: если первая строка скрипта начинается с `#!` и содержит слово «python», Distutils скорректирует первую строку, чтобы она указывала на текущее расположение интерпретатора. По умолчанию она заменяется на путь к текущему интерпретатору. Параметр *--executable* (или *-e*) позволяет явно переопределить путь к интерпретатору.286287Параметр *scripts* – это просто список файлов, которые будут обработаны таким образом. Из сценария установки PyXML:288289```python290setup(...,291 scripts=['scripts/xmlproc_parse', 'scripts/xmlproc_val']292 )293```294295## Установка данных пакета296297Часто в пакет нужно установить дополнительные файлы. Эти файлы – обычно данные, тесно связанные с реализацией пакета, или текстовые файлы с документацией, которая может быть полезна программистам, использующим пакет. Такие файлы называются *данными пакета*.298299Данные пакета можно добавить, используя именованный аргумент `package_data` функции `setup()`. Значение должно быть словарем, сопоставляющим имя пакета со списком относительных путей к файлам, которые должны быть скопированы в пакет. Пути интерпретируются относительно каталога, содержащего пакет (если уместно, используется информация из словаря `package_dir`); то есть файлы должны быть частью пакета в исходных каталогах. Они также могут содержать шаблоны glob.300301Имена путей могут содержать части каталогов; все необходимые каталоги будут созданы при установке.302303Например, если пакет должен содержать подкаталог с несколькими файлами данных, файлы можно расположить в дереве исходников следующим образом:304305```python306setup.py307src/308 mypkg/309 __init__.py310 module.py311 data/312 tables.dat313 spoons.dat314 forks.dat315```316317Соответствующий вызов `setup()` может выглядеть так:318319```python320setup(...,321 packages=['mypkg'],322 package_dir={'mypkg': 'src/mypkg'},323 package_data={'mypkg': ['data/*.dat']},324 )325```326327## Установка дополнительных файлов328329Параметр *data\_files* можно использовать для указания дополнительных файлов, необходимых дистрибутиву модуля: конфигурационные файлы, файлы сообщений, файлы данных – всё, что не подходит под предыдущие категории.330331Параметр *data\_files* задаёт последовательность пар (*directory*, *files*) следующим образом:332333```python334setup(...,335 data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),336 ('config', ['cfg/data.cfg']),337 ('/etc/init.d', ['init-script'])]338 )339```340341Обратите внимание: можно указать имена каталогов, в которые будут установлены файлы данных, но сами файлы переименовать нельзя.342343Каждая пара (*directory*, *files*) в последовательности задает каталог установки и файлы для установки в нем. Если *directory* – относительный путь, он интерпретируется относительно префикса установки (`sys.prefix` для чисто Python-пакетов, `sys.exec_prefix` для пакетов, содержащих расширения). Каждый файл в *files* интерпретируется относительно скрипта `setup.py` из корня пакета исходного кода. Информация о каталоге из *files* не используется для определения конечного расположения устанавливаемого файла; используется только имя файла.344345Параметр *data\_files* можно задать как простую последовательность файлов без указания целевого каталога, но это не рекомендуется; в этом случае команда **install** выведет предупреждение. Чтобы установить файлы данных непосредственно в целевой каталог, в качестве каталога следует указать пустую строку.346347## Дополнительные метаданные348349Скрипт setup может включать дополнительные метаданные помимо имени и версии. Эта информация включает:350351| Метаданные | Описание | Значение | Примечания |352| --- | --- | --- | --- |353| `name` | имя пакета | короткая строка | (1) |354| `version` | версия этого релиза | короткая строка | (1)(2) |355| `author` | имя автора пакета | короткая строка | (3) |356| `author_email` | адрес электронной почты автора пакета | адрес электронной почты | (3) |357| `maintainer` | имя сопровождающего пакета | короткая строка | (3) |358| `maintainer_email` | адрес электронной почты сопровождающего пакет | адрес электронной почты | (3) |359| `url` | домашняя страница пакета | URL | (1) |360| `description` | краткое описание пакета | короткая строка | |361| `long_description` | подробное описание пакета | длинная строка | |362| `download_url` | расположение, откуда можно загрузить пакет | URL | (4) |363| `classifiers` | список классификаторов | список строк | (4) |364| `платформы` | список платформ | список строк | |365366Примечания:3673681. Эти поля обязательны.3692. Рекомендуется, чтобы версии имели формат *major.minor\[.patch\[.sub\]\]*.3703. Должен быть указан либо автор, либо сопровождающий.3714. Эти поля не следует использовать, если пакет должен быть совместим с версиями Python до 2.2.3 или 2.3. Список доступен на [сайте PyPI](https://python-all.ru/3.0/distutils/setupscript.html).372373**«короткая строка»**374375Одна строка текста, не более 200 символов.376377**«длинная строка»**378379Многострочный простой текст в формате reStructuredText (см.380381[http://docutils.sf.net/](https://python-all.ru/3.0/distutils/setupscript.html)382383).384385**«список строк»**386387См. ниже.388389Указание версии – это искусство само по себе. Пакеты Python обычно следуют формату версии *major.minor\[.patch\]\[sub\]*. Основной номер равен 0 для начальных экспериментальных выпусков ПО. Он увеличивается для выпусков, представляющих важные вехи в пакете. Второстепенный номер увеличивается, когда добавляются важные новые функции. Номер патча увеличивается при выпусках с исправлениями ошибок. Дополнительная завершающая информация о версии иногда используется для обозначения подвыпусков. Это «a1,a2,...,aN» (для альфа-выпусков, где функциональность и API могут измениться), «b1,b2,...,bN» (для бета-выпусков, которые только исправляют ошибки) и «pr1,pr2,...,prN» (для финального предрелизного тестирования). Некоторые примеры:390391**0.1.0**392393первый экспериментальный выпуск пакета394395**1.0.1a2**396397второй альфа-выпуск первой патч-версии 1.0398399*Классификаторы* указываются в виде списка Python:400401```python402setup(...,403 classifiers=[404 'Development Status :: 4 - Beta',405 'Environment :: Console',406 'Environment :: Web Environment',407 'Intended Audience :: End Users/Desktop',408 'Intended Audience :: Developers',409 'Intended Audience :: System Administrators',410 'License :: OSI Approved :: Python Software Foundation License',411 'Operating System :: MacOS :: MacOS X',412 'Operating System :: Microsoft :: Windows',413 'Operating System :: POSIX',414 'Programming Language :: Python',415 'Topic :: Communications :: Email',416 'Topic :: Office/Business',417 'Topic :: Software Development :: Bug Tracking',418 ],419 )420```421422Если требуется включить классификаторы в файл `setup.py` и при этом сохранить обратную совместимость с версиями Python до 2.2.3, то можно добавить следующий фрагмент кода в `setup.py` перед вызовом `setup()`.423424```python425# исправить distutils, если он не справляется с ключевыми словами "classifiers" или426# ключевые слова "download_url"427from sys import version428if version < '2.2.3':429 from distutils.dist import DistributionMetadata430 DistributionMetadata.classifiers = None431 DistributionMetadata.download_url = None432```433434## Отладка сценария установки435436Иногда что-то идет не так, и скрипт установки делает не то, что хочет разработчик.437438Distutils перехватывает любые исключения при запуске скрипта установки и выводит простое сообщение об ошибке перед завершением скрипта. Причина такого поведения – не запутывать администраторов, которые мало знают о Python и пытаются установить пакет. Если они получат длинную трассировку из глубин Distutils, они могут подумать, что пакет или установка Python сломаны, потому что не прочитают все до конца и не увидят, что проблема в правах доступа.439440С другой стороны, это не помогает разработчику найти причину сбоя. Для этого можно установить переменную окружения DISTUTILS\_DEBUG в любое непустое значение, и distutils будет выводить подробную информацию о том, что делает, а также полный стек вызовов в случае возникновения исключения.441