2. Rédaction du script setup.py

Le script setup.py est au centre de toute opération de construction, de distribution et d’installation des modules utilisant les Distutils. L’objectif principal du script setup.py est de décrire le module aux Distutils, de telle sorte que les diverses commandes qui agissent sur votre module fassent les bonnes choses. Comme nous avons vu dans la section Un exemple simple au-dessus, le script setup.py consiste principalement à un appel à setup(), et la plupart des informations fournies aux Distutils par le développeur du module sont fournies en tant qu’arguments nommés à setup.py().

Voici un exemple un peu plus concret, que nous allons suivre pour les quelques sections suivantes : le propre script setup.py des Distutils (gardez toujours à l’esprit qu’en dépit de l’inclusion des Distutils dans python 1.6 et ses versions successives, ils ont aussi une existence à part entière de telle sorte que les utilisateurs de Python 1.5.2 puissent les utiliser pour installer d’autres modules. Le propre script setup.py des Distutils montré ici est utilisé pour installer le paquet dans 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'],
     )

Il y a seulement deux différences entre cet exemple et l’exemple trivial de la distribution d’un unique fichier présenté dans la partie Un exemple simple : plus de métadonnées, et la définition de modules purement Python par paquet, plutôt que par module. C’est important car les Distutils sont composés de quelques douzaines de modules séparés (pour le moment) en deux paquets ; une liste explicite de chaque module serait pénible à générer et difficile à maintenir. Pour plus d’information sur les métadonnées supplémentaires, voir la partie Métadonnées additionnelles.

À noter que chaque chemin d’accès fourni au script setup.py doit être écrit selon la convention Unix. Autrement dit, séparé par des barres obliques (slash). Les Distutils prendront soin de convertir cette représentation indépendante de la plateforme en une représentation adaptée à votre plateforme actuelle avant d’effectivement utiliser le chemin d’accès. Cela rend votre script setup.py portable d’un système d’exploitation à l’autre, ce qui évidemment est l’un des buts majeurs des Distutils. Dans cet esprit, tous les chemins d’accès dans ce document sont séparés par des barres obliques (slash).

Cela, évidemment, s’applique uniquement aux chemins d’accès passés aux fonctions de Distutils. Si vous, par exemple, vous utilisez les fonctions standards de Python telles que glob.glob() or os.listdir() pour définir des fichiers, vous devez prendre soin d’écrire du code portable au lieu de coder en dur les séparateurs de chemin :

glob.glob(os.path.join('mydir', 'subdir', '*.html'))
os.listdir(os.path.join('mydir', 'subdir'))

2.1. Lister l’ensemble des paquets

L’option packages dit aux Distutils de traiter (construire, distribuer, installer, etc.) tous les modules en Python pur trouvés dans chaque paquet mentionné dans la liste packages. À cette fin, évidemment, il faut une correspondance entre les noms des paquets et des répertoires dans le système de fichiers. La correspondance par défaut est la plus évidente. À savoir : le paquet distutils se trouve dans le répertoire distutils situé à la racine de la distribution. Ainsi, quand vous écrivez packages = ['foo'] dans votre script setup.py, vous vous engagez à ce que les Distutils trouvent un fichier foo/__init__.py (qui peut s’épeler différemment sur votre système, mais vous voyez l’idée) à un emplacement relatif au répertoire où se trouve le script setup.py. Si ce n’est pas le cas, les Distutils lèvent un avertissement mais traitent tout de même le paquet défectueux.

Si vous utilisez une convention différente pour arranger votre répertoire de sources, ce n’est pas un problème : vous avez seulement à fournir l’option package_dir pour prévenir les Distutils de l’usage de cette convention. Par exemple, supposons que vous gardez toutes les sources Python sous lib, de telle sorte que les modules dans le « paquet racine » (c’est-à-dire dans aucun paquet du tout) sont dans lib, les modules dans le paquet foo sont dans lib/foo, et ainsi de suite. Alors, vous pouvez mettre :

package_dir = {'': 'lib'}

dans votre script setup.py. Les clés de ce dictionnaire sont les noms des paquets, et un nom de paquet vide fait office de paquet racine. Les valeurs sont des noms de répertoires relatifs à la racine de votre distribution. Dans ce cas, lorsque vous dites packages = ['foo'], vous vous engagez à ce que le fichier lib/foo/__init__.py existe.

Une autre convention possible est de mettre le paquet foo directement dans lib, le paquet foo.bar dans lib/bar, etc. Cela s’écrirait ainsi dans le script setup.py : :

package_dir = {'foo': 'lib'}

A package: dir entry in the package_dir dictionary implicitly applies to all packages below package, so the foo.bar case is automatically handled here. In this example, having packages = ['foo', 'foo.bar'] tells the Distutils to look for lib/__init__.py and lib/bar/__init__.py. (Keep in mind that although package_dir applies recursively, you must explicitly list all packages in packages: the Distutils will not recursively scan your source tree looking for any directory with an __init__.py file.)

2.2. Lister chaque module indépendamment

Pour un petit projet, vous pouvez préférer lister tous les modules plutôt que les paquets — surtout le cas d’un module seul qui va dans le « paquet racine » (à savoir, aucun paquet du tout). Le cas le plus simple a été montré dans la partie Un exemple simple ; voici un exemple plus concret :

py_modules = ['mod1', 'pkg.mod2']

Deux modules sont décrits, l’un dans le paquet « racine », l’autre dans le paquet pkg. Encore une fois, la structure paquet/répertoire par défaut implique que ces deux modules peuvent être trouvés dans mod1.py et pkg/mod2.py, et que pkg/__init__.py existe aussi. Là aussi, vous pouvez redéfinir la correspondance paquet/répertoire en utilisant l’option package_dir.

2.3. Description des modules d’extension

Tout comme écrire des modules d’extension Python est un peu plus compliqué que d’écrire des modules purement en Python, les décrire aux Distutils est un peu plus compliqué. Contrairement aux modules purs, il ne suffit pas de simplement lister les modules ou les paquets et d’attendre que les Distutils trouvent par eux-mêmes les bons fichiers ; vous devez définir le nom de l’extension, du ou des fichiers de sources, et les prérequis de compilation/lien (répertoires à inclure, bibliothèques à lier, etc.).

Tout ceci est fait à l’aide d’un autre argument nommé passé à setup(), l’option ext_modules. ext_modules est simplement une liste de classes Extension, chacune décrivant une seule extension de module. Supposons que votre distribution inclut une seule extension appelée foo et implémentée par foo.c. Si aucune instruction supplémentaire au compilateur/lieur n’est requise, décrire cette extension est assez simple :

Extension('foo', ['foo.c'])

La classe Extension peut être importée depuis distutils.core en même temps que setup(). Ainsi, le script setup.py pour un module qui ne contient que cette seule extension et rien d’autre peut être :

from distutils.core import setup, Extension
setup(name='foo',
      version='1.0',
      ext_modules=[Extension('foo', ['foo.c'])],
      )

La classe Extension (en réalité, la machinerie sous-jacente construisant les extensions implémentées par la commande build_ext) permet une grande flexibilité dans la description des extensions Python, ce qui est expliqué dans les parties suivantes.

2.3.1. Nom des extensions et paquets

Le premier argument du constructeur Extension est toujours le nom de l’extension, incluant tout nom de paquet. Par exemple :

Extension('foo', ['src/foo1.c', 'src/foo2.c'])

décrit une extension qui se situe dans le paquet racine, tandis que :

Extension('pkg.foo', ['src/foo1.c', 'src/foo2.c'])

décrit la même extension dans le paquet pkg. Les fichiers sources et le code objet résultant sont identiques dans les deux cas ; la seule différence est où, dans le système de fichier (et conséquemment dans la hiérarchie de l’espace de nommage de Python), l’extension résultante se situe.

Si vous avez un certain nombre d’extensions toutes dans le même paquet (ou toutes sous le même paquet de base), utilisez l’argument nommé ext_package de setup(). Par exemple :

setup(...,
      ext_package='pkg',
      ext_modules=[Extension('foo', ['foo.c']),
                   Extension('subpkg.bar', ['bar.c'])],
     )

compile foo.c en l’extension pkg.foo, et bar.c en pkg.subpkg.bar.

2.3.2. Fichiers sources d’extension

Le second argument du constructeur d” Extension est une liste de fichiers sources. Puisque les Distutils ne gèrent que les extensions en C, C++ et Objective-C, ce sont normalement des fichiers sources en C/C++/Objective-C (assurez vous d’utiliser les extensions appropriées pour détecter les fichiers sources en C++ : .cc et .cpp semblent être reconnus tant par les compilateurs Unix que Windows).

Néanmoins, vous pouvez également inclure des fichiers d’interface SWIG (.i) dans la liste ; la commande build_ext sait comment gérer les extensions SWIG : il lancera SWIG sur un fichier d’interface et compilera le fichier en C/C++ en une extension.

Malgré cet avertissement, les options peuvent être actuellement passées à SWIG de la façon suivante :

setup(...,
      ext_modules=[Extension('_foo', ['foo.i'],
                             swig_opts=['-modern', '-I../include'])],
      py_modules=['foo'],
     )

Ou en ligne de commande de cette façon :

> python setup.py build_ext --swig-opts="-modern -I../include"

Sur certaines plateformes, vous pouvez inclure des fichiers autres que des sources qui seront traités par le compilateur et inclus dans votre extension. Pour l’instant, cela concerne seulement les fichiers de messages texte Windows (.mc) et les fichiers de définition de ressource pour Visual C++ (.rc). Ils seront compilés en fichiers de ressources binaires (.res) et liés à l’exécutable.

2.3.3. Options de préprocesseur

Trois arguments optionnels de Extension aident si vous avez besoin de préciser les dossiers d’en-têtes à chercher ou les macros de préprocesseurs à charger ou ignorer : include_dirs, define_macros, et undef_macros.

Par exemple, si votre extension nécessite des fichiers d’en-tête dans le répertoire include à la racine de votre distribution, utilisez l’option include_dirs :

Extension('foo', ['foo.c'], include_dirs=['include'])

Ici, vous pouvez définir le chemin absolu des répertoires ; si vous savez que votre extension sera compilée sur un système Unix avec X11R6 installé dans /usr, vous pouvez vous en sortir avec :

Extension('foo', ['foo.c'], include_dirs=['/usr/include/X11'])

Il convient d’éviter ce type d’utilisation non portable si vous envisagez de distribuer votre code : Il est probablement mieux d’écrire du code C comme :

#include <X11/Xlib.h>

Si vous avez besoin d’inclure des fichiers d’en-tête provenant d’autres extensions Python, vous pouvez profiter du fait que les fichiers d’en-têtes sont installés de façon cohérente par la commande install_headers des Distutils. Par exemple, les fichiers d’en-têtes de Numerical Python (NumPy) sont installés (dans le cas d’une installation Unix standard) dans /usr/local/include/python1.5/Numerical — l’emplacement exact diffère selon votre plateforme et votre installation de Python. Vu que le répertoire include de Python — /usr/local/include/python1.5 dans ce cas-ci — est toujours inclus dans le chemin de recherche quand vous construisez des extensions Python, la meilleure approche est d’écrire du code C comme :

#include <Numerical/arrayobject.h>

Si vous devez mettre le répertoire include de Numerical directement dans l’en-tête du chemin de recherche, cependant, vous pouvez trouver ce répertoire en utilisant le module distutils.sysconfig des Distutils :

from distutils.sysconfig import get_python_inc
incdir = os.path.join(get_python_inc(plat_specific=1), 'Numerical')
setup(...,
      Extension(..., include_dirs=[incdir]),
      )

Même si c’est assez portable — ça marche sur la plupart des installations de Python, indépendamment de la plateforme — il est probablement plus facile d’écrire un code C un peu plus réfléchi.

Vous pouvez définir ou ignorer des macros de pré-processeur avec les options define_macros et undef_macros. define_macros prend une liste de paires (nom, valeur), où nom est le nom de la macro à définir (une chaîne de caractères) et valeur est sa valeur ; soit une chaîne de caractères, soit None (définir une macro FOO à None est équivalent à un simple #define FOO dans votre source en C ; pour la majorité des compilateurs, cela définit la valeur de FOO à la chaîne de caractère 1). undef_macros est juste une liste de macros à supprimer.

Par exemple :

Extension(...,
          define_macros=[('NDEBUG', '1'),
                         ('HAVE_STRFTIME', None)],
          undef_macros=['HAVE_FOO', 'HAVE_BAR'])

est équivalent à avoir ceci au début de chaque fichier source en C :

#define NDEBUG 1
#define HAVE_STRFTIME
#undef HAVE_FOO
#undef HAVE_BAR

2.3.4. Options des bibliothèques

Vous pouvez aussi définir les bibliothèques à lier quand vous construisez votre extension, ainsi que le répertoire de recherche pour ces bibliothèques. L’option libraries est une liste de bibliothèques à lier, library_dirs est une liste de répertoires dans lesquels chercher des bibliothèques au moment de la liaison, et runtime_library_dirs est une liste de répertoires pour la recherche des bibliothèques partagées (chargées dynamiquement) à l’exécution.

Par exemple, pour lier des bibliothèques que l’on sait dans le chemin des bibliothèques standards des systèmes cibles :

Extension(...,
          libraries=['gdbm', 'readline'])

Pour lier une bibliothèque se trouvant à un emplacement non standard, vous devez inclure son emplacement dans library_dirs :

Extension(...,
          library_dirs=['/usr/X11R6/lib'],
          libraries=['X11', 'Xt'])

Là aussi, ce genre de construction non portable doit être évité si vous avez l’intention de distribuer votre code.

2.3.5. Autres options

Il y a encore d’autres options qui peuvent être utilisées pour gérer des cas spéciaux.

L’option optional est un booléen ; s’il est vrai, un échec de la construction dans l’extension n’annule pas le processus de construction, mais à la place, l’extension en échec ne sera pas installée.

L’option extra_objects est une liste d’objets fichiers à passer à l’éditeur de liens. Ces fichiers ne doivent pas avoir d’extensions car l’extension par défaut du compilateur est utilisée.

extra_compile_args et extra_link_args peuvent être utilisées pour définir des options additionnelles en ligne de commande propres aux lignes de commandes respectives du compilateur et de l’éditeur de liens.

export_symbols est seulement utile sur Windows. Elle peut contenir une liste de symboles (fonctions ou variables) à exporter. Cette option n’est pas requise pour la construction d’extensions compilées : Distutils ajoute automatiquement initmodule à la liste des symboles exportés.

L’option depends est une liste de fichiers dont les extensions dépendent (par exemple les fichiers d’en-têtes). La commande build appelle le compilateur sur les sources pour reconstruire l’extension si un de ces fichiers a été modifié depuis la dernière construction.

2.4. Relations entre distributions et paquets

Une distribution peut se rapporter à des paquets de trois manières spécifiques :

  1. elle peut nécessiter des paquets ou des modules ;

  2. elle peut fournir des paquets ou des modules ;

  3. elle peut rendre obsolète des paquets ou des modules.

Ces relations peuvent être définies en utilisant des paramètres nommés dans la fonction distutils.core.setup().

Les dépendances à d’autres modules et paquets Python peuvent être définies en fournissant le paramètre nommé requires à setup(). La valeur doit être une liste de chaînes de caractères. Chaque chaîne de caractères définit un paquet requis et, en option, les versions minimales.

S’il n’est pas nécessaire de préciser la version d’un module ou d’un paquet, la chaîne de caractères contient simplement les noms de modules ou de paquets. Par exemple mymodule et 'xml.parsers.expat'.

Si des versions spécifiques sont requises, une suite de qualificatifs peut être fournie entre parenthèses. Chaque qualificatif peut contenir un opérateur de comparaison et un numéro de version. Les opérateurs de comparaison acceptés sont :

<    >    ==
<=   >=   !=

Ils peuvent être combinés en utilisant plusieurs qualificatifs séparés par des virgules (et de façon optionnelle, des espaces). Dans ce cas, tous les qualificatifs doivent être respectés ; un ET logique est utilisé pour combiner les évaluations.

Jetons un œil à quelques exemples :

Valeur de requires

Explication

==1.0

Seule la version 1.0 est compatible.

>1.0, !=1.5.1, <2.0

Toute version après 1.0 et avant 2.0 est compatible, à l’exception de 1.5.1.

Maintenant que nous pouvons définir des dépendances, nous devons également être en mesure de définir ce que d’autres distributions peuvent attendre de notre part. Cela est réalisé en utilisant l’argument nommé provides dans setup(). La valeur de cet argument est une liste de chaînes de caractères, chacune d’entre elles étant un module Python ou un paquet et, de façon optionnelle, identifie une version. Si la version n’est pas définie, il est supposé qu’elle correspond à celle de la distribution.

Quelques exemples :

Valeur de provides

Explication

mypkg

Fournit mypkg en utilisant la version de la distribution.

mypkg (1.1)

Fournit mypkg en version 1.1, indépendamment de la version de la distribution.

On peut déclarer d’autres paquets obsolètes dans un paquet en utilisant l’argument nommé obsoletes. La valeur pour celui-ci est similaire à celui de l’argument nommé requires : une liste de chaînes de caractères donnant les spécifications du module ou du paquet. Chaque spécification est constituée d’un nom de module ou de paquet qui peut être suivi au choix par un ou plusieurs qualificateurs de versions. Les qualificateurs de versions sont donnés entre parenthèses après le nom de module ou de paquet.

Les versions identifiées par les qualificateurs sont celles qui sont rendues obsolètes par la distribution décrite. Si aucun qualificateur n’est donné, toutes les versions du module ou du paquet nommé sont considérées comme obsolètes.

2.5. Installation des scripts

Jusqu’à présent nous avons interagi avec des modules Python purs ou non, qui ne sont habituellement pas lancés par eux-mêmes mais importés par des scripts.

Les scripts sont des fichiers contenant du code source Python prévus pour être lancés en ligne de commande. Les scripts n’ont pas besoin des Distutils pour faire quoi que ce soit de très compliqué. La seule fonctionnalité astucieuse est que la première ligne du script commence par #! et contient le mot « python », les Distutils ajusteront la première ligne pour faire référence à l’emplacement actuel de l’interpréteur. Par défaut, elle est remplacée par l’emplacement de l’interpréteur en fonction. L’option --executable (ou -e) permet de définir explicitement le chemin vers l’interpréteur.

L’option scripts est simplement une liste de fichiers à utiliser de cette façon. Dans le script setup.py de PyML :

setup(...,
      scripts=['scripts/xmlproc_parse', 'scripts/xmlproc_val']
      )

Modifié dans la version 3.1: Tous les scripts seront aussi ajoutés au fichier MANIFEST si aucun modèle n’est fourni. Voir Spécifier les fichiers à distribuer.

2.6. Installation de paquets de données

Souvent, des fichiers additionnels doivent être installés dans le paquet. Ces fichiers sont souvent de la donnée qui est intimement liée à l’implémentation du paquet, ou des fichiers textes contenant de la documentation intéressant le programmeur utilisant le paquet. Ces fichiers sont appelés paquets de données <package data>.

Les paquets de données peuvent être ajoutés en utilisant l’argument nommé package_data dans la fonction setup(). La valeur doit être un tableau de correspondances entre le nom du paquet et une liste de chemins relatifs à copier dans le paquet. Les chemins sont interprétés relativement au répertoire contenant le paquet (l’information du mappage package_dir est utilisée le cas échéant) ; ceci étant, il convient que les fichiers fassent partie du répertoire source du paquet. Ils peuvent également contenir des motifs glob.

Les chemins d’accès peuvent contenir une hiérarchie de répertoires ; tout répertoire nécessaire sera créé dans cette installation.

Par exemple, si un paquet doit inclure un sous-répertoire avec plusieurs fichiers de donnée, les fichiers peuvent être organisés dans l’arborescence de la façon suivante :

setup.py
src/
    mypkg/
        __init__.py
        module.py
        data/
            tables.dat
            spoons.dat
            forks.dat

L’appel correspondant à setup() peut s’écrire :

setup(...,
      packages=['mypkg'],
      package_dir={'mypkg': 'src/mypkg'},
      package_data={'mypkg': ['data/*.dat']},
      )

Modifié dans la version 3.1: Tous les fichiers correspondant à package_data seront ajoutés au fichier MANIFEST si aucun modèle n’est fourni. Voir Spécifier les fichiers à distribuer.

2.7. Installation de fichiers additionnels

L’option data_files peut être utilisée pour définir des fichiers additionnels requis pour la distribution du module : fichiers de configuration, catalogues de messages, fichiers de donnée, tout ce qui ne rentre pas dans les catégories précédentes.

data_files définit une séquence de paires (répertoires, fichiers) de la façon suivante :

setup(...,
      data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
                  ('config', ['cfg/data.cfg']),
                  ('/etc/init.d', ['init-script'])]
     )

Note that you can specify the directory names where the data files will be installed, but you cannot rename the data files themselves.

Each (directory, files) pair in the sequence specifies the installation directory and the files to install there. If directory is a relative path, it is interpreted relative to the installation prefix (Python’s sys.prefix for pure-Python packages, sys.exec_prefix for packages that contain extension modules). Each file name in files is interpreted relative to the setup.py script at the top of the package source distribution. No directory information from files is used to determine the final location of the installed file; only the name of the file is used.

Vous pouvez définir les options data_files comme une simple succession de fichiers sans définir de répertoire cible, mais cela n’est pas recommandé, et la commande install affichera un message d’alerte dans ce cas. Pour installer des fichiers de donnée directement dans le répertoire cible, une chaîne de caractère vide doit être donnée en tant que répertoire.

Modifié dans la version 3.1: Tous les fichiers correspondant à data_files seront ajoutés au fichier MANIFEST si aucun modèle n’est fourni. Voir Spécifier les fichiers à distribuer.

2.8. Métadonnées additionnelles

Le script setup.py peut inclure des métadonnées additionnelles en plus du nom et de la version. Cela inclut les informations suivantes :

Métadonnées

Description

Valeur

Notes

name

nom du paquet

courte chaîne de caractères

(1)

version

version de la publication

courte chaîne de caractères

(1)(2)

author

nom de l’auteur du paquet

courte chaîne de caractères

(3)

author_email

adresse courriel de l’auteur du paquet

adresse de courriel

(3)

maintainer

nom du mainteneur du paquet

courte chaîne de caractères

(3)

maintainer_email

adresse du courriel du mainteneur du paquet

adresse de courriel

(3)

url

page d’accueil du paquet

URL

(1)

description

bref résumé décrivant le paquet

courte chaîne de caractères

long_description

description plus complète du paquet

longue chaîne de caractères

(5)

download_url

endroit où le paquet peut être téléchargé

URL

(4)

classifiers

une liste de classificateurs

liste de chaînes de caractères

(4)

platforms

une liste de plateformes

liste de chaînes de caractères

license

licence du paquet

courte chaîne de caractères

(6)

Notes :

  1. Ces champs sont requis.

  2. Il est recommandé que les versions prennent la forme majeure.mineure[.correctif[.sous-correctif]].

  3. L’auteur ou un mainteneur doit être identifié. Si un mainteneur est fourni, distutils l’indique en tant qu’auteur dans le fichier PKG-INFO.

  4. These fields should not be used if your package is to be compatible with Python versions prior to 2.2.3 or 2.3. The list is available from the PyPI website.

  5. The long_description field is used by PyPI when you are registering a package, to build its home page.

  6. Le champ license est un texte indiquant la licence du paquet quand la licence n’est pas indiquée dans les classificateurs de type « Licence » Trove. Voir le champ Classifier. À noter qu’il y a une option de distribution licence qui est obsolète mais agit toujours comme un alias pour license.

“chaîne courte”

Une simple ligne de texte ne dépassant par 200 caractères.

“chaîne longue”

De multiples lignes de texte au format ReStructuredText (voir http://docutils.sourceforge.net/).

“liste de chaînes”

Voir ci-dessous.

Encoder les informations de version est un art en soi. Les paquets Python adhèrent généralement au format de version majeure.mineure[.correctif][sous]. Le numéro majeur 0 est utilisé pour les publications expérimentales, initiales d’un logiciel. Il est incrémenté pour les publications qui représentent des étapes majeures pour le paquet. Le nombre mineur est incrémenté quand d’importantes nouvelles fonctionnalités sont ajoutées au paquet. Le numéro de correctif s’incrémente lors de la publication d’une correction de bogue est faite. Celles-ci sont « a1,a2,…,aN » (pour les publications alpha, où les fonctionnalités et l’API peut changer), « b1,b2,…,bN » (pour les publications beta, qui corrigent seulement les bogues) et « pr1,pr2,…,prN » (pour les ultimes pré-publication et publications de test). Quelques exemples :

0.1.0

la première, publication expérimentale du paquet

1.0.1a2

la seconde publication alpha du premier correctif de la version 1.0

classifiers are specified in a Python list:

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',
          ],
      )

2.9. Débogage du script setup.py

Parfois les choses tournent mal et le script setup.py ne fait pas ce que le développeur veut.

Distutils intercepte toute exception lors de l’exécution du script setup.py et affiche un message d’erreur simple avant d’arrêter le script. L’idée est de ne pas embrouiller les administrateurs qui ne savent pas grand-chose de Python et qui essayent d’installer un paquet. S’ils reçoivent une grosse et longue trace d’appels provenant des entrailles de Distutils, ils peuvent penser que le paquet ou que l’installation de Python est corrompue car, ils ne lisent pas tout jusqu’en bas alors que c’est un problème de droits.

D’un autre côté, cela n’aide pas le développeur à trouver la cause du problème. À cette fin, la variable d’environnement DISTUTILS_DEBUG peut être assignée à n’importe quoi sauf une chaîne de caractères vide, et distutils affichera maintenant une information détaillée à propos de ce qu’il fait, déversera la trace d’appels complète lors d’une exception, et affichera la ligne de commande complète quand un programme externe (comme un compilateur C) échoue.