6. Ejemplos de distutils¶
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í.
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'