Tu primera lib de Python ft. PyPI

Como usar y contribuir en Python Package Index🐍

Mauricio Matias C.
9 min readJul 21, 2021
Python packages PyPI
PyPI, https://pypi.org/

A veces es complicado encontrar la biblioteca adecuada para un problema en concreto, muchas veces ni siquiera existe una, y es el punto donde te planteas ¿Qué tal si hago mi propia lib? y cuando menos lo piensas ya tienes una, https://pypi.org/project/kibana-api/ 😆, es lo que veremos en este Post. Por cierto, lib (biblioteca) y paquete son algo distinto dependiendo el contexto, no obstante, mencionaré a ambos como si fueran lo mismo.

PyPI por sus acrónimos Python Package Index es algo así como un compendio libre de paquetes de Python donde la comunidad puede compartir y obtener acceso sin restricciones a tales paquetes, algo que inconscientemente haces cuando usas pip (para instalar/desinstalar algún paquete). Es tan libre que existen paquetes que no tienen ningún sentido, incluso sufre ataques de spam constantemente, tales ataques están protagonizados por personas malintencionadas que suben paquetes basura, no es un lugar para subir un hola mundo o códigos de prueba, pienso que debería tomarse como algo un tanto serio, después de todo es como un patio que compartimos como vecinos jajaja si eres Pythonista claro, así como PyPI cada lenguaje tiene su patio y es común que el caso mencionado pase constantemente, tratemos de cuidarlo 👌.

Requerimientos

Crear una biblioteca no es complejo una vez que llevas tiempo realizando pequeñas aplicaciones y scripts alocados, sin embargo, no es algo que se deba realizar si no tiene un fin, es una cuestión filosófica, dar a conocer un pedazo de código tuyo al mundo 🌎; como tal estos son los requerimientos de conocimientos básicos para realizar tu primer gran paso a la contribución.

  • Tener un propósito, probablemente exista una biblioteca similar a la tuya, asi que puedes preguntarte ¿Qué hace esa lib que la tuya no?¿Porque la tuya es mejor?, las conclusiones vienen por si solas. PyPI no es un espacio regulado y bien o mal tu biblioteca puede indexarse sin controles de calidad, es por ello que tu juicio debe ser claro, se que lo es :D.
  • Conocimientos en GIT, si de software y contribución se trata, GIT resalta por su excelencia ya que aparte de usarlo para gestionar tu código, debes mantenerlo, muchas personas pueden forkear tu repo y hacer PRs esperando contribuir a tu lado, ¡es grandioso!, por lo tanto tu destreza con GIT es importante.

Estructura tu código

Comencemos por ver la estructura de tu código, haremos un pequeño arreglo, esta es la estructura que se recomienda en la mayoría de los casos, si no lo tienes así, no te preocupes, es cuestión de adaptarlo.

│   .gitignore
│ LICENSE
│ README.md
│ setup.py

├─── nombre_de_tu_lib
│ codigo1.py
│ codigo2.py
│ ...
│ __init__.py

└─── tests
tests.py

Abarquemos la estructura poco a poco, el archivo .gitignore es un clásico, cuando subes código a GitHub o cualquier otro GIT based repository, es un archivo en donde se define lo que no quieres que se llega a almacenar o tomar en cuenta en el repositorio, por defecto, lo demás si es tomado en cuenta.

LICENSE, la licencia de tu código es importante, dependerá de que tan libre quieres que este sea; este es un cuadro de comparación de los tipos de licencias que existen y sus características.

Comparativa de licencias de software (magen extraida de BitsAndBuzz Blog)

En mi caso opte por una MIT (similar a la BSD) que a diferencia de otras licencias es la menos restrictiva; MIT hace énfasis en estos tres aspectos:

  1. Condiciones, la condición es que la nota de copyright y la parte de los derechos se incluya en todas las copias o partes sustanciales del Software. Esta es la condición que invalidaría la licencia en caso de no cumplirse.
  2. Derechos, sin restricciones; incluyendo usar, copiar, modificar, integrar con otro Software, publicar, sublicenciar o vender copias del Software, y además permitir a las personas a las que se les entregue el Software hacer lo mismo.
  3. Limitación de responsabilidad, es la ultima parte de la licencia y se encuentra en mayúsculas pa’ que no te olvides jajaja, la intención con todo ese texto es dar a entender que el autor no se hace responsable de ningún daño u otras responsabilidades.

Este es un template de la licencia MIT:

MIT License

Copyright (c) 2021 PON_AQUI_TU_NOMBRE(AUTOR)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

El template se ve deformado, pero la intención es que se vea de otra forma en el archivo de texto al que copies el contenido, no olvide agregarle tu nombre de autoría.

README.md, como su nombre lo indica es lo primero que se debería leer al intentar usar el código, ya que en el se encuentran pautas sumamente importantes como por ejemplo:

  • Descripción
  • Requerimientos tecnológicos
  • Estado de la biblioteca: active, unmaintained, deprecated, etc
  • Ejemplos de uso
  • Detalles extra como: formulas matemáticas, referencias a documentación externa, explicaciones del funcionamiento interno del código, entre otros

Me olvidaba, también necesitas saber la sintaxis del lenguaje de marcado en la que se redacta este archivo 😛, tal lenguaje de marcado se llama markdown en este link te dejo los recursos necesarios para que lo entiendas.

Tocaría profundizar el archivo setup.py (el archivo donde sucede la magia), pero ya lo veremos más adelante, nombre_de_tu_lib es una carpeta en el que debería plasmarse el nombre de tu lib, por ejemplo: kibana_api; en tal carpeta se encuentra tu código estructurado de la manera que creas más conveniente, te sugiero que tu código se encuentre escrito bajo el estándar de código PEP-8, así tu código será más sencillo de entender y leer, por otro lado el archivo __init__.py actúa como puente entre tu código y el exterior, en el archivo __init__.py importas las clases, funciones y variables que desees exportar al exterior, es algo así como la aduana de un país, un archivo __init__.py puede lucir así:

from .codigo1 import ObjectDemo
from .codigo2 import function_demo_1, function_demo_2

solo tiene dos líneas y en todas el objetivo es importar las clases más relevantes de tu lib, para que posteriormente puedan ser importadas usando el nombre del folder directamente:

from nombre_de_tu_lib import ObjectDemo, function_demo_1

Otro aspecto importante es la carpeta tests donde se encuentra el archivo tests.py, a pesar de que sea aburrido realizar tests es una práctica muy recomendable, un DEV saludable las toma siempre en cuenta, hasta hace un tiempo los tests no eran una de mis prioridades, ahora las aplico con más rigurosidad, es más, cuando realizas el código indirectamente haces tests o pruebas, solo que las vas sepultando a medida que construyes el código principal, hacer tests no es más que guardar cada una de esas pruebas que realizas indirectamente en un archivo con este tipo de estructura:

import unittest

class TestStringMethods(unittest.TestCase):

def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')

def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())

def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)

if __name__ == '__main__':
unittest.main()

Este ejemplo de test lo saque de la pagina oficial de documentación de python

Dependiendo del tamaño de tu biblioteca puedes llegar a tener mas funciones de testing o mas clases también, no hay una regla que te impida tener tantos tests como quieras, sin embargo, con que existan los necesarios basta.

Hasta este punto tienes tu código bien estructurado, la documentación redactada correctamente en markdown y la licencia de software convenientemente seleccionada, ya estas list@ para empaquetar tu idea ;D.

setup.py, es el archivo en el cual defines los parámetros que tendrá tu biblioteca en PyPI, este es un ejemplo de archivo setup.py:

Este archivo setup.py esta compuestos por varios argumentos, entendamos algunos de ellos:

  • name, será el nombre de tu lib, es como aparecerá en PyPI la convención es usar el guion “-” como concatenador, por ejemplo: my-awesome-lib
  • version, por ejemplo 1.2.3, 1 es la versión mayor (del software principal), el 2 es nueva funcionalidad incrementa conforme se agreguen más y el 3 se conoce como revisión, por si se modifico algo por un error suscitado o algo así.
  • author, ahí va tu nombre de la forma que gustes ;D.
  • author_email. ahí va tu correo electrónico, te recomiendo usar uno secundario.
  • description, será la descripción que usara PyPI para tu lib en cada una de las páginas en las que aparezca, procura que sea breve y concisa.
  • long_description, si lo notaste el valor que se encuentra en el ejemplo es tomado de una lectura del archivo README.md, es la descripción completa y se adhiere como un string cualquiera, PyPI tiene su propia forma de interpretarlo del lado del servidor ;D.
  • long_description_content_type, le dice a PyPI cual es el formato que tiene el long_description insertado, en este caso será: “text/markdown”
  • license, el nombre de la licencia seleccionada: MIT
  • url, es la URL del sitio principal o host dedicado a la documentación y explicación de tu lib, a menudo ahí se coloca la url del repositorio de tu lib.
  • project_urls, son URLs extra que se le puede pasar en formato de diccionario, esta es la lista completa de parámetros que admite.
  • classifiers, son metadatos que clasifican tu paquete, estos son algunos clasificadores extra.
  • keywords, son palabras claves con las que se relaciona tu proyecto es un arreglo de cadenas, por lo tanto, agrega algo como: [“web”, “machine-learning”, “robotics” ], selecciona algunos términos con los que se relacione tu proyecto.
  • packages, es un arreglo de cadenas que tiene como objetivo identificar la carpeta en la que se encuentra tu lib.
  • package_data, por defecto setup.py agrega archivos .py al paquete generado, se debe especificar explícitamente si se tiene otros tipos de archivos importantes para la lib.
  • install_requires, seguramente te suena a requirements.txt, es algo así solo que en este caso no se alimentar del requirements.txt como tal, si no de un proceso manual de selección de paquetes de los cuales depende la lib (en formato de arreglo de cadenas), por ejemplo: [“requests”, “numpy”, “pandas”].
  • python_requires, es importante ya que anuncia la compatibilidad de tu lib en función de la versión de Python en la que este programada, dependerá de que tan compatible hagas tu código a versiones menores (mientras más compatible, mejor), por ejemplo puede ser: “>=3.6” , “3.8”, “<2.7”, etc; link para más ejemplos.

Construcción del Paquete

setup.py es otro fragmento de código en Python más, pero es importante ya que se encarga de realizar el build de tu lib o paquete. Una vez tengas listo tu archivo setup.py, introduce el comando:

python setup.py sdist

Acto seguido, aparecerá un directorio con el nombre dist, que fue generado automáticamente por el comando anterior, dentro del mismo verás que existe un archivo comprimido (por ejemplo: nombre-de-tu-lib-0.0.1.tar.gz), es tu lib empaquetada y comprimida.

Es recomendable instalar y probar de forma local el paquete que generaste antes de subirlo a PyPI, el siguiente comando te ayuda con ello:

pip install -e ./dist/nombre-de-tu-lib-0.0.1.tar.gz

Finalmente nos ponemos cara a cara con PyPI ya solo que da unos cuantos pasos, crea tu cuenta personal en PyPI verifícate correctamente y recuerda tus credenciales, las necesitaremos.

PyPI usa un paquete utilitario llamado twine para subir paquetes a PyPI lo instalaremos con pip, posteriormente ya podemos usar twine para subir los archivos de la carpeta dist:

pip install twine twine upload dist/*

Introduce tus credenciales correctamente y ¡Listo!… ya tienes tu lib como paquete indexado en PyPI, si necesitas un ejemplo real puedes revisar esta lib o la lib que hice para mapear algo de la API de Kibana.

Casi al finalizar este Post me tope con este video de YouTube, si tienes algo de tiempo te lo recomiendo, habla de lo mismo, pero con más experiencia 😆.

Espero que te haya sido útil, pero no me voy sin una frase de regalo jajaja:

Criptomonedas vemos, futuros valores no sabemos :C

hasta el próximo Post 👋. Se despide cr0wg4n.

--

--