2. Написання сценарію налаштування

Примітка

Цей документ зберігається лише до тих пір, поки документація 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, ви можете скористатися тим фактом, що файли заголовків установлюються узгоджено за допомогою команди Distutils install_headers. Наприклад, числові файли заголовків 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''.

Якщо потрібні певні версії, у дужках можна вказати послідовність кваліфікаторів. Кожен кваліфікатор може складатися з оператора порівняння та номера версії. Прийнятні оператори порівняння:

<    >    ==
<=   >=   !=

Їх можна комбінувати за допомогою кількох кваліфікаторів, розділених комами (і необов’язковими пробілами). У цьому випадку всі кваліфікатори повинні збігатися; логічне І використовується для об’єднання оцінок.

Давайте розглянемо кілька прикладів:

Вимагає експресії

Пояснення

==1,0

Лише версія 1.0 сумісна

>1.0, !=1.5.1, <2.0

Будь-яка версія після 1.0 і до 2.0 сумісна, крім 1.5.1

Тепер, коли ми можемо вказати залежності, нам також потрібно мати можливість вказати, що ми надаємо, що можуть вимагати інші дистрибутиви. Це робиться за допомогою ключового аргументу provides для setup(). Значення цього ключового слова — це список рядків, кожен з яких іменує модуль або пакет Python і, за бажанням, визначає версію. Якщо версія не вказана, вважається, що вона відповідає версії дистрибутива.

Деякі приклади:

Забезпечує експресію

Пояснення

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.

Дані пакетів можна додати до пакетів за допомогою ключового аргументу 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'])],
     )

Кожна пара (каталог, файли) у послідовності визначає каталог інсталяції та файли для інсталяції.

Кожне ім’я файлу в files інтерпретується відносно сценарію setup.py у верхній частині вихідного коду пакета. Зверніть увагу, що ви можете вказати каталог, куди будуть встановлені файли даних, але ви не можете перейменувати самі файли даних.

Каталог має бути відносним шляхом. Він інтерпретується відносно префікса встановлення (sys.prefix Python для системних установок; site.USER_BASE для установок користувача). Distutils дозволяє каталог бути абсолютним шляхом встановлення, але це не рекомендується, оскільки це несумісно з форматом упаковки коліс. Для визначення кінцевого розташування встановленого файлу інформація про каталог із файлів не використовується; використовується лише ім’я файлу.

Ви можете вказати параметри data_files як просту послідовність файлів без вказівки цільового каталогу, але це не рекомендується, і команда install у цьому випадку виведе попередження. Щоб установити файли даних безпосередньо в цільовий каталог, як каталог слід вказати порожній рядок.

Змінено в версії 3.1: Усі файли, які відповідають data_files, будуть додані до MANIFEST файлу, якщо шаблон не надано. Див. Визначення файлів для розповсюдження.

2.8. Додаткові метадані

Сценарій налаштування може містити додаткові метадані, окрім імені та версії. Ця інформація включає:

Мета-дані

опис

Значення

Примітки

ім'я

назву пакета

короткий рядок

(1)

версія

версія цього випуску

короткий рядок

(1)(2)

автор

ім’я автора пакета

короткий рядок

(3)

author_email

адреса електронної пошти автора пакета

адреса електронної пошти

(3)

підтримувач

ім’я супроводжуючого пакета

короткий рядок

(3)

maintainer_email

адреса електронної пошти супроводжуючого пакет

адреса електронної пошти

(3)

url

домашня сторінка для пакета

URL

(1)

опис

короткий короткий опис пакету

короткий рядок

довгий_опис

додатковий опис пакета

довгий рядок

(4)

URL-адреса_завантаження

місце, де можна завантажити пакет

URL

класифікатори

список класифікаторів

список рядків

(6)(7)

платформи

список платформ

список рядків

(6)(8)

ключові слова

список ключових слів

список рядків

(6)(8)

ліцензія

ліцензія на пакет

короткий рядок

(5)

Примітки:

  1. Ці поля є обов’язковими.

  2. Рекомендується, щоб версії мали форму major.minor[.patch[.sub]].

  3. Має бути ідентифікований або автор, або супроводжувач. Якщо вказано супроводжуючого, distutils вказує його як автора в PKG-INFO.

  4. Поле long_description використовується PyPI, коли ви публікуєте пакет, для створення його сторінки проекту.

  5. Поле «ліцензія» — це текст, що вказує на ліцензію, що охоплює пакет, де ліцензія не є вибором із класифікаторів Trove «Ліцензії». Перегляньте поле Класифікатор. Зауважте, що існує опція розповсюдження ліцензія, яка є застарілою, але все ще діє як псевдонім для ліцензії.

  6. Це поле має бути списком.

  7. Дійсні класифікатори перераховані на PyPI.

  8. Щоб зберегти зворотну сумісність, це поле також приймає рядок. Якщо ви передасте розділений комами рядок 'foo, bar'', він буде перетворений на ['foo', 'bar'], інакше він буде перетворений на список з одного рядка.

„короткий рядок“

Один рядок тексту, не більше 200 символів.

«довгий рядок»

Multiple lines of plain text in reStructuredText format (see https://docutils.sourceforge.io/).

„список рядків“

Дивіться нижче.

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

0.1.0

перший, експериментальний випуск пакету

1.0.1a2

друга альфа-версія першої версії патча 1.0

класифікатори повинні бути вказані в списку:

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 тепер попереджає, коли поля класифікатори, ключові слова або платформи не вказані як список або рядок.

2.9. Налагодження сценарію налаштування

Іноді щось йде не так, і сценарій налаштування не виконує те, що хоче розробник.

Distutils вловлює будь-які винятки під час запуску сценарію налаштування та друкує просте повідомлення про помилку перед завершенням сценарію. Мотивація такої поведінки полягає в тому, щоб не заплутати адміністраторів, які мало знають про Python і намагаються встановити пакет. Якщо вони отримають велике довге відстеження з глибини нутрощів Distutils, вони можуть подумати, що пакет або інсталяція Python зламані, оскільки вони не прочитали весь шлях до кінця й побачать, що це проблема з дозволом.

З іншого боку, це не допомагає розробнику знайти причину збою. З цією метою для змінної середовища DISTUTILS_DEBUG можна встановити будь-яке значення, окрім порожнього рядка, і distutils тепер друкуватиме детальну інформацію про те, що він робить, створюватиме повну трасування, коли станеться виняткова ситуація, і друкуватиме всю команду рядок, коли зовнішня програма (наприклад, компілятор C) дає збій.