2. Escribir el script de configuración

Nota

This document is being retained solely until the setuptools documentation at https://setuptools.readthedocs.io/en/latest/setuptools.html independently covers all of the relevant information currently included here.

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 Un ejemplo simple 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 Un ejemplo simple: 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”

Múltiples líneas de texto plano en formato reStructuredText (consulte http://docutils.sourceforge.net/).

“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).