En este post veremos como publicar un paquete de software al repositorio pypi.python.org (Python Package Index), así estará disponible públicamente y para que cualquiera lo instale sólo hará falta usar `pip install nombre_del_paquete`.

Si tienes un módulo o paquete python que te ha servido mucho, lo hayas escrito tu o con amigos, puedes compartirlo en el repositorio [https://pypi.python.org](https://pypi.python.org) y así le servirá a cualquiera que lo necesite. En este post veremos el proceso paso a paso, empecemos.

## ¿ Qué es pypi.python.org ? ##

Pypi.python.org es un repositorio público que alberga software escrito en el lenguaje de programación python. A esta fecha hay más de 129000 paquetes disponibles.

Este repositorio facilita enormente en el desarrollo de software, por que para incluir uno o varios módulos, sólo hace falta utilizar [pip](https://pip.pypa.io/en/stable/) en un entorno de sistema o virtual para un programa que estemos escribiendo.

Por ejemplo para este sitio web, utilizo el [micro-framework Flask](http://flask.pocoo.org/) y otros paquetes python, de **no ser por pip** para instalarlo tendría que posiblemente descargarme el código fuente y hacer una serie de pasos manuales para que esta página web pueda utilizar sus funcionalidades. Pero gracias a pip y el repositorio pypi.python.org para instalar flask se puede hacer comdamente en un entorno virtual:

    :::bash
    mkdir nombre_proyecto
	cd nombre_proyecto
    virtualenv venv
    source venv/bin/activate
    # con la siguiente línea se descargará e instalará todo el framework Flask
    # en el entorno virtual de nuestra computadora (la carpeta venv)
    # y estará listo para usarse.
    pip install flask


## Escribiendo el paquete o módulo python ##

Este el paso más largo e importante, una vez tengamos el módulo python funcional es cuando debemos pensar en si lo vamos a compartir con el resto del mundo. Para este ejemplo he escrito un pequeño paquete en python llamado simplemotds.

### Rápidamente sobre simplemotds ###

El paquete [simplemotds](https://pypi.python.org/pypi/simplemotds) ayuda a obtener un mensage del día y que cambie automáticamente, de ahí el nombre simple motds (motd = *Message Of The Day*).

Básicamente lo que hace es leer un directorio con archivos donde cada uno tiene un mensaje o consejo del día, al llamar al método `getMotdContent()`, este devuelve el contenido del archivo seleccionado para el día de hoy. Al día siguiente este mensaje cambiará automáticamente.

Adicionalmente a este módulo se le puede configurar fácilmente para que el mensaje cambie por ejemplo al cabo de un mes, una semana, una hora o hasta un minuto. La selección del mensaje tambíen puede cambiarse.

Para más detalles puedes ver el [código fuente de python-simplemotds](https://notabug.org/strysg/python-simplemotds) y una demostración de cómo funciona se la ve en esta misma página que muestra los consejos para cada día utilizando simplemotds.

## La estructura necesaria para subir el paquete python ##

Hay un buen tutorial para empaquetar software python [ [1] ](http://www.diveintopython3.net/packaging.html), para el ejemplo de simplemotds, tenemos la siguiente estrucutra:

    :::bash
    ├── LICENSE.txt
    ├── MANIFEST.in
    ├── README.md
    ├── setup.cfg
    ├── setup.py
    └── simplemotds     # esta es la carpeta con el software en si
        ├── config.json
        ├── __init__.py
        ├── messages   
        │   ├── m1.html
        │   ├── m2.html
        │   └── m3.html
        └── simplemotds.py

Independientemente del módulo python que desarrollemos, son obligatorios los archivos: `LICENSE.txt`, `MANIFEST.in`, `README` y `setup.py`. Estos son la meta-data que pypi.python.org usará para identificar nuestro paquete y deben estar **un directorio arriba de nuestro módulo**. Algo que difiere es que el archivo README debería estar en formato rst según la documentación oficial de python [ [2] ](https://packaging.python.org/tutorials/distributing-packages/#readme-rst).

El paquete simplemotds es tan simple que sólo tiene un archivo de código fuente `simplemotds.py` aunque también tiene otros archivos como `config.json` y un directorio `messages` donde hay unos mensajes de prueba, por supuesto para que python interprete el directorio como un módulo está el archivo `__init__.py`.

### setup.py ###

Este archivo es muy importante y se utiliza para configurar la instalación del paquete, para nuestro caso su contenido es:

    :::python
    from setuptools import setup, find_packages
    
    setup(
        name = 'simplemotds',
        packages = ['simplemotds'],   
        include_package_data=True,    # muy importante para que se incluyan archivos sin extension .py
        version = '0.23',
        description = 'Configurable package that returns the message of the day (motd)',
        author='Rodrigo Garcia',
        author_email="strysg@riseup.net",
        license="GPLv3",
        url="https://github.com/strymsg/python-simplemotds",
        classifiers = ["Programming Language :: Python :: 3",\
		    "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",\
			"Development Status :: 4 - Beta", "Intended Audience :: Developers", \
			"Operating System :: OS Independent"],
		)

Para empaquetar este proyecto usaremos la biblioteca [setuptools](https://pypi.python.org/pypi/setuptools) y es mejor tenerla instalada en el sistema en su versión más reciente, si usamos una distribución de GNU linux basada en debian podríamos instalarlo con `sudo apt install python-setuptools`, pero puede que el paquete debian no sea actualizado, en todo caso podríamos utilizar pip.

    pip install -U pip setuptools    # que instalará setuptools en el sistema

* `name`: Es el nombre del paquete.
* `packages`: Es la lista de paquetes que contiene nuestro módulo, para el caso de simplemotds sólo existe un paquete que se llama simplemotds.
* `include_package_data`: Por defecto setuptools sólo empaqueta archivos con estensión .py, en este cas se utiliza un archivo de configuración `config.json` y varos archivos de prueba `.html`, esta variable debe ser `True` para que sean incluidos.
* `version`: La versión del paquete (debemos cambiarla cada que necesitemos actualizar.
* `description`: Una descripción corta
* `author` y `author_email`
* `license`: Obligatorio especificar una licencia de software libre o al menos código abierto, puedes revisar [esta guía](https://hipertextual.com/archivo/2014/05/como-elegir-licencias-open-source/) si no sabes cuál escoger. `url`: Sitio web donde se puede revisar el proyecto.
* `calssifiers`: Sirven para clasificar apropiadamente tu paquete en pypi.python.org [ [1] ](http://www.diveintopython3.net/packaging.html#trove).

Hay más opciones [ [2] ](https://packaging.python.org/tutorials/distributing-packages/#setup-args), [ [3] ](https://setuptools.readthedocs.io/en/latest/setuptools.html).

### MANIFEST.in ###

Este archivo es para especificar archivos adicionales [ [1] ](http://www.diveintopython3.net/packaging.html#manifest), para este caso queremos incluir el archivo `config.json` y los mensajes de prueba dentro el directorio `messages/`.

    recursive-include simplemotds config.json
    recursive-include simplemotds/messages *.html

Con esta configuración básica tenemos lo necesario para empaquetar el software python y luego subirlo.

## Empaquetando ##

Para empaquetar ejecutamos en el directorio raíz del proyecto:

    python setup.py sdist

Lo que ocurrirá será que se interpreta `setup.py` se aplican las configuraciones y se leerá el archivo `MANIFEST.in` para incluir archivos adicionales. Una vez se termina, todo el módulo python quedará dentro un archivo `.tar.gz` **dentro el directorio** `dist`/ que setup creará.

En el caso de simplemotds se ha empaquetado en `simplemotds-0.23.tar.gz`, deberíamos revisar en el archivo comprimido si esta todo lo que se requiere.

## Subiendo el archivo empaquetado ##

Primero es necesario que tengamos una cuenta de usuario en pypi.python.org, [afortunadamente el registro es libre](https://pypi.python.org/pypi?%3Aaction=register_form).

### .pypirc (opcional) ###

Una vez hayamos creado la cuenta para facilitar el proceso de autenticación con pypi.python.org, podemos incluir las credenciales de la cuenta que tengamos en pypi.python.org en un archivo. Usualmente el archivo debería estar en el directorio HOME del usuario actual es decir `$HOME/.pypirc`, luego en ese archivo poner las credenciales de la siguiente manera:

    [pypi]
    username = <usuario>
    password = <password>

Para que el archvivo este más seguro:

    :::bash
    chmod 600 $HOME/.pypirc

Una nota sobre passwords [ [4] ](http://peterdowns.com/posts/first-time-with-pypi.html).

### Instalando twine para facilitar la subida del paquete ###

Para subir el paquete he utilizado la herramienta [twine](https://github.com/pypa/twine) que ayuda a interactuar con [PyPI](https://packaging.python.org/glossary/#term-python-package-index-pypii) enviando las credenciales, y subiendo el paquete que preparamos antes al repositorio PyPI.

Twine no viene por defecto con python y por eso hay que instalarlo en el sistema, usualmente se debería poder con `sudo apt install twine`, pero en el caso de mi distribución la versión de twine estaba muy desactualizada y al tratar de usarlo retornaba error 401 [ [5] ](https://stackoverflow.com/questions/45207128/failed-to-upload-packages-to-pypi-410-gone).

Para solucionarlo he tenido que desinstalar twine del sistema e instalar la última versión estable con pip:

    pip install -U pip setuptools twine

Luego confirmar la versión de twine con `twine --version` que debería devolver 1.9.1 o superior

**Nota:** En mi sistema (basado en ubuntu 16) hubo el problema que al desinstalar twine con `sudo apt-get purge twine` e instalarlo con pip, la referencia a la nueva versión de twine no se resolvía correctamente, entonces uso `whereis twine` que me dice que el binario de twine está en `/usr/local/bin/twine`. Para llamar al twine correcto uso `/usr/local/bin/twine` seguido de las opciones.

### Subiendo el paquete ###

Ahora usamos:

    twine upload dist/*

Que subirá a pypi.python.org lo que tengamos en el directorio dist/ que es donde quedó empaquetado nuestro paquete python.

Una vez se haga esto correctamente deberíamos comprobar ingresando a [https://pypi.python.org](https://pypi.python.org) y buscando por el nombre del paquete que hemos subido recién.

### Habilitando para que esté disponible usando pip ###

En pypi.python.org es necesario indicar explícitamente que versión de nuestro paquete estará disponible públicamente. Par eso debemos ingresar con nuestra cuenta de usuario al sitio y revisar la página relacionada a nuestro paquete, luego **liberarla** manualmente. Para el caso de simplemotds, la imagen siguiente muestra como hacerlo.

![simplemotds_en_pypi.python.org](/static/imgs/posts/pypi-simplemotds.jpg)

Como se ve, se listan las versiones que he subido de simplemotds, finalmente para **liberar** la última versión solo se hace click en *Update Releases*.

Bien, ahora si desde cualquier proyecto utilizamos

    pip search simplemotds

Nos devuelve:

    simplemotds (0.23)  - Configurable package that returns the message of the day
                          (motd)

Esto indica que el paquete simplemotds se ha subido correctamente al índice de paquetes python https://pypi.python.org y por eso para cualquier proyecto lo podemos instalar con:

    pip install simplemotds

### Conclusión ###

Puede que subir un paquete la primera vez sea algo tedioso, sin embargo como vimos existen las herramientas necesarias para hacerlo bien y facilitar el proceso.

Si tienes un pedazo de código tuyo escrito en python que funcione bien como módulo, piensa en compartirlo con todo el mundo o también si te gusta un módulo de python en especial haz tu aporte para mejorarlo y que otr@s se beneficien ;)

## Referencias

1. [Guía detallada para empaquetar bibliotecas python y subirlas a pypi.org](http://www.diveintopython3.net/packaging.html#manifest)
2. [Documentación oficial de python para empaquetar y distribuir paquetes](https://packaging.python.org/tutorials/distributing-packages/)
3. [Documentación de setuptools](https://setuptools.readthedocs.io/en/latest/setuptools.html)
4. [Post rápido para subir paquetes (desactualizado pero útil como referencia)](http://peterdowns.com/posts/first-time-with-pypi.html).
5. [Error 401 al enviar paquetes (hilo en stackoverflow)](https://stackoverflow.com/questions/45207128/failed-to-upload-packages-to-pypi-410-gone)
