# 2. Escribir el script de configuración

Nota

Este documento se conserva únicamente hasta que la documentación de `setuptools` en https://setuptools.readthedocs.io/en/latest/setuptools.html cubra de forma independiente toda la información relevante que se incluye actualmente aquí.

El script de configuración es el centro de toda actividad en la construcción, distribución e instalación de módulos utilizando Distutils. El propósito principal del script de configuración es describir la distribución de su módulo a Distutils, de modo que los diversos comandos que operan en sus módulos hagan lo correcto. Como vimos en la sección ejemplo simple de distutils anterior, el script de configuración consiste principalmente en una llamada a `setup()`, y la mayoría de la información suministrada a Distutils por el desarrollador del módulo se proporciona como argumentos de palabras clave para `setup()`.

Aquí hay un ejemplo un poco más complicado, que seguiremos en las próximas secciones: el propio script de configuración de Distutils. (Tenga en cuenta que aunque los Distutils se incluyen con Python 1.6 y posteriores, también tienen una existencia independiente para que los usuarios de Python 1.5.2 puedan usarlos para instalar otras distribuciones de módulos. Se utiliza el propio script de configuración de Distutils, que se muestra aquí). instalar el paquete en 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'],
         )

Solo hay dos diferencias entre esto y la trivial distribución de un archivo presentada en la sección ejemplo simple de distutils: más metadatos y la especificación de módulos Python puros por paquete, en lugar de por módulo. Esto es importante ya que los Distutils consisten en un par de docenas de módulos divididos en (hasta ahora) dos paquetes; Una lista explícita de cada módulo sería tediosa de generar y difícil de mantener. Para obtener más información sobre los metadatos adicionales, consulte la sección Metadatos adicionales.

Tenga en cuenta que los nombres de ruta (archivos o directorios) proporcionados en el script de configuración deben escribirse utilizando la convención de Unix, es decir, separados por barras. Distutils se encargará de convertir esta representación neutral de la plataforma en lo que sea apropiado en su plataforma actual antes de usar el nombre de ruta. Esto hace que su script de configuración sea portátil en todos los sistemas operativos, lo que, por supuesto, es uno de los principales objetivos de Distutils. En este espíritu, todos los nombres de ruta en este documento están separados por barras.

Esto, por supuesto, solo se aplica a los nombres de ruta asignados a las funciones de Distutils. Si, por ejemplo, utiliza funciones estándar de Python como `glob.glob()` o `os.listdir()` para especificar archivos, debe tener cuidado al escribir código portátil en lugar de codificar separadores de ruta:

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

## 2.1. Listado de paquetes completos

La opción `packages` le dice a Distutils que procese (compile, distribuya, instale, etc.) todos los módulos de Python puros que se encuentran en cada paquete mencionado en la lista de `packages`. Para hacer esto, por supuesto, debe haber una correspondencia entre los nombres de los paquetes y los directorios en el sistema de archivos. La correspondencia predeterminada es la más obvia, es decir, el paquete `distutils` se encuentra en el directorio `distutils` en relación con la raíz de distribución. Por lo tanto, cuando diga `packages = ['foo']` en su secuencia de comandos de configuración, promete que Distutils encontrará un archivo `foo/__init__.py` (que podría estar escrito de manera diferente en su sistema , pero te haces una idea) en relación con el directorio donde vive tu script de configuración. Si no cumple esta promesa, Distutils emitirá una advertencia pero de todos modos procesará el paquete roto.

Si usa una convención diferente para diseñar su directorio de origen, no hay problema: solo tiene que proporcionar la opción `package_dir` para informar a los Distutils sobre su convención. Por ejemplo, supongamos que mantiene toda la fuente de Python en `lib`, de modo que los módulos en el «paquete raíz» (es decir, no en ningún paquete) estén en `lib`, módulos en el paquete `foo` está en archivo `lib/foo`, y así sucesivamente. Entonces pondrías

    package_dir = {'': 'lib'}

en tu script de configuración. Las claves de este diccionario son nombres de paquetes, y un nombre de paquete vacío representa el paquete raíz. Los valores son nombres de directorio relativos a su raíz de distribución. En este caso, cuando dices `packages = ['foo']`, estás prometiendo que el archivo `lib/foo/__init__.py` existe.

Otra posible convención es colocar el paquete `foo` directamente en `lib`, el paquete `foo.bar` en `lib/bar`, etc. Esto se escribiría en el script de configuración como

    package_dir = {'foo': 'lib'}

Una entrada `package: dir` en el diccionario `package_dir` se aplica implícitamente a todos los paquetes debajo de package, por lo que el caso `foo.bar` se maneja automáticamente aquí. En este ejemplo, tener `packages = ['foo', 'foo.bar']` le dice a los Distutils que busquen `lib/__init__.py` y `lib/bar/__init__.py`. (Tenga en cuenta que, aunque `package_dir` se aplica de forma recursiva, debe enumerar explícitamente todos los paquetes en `packages`: los Distutils no escanearán recursivamente su árbol de origen buscando cualquier directorio con un archivo `__init__.py`.)

## 2.2. Listado de módulos individuales

Para una distribución de módulos pequeños, es posible que prefiera enumerar todos los módulos en lugar de enumerar los paquetes, especialmente el caso de un solo módulo que va en el «paquete raíz» (es decir, ningún paquete). Este caso más simple se mostró en la sección Un ejemplo simple; Aquí hay un ejemplo un poco más complicado:

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

Esto describe dos módulos, uno en el paquete «raíz», el otro en el paquete `pkg`. Nuevamente, el diseño predeterminado del paquete/directorio implica que estos dos módulos se pueden encontrar en `mod1.py` y `pkg/mod2.py`, y que `pkg/__init__.py` existe también. Y nuevamente, puede anular la correspondencia paquete/directorio utilizando la opción `package_dir`.

## 2.3. Describiendo módulos de extensión

Así como escribir módulos de extensión Python es un poco más complicado que escribir módulos Python puros, describirlos a Distutils es un poco más complicado. A diferencia de los módulos puros, no basta con enumerar módulos o paquetes y esperar que Distutils salga y encuentre los archivos correctos; debe especificar el nombre de la extensión, el (los) archivo (s) de origen y cualquier requisito de compilación/enlace (incluir directorios, bibliotecas para enlazadores, etc.).

Todo esto se realiza a través de otro argumento de palabra clave para `setup()`, la opción `ext_modules`. `ext_modules` es solo una lista de instancias `Extension`, cada una de las cuales describe un único módulo de extensión. Suponga que su distribución incluye una sola extensión, llamada `foo` e implementada por `foo.c`. Si no se necesitan instrucciones adicionales para el compilador/enlazador, describir esta extensión es bastante simple:

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

La clase `Extension` se puede importar desde `distutils.core` junto con `setup()`. Por lo tanto, el script de configuración para una distribución de módulo que contiene solo esta extensión y nada más podría ser:

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

La clase `Extension` (en realidad, la maquinaria de construcción de extensiones subyacente implementada por el comando build_ext) admite una gran flexibilidad al describir las extensiones de Python, que se explica en las siguientes secciones.

### 2.3.1. Nombres de extensión y paquetes

El primer argumento para el constructor `Extension` es siempre el nombre de la extensión, incluidos los nombres de los paquetes. Por ejemplo,

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

describe una extensión que vive en el paquete raíz, mientras que

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

describe la misma extensión en el paquete `pkg`. Los archivos fuente y el código objeto resultante son idénticos en ambos casos; la única diferencia es dónde en el sistema de archivos (y, por lo tanto, dónde en la jerarquía del espacio de nombres de Python) vive la extensión resultante.

Si tiene varias extensiones, todas en el mismo paquete (o todas en el mismo paquete base), use el argumento de palabra clave `ext_package` para `setup()`. Por ejemplo,

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

compilará `foo.c` a la extensión `pkg.foo`, y `bar.c` a `pkg.subpkg.bar`.

### 2.3.2. Extensión de archivos fuente

El segundo argumento para el constructor `Extension` es una lista de archivos fuente. Dado que Distutils actualmente solo admite extensiones C, C++ y Objective-C, estos normalmente son archivos fuente C/C++/Objective-C. (Asegúrese de usar las extensiones apropiadas para distinguir los archivos fuente de C++ `.cc` y `.cpp` que parecen ser reconocidos por los compiladores de Unix y Windows).

Sin embargo, también puede incluir archivos de interfaz SWIG (`.i`) en la lista; el comando build_ext sabe cómo manejar las extensiones SWIG: ejecutará SWIG en el archivo de interfaz y compilará el archivo C/C++ resultante en su extensión.

A pesar de esta advertencia, las opciones para SWIG se pueden pasar actualmente de esta manera:

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

O en la línea de comandos como esta

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

En algunas plataformas, puede incluir archivos que no sean de origen procesados por el compilador e incluidos en su extensión. Actualmente, esto solo significa archivos de texto de mensaje de Windows (`.mc`) y archivos de definición de recursos (`.rc`) para Visual C ++. Estos serán compilados en archivos de recursos binarios (`.res`) y enlazados.

### 2.3.3. Opciones de preprocesador

Tres argumentos opcionales para `Extension` le ayudarán si necesita especificar directorios de inclusión para buscar o preprocesar macros para definir/indefinir: `include_dirs`, `define_macros` y `undef_macros`.

Por ejemplo, si su extensión requiere archivos de encabezado en el directorio `include` bajo su raíz de distribución, use la opción `include_dirs`:

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

Puede especificar directorios absolutos allí; si sabe que su extensión solo se construirá en sistemas Unix con X11R6 instalado en `/usr`, puede salirse con

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

Debería evitar este tipo de uso no portátil si planea distribuir su código: probablemente sea mejor escribir código C como

    #include <X11/Xlib.h>

Si necesita incluir archivos de encabezado de alguna otra extensión de Python, puede aprovechar el hecho de que los archivos de encabezado se instalan de manera coherente mediante el comando Distutils install_headers. Por ejemplo, los archivos de encabezado Python numéricos se instalan (en una instalación estándar de Unix) en `/usr/local/include/python1.5/ Numerical`. (La ubicación exacta diferirá según la plataforma y la instalación de Python). Dado que el directorio de inclusión de Python — `/usr/local/include/python1.5` en este caso — siempre se incluye en ruta de búsqueda al construir extensiones de Python, el mejor enfoque es escribir código C como

    #include <Numerical/arrayobject.h>

Sin embargo, si debe colocar el directorio `Numerical` en la ruta de búsqueda del encabezado, puede encontrar ese directorio utilizando el módulo 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]),
          )

Aunque esto es bastante portátil, funcionará en cualquier instalación de Python, independientemente de la plataforma, probablemente sea más fácil escribir su código C de manera sensata.

Puede definir y no definir macros de preprocesador con las opciones `define_macros` y `undef_macros`. `define_macros` toma una lista de tuplas `(name, value)`, donde `name` es el nombre de la macro a definir (una cadena de caracteres) y `value` es su valor: ya sea un cadena de caracteres o `None`. (Definir una macro `FOO` en `None` es el equivalente de un simple `#define FOO` en su fuente C: con la mayoría de los compiladores, esto establece `FOO` en la cadena `1`.) `undef_macros` es solo una lista de macros para indefinir.

Por ejemplo:

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

es el equivalente a tener esto en la parte superior de cada archivo fuente C:

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

### 2.3.4. Opciones de biblioteca

También puede especificar las bibliotecas para enlazarlas al crear su extensión y los directorios para buscar esas bibliotecas. La opción `bibliotecas` es una lista de bibliotecas para enlazar, `library_dirs` es una lista de directorios para buscar bibliotecas en el momento del enlace, y `runtime_library_dirs` es una lista de directorios para buscar compartidos (cargadas dinámicamente) bibliotecas en tiempo de ejecución.

Por ejemplo, si necesita enlazar con bibliotecas que se sabe que están en la ruta de búsqueda de biblioteca estándar en los sistemas de destino:

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

Si necesita enlazar con bibliotecas en una ubicación no estándar, deberá incluir la ubicación en `library_dirs`:

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

(Nuevamente, este tipo de construcción no portátil debe evitarse si tiene la intención de distribuir su código.)

### 2.3.5. Otras opciones

Todavía hay algunas otras opciones que se pueden usar para manejar casos especiales.

La opción `optional` es booleana; si es cierto, una falla de compilación en la extensión no abortará el proceso de compilación, sino que simplemente no instalará la extensión que falla.

La opción `extra_objects` es una lista de archivos de objetos que se pasarán al enlazador. Estos archivos no deben tener extensiones, ya que se usa la extensión predeterminada para el compilador.

`extra_compile_args` y `extra_link_args` se pueden usar para especificar opciones de línea de comando adicionales para las líneas de comando del compilador y enlazador respectivo.

`export_symbols` solo es útil en Windows. Puede contener una lista de símbolos (funciones o variables) para exportar. Esta opción no es necesaria cuando se crean extensiones compiladas: Distutils agregará automáticamente `initmodule` a la lista de símbolos exportados.

La opción `depends` es una lista de archivos de los que depende la extensión (por ejemplo, archivos de encabezado). El comando de compilación llamará al compilador en las fuentes para reconstruir la extensión si alguno de estos archivos se ha modificado desde la compilación anterior.

## 2.4. Relaciones entre distribuciones y paquetes

Una distribución puede relacionarse con paquetes de tres maneras específicas:

1. Puede requerir paquetes o módulos.

2. Puede proporcionar paquetes o módulos.

3. Puede paquetes o módulos obsoletos.

Estas relaciones se pueden especificar utilizando argumentos de palabras clave para la función `distutils.core.setup()`.

Las dependencias en otros módulos y paquetes de Python se pueden especificar proporcionando el argumento de palabra clave requires a `setup()`. El valor debe ser una lista de cadenas de caracteres. Cada cadena especifica un paquete que se requiere y, opcionalmente, qué versiones son suficientes.

Para especificar que se requiere cualquier versión de un módulo o paquete, la cadena debe consistir completamente en el nombre del módulo o paquete. Los ejemplos incluyen `'mymodule'` y `'xml.parsers.expat'`.

Si se requieren versiones específicas, se puede proporcionar una secuencia de calificadores entre paréntesis. Cada calificador puede consistir en un operador de comparación y un número de versión. Los operadores de comparación aceptados son:

    <    >    ==
    <=   >=   !=

Estos se pueden combinar usando múltiples calificadores separados por comas (y espacios en blanco opcionales). En este caso, todos los calificadores deben coincidir; Se utiliza un AND lógico para combinar las evaluaciones.

Veamos algunos ejemplos:

Expresión Requiere | Explicación
--- | ---
`==1.0` | Solo la versión `1.0` es compatible
`>1.0, !=1.5.1, <2.0` | Cualquier versión posterior a `1.0` y anterior a `2.0` es compatible, excepto `1.5.1`

Ahora que podemos especificar dependencias, también debemos poder especificar qué proporcionamos que otras distribuciones pueden requerir. Esto se hace usando el argumento de palabra clave provides para `setup()`. El valor de esta palabra clave es una lista de cadenas, cada una de las cuales nombra un módulo o paquete Python, y opcionalmente identifica la versión. Si no se especifica la versión, se supone que coincide con la de la distribución.

Algunos ejemplos:

Expresión Proporciona | Explicación
--- | ---
`mypkg` | Proporciona `mypkg`, utilizando la versión de distribución
`mypkg (1.1)` | Proporcione `mypkg` versión 1.1, independientemente de la versión de distribución

Un paquete puede declarar que obsoleto otros paquetes utilizando el argumento de palabra clave obsoletes. El valor para esto es similar al de la palabra clave requires: una lista de cadenas que dan especificadores de módulo o paquete. Cada especificador consta de un nombre de módulo o paquete opcionalmente seguido de uno o más calificadores de versión. Los calificadores de versión se dan entre paréntesis después del nombre del módulo o paquete.

Las versiones identificadas por los calificadores son aquellas que están obsoletas por la distribución que se describe. Si no se dan calificadores, se entiende que todas las versiones del módulo o paquete nombrado están obsoletas.

## 2.5. Instalar scripts

Hasta ahora hemos estado tratando con módulos Python puros y no puros, que generalmente no se ejecutan solos sino que se importan mediante scripts.

Los scripts son archivos que contienen el código fuente de Python, destinados a iniciarse desde la línea de comandos. Los scripts no requieren que Distutils haga nada muy complicado. La única característica inteligente es que si la primera línea del script comienza con `#!` Y contiene la palabra «python», Distutils ajustará la primera línea para referirse a la ubicación actual del intérprete. Por defecto, se reemplaza con la ubicación actual del intérprete. La opción `-executable` (o `-e`) permitirá que la ruta del intérprete se anule explícitamente.

La opción `scripts` simplemente es una lista de archivos a manejar de esta manera. Desde el script de configuración PyXML:

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

Distinto en la versión 3.1: Todos los scripts también se agregarán al archivo `MANIFEST` si no se proporciona una plantilla. Ver Especificar los archivos a distribuir.

## 2.6. Instalar datos del paquete

A menudo, se necesitan instalar archivos adicionales en un paquete. Estos archivos son a menudo datos que están estrechamente relacionados con la implementación del paquete, o archivos de texto que contienen documentación que podría ser de interés para los programadores que usan el paquete. Estos archivos se llaman paquetes de datos <package data>.

Los datos del paquete se pueden agregar a los paquetes utilizando el argumento de palabra clave `package_data` para la función `setup()`. El valor debe ser una asignación del nombre del paquete a una lista de nombres de ruta relativos que deben copiarse en el paquete. Las rutas se interpretan como relativas al directorio que contiene el paquete (la información de la asignación `package_dir` se usa si corresponde); es decir, se espera que los archivos formen parte del paquete en los directorios de origen. También pueden contener patrones glob.

Los nombres de ruta pueden contener porciones de directorio; cualquier directorio necesario se creará en la instalación.

Por ejemplo, si un paquete debe contener un subdirectorio con varios archivos de datos, los archivos se pueden organizar de esta manera en el árbol de origen:

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

La llamada correspondiente a `setup()` podría ser:

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

Distinto en la versión 3.1: Todos los archivos que coincidan con `package_data` se agregarán al archivo `MANIFEST` si no se proporciona una plantilla. Ver Especificar los archivos a distribuir.

## 2.7. Instalar archivos adicionales

La opción `data_files` se puede usar para especificar archivos adicionales necesarios para la distribución del módulo: archivos de configuración, catálogos de mensajes, archivos de datos, cualquier cosa que no se ajuste a las categorías anteriores.

`data_files` especifica una secuencia de pares (directory, files) de la siguiente manera:

    setup(...,
          data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
                      ('config', ['cfg/data.cfg'])],
         )

Cada par (directory, files) en la secuencia especifica el directorio de instalación y los archivos a instalar allí.

Cada nombre de archivo en files se interpreta en relación con el script `setup.py` en la parte superior de la distribución de origen del paquete. Tenga en cuenta que puede especificar el directorio donde se instalarán los archivos de datos, pero no puede cambiar el nombre de los archivos de datos.

El directory debe ser una ruta relativa. Se interpreta en relación con el prefijo de instalación (`sys.prefix` de Python para instalaciones del sistema; `site.USER_BASE` para instalaciones de usuario). Distutils permite que directory sea una ruta de instalación absoluta, pero esto se desaconseja ya que es incompatible con el formato de empaquetado de la rueda. No se utiliza información de directorio de files para determinar la ubicación final del archivo instalado; solo se usa el nombre del archivo.

Puede especificar las opciones `data_files` como una secuencia simple de archivos sin especificar un directorio de destino, pero esto no es recomendable, y el comando install imprimirá una advertencia en este caso. Para instalar archivos de datos directamente en el directorio de destino, se debe dar una cadena vacía como directorio.

Distinto en la versión 3.1: Todos los archivos que coincidan con `data_files` se agregarán al archivo `MANIFEST` si no se proporciona una plantilla. Ver Especificar los archivos a distribuir.

## 2.8. Metadatos adicionales

El script de configuración puede incluir metadatos adicionales más allá del nombre y la versión. Esta información incluye:

Metadatos | Descripción | Valor | Notas
--- | --- | --- | ---
`name` | nombre del paquete | cadena de caracteres corta | (1)
`version` | versión de este lanzamiento | cadena de caracteres corta | (1)(2)
`author` | nombre del autor del paquete | cadena de caracteres corta | (3)
`author_email` | dirección de correo electrónico del autor del paquete | dirección de correo electrónico | (3)
`maintainer` | nombre del responsable del paquete | cadena de caracteres corta | (3)
`maintainer_email` | dirección de correo electrónico del mantenedor del paquete | dirección de correo electrónico | (3)
`url` | página de inicio del paquete | URL | (1)
`description` | descripción breve y resumida del paquete | cadena de caracteres corta |
`long_description` | descripción más larga del paquete | cadena de caracteres larga | (4)
`download_url` | ubicación donde se puede descargar el paquete | URL |
`classifiers` | una lista de clasificadores | lista de cadenas de caracteres | (6)(7)
`platforms` | una lista de plataformas | lista de cadenas de caracteres | (6)(8)
`keywords` | una lista de palabras clave | lista de cadenas de caracteres | (6)(8)
`license` | licencia para el paquete | cadena de caracteres corta | (5)

Notas:

1. Estos campos son obligatorios.

2. Se recomienda que las versiones tomen la forma major.minor[.patch[.sub]].

3. Se debe identificar al autor o al mantenedor. Si se proporciona el mantenedor, distutils lo enumera como el autor en `PKG-INFO`.

4. PyPI utiliza el campo `long_description` cuando publica un paquete para construir su página de proyecto.

5. El campo `license` es un texto que indica la licencia que cubre el paquete donde la licencia no es una selección de los clasificadores de Trove «License». Vea el campo `Classifier`. Tenga en cuenta que hay una opción de distribución de `license` que está en desuso pero que aún actúa como un alias para la `license`.

6. Este campo debe ser una lista.

7. Los clasificadores válidos se enumeran en PyPI.

8. Para preservar la compatibilidad con versiones anteriores, este campo también acepta una cadena. Si pasa una cadena separada por comas `'foo, bar'`, se convertirá en `['foo', 'bar']`, de lo contrario, se convertirá en una lista de una cadena de caracteres.

“cadenas de caracteres cortas”

  Una sola línea de texto, no más de 200 caracteres.

“cadenas de caracteres largas”

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

“lista de cadenas de caracteres”

  Vea abajo.

Codificar la información de la versión es un arte en sí mismo. Los paquetes de Python generalmente se adhieren al formato de versión major.minor[.patch][sub]. El número principal es 0 para las versiones iniciales y experimentales de software. Se incrementa para versiones que representan hitos importantes en un paquete. El número menor se incrementa cuando se agregan nuevas características importantes al paquete. El número de parche aumenta cuando se realizan versiones de corrección de errores. La información adicional de la versión final a veces se usa para indicar sublanzamientos. Estos son «a1, a2, …, aN» (para versiones alfa, donde la funcionalidad y la API pueden cambiar), «b1, b2, …, bN» (para versiones beta, que solo corrigen errores) y «pr1 , pr2, …, prN» (para la prueba final de lanzamiento previo al lanzamiento). Algunos ejemplos:

0.1.0

  el primer lanzamiento experimental de un paquete

1.0.1a2

  la segunda versión alfa de la primera versión del parche 1.0

`classifiers` debe ser especificado en una lista:

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

Distinto en la versión 3.7: `setup` ahora advierte cuando los campos `classifiers`, `keywords` o `platforms` no se especifican como una lista o una cadena de caracteres.

## 2.9. Depuración del script de configuración

A veces las cosas salen mal y el script de configuración no hace lo que el desarrollador quiere.

Distutils detecta cualquier excepción al ejecutar el script de configuración e imprime un mensaje de error simple antes de que finalice el script. La motivación para este comportamiento es no confundir a los administradores que no saben mucho acerca de Python y están tratando de instalar un paquete. Si obtienen un gran rastreo desde las profundidades de Distutils, pueden pensar que el paquete o la instalación de Python están rotos porque no leen hasta el final y ven que es un problema de permiso.

Por otro lado, esto no ayuda al desarrollador a encontrar la causa de la falla. Para este propósito, la variable de entorno `DISTUTILS_DEBUG` se puede establecer en cualquier cosa excepto una cadena vacía, y distutils ahora imprimirá información detallada sobre lo que está haciendo, volcará el rastreo completo cuando ocurra una excepción e imprimirá todo el comando línea cuando falla un programa externo (como un compilador de C).