Nota

¡Ayúdanos a traducir la documentación oficial de Python al Español! Puedes encontrar más información en Como contribuir. Ayuda a acercar Python a más personas de habla hispana.

6. Ejemplos de distutils

Este capitulo provee varios ejemplos básicos para ayudar a comenzar con distutils. Información adicional sobre el uso de distutils puede ser encontrado en el Distutils Cookbook.

Ver también

Distutils Cookbook

Colección de recetas que muestran como lograr mayor control sobre distutils.

6.1. Distribución de Python pura (por módulo)

Si solo distribuyes un par de módulos, especialmente si no viven en un paquete en particular, puedes especificarlos individualmente usando la opción py_modules en el script de instalación.

En el caso más simple, tendrás dos archivos de los cuales preocuparte: un script de instalación y el único modulo que estás distribuyendo, en este ejemplo foo.py:

<root>/
        setup.py
        foo.py

(En todos los diagramas en esta sección, <root> se referirá al directorio raíz de la distribución.) Un script de instalación mínimo para describir esta situación seria:

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

Observe que el nombre de la distribución esta especificada de forma independiente con la opción name, y no hay ninguna regla que diga que tiene que ser el mismo que el nombre del único modulo de la distribución (aunque probablemente sea una buena convención a seguir). Sin embargo, el nombre de la distribución es usado para generar nombres de archivo, así que deberías limitarte a letras, dígitos, guión bajo, y guiones.

Dado que py_modules es una lista, puedes por supuesto especificar múltiples módulos, por ejemplo, si estás distribuyendo los módulos foo y bar, tu configuración podría verse así:

<root>/
        setup.py
        foo.py
        bar.py

y el script de instalación podría ser:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      py_modules=['foo', 'bar'],
      )

Puedes poner los archivos fuente de los módulos en otro directorio, pero si tienes suficientes módulos para hacerlo, probablemente sea mas fácil especificar los módulos por paquete en lugar de enumerarlos individualmente.

6.2. Distribución de Python pura (por paquete)

Si tienes más de un par de módulos para distribuir, especialmente si están en múltiples paquetes, probablemente sea más fácil especificar paquetes completos en lugar de módulos individuales. Esto funciona incluso si sus módulos no están en un paquete; solo puedes decirle a los Distutils que procese los módulos desde el paquete raíz, y eso funciona igual que cualquier otro paquete (excepto que no tiene que tener un archivo __init__.py.

El script de instalación del último ejemplo también podría ser escrito como:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      packages=[''],
      )

(La cadena de caracteres vacía representa el paquete raíz.)

Si esos dos archivos son movidos a un subdirectorio, pero permanecen en el paquete raíz, por ejemplo:

<root>/
        setup.py
        src/      foo.py
                  bar.py

entonces seguirías especificando el paquete raíz, pero tienes que decirle a los Distutils dónde viven los archivos fuente del paquete raíz:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      package_dir={'': 'src'},
      packages=[''],
      )

No obstante, lo mas típico es que quieras distribuir múltiples módulos en el mismo paquete (o en subpaquetes). Por ejemplo, si los módulos foo y bar pertenecen al paquete foobar, una forma de diseñar su estructura fuente es:

<root>/
        setup.py
        foobar/
                 __init__.py
                 foo.py
                 bar.py

Este es, de hecho, la distribución por defecto esperada por los Distutils, y la que requiere menos trabajo para describir en su script de instalación:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      packages=['foobar'],
      )

Si quieres poner módulos en directorios no nombrados por su paquete, entonces necesitas usar la opción package_dir otra vez. Por ejemplo, si el directorio src contiene los módulos en el paquete foobar:

<root>/
        setup.py
        src/
                 __init__.py
                 foo.py
                 bar.py

un script de instalación apropiado sería:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      package_dir={'foobar': 'src'},
      packages=['foobar'],
      )

O, podrías poner módulos de tu paquete principal justo en la raíz de la distribución:

<root>/
        setup.py
        __init__.py
        foo.py
        bar.py

en cuyo caso tu script de instalación sería:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      package_dir={'foobar': ''},
      packages=['foobar'],
      )

(La cadena de caracteres vacía también representa el directorio actual.)

Si tienes subpaquetes, deben ser listados explícitamente en packages, pero cualquier entrada en package_dir se extiende automáticamente a los subpaquetes. (En otras palabras, los Distutils no escanean tu estructura fuente, intentando descubrir que directorios corresponden a los paquetes de Python buscando por archivos __init__.py.) Por lo tanto, si la distribución por defecto hace crece un subpaquete:

<root>/
        setup.py
        foobar/
                 __init__.py
                 foo.py
                 bar.py
                 subfoo/
                           __init__.py
                           blah.py

entonces el script de instalación correspondiente sería:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      packages=['foobar', 'foobar.subfoo'],
      )

6.3. Módulo de extensión única

Los módulos de extensión son especificados usando la opción ext_modules. package_dir no tiene efecto sobre donde se encuentren los archivos fuente de la extensión; solo afecta a la fuente de los módulos de Python puro. El mas simple caso, un único modulo de extensión en un único archivo fuente de C, es:

<root>/
        setup.py
        foo.c

Si la extensión foo pertenece al paquete raíz, el script de instalación para este podría ser:

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

Si la extensión realmente pertenece a un paquete, digamos foopkg, entonces

Con exactamente la misma distribución del árbol fuente, esta extensión puede ser puesta en el paquete foopkg simplemente cambiando el nombre de la extensión:

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

6.4. Verificando un paquete

El comando check le permite verificar si los metadatos de su paquete cumplen los requisitos mínimos para construir la distribución.

Para ejecutarlo, sólo tienes que llamarlo usando tu script setup.py. Si falta algo, check mostrará una advertencia.

Tomemos un ejemplo con un script simple:

from distutils.core import setup

setup(name='foobar')

La ejecución del comando check mostrará algunas advertencias:

$ python setup.py check
running check
warning: check: missing required meta-data: version, url
warning: check: missing meta-data: either (author and author_email) or
         (maintainer and maintainer_email) should be supplied

Si usas la sintaxis reStructuredText en el campo long_description y docutils esta instalado puedes comprobar si la sintaxis está bien con el comando check, usando la opción restructuredtext.

Por ejemplo, si el script setup.py es cambiado así:

from distutils.core import setup

desc = """\
My description
==============

This is the description of the ``foobar`` package.
"""

setup(name='foobar', version='1', author='tarek',
    author_email='tarek@ziade.org',
    url='http://example.com', long_description=desc)

Donde se rompa la descripción larga, check será capaz de detectarla usando el analizador docutils:

$ python setup.py check --restructuredtext
running check
warning: check: Title underline too short. (line 2)
warning: check: Could not finish the parsing.

6.5. Leyendo los metadatos

La función distutils.core.setup() provee una interfaz de línea de comandos que te permite consultar los campos de metadatos de un proyecto a través del script setup.py de un proyecto dado:

$ python setup.py --name
distribute

Esta llamada lee los metadatos de name ejecutando la función distutils.core.setup(). Aunque, cuando se crea una distribución fuente o binaria con Distutils, los campos de metadatos son escritos en un archivo estático llamado PKG-INFO. Cuando un proyecto basado en Distutils es instalado en Python, el archivo PKG-INFO es copiado junto con los módulos y paquetes de la distribución en NAME-VERSION-pyX.X.egg-info, donde NAME es el nombre del proyecto, VERSION su versión como se define en los metadatos, y pyX.X la versión mayor y menor de Python como 2.7 o 3.2.

Puedes leer de nuevo este archivo estático usando la clase distutils.dist.DistributionMetadata y su método read_pkg_file():

>>> from distutils.dist import DistributionMetadata
>>> metadata = DistributionMetadata()
>>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info'))
>>> metadata.name
'distribute'
>>> metadata.version
'0.6.8'
>>> metadata.description
'Easily download, build, install, upgrade, and uninstall Python packages'

Note que la clase también puede ser instanciada con una ruta de archivo de metadatos para cargar sus valores:

>>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
>>> DistributionMetadata(pkg_info_path).name
'distribute'