pip: gestión de paquetes en la práctica

Cuando ejecutas pip install requests, parece magia: en segundos tienes una librería lista para importar. Pero detrás de esa simplicidad hay un sistema de resolución de paquetes, un índice global (PyPI) y decisiones de versiones que pueden arruinar un proyecto si no entiendes qué está pasando realmente.

pip es el gestor de paquetes oficial de Python. Su trabajo es descargar paquetes desde PyPI, resolver sus dependencias y colocarlos donde Python pueda encontrarlos. El detalle crítico está en ese “donde Python pueda encontrarlos”: pip instala en el entorno de Python que esté activo en ese momento. Si no hay ningún entorno virtual activo, instala en el Python del sistema, y eso casi nunca es lo que quieres en desarrollo (más sobre esto al final).

La gestión de versiones es donde pip muestra su complejidad real. pip install flask te da la última versión, lo cual está bien para explorar pero es una trampa en producción: la próxima semana flask puede publicar una versión con cambios que rompan tu código. Por eso existen los especificadores de versión: pip install flask==3.0.2 fija una versión exacta, y pip install "flask>=2.0,<3.0" define un rango, útil cuando quieres recibir parches de seguridad pero evitar cambios mayores.

El problema fundamental de pip con la reproducibilidad es que instalar flask no solo instala flask: instala también werkzeug, jinja2, click y varias otras dependencias. Si solo guardas flask==3.0.2 en tu lista de dependencias, no estás capturando las versiones exactas de todo ese árbol. Aquí entra pip freeze, que vuelca todas las versiones instaladas en el entorno, incluyendo las dependencias de las dependencias. El resultado de pip freeze es lo que va a requirements.txt para reproducir el entorno exacto, no tu lista manual de paquetes directos.

La limitación que no puedes ignorar: requirements.txt generado con pip freeze captura versiones exactas, pero no tiene mecanismo de verificación criptográfica de integridad. Si alguien sube un paquete malicioso con el mismo número de versión (aunque es raro, ha pasado), no te enterarías. Para eso existen herramientas como pip-tools o poetry, pero ese es otro tema.

# Este archivo NO es código Python ejecutable — es una sesión de terminal
# comentada para que veas el flujo completo de trabajo con pip.
# Ejecuta cada bloque en tu shell después de activar tu entorno virtual.

# ── 1. INSTALACIÓN DE PAQUETES ───────────────────────────────────────────

# Versión más reciente disponible (útil para explorar, arriesgado en prod)
# pip install requests

# Versión exacta — reproducible, sin sorpresas
# pip install requests==2.31.0

# Rango: acepta parches y minors, rechaza el salto mayor
# pip install "requests>=2.28.0,<3.0.0"

# Instalar varios paquetes a la vez
# pip install flask==3.0.2 sqlalchemy==2.0.29

# ── 2. CAPTURAR EL ESTADO DEL ENTORNO ───────────────────────────────────

# pip freeze produce algo así:
#
#   blinker==1.7.0
#   click==8.1.7
#   flask==3.0.2
#   itsdangerous==2.1.2
#   jinja2==3.1.3
#   markupsafe==2.1.5
#   werkzeug==3.0.1
#
# Fíjate: pediste flask, pero el freeze captura las 6 dependencias que
# flask trajo consigo. Eso es exactamente lo que quieres en requirements.txt.

# pip freeze > requirements.txt

# ── 3. REPRODUCIR EL ENTORNO EN OTRA MÁQUINA ────────────────────────────

# pip install -r requirements.txt

# ── 4. INSPECCIÓN ───────────────────────────────────────────────────────

# Ver todos los paquetes instalados con sus versiones
# pip list

# Información detallada de un paquete: versión, ubicación, dependencias
# pip show flask

# ── 5. DESINSTALAR ──────────────────────────────────────────────────────

# pip uninstall requests
# Ojo: esto NO desinstala las dependencias que requests trajo.
# Tendrías que hacerlo manualmente o usar pip-autoremove.
# requirements.txt generado con `pip freeze` — este SÍ es un archivo real
# que commitearías a tu repositorio.

blinker==1.7.0
click==8.1.7
flask==3.0.2
itsdangerous==2.1.2
jinja2==3.1.3
markupsafe==2.1.5
werkzeug==3.0.1
# script.py — código que usa las dependencias instaladas
import flask
import requests

print(f"Flask {flask.__version__} listo")
print(f"Requests {requests.__version__} listo")

Qué significa cada decisión

El flujo pip freeze > requirements.txt seguido de pip install -r requirements.txt en otro entorno es el contrato de reproducibilidad básico de Python. Cuando haces pip show flask, la línea Requires: te muestra exactamente qué trajo flask consigo — es útil para entender por qué tu requirements.txt tiene más entradas de las que esperabas.

pip list te da una vista rápida de todo lo que hay instalado. Úsalo justo después de activar un entorno nuevo para confirmar que estás trabajando con la pizarra limpia que esperas, no con paquetes sobrantes de otro proyecto.

La asimetría de pip uninstall es una trampa clásica: instalar un paquete arrastra sus dependencias, pero desinstalarlo no las limpia. Si instalaste flask y luego lo desinstalas, werkzeug, jinja2 y el resto se quedan ahí ocupando espacio y potencialmente causando conflictos. La solución práctica en entornos virtuales es simplemente borrar el entorno completo y recrearlo desde requirements.txt.

Errores que debes conocer

Error: instalar paquetes con pip install sin un entorno virtual activo contamina el Python del sistema o el Python global del usuario, mezclando dependencias de proyectos distintos y causando conflictos de versiones que son difíciles de diagnosticar.

# ❌ Wrong — sin entorno virtual activo, esto va al Python del sistema
pip install flask

# ✅ Right — primero activas el entorno, luego instalas
python -m venv .venv
source .venv/bin/activate   # En Windows: .venv\Scripts\activate
pip install flask

Cuando el entorno está activo, verás su nombre en el prompt ((.venv)) y pip instalará solo dentro de esa carpeta aislada.


Error: hacer pip freeze > requirements.txt en un entorno que tiene paquetes de desarrollo (pytest, black, mypy) mezcla dependencias de producción con herramientas que el servidor de producción no necesita ni debería tener.

# ❌ Wrong — un solo requirements.txt con todo mezclado
pip freeze > requirements.txt   # incluye pytest, black, ipython...

# ✅ Right — archivos separados por propósito
pip freeze > requirements-dev.txt    # entorno de desarrollo completo
# En requirements.txt solo listas tus dependencias directas de producción:
# flask==3.0.2
# sqlalchemy==2.0.29

Separar los archivos te permite hacer pip install -r requirements.txt en producción sin arrastrar 40 paquetes de herramientas de desarrollo.


Error: editar requirements.txt a mano añadiendo solo el paquete principal (flask==3.0.2) sin regenerar el freeze completo, y luego asumir que el entorno es reproducible.

# ❌ Wrong — requirements.txt editado a mano con solo dependencias directas
# flask==3.0.2
# (faltan werkzeug, jinja2, click, etc.)

# pip install -r requirements.txt instalará flask pero pip elegirá
# libremente las versiones de sus dependencias — pueden ser distintas
# a las que tienes en tu máquina.

# ✅ Right — siempre regenera desde el entorno completo
pip freeze > requirements.txt

El freeze captura el grafo entero de versiones, no solo la capa superficial que tú pediste explícitamente.

71

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio