setupscript.md
1> **Источник:** https://python-all.ru/2.7/distutils/setupscript.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 2. Написание сценария установки89Сценарий установки является центром всей деятельности по сборке, распространению и установке модулей с помощью Distutils. Основная цель сценария установки – описать ваш дистрибутив модулей для Distutils, чтобы различные команды, работающие с вашими модулями, делали правильные вещи. Как мы видели в разделе [A Simple Example](https://python-all.ru/2.7/distutils/introduction.html#distutils-simple-example) выше, сценарий установки состоит в основном из вызова `setup()`, и большая часть информации, передаваемой Distutils разработчиком модуля, передаётся в виде именованных аргументов `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='https://www.python.org/sigs/distutils-sig/',24 packages=['distutils', 'distutils.command'],25 )26```2728Есть только два отличия от тривиального однофайлового дистрибутива, представленного в разделе [A Simple Example](https://python-all.ru/2.7/distutils/introduction.html#distutils-simple-example): больше метаданных и указание чистых модулей Python по пакетам, а не по модулям. Это важно, поскольку Distutils состоят из нескольких десятков модулей, разбитых (пока) на два пакета; явный список всех модулей было бы утомительно составлять и сложно поддерживать. Дополнительную информацию о метаданных см. в разделе [Additional meta-data](https://python-all.ru/2.7/distutils/setupscript.html#meta-data).2930Обратите внимание: любые пути (к файлам или каталогам), указанные в сценарии установки, должны записываться в стиле Unix, то есть с разделителем-слешем. Distutils позаботится о преобразовании этого платформонезависимого представления в то, что подходит для вашей текущей платформы, перед фактическим использованием пути. Это делает ваш сценарий установки переносимым между операционными системами, что, конечно, является одной из главных целей Distutils. В этом духе все пути в данном документе записываются через слеш.3132Это, конечно, относится только к путям, передаваемым функциям Distutils. Если вы, например, используете стандартные функции Python, такие как [`glob.glob()`](https://python-all.ru/2.7/library/glob.html#glob.glob) или [`os.listdir()`](https://python-all.ru/2.7/library/os.html#os.listdir) для указания файлов, будьте внимательны и пишите переносимый код вместо жёсткого кодирования разделителей пути: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/2.7/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` неявно применяется ко всем пакетам ниже *пакета*, поэтому случай `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/2.7/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`](https://python-all.ru/2.7/distutils/apiref.html#distutils.core.Extension), каждый из которых описывает один модуль расширения. Предположим, ваш дистрибутив содержит одно расширение с именем `foo`, реализованное в `foo.c`. Если не требуется дополнительных указаний компилятору/компоновщику, описание этого расширения довольно просто:7475```python76Extension('foo', ['foo.c'])77```7879Класс `Extension` можно импортировать из [`distutils.core`](https://python-all.ru/2.7/distutils/apiref.html#module-distutils.core) вместе с `setup()`. Таким образом, сценарий 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`](https://python-all.ru/2.7/distutils/apiref.html#distutils.core.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`](https://python-all.ru/2.7/distutils/apiref.html#distutils.core.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`](https://python-all.ru/2.7/distutils/apiref.html#distutils.core.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, можно воспользоваться тем, что заголовочные файлы устанавливаются согласованным образом командой Distutils **install\_headers**. Например, заголовочные файлы 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Если вам всё же нужно поместить каталог включения `Numerical` непосредственно в путь поиска заголовков, вы можете найти этот каталог с помощью модуля Distutils [`distutils.sysconfig`](https://python-all.ru/2.7/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Опция `extra_objects` задаёт список объектных файлов, передаваемых компоновщику. Эти файлы не должны иметь расширений, так как используется расширение по умолчанию для компилятора.229230`extra_compile_args` и `extra_link_args` можно использовать для указания дополнительных параметров командной строки для компилятора и компоновщика соответственно.231232`export_symbols` применим только в Windows. Он может содержать список символов (функций или переменных), подлежащих экспорту. Эта опция не нужна при сборке скомпилированных расширений: Distutils автоматически добавит `initmodule` в список экспортируемых символов.233234Опция `depends` задаёт список файлов, от которых зависит расширение (например, заголовочные файлы). Команда сборки вызовет компилятор для перестроения расширения, если какой-либо из этих файлов был изменён после предыдущей сборки.235236## 2.4. Взаимосвязи между дистрибутивами и пакетами237238Дистрибутив может относиться к пакетам тремя определёнными способами:2392401. Он может требовать пакеты или модули.2412. Он может предоставлять пакеты или модули.2423. Он может заменять (делать устаревшими) пакеты или модули.243244Эти взаимосвязи можно задать с помощью именованных аргументов функции [`distutils.core.setup()`](https://python-all.ru/2.7/distutils/apiref.html#distutils.core.setup).245246Зависимости от других модулей и пакетов Python можно указать, передав именованный аргумент *requires* функции `setup()`. Значение должно быть списком строк. Каждая строка задаёт необходимый пакет и, опционально, какие версии достаточны.247248Чтобы указать, что требуется любая версия модуля или пакета, строка должна состоять только из имени модуля или пакета. Примеры: `'mymodule'` и `'xml.parsers.expat'`.249250Если требуются конкретные версии, можно указать последовательность квалификаторов в скобках. Каждый квалификатор может состоять из оператора сравнения и номера версии. Допустимые операторы сравнения:251252```python253< > ==254<= >= !=255```256257Их можно комбинировать, используя несколько квалификаторов, разделённых запятыми (и необязательными пробелами). В этом случае все квалификаторы должны совпадать; используется логическое И для объединения результатов.258259Рассмотрим несколько примеров:260261| Выражение Requires | Пояснение |262| --- | --- |263| `==1.0` | Совместима только версия `1.0` |264| `>1.0, !=1.5.1, <2.0` | Любая версия после `1.0` и до `2.0` совместима, за исключением `1.5.1` |265266Теперь, когда мы умеем указывать зависимости, нам также нужно уметь указывать, что мы предоставляем и что могут требовать другие дистрибутивы. Это делается с помощью именованного аргумента *provides* функции `setup()`. Значение этого аргумента – список строк, каждая из которых указывает имя модуля или пакета и, опционально, версию. Если версия не указана, считается, что она совпадает с версией дистрибутива.267268Несколько примеров:269270| Выражение Provides | Пояснение |271| --- | --- |272| `mypkg` | Предоставить `mypkg`, используя версию дистрибутива |273| `mypkg (1.1)` | Предоставить `mypkg` версии 1.1, независимо от версии дистрибутива |274275Пакет может объявлять, что он заменяет (делает устаревшими) другие пакеты, с помощью именованного аргумента *obsoletes*. Его значение аналогично значению аргумента *requires*: список строк, задающих спецификаторы модуля или пакета. Каждый спецификатор состоит из имени модуля или пакета, за которым необязательно следуют один или несколько квалификаторов версии. Версионные квалификаторы указываются в скобках после имени модуля или пакета.276277Версии, указанные квалификаторами, считаются заменяемыми (устаревшими) данным дистрибутивом. Если квалификаторы не указаны, считаются устаревшими все версии указанного модуля или пакета.278279## 2.5. Установка скриптов280281До сих пор мы имели дело с чистыми и нечистыми модулями Python, которые обычно не запускаются сами по себе, а импортируются скриптами.282283Скрипты – это файлы, содержащие исходный код Python, предназначенные для запуска из командной строки. Скрипты не требуют от Distutils каких-либо сложных действий. Единственная умная особенность: если первая строка скрипта начинается с `#!` и содержит слово «python», Distutils изменит первую строку так, чтобы она указывала на текущий интерпретатор. По умолчанию она заменяется на путь к текущему интерпретатору. Опция `--executable` (или `-e`) позволяет явно переопределить путь к интерпретатору.284285Опция `scripts` – это просто список файлов, которые обрабатываются таким образом. Из скрипта установки PyXML:286287```python288setup(...,289 scripts=['scripts/xmlproc_parse', 'scripts/xmlproc_val']290 )291```292293Изменено в версии 2.7: Все сценарии также будут добавлены в `MANIFEST` файл, если шаблон не предоставлен. См. [Указание файлов для распространения](https://python-all.ru/2.7/distutils/sourcedist.html#manifest).294295## 2.6. Установка данных пакета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Новое в версии 2.4.328329Изменено в версии 2.7: Все файлы, соответствующие `package_data`, будут добавлены в `MANIFEST` файл, если шаблон не предоставлен. См. [Указание файлов для распространения](https://python-all.ru/2.7/distutils/sourcedist.html#manifest).330331## 2.7. Установка дополнительных файлов332333Опция `data_files` может использоваться для указания дополнительных файлов, необходимых для распространяемого модуля: файлов конфигурации, каталогов сообщений, файлов данных, всего, что не подходит под предыдущие категории.334335`data_files` задаёт последовательность пар (*каталог*, *файлы*) следующим образом:336337```python338setup(...,339 data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),340 ('config', ['cfg/data.cfg']),341 )342```343344Каждая пара (*каталог*, *файлы*) в последовательности указывает каталог установки и файлы, которые следует туда установить.345346Каждое имя файла в *files* интерпретируется относительно скрипта `setup.py` в корне исходного дистрибутива пакета. Обратите внимание: можно указать каталог, куда будут установлены файлы данных, но нельзя переименовать сами файлы данных.347348Параметр *directory* должен быть относительным путём. Он интерпретируется относительно префикса установки (`sys.prefix` Python для системных установок; `site.USER_BASE` для пользовательских установок). Distutils позволяет *directory* быть абсолютным путём установки, но это не рекомендуется, так как несовместимо с форматом упаковки wheel. Информация о каталогах из *files* не используется для определения конечного расположения устанавливаемого файла; используется только имя файла.349350Можно указать опцию `data_files` как простую последовательность файлов без указания целевого каталога, но это не рекомендуется, и команда **install** выведет предупреждение. Чтобы установить файлы данных непосредственно в целевой каталог, в качестве каталога нужно задать пустую строку.351352Изменено в версии 2.7: Все файлы, соответствующие `data_files`, будут добавлены в `MANIFEST` файл, если шаблон не предоставлен. См. [Указание файлов для распространения](https://python-all.ru/2.7/distutils/sourcedist.html#manifest).353354## 2.8. Дополнительные метаданные355356Скрипт setup может включать дополнительные метаданные помимо имени и версии. Эта информация включает:357358| Метаданные | Описание | Значение | Примечания |359| --- | --- | --- | --- |360| `name` | имя пакета | короткая строка | (1) |361| `version` | версия этого релиза | короткая строка | (1)(2) |362| `author` | имя автора пакета | короткая строка | (3) |363| `author_email` | адрес электронной почты автора пакета | адрес электронной почты | (3) |364| `maintainer` | имя сопровождающего пакета | короткая строка | (3) |365| `maintainer_email` | адрес электронной почты сопровождающего пакет | адрес электронной почты | (3) |366| `url` | домашняя страница пакета | URL | (1) |367| `description` | краткое описание пакета | короткая строка | |368| `long_description` | подробное описание пакета | длинная строка | (5) |369| `download_url` | расположение, откуда можно загрузить пакет | URL | (4) |370| `classifiers` | список классификаторов | список строк | (4) |371| `platforms` | список платформ | список строк | |372| `license` | лицензия для пакета | короткая строка | (6) |373374Примечания:3753761. Эти поля обязательны.3772. Рекомендуется, чтобы версии имели формат *major.minor\[.patch\[.sub\]\]*.3783. Должен быть указан либо автор, либо сопровождающий. Если указан сопровождающий, distutils указывает его как автора в `PKG-INFO`.3794. Эти поля не следует использовать, если пакет должен быть совместим с версиями Python до 2.2.3 или 2.3. Список доступен на [сайте PyPI](https://python-all.ru/2.7/distutils/setupscript.html).3805. Поле `long_description` используется PyPI при публикации пакета для построения его страницы проекта.3816. Поле `license` – это текст, указывающий лицензию, покрывающую пакет, если лицензия не выбрана из классификаторов Trove «License». См. поле `Classifier`. Обратите внимание, что существует опция распространения `licence`, которая устарела, но всё ещё является псевдонимом для `license`.382383**«короткая строка»**384385Одна строка текста, не более 200 символов.386387**«длинная строка»**388389Несколько строк обычного текста в формате reStructuredText (см. [http://docutils.sourceforge.net/](https://python-all.ru/2.7/distutils/setupscript.html)).390391**«список строк»**392393См. ниже.394395Ни одно строковое значение не может быть Unicode.396397Кодирование информации о версии – само по себе искусство. Пакеты Python обычно придерживаются формата версии *major.minor\[.patch\]\[sub\]*. Основной номер (major) равен 0 для начальных экспериментальных выпусков ПО. Он увеличивается для выпусков, представляющих собой важные вехи в пакете. Дополнительный номер (minor) увеличивается, когда в пакет добавляются важные новые функции. Номер патча увеличивается при выпусках с исправлением ошибок. Иногда дополнительная информация о версии в конце используется для обозначения подвыпусков. Это «a1,a2,…,aN» (для альфа-версий, где функциональность и API могут меняться), «b1,b2,…,bN» (для бета-версий, которые только исправляют ошибки) и «pr1,pr2,…,prN» (для финального тестирования перед релизом). Некоторые примеры:398399**0.1.0**400401первый экспериментальный выпуск пакета402403**1.0.1a2**404405второй альфа-выпуск первой патч-версии 1.0406407`classifiers` задаются в списке Python:408409```python410setup(...,411 classifiers=[412 'Development Status :: 4 - Beta',413 'Environment :: Console',414 'Environment :: Web Environment',415 'Intended Audience :: End Users/Desktop',416 'Intended Audience :: Developers',417 'Intended Audience :: System Administrators',418 'License :: OSI Approved :: Python Software Foundation License',419 'Operating System :: MacOS :: MacOS X',420 'Operating System :: Microsoft :: Windows',421 'Operating System :: POSIX',422 'Programming Language :: Python',423 'Topic :: Communications :: Email',424 'Topic :: Office/Business',425 'Topic :: Software Development :: Bug Tracking',426 ],427 )428```429430Если требуется включить классификаторы в файл `setup.py`, а также сохранить обратную совместимость с версиями Python до 2.2.3, то можно включить следующий фрагмент кода в `setup.py` перед вызовом `setup()`.431432```python433# исправить distutils, если он не справляется с ключевыми словами "classifiers" или434# ключевые слова "download_url"435from sys import version436if version < '2.2.3':437 from distutils.dist import DistributionMetadata438 DistributionMetadata.classifiers = None439 DistributionMetadata.download_url = None440```441442## 2.9. Отладка скрипта установки443444Иногда что-то идет не так, и скрипт установки делает не то, что хочет разработчик.445446Distutils перехватывает любые исключения при запуске скрипта установки и выводит простое сообщение об ошибке перед завершением скрипта. Причина такого поведения – не запутывать администраторов, которые мало знают о Python и пытаются установить пакет. Если они получат длинную трассировку из глубин Distutils, они могут подумать, что пакет или установка Python сломаны, потому что не прочитают все до конца и не увидят, что проблема в правах доступа.447448С другой стороны, это не помогает разработчику найти причину сбоя. Для этой цели переменная окружения `DISTUTILS_DEBUG` может быть установлена в любое значение, кроме пустой строки, и distutils теперь будет выводить подробную информацию о том, что он делает, выводить полную трассировку при возникновении исключения и выводить всю командную строку при сбое внешней программы (например, компилятора C).449