# 🏗️ Cómo publicar tu propia librería de Python: Guía paso a paso

---

El objetivo de este tutorial es guiarte paso a paso en el proceso de creación y publicación de tu propia librería en Python. Aunque Python ofrece una biblioteca estándar muy completa, aprovechar las contribuciones de la comunidad en [PyPI](https://pypi.org/) te permite extender sus capacidades y crear soluciones personalizadas que se adapten a tus necesidades.

La motivación detrás de este proyecto es doble: por un lado, adquirir un conocimiento profundo sobre el proceso de preparación, versionado, construcción y despliegue de paquetes; y por el otro, consolidar un repositorio centralizado de herramientas que funcione como una tarjeta de presentación profesional en el mundo del desarrollo.

%[https://github.com/rafnixg/rafnixg-lib] 

## 🧭 Introducción y primeros pasos

El primer paso es comprender el ecosistema de paquetes en Python, especialmente el rol fundamental que juega [PyPI](https://pypi.org/) (Python Packaging Index). Este es el repositorio oficial de paquetes de Python, y alberga una vasta colección de librerías, desde implementaciones simples hasta complejas soluciones en áreas como ciencia de datos, inteligencia artificial y desarrollo web.

Al entender cómo se organizan y distribuyen los paquetes en [PyPI](https://pypi.org/), puedes orientar el desarrollo de tu librería para que cumpla con los estándares que facilitan su instalación y uso por parte de otros desarrolladores. Además, al prepararla para su publicación, te adentras en prácticas modernas como el versionado semántico y la automatización del despliegue.

Nuestro inicio en el mundo de las librerías lo vamos a tener en la próxima sección donde ya iniciaremos el código fuente que usaremos como base para todo el proceso de tener nuestra propia librería en [PyPI](https://pypi.org/).

[https://pypi.org/project/rafnixg/](https://pypi.org/project/rafnixg/)

## 🏗️ Crear la base de tu librería en Python

En esta sección crearemos el código base que usaremos para subir a PyPI, tú puedes usar este código como ejemplo o ser libre de usar el código de tu preferencia, y saltar a la siguiente sección.

Si te quedaste acá el paquete que vamos a crear se llama `rafnixg` y muestra por consola tus datos personales y por otro lado podrá ser usado en tu propio código para descargar post de tu blog de ***HashNode*** usando ***GraphQL***. Este es básicamente mi caso de uso de ejemplo, pero tu librería puede tener las funciones que tu consideres necesarias.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743543201582/f92974d6-c2cd-4bd3-b85c-4654144a89c7.png align="center")

Para lograr obtener este diseño de card vamos a hacer uso de la librería `rich` que nos ayuda a crear diseños de tablas para la terminal de forma fácil, los invito a revisar el potencial de `rich`, puede agregar iconos, gestionar paleta de colores, Markdown.

%[https://pypi.org/project/rich/] 

### 🧪Preparación del entorno de desarrollo

Para este caso hare uso de **VSCode** pero puedes usar el editor que prefieras, acá lo importante es crear un entorno virtual de Python para aislar las dependencias y no tener problemas en el futuro.

```powershell
$ python -m venv env
$ source env/bin/activate  # Para Linux
$ env\Scripts\activate    # Para Windows
(env) $ pip install rich
```

Lo segundo será crear un archivo `.gitignore` que nos ayudará a indicar que no queremos que se suba a nuestro repositorio, podemos hacer uso de la siguiente web para generar uno con la configuración para Python.

[Create Useful .gitignore Files For Your Project](https://www.toptal.com/developers/gitignore)

```powershell
# Created by https://www.toptal.com/developers/gitignore/api/python
# Edit at https://www.toptal.com/developers/gitignore?templates=python

### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

env
.env
/venv
venv

# End of https://www.toptal.com/developers/gitignore/api/python
```

> Debemos recordar que es importante evitar subir archivos con contenido sensibles como API Keys, Claves o algún tipo de información que permita acceso no autorizado.

Luego de esto inicializamos nuestro repositorio de `git` y creamos nuestra estructura de archivos.

```powershell
(env) $ git init
```

### 📁 Estructura del proyecto

Toda librería de Python inicia dentro de una carpeta, así que para esto cree el directorio `rafnixg-lib` y dentro creo la siguiente estructura de archivos:

```plaintext
rafnixg-lib/
│
├── src/
│   └── rafnixg/
│       ├── __init__.py
│       ├── __main__.py
│       └── rafnixg.py
│
├── LICENSE
├── README.md
└── pyproject.toml
```

Todo el código fuente se encuentra de `src/` esto no es obligatorio, pero es una buena práctica. Si estas usando tu propio código, dentro de `src/` es donde debería ir para mantener la mejor estructura.

En esta sección nos enfocaremos en los archivos de Python y en las siguientes secciones veremos estos archivos especiales `LICENSE, README.md, pyproject.toml`.

### 🧾 Crear el archivo principal src/rafnixg/rafnixg.py

```python
"""src/rafnixg/rafnixg.py
RafnixG - Personal Card
"""

from rich.console import Console
from rich.table import Table


class RafnixG:
    """RafnixG - Personal Card"""

    def __init__(self):
        self.username = "rafnixg"
        self.name = "Rafnix Guzmán"
        self.position = "Python Software Developer"
        self.links = "https://links.rafnixg.dev"
        self.web = "https://rafnixg.dev"
        self.blog = "https://blog.rafnixg.dev"
        self.cv = "https://resume.rafnixg.dev"
        self.github = "https://github.com/rafnixg"
        self.twitter = "@rafnixg"
        self.about = "Experienced software developer with 10+ years of expertise in designing, developing and implementing web systems across various sectors. Backend specialist skilled in Python, Linux, and Git. Passionate about continuous learning and open-source technology."

    def __str__(self):
        return f"{self.name} (@{self.username}) - {self.position}"

    def display(self):
        """Display personal card"""
        # Crea un objeto Console para imprimir en la consola
        console = Console()
        table = Table(
            show_header=False, # No mostrar encabezados
            title=str(self), # Título de la tabla
            highlight=True, # Resaltar la tabla
            title_style="bold magenta", # Estilo del título
        )
        # Agrega columnas a la tabla
        table.add_column("Attribute", style="bold", width=16)
        table.add_column("Value")
        # Agrega filas a la tabla con los atributos y valores de la clase
        # Itera sobre los atributos de la clase y los agrega a la tabla
        for key, value in self.__dict__.items():
            if isinstance(value, dict):
                for sub_key, sub_value in value.items():
                    table.add_row(sub_key, ", ".join(sub_value))
            elif isinstance(value, list):
                table.add_row(key, ", ".join(value))
            else:
                table.add_row(key, value)
        # Imprime la tabla en la consola
        console.print(table)
```

### 🧩 Inicializar el paquete con src/rafnixg/\_\_init\_\_.py

```python
"""src/rafnixg/__init__.py
RafnixG - Personal Card
"""
from rafnixg.rafnixg import RafnixG

__version__ = "1.0.0"
```

### 🧩 Ejecutar como modulo con src/rafnixg/\_\_main\_\_.py

```python
"""src/rafnixg/__main__.py
RafnixG - Personal Card
"""
from rafnixg import RafnixG


def main():
    """Main function."""
    me = RafnixG()
    me.display()

if __name__ == '__main__':
    main()
```

### 🖥️ Ejecutar y probar tu código localmente

Para probar nuestro código debemos movernos a la carpeta `src/` y luego correr el paquete como un módulo de Python:

```powershell
(env) $ cd src
(env) $ ls
  rafnixg/
(env) $ python -m rafnixg
```

Recuerda que si estas usando tu código aquí debes colocar el nombre la carpeta que contiene tu código fuente.

## 📦 Preparar la librería para ser publicada

### 📘Documentando nuestra librería

Un **README** es esencial para cualquier proyecto ya que aquí es donde otros desarrolladores y usuarios obtendrán información sobre tu librería, en este archivo no solo se explica que es y lo que hace tu proyecto, sino que también contiene información de como instalarlo, utilizarlo y contribuir. En una próxima publicación profundizaremos más sobre el **README** y que debería contener, por los momentos creamos el archivo `README.md` con el siguiente contenido:

````markdown
# Rafnix Guzmán - Personal Card (README.md)

## Hi there 👋

This is my personal card [rafnixg.dev](https://rafnixg.dev)

![image](https://github.com/user-attachments/assets/4c1c368b-83ca-4ff7-89d0-c131efe60c9f)


## How to use it? 🤔

Install using pip:

```bash
pip install rafnixg
```

Then run it:

```bash
rafnixg
```
````

### 🛠️Configurar el sistema de construcción (build system)

Para preparar nuestra librería para ser publicada en ***PyPI*** necesitamos configurar algunas secciones en el archivo `pyproject.toml` primero debemos indicar el **build system** que es la parte responsable de crear los archivos que se suben a PyPI, usualmente se usa el formato **wheel** o **sdist**.

Nosotros usaremos el [setuptools](https://setuptools.pypa.io/) como **build system.**

```ini
# pyproject.toml

[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"
```

### 🗂️ Organizar el archivo `pyproject.toml`

Ahora agregaremos una sección para configurar información del proyecto, acá es donde indicaremos el nombre de nuestro paquete, recordemos que debemos verificar que el nombre no este usado por ningún otro paquete dentro del ecosistema ***PyPI***.

```ini
# pyproject.toml
...

[project]
name = "rafnixg"
version = "1.0.0"
description = "Rafnix Guzman Personal Card"
readme = "README.md"
authors = [{ name = "Rafnix Guzman", email = "rafnixg@gmail.com" }]
license = { file = "LICENSE" }
classifiers = [
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python",
    "Programming Language :: Python :: 3",
]
keywords = ["personal card", "console"]
dependencies = [
    "rich",
]
requires-python = ">=3.9"

[project.optional-dependencies]
dev = ["black", "bumpver", "isort", "pip-tools", "pytest"]

[project.urls]
Homepage = "https://github.com/rafnixg/rafnixg-lib"

[project.scripts]
rafnixg = "rafnixg.__main__:main"
```

> No toda esta información es obligatoria, pero es importante dar la mayor cantidad de información posible sobre nuestra librería, la información mínima que podemos ingresar es `name` y `version` .

Las siguientes secciones son importantes por la información que le proporcionan a PyPI:

* `classifiers`: Lista de [classifiers](https://pypi.org/classifiers/) de ***PyPI*** que ayudan a la búsqueda.
    
* `keywords`: Lista de etiquetas que seran usadas para identicar y categorizar la libreria.
    
* `dependencies`: Lista de dependencias que tu librería necesita, en nuestro caso **rich.**
    
* `project.optional-dependencies`: Lista de las dependencias de desarrollo.
    
* `project.urls`: Links que relacione a tu proyecto en github o alguna página web.
    
* `project.scripts`: Punto de entrada para tu librería. en este caso el comando será `rafnixg` y el punto de entrada será `rafnixg.__main__:main`
    

Toda esta información hace que en ***PyPI*** tu librería se vea mucho mejor y cuando se haga una búsqueda también sea más fácil de encontrar. acá un ejemplo de la información que se muestra en ***PyPI***:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743546709575/1b54dd48-9bb9-434e-aa6f-4b27c783be9b.png align="center")

Vemos como también usa el archivo `README.md` para mostrar del lado derecho la documentación de la librería en ***PyPI***, y los datos del archivo `pyproject.toml` también se muestran a la izquierda.

Para saber más sobre este archivo de configuración acá esta la [documentación](https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html).

### 🔢 Usar versionamiento semántico

Toda librería debe tener un versionamiento para poder tener un control de lo que se publica, existen diferentes esquemas de versionamiento, en nuestro caso usaremos [Semantic Versioning](https://semver.org/) que es una forma simple de gestionar el versionamiento formado por 3 grupo de números, ejemplo: **MAJOR.MINOR.PATCH** las recomendaciones para cambiar estos números son:

* **MAJOR**: Cuando tus cambios son tan grandes que rompen tu API anterior.
    
* **MINOR**: Cuando agregas nuevas funciones y todo se mantiene compatible, Vuelve a 0 cuando MAJOR cambia.
    
* **PATCH**: Cuando agregas bug fixes, vuelve a 0 cuando MINOR cambia.
    

Para gestionar esto en Python haremos uso de una librería llamada `bumpver` esto modifica directamente los archivos y así mantiene sincronizado en todos lados la versión.

```powershell
(venv) $ python -m pip install bumpver
(venv) $ bumpver init
WARNING - Couldn't parse pyproject.toml: Missing version_pattern
Updated pyproject.toml
```

Este comando inicializa en `pyproject.toml` la gestión de las versiones, si vemos agrego una nueva sección:

```ini
[tool.bumpver]
current_version = "1.0.0"
version_pattern = "MAJOR.MINOR.PATCH"
commit_message = "bump version {old_version} -> {new_version}"
commit = true
tag = true
push = false

[tool.bumpver.file_patterns]
"pyproject.toml" = [
    'current_version = "{version}"',
    'version = "{version}"'
]
"src/rafnixg/__init__.py" = ["{version}"]
```

Si no se parece a esta ajustar el `version_pattern` para que sean iguales, después de configurar esto, tú puedes cambiar la versión usando los comandos de `bumpver`:

```powershell
(venv) $ bumpver update --minor
INFO    - Old Version: 1.0.0
INFO    - New Version: 1.1.0
INFO    - git commit --message 'bump version 1.0.0 -> 1.1.0'
INFO    - git tag --annotate 1.1.0 --message '1.1.0'
```

### 📜 Elegir una licencia adecuada

Cuando creamos una librería debemos elegir que permisos queremos que los demás tengan sobre nuestro código, así se podrá saber qué es lo que quiere que se haga o no con tu librería. Una licencia muy usada para compartir código es la [Licencia MIT](https://mit-license.org/) con esta licencia simple y bastante permisiva.

Lo que debemos hacer es crear un archivo de texto llamado `LICENSE` que contenga el texto de nuestra licencia, si no sabes que licencia escoger existe esta web que permite ver cuál es la más conveniente según tus necesidades: [Choose an open source license](https://choosealicense.com/)

### 📥 Instalar tu librería localmente

Para este punto ya tenemos nuestra librería lista para ser publicada, ahora lo que vamos a necesitar hacer es probar nuestra librería instalándola directamente en nuestro entorno virtual, para esto haremos uso de los siguientes comandos:

```powershell
(env) $ python -m pip install -e .
```

Con el flag `-e` se instala tu librería en modo editable y con `.` indicamos donde se encuentra el archivo `pyproject.toml` esto ya deja disponible nuestro comando `rafnixg` que está definido en la sección `project.scripts` indicando el punto de entrada.

```powershell
(env) $ rafnixg
                            Rafnix Guzmán Garcia (@rafnixg) - Python Software Developer                             
┌──────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────┐
│ username         │ rafnixg                                                                                       │
│ name             │ Rafnix Guzmán Garcia                                                                          │
│ position         │ Python Software Developer                                                                     │
│ links            │ https://links.rafnixg.dev                                                                     │
│ web              │ https://rafnixg.dev                                                                           │
│ blog             │ https://blog.rafnixg.dev                                                                      │
│ cv               │ https://resume.rafnixg.dev                                                                    │
│ github           │ https://github.com/rafnixg                                                                    │
│ twitter          │ @rafnixg                                                                                      │
│ about            │ Experienced software developer with 10+ years of expertise in designing, developing and       │
│                  │ implementing web systems across various sectors. Backend specialist skilled in Python, Linux, │
│                  │ and Git. Passionate about continuous learning and open-source technology.                     │
└──────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────┘
```

## 🚀 Publica tu librería a PyPI

Ya nuestra librería se encuentra lista y a la espera de conocer el mundo, en esta sección haremos el empaquetado y despliegue a **PyPI.**

### 🧑‍💻 Crear cuentas en PyPI y TestPyPI

Lo primero que debemos tener es una cuenta en ***PyPI***, así que si no la tienes este es tu momento de registrarte: [https://pypi.org/account/register/](https://pypi.org/account/register/)

También deberíamos crear una cuenta en el ambiente de pruebas de ***PyPI***, así siempre podemos verificar que todo va bien antes de lanzar algo a producción: [https://test.pypi.org/account/register/](https://test.pypi.org/account/register/)

Recuerden crear sus `API Key` porque en el proceso de publicación mas adelante serán necesarias.

### 🔐 Generar una API Key

Para esto ingresamos a [Configuracion de la cuenta](https://pypi.org/manage/account/) bajamos y buscamos la opción **Fichas de API**, hacemos clic en el botón `Añadir ficha de API`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743792251750/e6005144-893b-4ebd-9ace-3ffe2dff784a.png align="center")

Luego le ponen algún nombre descriptivo a esta **Key**, seleccionamos el **Alcance** y por último clic al botón `Create Token`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743792355464/0d294b80-640d-4b6b-8434-4965cb2ca50b.png align="center")

Con esto nos mostrara nuestra API Key que siempre empieza por `pypy-` como se muestra en la imagen de abajo:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743793988095/52016b85-72c6-4375-ab7f-0a53ab09d0a2.png align="center")

Hacemos clic en Copiar Ficha y guardamos nuestra `API Key` en algún lugar seguro\*\*.\*\* Siempre van a tener la posibilidad de borrar la key y generar otra si es necesario la pierden.

<div data-node-type="callout">
<div data-node-type="callout-emoji">🚩</div>
<div data-node-type="callout-text">Nunca debemos compartir la API Key o agregarla directamente a un archivo que pueda estar trackeado en <strong>GIT.</strong></div>
</div>

Luego de todo esto debemos instalar 2 librerías que nos ayudaran a construir y publicar nuestro paquete:

```powershell
(env) $ python -m pip install build twine
```

### 🛠️ Construir el paquete con `build`

Ahora que tenemos nuestra librería lista, ya podemos hacer la distribución del código a **PyPI**, para esto primero debemos empaquetar nuestra librería en formato **wheels**, un formato que consiste en empaquetar en un archivo `tar` todo el código fuente de la librería. Para crear este archivo haremos uso de la librería `build`:

```powershell
(env) $ python -m build
[...]
Successfully built rafnixg-1.0.0.tar.gz and rafnixg-1.0.0-py3-none-any.whl
```

Esto nos crea una nueva carpeta llamada `dist/` que contiene el archivo `.tar.gz` con el código de nuestra librería y el archivo `.whl` que es nuestro archivo **wheels**, esto es todo lo que necesitamos para subir a **PyPI**.

### ✅ Verificar el paquete con `twine check`

Para validar que todo fue empaquetado correctamente podemos usar `twine`:

```powershell
(env) $ twine check dist/*
Checking dist/rafnixg-1.0.0-py3-none-any.whl: PASSED
Checking dist/rafnixg-1.0.0.tar.gz: PASSED
```

### ☁️ Subir el paquete a PyPI

Ahora que tenemos todo listo y verificado, podemos subir a ***TestPyPI*** para ver que todo va con normalidad y no tenemos ningún error en nuestra librería:

```powershell
(env) $ twine upload -r testpypi dist/*
```

Nos pedirá nuestra `API Key`. Ya con esto podemos probar nuestra librería usando el siguiente comando:

```powershell
(env) $ pip install -i https://test.pypi.org/simple/ rafnixg
```

Si todo salió con normalidad, podemos subir a él repositorio principal de ***PyPI***:

```powershell
(env) $ twine upload dist/*
```

Con esto tendríamos nuestro proyecto ya disponible para usar con `pip`, podemos a ***PyPI*** y buscar nuestra librería.

%[https://pypi.org/project/rafnixg] 

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743790696920/9726f027-4b6f-438b-bb66-09421f8c08e0.png align="center")

### 📥 Instalar tu paquete desde PyPI

Ya con nuestra librería publicada en ***PyPI*** podemos usarla con el siguiente comando:

```powershell
(env) $ python -m pip install rafnixg
(env) $ rafnixg
```

## 🧠 Conclusiones

Crear y publicar tu propio paquete en Python es una experiencia enriquecedora que va más allá de compartir código: es una oportunidad para aprender sobre la estructuración de proyectos, el versionado semántico y las buenas prácticas de la comunidad. A lo largo de este tutorial, hemos recorrido desde la configuración del entorno de desarrollo hasta la publicación en ***PyPI***, enfatizando la importancia de una documentación clara y una estructura ordenada. Con estos conocimientos, no solo mejoras tus habilidades técnicas, sino que también das un paso significativo hacia la consolidación de tu perfil profesional en el mundo del desarrollo. ¡Atrévete a experimentar, optimizar tu paquete y contribuir al ecosistema **open source**!

<div data-node-type="callout">
<div data-node-type="callout-emoji">📰</div>
<div data-node-type="callout-text">En una próxima publicación veremos cómo podemos crear un flujo de <strong>CI/CD</strong> con <strong>Github Actions</strong> para automatizar la publicación de nuestra librería, también como documentarla y publicar con <strong>Github Pages</strong> esta documentación. Cualquier duda o consulta déjalo en la sección de comentarios.</div>
</div>
