---
name: build-errors-python
description: >
  Resolución de errores de build e instalación Python: pip, poetry, virtualenv,
  pyproject.toml, errores de import, incompatibilidades de versión y compilación
  de extensiones C. Cargar cuando un build Python falle, pip install dé error,
  o haya ModuleNotFoundError/ImportError inesperados.
version: "1.0.0"
herramientasPermitidas: [Read, Bash, Grep]
exclusiones:
  - "No cargar para errores de runtime de la aplicación Python (AttributeError, KeyError, TypeError en ejecución) — esos son bugs de lógica, no errores de build; diagnosticar con el stack trace directamente."
  - "No cargar para diseñar la estructura de dependencias desde cero — si la pregunta es qué paquetes incluir en pyproject.toml, cargar `patrones-python` o el skill del framework (fastapi-experto, django-experto)."
  - "No cargar para errores de linting o formateo (ruff, black, flake8 reportando style issues) — esos no son errores de build; corregir según las reglas del linter directamente."
  - "No cargar cuando el error ya es resuelto y la pregunta es refactorizar el código de dependencias — eso es mantenimiento, no diagnóstico de build."
evolvable: true  # default para skill estandar
---
# Build Errors Python — Diagnóstico y Solución

## Cuándo NO cargar

- El error ocurre en runtime (AttributeError, TypeError, KeyError) — no es un error de build; leer el stack trace directamente.
- La pregunta es qué paquetes usar, no por qué fallan al instalar — para estructura de dependencias cargar `fastapi-experto` o `django-experto`.
- El problema es un warning de linting (ruff, flake8) — no es un error de instalación ni compilación.

## Cuándo cargar

- `pip install` falla con errores de compilación o dependencias
- `poetry install` o `poetry lock` reporta conflictos de versión
- `ModuleNotFoundError` o `ImportError` en código que debería funcionar
- Errores al ejecutar `python setup.py` o `pyproject.toml` mal configurado
- Incompatibilidades de versión de Python (3.9 vs 3.12)
- Errores de extensiones C (`gcc`, `wheel`, `manylinux`)

---

## Errores de pip — causa y solución

### `Could not find a version that satisfies the requirement X`

**Causa**: el paquete no existe, o no existe para la versión de Python/plataforma actual.

**Diagnóstico**:
```bash
# Verificar versión de Python y plataforma
python --version
pip debug --verbose | head -20

# Buscar versiones disponibles del paquete
pip index versions nombre-paquete
```

**Soluciones**:
1. Nombre del paquete incorrecto: `pip search` deprecado — buscar en https://pypi.org
2. Paquete no soporta la versión de Python: verificar `python_requires` del paquete
3. Paquete sin wheel para la plataforma: necesita compilar desde fuente (requiere build tools)

### `ERROR: No matching distribution found for X==Y`

**Causa**: la versión exacta no existe o no tiene wheel para la plataforma.

```bash
# Ver todas las versiones disponibles
pip install nombre-paquete==
# pip mostrará las versiones disponibles en el mensaje de error

# Instalar la versión más reciente compatible
pip install "nombre-paquete>=2.0,<3.0"
```

### `error: subprocess-exited-with-error` (compilación de extensiones C)

**Causa**: falta el compilador C o las cabeceras de desarrollo del sistema.

**Soluciones por sistema operativo**:
```bash
# Ubuntu/Debian
sudo apt-get install build-essential python3-dev libpq-dev libffi-dev

# macOS
xcode-select --install
brew install postgresql  # para psycopg2

# Windows
# Instalar "Build Tools for Visual Studio" desde visualstudio.microsoft.com
# O usar el wheel precompilado:
pip install psycopg2-binary  # en vez de psycopg2
```

**Gotcha**: `psycopg2` requiere libpq-dev. Usar `psycopg2-binary` en desarrollo
y `psycopg2` con libpq en producción (el binary no es recomendado en prod).

### `ResolutionImpossible` (pip >= 22.0)

**Causa**: dos dependencias requieren versiones incompatibles de una tercera.

```bash
# Diagnóstico: ver el árbol de dependencias
pip install pipdeptree
pipdeptree --warn silence | grep -i conflicto

# Ver qué depende de qué
pipdeptree --reverse --packages nombre-paquete

# Forzar resolución (último recurso, puede romper cosas)
pip install --force-reinstall nombre-paquete==version
```

**Solución real**: actualizar las dependencias en conflicto o fijar versiones compatibles
en `requirements.txt` / `pyproject.toml`.

---

## Errores de poetry — causa y solución

### `SolverProblemError: ... is not compatible with ...`

**Causa**: poetry usa un solver estricto que no permite conflictos.

```bash
# Ver por qué falla la resolución
poetry install -vvv

# Actualizar una dependencia específica
poetry update nombre-paquete

# Si el conflicto es con la versión de Python
poetry env use python3.12
```

### `poetry.lock` desactualizado respecto a `pyproject.toml`

```bash
# Regenerar el lock file
poetry lock --no-update  # mantener versiones actuales donde sea posible
poetry lock              # resolver desde cero

# Instalar después de actualizar el lock
poetry install
```

---

## Errores de import — causa y solución

### `ModuleNotFoundError: No module named 'X'`

**Diagnóstico paso a paso**:
```bash
# 1. ¿El paquete está instalado?
pip show nombre-paquete

# 2. ¿Estoy en el virtualenv correcto?
which python  # Unix
where python  # Windows

# 3. ¿El nombre de import difiere del nombre del paquete?
# Ejemplo: pip install Pillow → import PIL
# Ejemplo: pip install python-dateutil → import dateutil
# Ejemplo: pip install scikit-learn → import sklearn

# 4. ¿El sys.path incluye el directorio del módulo?
python -c "import sys; print('\n'.join(sys.path))"
```

**Gotcha de nombres**: el nombre en pip NO siempre coincide con el nombre de import.
Casos frecuentes:

| Nombre pip | Nombre import |
|-----------|--------------|
| `Pillow` | `PIL` |
| `python-dateutil` | `dateutil` |
| `scikit-learn` | `sklearn` |
| `beautifulsoup4` | `bs4` |
| `python-dotenv` | `dotenv` |
| `PyYAML` | `yaml` |
| `opencv-python` | `cv2` |

### `ImportError: cannot import name 'X' from 'Y'`

**Causas comunes**:
1. Versión vieja del paquete que no tiene la clase/función
2. Importación circular entre módulos propios
3. Archivo local con el mismo nombre que un módulo estándar (shadowing)

```bash
# Verificar versión instalada
pip show pydantic | grep Version

# Ejemplo: BaseSettings se movió en Pydantic v2
# Pydantic v1: from pydantic import BaseSettings
# Pydantic v2: from pydantic_settings import BaseSettings
```

**Gotcha de shadowing**: un archivo `email.py` en tu proyecto oculta
`import email` de la biblioteca estándar. Renombrar el archivo local.

### `ImportError: attempted relative import with no known parent package`

**Causa**: ejecutar un módulo como script (`python modulo.py`) en vez de como
módulo (`python -m paquete.modulo`).

```bash
# MAL
python src/app/services/factura.py

# BIEN
python -m src.app.services.factura

# O ejecutar desde la raíz del proyecto con el paquete instalado
pip install -e .
```

---

## Errores de pyproject.toml / setup.cfg

### `Invalid value for requires-python`

```toml
# MAL
[project]
requires-python = "3.12"     # sin operador de comparación

# BIEN
[project]
requires-python = ">=3.10"
```

### `build-system.requires` faltante

```toml
# Obligatorio en pyproject.toml para que pip pueda construir el paquete
[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.backends._legacy:_Backend"

# Con Poetry
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
```

---

## Virtualenv — errores comunes

### `externally-managed-environment` (Python 3.12+ con PEP 668)

**Causa**: Python del sistema en Debian/Ubuntu/Fedora ya no permite `pip install` global.

```bash
# Crear virtualenv (solución correcta)
python -m venv .venv
source .venv/bin/activate  # Unix
.venv\Scripts\activate     # Windows

# Solo como último recurso (no recomendado)
pip install --break-system-packages nombre-paquete
```

### Virtualenv apunta a Python eliminado

```bash
# Verificar si el virtualenv está roto
python -c "import sys; print(sys.executable)"
# Si apunta a un Python que ya no existe:

# Recrear el virtualenv
rm -rf .venv
python3.12 -m venv .venv
pip install -r requirements.txt
```

---

## Gotchas / Errores comunes no obvios

- **`pip install` pasa pero `python -c "import X"` falla con ModuleNotFoundError**: el paquete se instaló en el Python del sistema, pero el proyecto usa el virtualenv. Causa: ejecutar `pip install` sin activar el virtualenv primero — instala en el intérprete global, no en `.venv`. Solución: verificar con `which pip` que apunta a `.venv/bin/pip` antes de instalar; si no, activar con `source .venv/bin/activate` y reinstalar.
- **`psycopg2-binary` funciona localmente pero falla en CI o Docker con `symbol lookup error`**: el binary wheel incluye la librería libpq compilada para una plataforma específica que no coincide con la imagen del contenedor. Causa: `psycopg2-binary` embebe libpq compilada para un libc/glibc diferente. Solución: usar `psycopg2` (sin `-binary`) en producción/CI e instalar `libpq-dev` en el Dockerfile; dejar `psycopg2-binary` solo para desarrollo local.
- **Poetry resuelve el lockfile sin errores pero `poetry install` en CI falla con conflicto de versión**: el `poetry.lock` fue generado en una versión de Poetry diferente a la del CI. Causa: Poetry tiene diferencias de resolución entre versiones menores que afectan los hashes del lockfile. Solución: fijar la versión de Poetry en CI con `pip install poetry==X.Y.Z` — la misma que usaron los desarrolladores localmente.
- **`ModuleNotFoundError` en import relativo aunque el archivo existe**: el módulo se ejecuta como script (`python src/modulo.py`) en vez de como módulo del paquete. Causa: los imports relativos requieren que el módulo sea parte de un paquete (invocado con `-m`). Solución: ejecutar `python -m src.modulo` desde la raíz del proyecto, o instalar el proyecto en modo editable con `pip install -e .`.

## Checklist de diagnóstico

- [ ] `python --version` — ¿versión correcta?
- [ ] `which python` / `where python` — ¿virtualenv correcto?
- [ ] `pip list` — ¿paquete instalado? ¿versión correcta?
- [ ] `pipdeptree` — ¿conflictos de dependencias?
- [ ] ¿Nombre de import ≠ nombre de pip? (tabla de nombres comunes)
- [ ] ¿Archivo local con nombre de módulo estándar? (shadowing)
- [ ] Para errores de compilación C: ¿build-essential/python3-dev instalados?
- [ ] `pip install -e .` — ¿proyecto instalado en modo editable?
