Guía práctica para el uso de Setup.py

Datos &Guía de formación en IA 2021

Descargue el folleto de GoDataDriven para obtener una visión completa de las sesiones de formación disponibles y de los itinerarios de aprendizaje de ingeniería de datos, ciencia de datos, analista de datos y traductor de analítica.

Cuando usas python profesionalmente vale la pena configurar tus proyectos
de manera consistente. Esto ayuda a tus colaboradores a entender rápidamente la estructura de un proyecto, y hace más fácil para ellos configurar el proyecto en su máquina. La clave para configurar tu proyecto es el archivo setup.py.
En este blog entraré en los detalles de este archivo.

Por dónde empezamos

Aquí asumo que ya tienes un paquete que quieres configurar.
Este no necesita ser un paquete terminado – idealmente deberías crear el
setup.py mucho antes de que tu proyecto esté terminado. Incluso podría ser un paquete vacío;
sólo asegúrese de que la carpeta del paquete existe
y contiene un archivo llamado init.py (que puede estar vacío).

Si sigues la estructura de mi colega Henk
para tu proyecto, tu situación inicial debería ser algo así:

example_project/├── exampleproject/ Python package with source code.│ ├── __init__.py Make the folder a package.│ └── example.py Example module.└── README.md README with info of the project.

Puedes tener otros archivos o carpetas en tu estructura, por ejemplo
carpetas llamadas notebooks/, tests/ o data/, pero no son necesarias.

El caso de un setup.py

Una vez que haya creado un paquete como este, entonces es probable que
utilice parte del código en otros lugares. Por ejemplo, podría querer
hacer esto en un cuaderno:

from exampleproject.example import example_function

Esto funcionaría si su directorio de trabajo actual es example_project/, pero en
todos los demás casos python le dará una salida como:

ModuleNotFoundError: No module named 'exampleproject'

Podrías decirle a python dónde buscar el paquete estableciendo la variable de entorno PYTHONPATH
o añadiendo la ruta a sys.path,
pero eso está lejos de ser lo ideal: requeriría diferentes acciones en diferentes
plataformas, y la ruta que necesitas establecer depende de la ubicación de tu código.
Una forma mucho mejor es instalar tu paquete usando un setup.py y un pip,
ya que el pip es la forma estándar de instalar todos los demás paquetes, y está destinado
a funcionar igual en todas las plataformas.

Un ejemplo mínimo

Entonces, ¿qué aspecto tiene un archivo setup.py? Aquí hay un ejemplo mínimo0:

from setuptools import setup, find_packagessetup( name='example', version='0.1.0', packages=find_packages(include=))

Aquí especificamos tres cosas:

  • El nombre del paquete, que es el nombre que pipusará para su paquete.
    No tiene por qué ser el mismo que el nombre de la carpeta en la que vive el paquete
    , aunque puede resultar confuso si no lo es. Un ejemplo en el que el nombre del paquete
    y el directorio no coinciden es Scikit-Learn: lo instalas
    usando pip install scikit-learn, mientras que lo usas importando desde sklearn.
  • La versión de tu paquete. Esta es la versión que pip reportará, y se usa
    por ejemplo cuando publicas tu paquete en PyPI1.
  • Qué paquetes incluir; en nuestro caso esto es sólo exampleproject/.
    Aquí dejamos que setuptools lo averigüe
    automáticamente2. Aunque en principio podría utilizar find_packages()
    sin ningún argumento, esto puede dar lugar a que se incluyan paquetes no deseados
    . Esto puede suceder, por ejemplo,
    si incluyó un __init__.pyen su directorio tests/
    . Alternativamente, también puede utilizar el argumento exclude para impedir explícitamente
    la inclusión de pruebas en el paquete, pero esto es ligeramente
    menos robusto.

Ahora todo lo que necesitas hacer para instalar tu paquete es ejecutar lo siguiente
desde dentro del directorio example_project/3:

pip install -e .

El . aquí se refiere al directorio de trabajo actual, que asumo que es el directorio
donde se puede encontrar el setup.py. La bandera -e especifica que queremos instalar
en modo editable, lo que significa
que cuando editemos los archivos de nuestro paquete no necesitamos reinstalar el
paquete antes de que los cambios surtan efecto. Sin embargo, tendrás que reiniciar
python o recargar el paquete.

Cuando edites información en el propio setup.py tendrás que reinstalar
el paquete en la mayoría de los casos, y también si añades nuevos (sub)paquetes.
Cuando tengas dudas, nunca está de más reinstalar. Simplemente ejecute pip install -e . de nuevo.

Requisitos

La mayoría de los proyectos tienen algunas dependencias. Lo más probable es que hayas usado antes un archivo requirements.txt
, o un environment.yml
si estás usando conda. Ahora que está creando un setup.py, puede especificar sus
dependencias en el argumento install_requires.
Por ejemplo, para un proyecto típico de ciencia de datos puede tener:

setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=)

Puede especificar los requisitos sin una versión (PyYAML), fijar una versión (pandas==0.23.3), especificar una
versión mínima ('numpy>=1.14.5) o establecer un rango de versiones (matplotlib>=2.2.0,<3.0.0). Estos
requisitos serán instalados automáticamente por pip cuando instale su paquete.

Extras-require

A veces puede tener dependencias que sólo se requieren en ciertas situaciones. Como científico de datos
A menudo hago paquetes que uso para entrenar un modelo. Cuando trabajo en dicho modelo de forma interactiva
puedo necesitar tener matplotlib y jupyterinstalados para poder trabajar interactivamente con los
datos y crear visualizaciones
del rendimiento del modelo. Por otro lado, si el modelo se ejecuta en producción no
quiero instalar matplotlib ni jupyter en la máquina (o contenedor) donde entreno
o hago inferencia. Por suerte setuptoolspermite especificar dependencias opcionales en extras_require:

setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=, extras_require={ 'interactive': , })

Ahora bien, si instalamos el paquete normalmente (pip install exampledesde PyPI o pip install -e .localmente)
sólo instalará las dependencias PyYAML, pandasy numpy. Sin embargo, cuando especificamos
que queremos las dependencias opcionales interactive(pip install example
o pip install -e .),
entonces también se instalarán matplotlib y jupyter.

Scripts y puntos de entrada

El principal caso de uso de la mayoría de los paquetes python que se instalan desde PyPI es el de proporcionar funcionalidad
que puede ser utilizada en otro código python. En otras palabras, puedes importdesde esos paquetes.
Como científico de datos a menudo hago paquetes que no están destinados a ser utilizados por otro código python pero
están destinados a hacer algo, por ejemplo entrenar un modelo. Como tal, a menudo tengo un script de python que
quiero ejecutar desde la línea de comandos.

La mejor manera4 de exponer la funcionalidad de tu paquete a la línea de comandos es definir
un entry_point como tal:

setup( # ..., entry_points={ 'console_scripts': })

Ahora puedes usar el comando my-command desde la línea de comandos, que a su vez ejecutará la main
función dentro de exampleproject/example.py. No olvide reinstalar – de lo contrario el comando
no se registrará.

Pruebas

Cuando escriba cualquier código, le recomiendo encarecidamente que también escriba pruebas para este código. Para probar
con python te sugiero que uses pytest. Por supuesto, no quieres añadir pytest a tus dependencias
en install_requires: no es necesario para los usuarios de tu paquete. Para que se instale
automáticamente cuando ejecute las pruebas puede añadir lo siguiente a su setup.py:

setup( # ..., setup_requires=, tests_require=,)

Además tendrá que crear un archivo llamado setup.cfg con el siguiente contenido:

test=pytest

¡Ahora puede simplemente ejecutar python setup.py test y setuptools se asegurará de que se instalen las dependencias necesarias
y ejecutará pytest por usted! Echa un vistazo aquí si
quieres proporcionar argumentos o establecer opciones de configuración para pytest.

Si tienes algún requisito adicional para las pruebas (por ejemplo, pytest-flask) puedes añadirlo a tests_require.

Flake8

Personalmente creo que es una buena idea ejecutar Flake8 para
comprobar el formato de tu código. Al igual que con pytest, no quieres añadir flake8 a las dependencias de
install_requires: no es necesario que esté instalado para poder utilizar tu
paquete. En su lugar, puede añadirlo a setup_requires:

setup( # ..., setup_requires=)

Ahora puede simplemente ejecutar python setup.py flake8. Por supuesto, también puedes fijar la versión
de flake8 (o cualquier otro paquete) en setup_requires:

Si quieres cambiar algunos de los parámetros de configuración de Flake8 puedes añadir una sección a
tu setup.cfg. Por ejemplo:

max-line-length=120

Datos del paquete

A veces puede querer incluir algunos archivos que no son depython en su paquete. Estos
pueden ser, por ejemplo, archivos de esquema o una pequeña tabla de búsqueda. Tenga en cuenta que tales archivos
serán empaquetados junto con su código, por lo que en general es una mala idea incluir
cualquier archivo grande.

Supongamos que tenemos un schema.jsonen nuestro proyecto, que colocamos en exampleproject/data/schema.json.
Si queremos incluirlo en nuestro paquete, debemos utilizar el argumento package_data de setup:

setup( # ..., package_data={'exampleproject': })

Esto hará que el archivo se incluya en el paquete. También podemos elegir incluir
todos los archivos basándonos en un patrón, por ejemplo:

setup( # ..., package_data={'': })

Esto añadirá todos los archivos *.json en cualquier paquete que encuentre.

Ahora no intentes averiguar la ubicación de los archivos instalados por ti mismo, ya que
pkg_resources tiene algunas funciones muy útiles:

  • pkg_resources.resource_stream te dará un stream del archivo, muy parecido al objeto
    que obtienes cuando llamas a open(),
  • pkg_resources.resource_string te dará el contenido del archivo como una cadena,
  • pkg_resources.resource_filename le dará el nombre del archivo (y lo extraerá
    en un temporal si está incluido en un paquete comprimido) por si las dos opciones
    anteriores no se ajustan a sus necesidades.

Por ejemplo, podríamos leer en nuestro esquema usando:

from json import loadfrom pkg_resources import resource_streamschema = load(resource_stream('exampleproject', 'data/schema.json'))

Metadatos

Si vas a publicar tu paquete, entonces probablemente quieras dar a tus
potenciales usuarios algo más de información sobre tu paquete, incluyendo una descripción,
el nombre del autor o mantenedor, y la url a la página principal del paquete.
Puede encontrar una lista completa de todos los metadatos permitidos en los setuptools
docs.

Además, si vas a publicar en PyPI, entonces puedes querer
cargar automáticamente el contenido de tu README.md
en el long_description,
y proporcionar clasificadores para decir pipaún
más sobre tu paquete.

Resumen

Este blog debería ser un buen punto de partida para configurar la mayoría de tus proyectos python.
Si quieres leer más sobre el empaquetado de python echa un vistazo
a la documentación. Aquí hay un ejemplo setup.py
que combina todas las partes mostradas en este blog:

from setuptools import setup, find_packagessetup( name='example', version='0.1.0', description='Setting up a python package', author='Rogier van der Geer', author_email='[email protected]', url='https://blog.godatadriven.com/setup-py', packages=find_packages(include=), install_requires=, extras_require={'plotting': }, setup_requires=, tests_require=, entry_points={ 'console_scripts': }, package_data={'exampleproject': })

y el setup.cfgque lo acompaña:

test=pytestmax-line-length=120

¡Mejora tus habilidades en Python, aprende de los expertos!

En GoDataDriven ofrecemos una gran cantidad de cursos de Python desde principiantes hasta expertos, impartidos por los mejores profesionales del sector. Únase a nosotros y suba el nivel de su juego de Python:

  • Python Essentials – Genial si está empezando con Python.
  • Certified Data Science with Python Foundation – ¿Quiere dar el paso de análisis y visualización de datos a la verdadera ciencia de datos? Este es el curso adecuado.
  • Advanced Data Science with Python – Aprende a producir tus modelos como un profesional y a utilizar Python para el aprendizaje automático.
Footnotes

0: En este blog he utilizado setuptools
para configurar mi proyecto de ejemplo. Alternativamente
también podrías usar distutils,
que es la herramienta estándar para empaquetar en python, pero carece de características
como la función find_packages()y entry_points.
Dado que el uso de setuptools es muy común hoy en día y muchas de sus características
pueden ser particularmente útiles, sugiero que utilices setuptools.

1: Si quieres que la versión de tu paquete también esté disponible dentro de python,
echa un vistazo aquí.

2: También podría listar sus paquetes manualmente, pero esto es particularmente propenso a errores.

3: Alternativamente podría ejecutar python setup.py install, pero el uso de pip tiene
muchos beneficios, entre ellos la instalación automática de dependencias y la
capacidad de desinstalar o actualizar su paquete.

4: También podría utilizar el argumento scripts(ver para
ejemplo aquí)
pero como esto requiere crear un script de shell de python puede no funcionar
tan bien (o en absoluto) en Windows.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.