Publicando artefactos Python
Hace un par de semanas que comencé un proyectillo Python que se ha transformado en mi primer paquete pypi serio. Bueno, realmente se ha transformado en dos paquetes, lo que me ha hecho darme cuenta de lo repetitivo de algunas tareas… Y cómo no, he decidido compartirlo aquí.
Así aprovecharé para contar algunas lecciones aprendidas, ahorrando así tiempo la próxima vez y ayudando a otros. De hecho, ya estoy preparando el siguiente XD
Comenzaré desde el principio del todo: la creación del repositorio.
Antes de publicar
Creando un repositorio
Lo primero es crear un repositorio. No me voy a liar aquí a contar cómo hay que hacerlo, porque ya conté en su día cómo crear un repositorio Git. Baste decir que recomiendo Git en GitHub, y más tarde veremos por qué.
README
Lo primero en el repositorio es crear el archivo README. En principio, tenemos varios formatos a elegir… Pero si queremos reutilizarlo para que se muestre lo mismo en pypi y en GitHub, es recomendable usar ReStructured Text, que es lo único que entiende pypi. Por lo tanto, debería llamarse README.rst.
Estructura
Lo segundo a tener en cuenta es la estructura de directorios. Recomiendo la siguiente:
|
|
En este tutorial me ha quedado muy largo porque tengo que mostrar casi todos ellos, pero podéis ver dos ejemplos funcionales: python-readchar y python-inquirer. Recomiendo el primero por ser más sencillo.
Pues ya tenemos el repositorio y un archivo… ¡Comencemos!
Comenzando el proyecto
Lo mejor es comenzar por definir el proyecto, con el archivo setup.py. Para su concepción recomiendo echar un ojo a las setuptools. Como suelo hacerle algún hack, os muestro un ejemplo:
setup.py
|
|
Varias cosas aquí: como veis, importo la versión y la descripción del propio paquete Eso me facilita tocar un único punto (más o menos) a la hora de crear el paquete. Luego veremos este archivo. El nombre de variable __version__
es estándar, vamos, que se tiene que llamar así.
Además, la descripción larga la leo del propio archivo README.rst que comenté antes, de manera que se vea chulo en línea de órdenes y en pypi. Tened cuidado, porque cualquier error y pypi no lo renderizará como debe. GitHub es bastante más permisivo.
Finalmente, en el apartado install_requires
podéis añadir todas las dependencias de la misma manera que en el requirements.txt. Intenté un hack para leerlo, pero durante la instalación no me lo encontraba… Así que opté por eliminar el archivo y gestionar los requisitos desde aquí. Es un tema sobre el que tengo que volver.
<paquete>/__init__.py
|
|
Es necesario algo así para que lo lea bien nuestro programita setup.py. Para la versión hay mogollón de opiniones… La mía es que con dos ó tres números es suficiente. Tres como mucho si usais la fecha con formato YYYYMMDD (mayor.fecha.minor
).
Probando
Un paquetito que se precie debe estar acompañado de pruebas… Y a ser posible de porcentajes de cobertura. Pues podemos usar herramientas gratuitas para ello: Travis y Coveralls.
Travis
Es un sistema de integración continua gratuito para proyectos libres y de pago para los que no lo son. Permite ejecutar los tests de todos los changesets. Se configura mediante el archivo .travis.yml, situado en el directorio principal y con formato YAML. Veamos un ejemplo:
|
|
Básicamente crea un ejecutor para cada versión de Python y ejecuta los scripts del install
y script
, y si todo va bien, el after_success
. Hay más pasos en el ciclo de vida, pero podéis verlos en la documentación de Travis.
Para que funcione, tenéis que:
- daros de alta en Travis,
- sincronizar vuestros proyectos GitHub (ahora entendéis por qué lo recomendaba, ¿eh?),
- dar permisos a Travis para instalar un hook en el repositorio,
- y activarlo para el repositorio de vuestro proyecto.
Los tres primeros se hacen sólo una vez y el último hay que repetirlo cada vez que comencemos un proyecto.
Como veis, el paso de after_success
es llamar al plugin de Coveralls.
Coveralls
Requiere de un plugin para invocarlo. Yo suelo utilizar python-coveralls, pero también está disponible coveralls-python (no, no me estoy quedando con vosotros). Se configura con el archivo .coverage:
|
|
Además de instalar el paquete correspondiente, es necesario darse de alta en Coveralls. Veréis información sobre claves SSL en la documentación y tal… pero eso sólo es para los proyectos privados.
Es necesario generar el archivo .coverage para que Coveralls muestre los resultados correctamente. Si usais nose, como yo, necesitaréis también nosexcover.
Gestión
Veamos cómo orquesto toda esta maraña de archivos: mediante virtualenv. Siempre me creo el entorno venv
y lo añado al archivo .gitignore:
|
|
Claro… He mencionado mogollón de historias, pero no mis herramientas, que están en el requirements-dev.txt:
|
|
Me gusta indicar las versiones, por si algo se rompe por sorpresa, tenerlo controlado.
Además de éstas, suelo instalarme siempre ipython, pero no lo incluyo aquí porque es meter demasiada carga a Travis cuando no lo va a usar.
Y, finalmente, el director de la orquesta, el archivo Makefile:
|
|
Publicación
Ya sólo nos queda publicar el paquete en pypi. Para ello seguiremos los siguientes pasos:
- Registrarse en la web de pypi
- Registrar el paquete:
python setup.py register
- Empaquetar y subir:
python setup.py sdist upload
Como veis, yo distribuyo los fuentes, ya que los binarios me dieron problemas.
Afinando
Y sólo me queda contar cómo poner los iconos monos XD
Tanto Travis como pypi y Coveralls disponen de unos iconos accesibles con la misma URL. Como hemos dicho, vamos a usar el formato ReStructured Text, así que ésta es la manera más chula:
|
|
Como véis, hay que cambiar <USER>
, <REPOSITORY>
y <PIP_NAME>
, y vale para cualquier proyecto.
Más información
Hay muchas cosas en el tintero aún, como subir la documentación a read the docs, pero este artículo ya tiene suficiente caña XD
Recomiendo indagar un poquito en cada herramienta si queréis ampliar funcionalidad.