Документация Python неофициальный перевод

setupscript.md

450 строк · 42.5 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.1/distutils/setupscript.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 2. Написание сценария установки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.1/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.1/distutils/introduction.html#distutils-simple-example): больше метаданных и указание чистых модулей Python по пакетам, а не по модулям. Это важно, поскольку Distutils состоят из нескольких десятков модулей, разбитых (пока) на два пакета; явный список всех модулей было бы утомительно составлять и сложно поддерживать. Дополнительную информацию о метаданных см. в разделе [*Additional meta-data*](https://python-all.ru/3.1/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.1/library/glob.html#glob.glob) or [`os.listdir()`](https://python-all.ru/3.1/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## 2.1. Перечисление целых пакетов4041Параметр *packages* указывает Distutils обработать (собрать, распространить, установить и т.д.) все чистые модули Python, найденные в каждом пакете, указанном в списке *packages*. Для этого, разумеется, необходимо, чтобы имена пакетов соответствовали каталогам в файловой системе. По умолчанию это соответствие наиболее очевидное: пакет [`distutils`](https://python-all.ru/3.1/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## 2.2. Перечисление отдельных модулей6061Для небольшого дистрибутива модулей может быть удобнее перечислить все модули, а не пакеты – особенно случай одного модуля, который находится в «корневом пакете» (то есть вообще без пакета). Этот простейший случай был показан в разделе [*Простой пример*](https://python-all.ru/3.1/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## 2.3. Описание модулей расширений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.1/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### 2.3.1. Имена расширений и пакеты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### 2.3.2. Исходные файлы расширений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```python128setup(...,129      ext_modules=[Extension('_foo', ['foo.i'],130                             swig_opts=['-modern', '-I../include'])],131      py_modules=['foo'],132     )133```134135Или в командной строке так:136137```python138> python setup.py build_ext --swig-opts="-modern -I../include"139```140141На некоторых платформах можно включать в расширение неисходные файлы, которые обрабатываются компилятором. В настоящее время это касается файлов сообщений Windows (`.mc`) и файлов определения ресурсов (`.rc`) для Visual C++. Они будут скомпилированы в двоичные ресурсные файлы (`.res`) и подключатся к исполняемому файлу.142143### 2.3.3. Параметры препроцессора144145Три необязательных аргумента `Extension` помогут, если нужно указать каталоги для поиска включаемых файлов или макросы препроцессора для определения/отмены: `include_dirs`, `define_macros` и `undef_macros`.146147Например, если вашему расширению требуются заголовочные файлы из каталога `include` в корне дистрибутива, используйте опцию `include_dirs`:148149```python150Extension('foo', ['foo.c'], include_dirs=['include'])151```152153Там можно указывать абсолютные пути; если вы знаете, что ваше расширение будет собираться только в Unix-системах с установленным X11R6 в `/usr`, можно обойтись154155```python156Extension('foo', ['foo.c'], include_dirs=['/usr/include/X11'])157```158159Следует избегать такого непереносимого использования, если вы планируете распространять свой код: вероятно, лучше написать код на C так:160161```python162#include <X11/Xlib.h>163```164165Если вам нужно включить заголовочные файлы из другого расширения Python, можно воспользоваться тем, что заголовочные файлы устанавливаются единообразно командой **install\_header** из Distutils. Например, заголовочные файлы Numerical Python устанавливаются (в стандартной установке Unix) в `/usr/local/include/python1.5/Numerical`. (Точное расположение зависит от вашей платформы и установки Python.) Поскольку каталог включения Python – в данном случае `/usr/local/include/python1.5` – всегда включён в путь поиска при сборке расширений Python, лучше всего писать код на C так:166167```python168#include <Numerical/arrayobject.h>169```170171Если же необходимо поместить каталог include `Numerical` прямо в путь поиска заголовков, то этот каталог можно найти с помощью модуля Distutils [`distutils.sysconfig`](https://python-all.ru/3.1/distutils/apiref.html#module-distutils.sysconfig):172173```python174from distutils.sysconfig import get_python_inc175incdir = os.path.join(get_python_inc(plat_specific=1), 'Numerical')176setup(...,177      Extension(..., include_dirs=[incdir]),178      )179```180181Несмотря на то, что это вполне переносимо – будет работать в любой установке Python, независимо от платформы, – вероятно, проще просто написать код на C разумным способом.182183Можно определять и отменять макросы препроцессора с помощью опций `define_macros` и `undef_macros`. `define_macros` принимает список кортежей `(name, value)`, где `name` – имя определяемого макроса (строка), а `value` – его значение: строка или `None`. (Определение макроса `FOO` как `None` эквивалентно голому `#define FOO` в C-исходнике: для большинства компиляторов это устанавливает `FOO` в строку `1`.) `undef_macros` – это просто список макросов, которые нужно отменить.184185Например:186187```python188Extension(...,189          define_macros=[('NDEBUG', '1'),190                         ('HAVE_STRFTIME', None)],191          undef_macros=['HAVE_FOO', 'HAVE_BAR'])192```193194is the equivalent of having this at the top of every C source file:195196```python197#define NDEBUG 1198#define HAVE_STRFTIME199#undef HAVE_FOO200#undef HAVE_BAR201```202203### 2.3.4. Параметры библиотек204205Также можно указать библиотеки, с которыми нужно линковать расширение, и каталоги для поиска этих библиотек. Опция `libraries` – это список библиотек для линковки, `library_dirs` – список каталогов для поиска библиотек на этапе линковки, а `runtime_library_dirs` – список каталогов для поиска разделяемых (динамически загружаемых) библиотек во время выполнения.206207Например, если требуется скомпоновать расширение с библиотеками, которые заведомо находятся в стандартном пути поиска библиотек в целевых системах,208209```python210Extension(...,211          libraries=['gdbm', 'readline'])212```213214Если нужно линковаться с библиотеками в нестандартном расположении, придётся указать это расположение в `library_dirs`:215216```python217Extension(...,218          library_dirs=['/usr/X11R6/lib'],219          libraries=['X11', 'Xt'])220```221222(Повторим: подобные непереносимые конструкции следует избегать, если планируется распространять свой код.)223224### 2.3.5. Прочие параметры225226Существуют и другие опции, которые можно использовать для обработки особых случаев.227228Параметр *optional* имеет логический тип; если он истинен, сбой сборки расширения не прервёт процесс сборки, а просто не установит это расширение.229230Параметр *extra\_objects* – это список объектных файлов, передаваемых компоновщику. Эти файлы не должны иметь расширений, так как используется расширение по умолчанию для компилятора.231232Параметры *extra\_compile\_args* и *extra\_link\_args* можно использовать для указания дополнительных параметров командной строки для компилятора и компоновщика соответственно.233234Параметр *export\_symbols* полезен только в Windows. Он может содержать список символов (функций или переменных), которые нужно экспортировать. Этот параметр не требуется при сборке скомпилированных расширений: Distutils автоматически добавит `initmodule` в список экспортируемых символов.235236Параметр *depends* – это список файлов, от которых зависит расширение (например, заголовочные файлы). Команда сборки вызовет компилятор для исходных файлов, чтобы пересобрать расширение, если какой-либо из этих файлов был изменён после предыдущей сборки.237238## 2.4. Соотношения между дистрибутивами и пакетами239240Дистрибутив может относиться к пакетам тремя определёнными способами:2412421. Он может требовать пакеты или модули.2432. Он может предоставлять пакеты или модули.2443. Он может заменять (делать устаревшими) пакеты или модули.245246Эти зависимости можно указать с помощью именованных аргументов функции [`distutils.core.setup()`](https://python-all.ru/3.1/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## 2.5. Установка сценариев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Изменено в версии 3.1: Все скрипты также будут добавлены в файл `MANIFEST`, если не указан шаблон. См. [*Указание файлов для распространения*](https://python-all.ru/3.1/distutils/sourcedist.html#manifest).296297## 2.6. Установка данных пакетов298299Часто в пакет нужно установить дополнительные файлы. Эти файлы – обычно данные, тесно связанные с реализацией пакета, или текстовые файлы с документацией, которая может быть полезна программистам, использующим пакет. Такие файлы называются *данными пакета*.300301Данные пакета можно добавить, используя именованный аргумент `package_data` функции `setup()`. Значение должно быть словарем, сопоставляющим имя пакета со списком относительных путей к файлам, которые должны быть скопированы в пакет. Пути интерпретируются относительно каталога, содержащего пакет (если уместно, используется информация из словаря `package_dir`); то есть файлы должны быть частью пакета в исходных каталогах. Они также могут содержать шаблоны glob.302303Имена путей могут содержать части каталогов; все необходимые каталоги будут созданы при установке.304305Например, если пакет должен содержать подкаталог с несколькими файлами данных, файлы можно расположить в дереве исходников следующим образом:306307```python308setup.py309src/310    mypkg/311        __init__.py312        module.py313        data/314            tables.dat315            spoons.dat316            forks.dat317```318319Соответствующий вызов `setup()` может выглядеть так:320321```python322setup(...,323      packages=['mypkg'],324      package_dir={'mypkg': 'src/mypkg'},325      package_data={'mypkg': ['data/*.dat']},326      )327```328329Изменено в версии 3.1: Все файлы, соответствующие условиям `package_data`, будут добавлены в файл `MANIFEST`, если не указан шаблон. См. [*Указание файлов для распространения*](https://python-all.ru/3.1/distutils/sourcedist.html#manifest).330331## 2.7. Установка дополнительных файлов332333Параметр *data\_files* можно использовать для указания дополнительных файлов, необходимых дистрибутиву модуля: конфигурационные файлы, файлы сообщений, файлы данных – всё, что не подходит под предыдущие категории.334335Параметр *data\_files* задаёт последовательность пар (*directory*, *files*) следующим образом:336337```python338setup(...,339      data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),340                  ('config', ['cfg/data.cfg']),341                  ('/etc/init.d', ['init-script'])]342     )343```344345Обратите внимание: можно указать имена каталогов, в которые будут установлены файлы данных, но сами файлы переименовать нельзя.346347Каждая пара (*directory*, *files*) в последовательности задает каталог установки и файлы для установки в нем. Если *directory* – относительный путь, он интерпретируется относительно префикса установки (`sys.prefix` для чисто Python-пакетов, `sys.exec_prefix` для пакетов, содержащих расширения). Каждый файл в *files* интерпретируется относительно скрипта `setup.py` из корня пакета исходного кода. Информация о каталоге из *files* не используется для определения конечного расположения устанавливаемого файла; используется только имя файла.348349Параметр *data\_files* можно задать как простую последовательность файлов без указания целевого каталога, но это не рекомендуется; в этом случае команда **install** выведет предупреждение. Чтобы установить файлы данных непосредственно в целевой каталог, в качестве каталога следует указать пустую строку.350351Изменено в версии 3.1: Все файлы, соответствующие `data_files`, будут добавлены в файл `MANIFEST`, если не указан шаблон. См. [*Указание файлов для распространения*](https://python-all.ru/3.1/distutils/sourcedist.html#manifest).352353## 2.8. Дополнительные метаданные354355Скрипт setup может включать дополнительные метаданные помимо имени и версии. Эта информация включает:356357| Метаданные | Описание | Значение | Примечания |358| --- | --- | --- | --- |359| `name` | имя пакета | короткая строка | (1) |360| `version` | версия этого релиза | короткая строка | (1)(2) |361| `author` | имя автора пакета | короткая строка | (3) |362| `author_email` | адрес электронной почты автора пакета | адрес электронной почты | (3) |363| `maintainer` | имя сопровождающего пакета | короткая строка | (3) |364| `maintainer_email` | адрес электронной почты сопровождающего пакет | адрес электронной почты | (3) |365| `url` | домашняя страница пакета | URL | (1) |366| `description` | краткое описание пакета | короткая строка |  |367| `long_description` | подробное описание пакета | длинная строка | (5) |368| `download_url` | расположение, откуда можно загрузить пакет | URL | (4) |369| `classifiers` | список классификаторов | список строк | (4) |370| `платформы` | список платформ | список строк |  |371| `лицензия` | лицензия для пакета | короткая строка | (6) |372373Примечания:3743751. Эти поля обязательны.3762. Рекомендуется, чтобы версии имели формат *major.minor\[.patch\[.sub\]\]*.3773. Должен быть указан либо автор, либо сопровождающий.3784. Эти поля не следует использовать, если пакет должен быть совместим с версиями Python до 2.2.3 или 2.3. Список доступен на [сайте PyPI](https://python-all.ru/3.1/distutils/setupscript.html).3795. Поле `long_description` используется PyPI при регистрации пакета для формирования его домашней страницы.3806. Поле `license` представляет собой текст, указывающий лицензию, покрывающую пакет, когда лицензия не выбрана из классификаторов Trove «License». См. поле `Classifier`. Обратите внимание, что опция распространения `licence` устарела, но всё ещё действует как псевдоним для `license`.381382**«короткая строка»**383384Одна строка текста, не более 200 символов.385386**«длинная строка»**387388Многострочный простой текст в формате reStructuredText (см.389390[http://docutils.sf.net/](https://python-all.ru/3.1/distutils/setupscript.html)391392).393394**«список строк»**395396См. ниже.397398Указание версии – это искусство само по себе. Пакеты Python обычно следуют формату версии *major.minor\[.patch\]\[sub\]*. Основной номер равен 0 для начальных экспериментальных выпусков ПО. Он увеличивается для выпусков, представляющих важные вехи в пакете. Второстепенный номер увеличивается, когда добавляются важные новые функции. Номер патча увеличивается при выпусках с исправлениями ошибок. Дополнительная завершающая информация о версии иногда используется для обозначения подвыпусков. Это «a1,a2,...,aN» (для альфа-выпусков, где функциональность и API могут измениться), «b1,b2,...,bN» (для бета-выпусков, которые только исправляют ошибки) и «pr1,pr2,...,prN» (для финального предрелизного тестирования). Некоторые примеры:399400**0.1.0**401402первый экспериментальный выпуск пакета403404**1.0.1a2**405406второй альфа-выпуск первой патч-версии 1.0407408*Классификаторы* указываются в списке Python:409410```python411setup(...,412      classifiers=[413          'Development Status :: 4 - Beta',414          'Environment :: Console',415          'Environment :: Web Environment',416          'Intended Audience :: End Users/Desktop',417          'Intended Audience :: Developers',418          'Intended Audience :: System Administrators',419          'License :: OSI Approved :: Python Software Foundation License',420          'Operating System :: MacOS :: MacOS X',421          'Operating System :: Microsoft :: Windows',422          'Operating System :: POSIX',423          'Programming Language :: Python',424          'Topic :: Communications :: Email',425          'Topic :: Office/Business',426          'Topic :: Software Development :: Bug Tracking',427          ],428      )429```430431Если требуется включить классификаторы в файл `setup.py` и при этом сохранить обратную совместимость с версиями Python до 2.2.3, то можно добавить следующий фрагмент кода в `setup.py` перед вызовом `setup()`.432433```python434# исправить distutils, если он не справляется с ключевыми словами "classifiers" или435# ключевые слова "download_url"436from sys import version437if version < '2.2.3':438    from distutils.dist import DistributionMetadata439    DistributionMetadata.classifiers = None440    DistributionMetadata.download_url = None441```442443## 2.9. Отладка сценария установки444445Иногда что-то идет не так, и скрипт установки делает не то, что хочет разработчик.446447Distutils перехватывает любые исключения при запуске скрипта установки и выводит простое сообщение об ошибке перед завершением скрипта. Причина такого поведения – не запутывать администраторов, которые мало знают о Python и пытаются установить пакет. Если они получат длинную трассировку из глубин Distutils, они могут подумать, что пакет или установка Python сломаны, потому что не прочитают все до конца и не увидят, что проблема в правах доступа.448449С другой стороны, это не помогает разработчику найти причину сбоя. Для этого можно установить переменную окружения DISTUTILS\_DEBUG в любое непустое значение, и distutils будет выводить подробную информацию о том, что делает, а также полный стек вызовов в случае возникновения исключения.450