Guía Formal sobre Estructuras de Proyectos en Python

El desarrollo de proyectos en Python requiere una estructura bien definida que permita mantener el código organizado, escalable y fácil de mantener. Una estructura coherente facilita la colaboración entre desarrolladores, la integración continua y la distribución del software.

Este documento describe las estructuras más comunes de proyectos Python, analizando buenas prácticas, ejemplos y herramientas modernas para la gestión de entornos, con especial énfasis en ``uv``, una herramienta de alto rendimiento para la gestión de entornos y dependencias. Además, se incluyen recomendaciones sobre el uso de Jupyter Notebooks y la organización de datos en proyectos científicos o analíticos.


1. Introducción a las estructuras de proyectos

Una estructura de proyecto en Python define cómo se organizan los archivos y directorios del código fuente, las dependencias, los scripts de configuración y los recursos auxiliares.

Los objetivos principales son:

  • Separar el código fuente de los datos, las notebooks y la configuración.

  • Facilitar la reutilización del código y la automatización de tareas.

  • Permitir la distribución del proyecto como paquete instalable.

  • Favorecer la gestión de entornos virtuales reproducibles y seguros.

  • Integrar de forma ordenada los notebooks de experimentación.


2. Estructura básica de un proyecto Python

Una estructura simple, adecuada para proyectos pequeños o scripts personales, puede ser la siguiente:

mi_proyecto/
│
├── venv/                # Entorno virtual (opcional)
├── main.py              # Punto de entrada principal
├── requirements.txt     # Dependencias del proyecto
└── README.md            # Documentación básica

Esta estructura es suficiente para scripts o utilidades simples, pero no es adecuada para proyectos colaborativos o de larga duración.


3. Estructura modular (proyectos medianos y grandes)

A medida que el proyecto crece, se recomienda una organización modular y clara:

mi_proyecto/
│
├── src/                      # Código fuente principal
│   └── mi_proyecto/
│       ├── __init__.py
│       ├── core.py
│       ├── utils/
│       │   └── __init__.py
│       └── data_processing.py
│
├── data/                     # Carpeta para almacenar datos
│   ├── raw/                  # Datos sin procesar
│   ├── processed/            # Datos limpios y transformados
│   └── external/             # Datos externos o descargados
│
├── notebooks/                # Notebooks de análisis o experimentación
│   ├── 01_exploracion.ipynb
│   ├── 02_modelado.ipynb
│   └── utils.ipynb
│
├── requirements.txt          # Dependencias del proyecto
├── pyproject.toml            # Configuración avanzada (PEP 621)
├── .gitignore
└── README.md

Ventajas de esta estructura

  • Claridad modular: separación del código fuente, notebooks y datos.

  • Escalabilidad: permite mantener un flujo limpio entre desarrollo y análisis.

  • Colaboración eficiente: notebooks separados del código productivo.


4. Estructura de proyectos con Jupyter Notebooks

Los Jupyter Notebooks (.ipynb) son herramientas esenciales para exploración de datos, visualización y prototipado rápido. Sin embargo, deben mantenerse separados del código de producción para evitar confusión y mejorar la mantenibilidad.

Estructura recomendada con notebooks

mi_proyecto/
│
├── src/                      # Código fuente principal
│   └── mi_proyecto/
│       ├── __init__.py
│       ├── core.py
│       ├── model/
│       │   ├── train.py
│       │   └── evaluate.py
│       └── utils/
│           └── data_utils.py
│
├── notebooks/                # Notebooks de exploración y presentación
│   ├── 00_exploracion_inicial.ipynb
│   ├── 01_limpieza_datos.ipynb
│   ├── 02_modelado.ipynb
│   └── 03_visualizacion_resultados.ipynb
│
├── data/
│   ├── raw/
│   ├── processed/
│   ├── results/
│   └── external/
│
├── reports/                  # Resultados y documentación generada
│   ├── figuras/
│   └── informe_final.pdf
│
├── environment.yml           # (opcional) Configuración alternativa para Conda
├── pyproject.toml
├── requirements.txt
├── .gitignore
└── README.md

Buenas prácticas con Jupyter Notebooks

  1. Nombrar los notebooks con prefijos numéricos para reflejar el orden lógico del flujo de trabajo. Ejemplo: 01_preprocesamiento.ipynb, 02_modelado.ipynb.

  2. Evitar lógica de negocio compleja dentro de los notebooks. El código debe modularizarse y residir en src/.

  3. Importar funciones y módulos desde ``src/`` para mantener consistencia:

    from mi_proyecto.utils.data_utils import cargar_datos
    
  4. Mantener notebooks limpios y ejecutables desde cero. Deben poder ejecutarse completamente tras un Restart & Run All.

  5. Guardar los resultados procesados en data/processed/ o data/results/, no en el notebook.

  6. Exportar los notebooks a formatos reproducibles (.html o .pdf) para documentación final.

5. El archivo requirements.txt

El archivo requirements.txt lista todas las dependencias necesarias para ejecutar el proyecto. Es un componente esencial para garantizar que el entorno de desarrollo y producción sean idénticos.

5.1 Ejemplo básico

numpy==2.0.1
pandas>=2.2.0,<3.0.0
matplotlib==3.9.1
scikit-learn>=1.4.0
jupyterlab==4.2.0

5.2 Creación automática

Puedes generar el archivo a partir del entorno activo:

uv pip freeze > requirements.txt

o, si usas pip tradicional:

pip freeze > requirements.txt

5.3 Instalación de dependencias

Para reproducir un entorno:

uv pip install -r requirements.txt

5.4 Buenas prácticas con requirements.txt

  • Especificar versiones exactas (==) para despliegues productivos.

  • Usar rangos (>=, <) durante la fase de desarrollo.

  • Complementar con pyproject.toml para definir dependencias de desarrollo y metadatos.

  • Mantener actualizado mediante uv pip freeze o herramientas como pip-tools.


6. Gestión de entornos con uv (recomendado)

`uv <https://github.com/astral-sh/uv>`__ es una herramienta moderna desarrollada por Astral, los creadores de ruff y rye. Proporciona una gestión de entornos virtuales y dependencias ultrarrápida, reproducible y compatible con los estándares de Python.

6.1 Instalación

pip install uv

o mediante script oficial:

curl -LsSf https://astral.sh/uv/install.sh | sh

6.2 Creación y activación de entornos

uv venv
source .venv/bin/activate

Por defecto, el entorno se crea en .venv/. Es totalmente compatible con herramientas como jupyter, black y ruff.

6.3 Instalación de dependencias

uv pip install -r requirements.txt

o directamente:

uv pip install .

6.4 Ventajas de uv

Característica

Descripción

Velocidad

Hasta 20 veces más rápido que pip o conda.

Compatibilidad

Totalmente interoperable con pyproject.toml y requirements.txt.

Reproducibilidad

Crea entornos deterministas y caché inteligente.

Ligereza

Sin dependencias externas, multiplataforma.

Integración

Soporte directo para jupyter y herramientas modernas de desarrollo.


7. Propuesta para almacenar datos

En proyectos de análisis o ciencia de datos, los datasets deben organizarse con una estructura clara y reproducible.

data/
├── raw/              # Datos originales sin modificar
├── processed/        # Datos limpios y listos para análisis
├── external/         # Datos descargados de fuentes externas
└── results/          # Resultados o predicciones generadas

Buenas prácticas

  1. Evitar almacenar datos grandes en el repositorio. Usa .gitignore para excluir /data/raw y /data/processed.

  2. Documentar el origen y formato de los datos en data/README.md.

  3. Usar rutas relativas en el código.

  4. Mantener una convención de nombres consistente entre datasets.

  5. Guardar resultados reproducibles (como modelos o métricas) en data/results/.


8. Buenas prácticas generales

  1. Usar ``pyproject.toml`` como fuente principal de configuración.

  2. Gestionar dependencias con ``uv`` para lograr entornos reproducibles y rápidos.

  3. Mantener notebooks separados en /notebooks/ y código reutilizable en /src/.

  4. Guardar datos estructurados en ``/data/`` y documentar su procedencia.

  5. Evitar almacenar entornos (``.venv/``) o datos pesados en Git.

  6. Exportar notebooks a formatos estáticos para documentación (.html, .pdf).

  7. Nombrar notebooks secuencialmente para reflejar el flujo de trabajo.


9. Archivo pyproject.toml

El archivo ``pyproject.toml`` es el estándar moderno para la configuración de proyectos Python definido por PEP 518 y extendido por PEP 621. Su objetivo es centralizar la información del proyecto, las dependencias, los requisitos de construcción y la configuración de herramientas en un solo archivo, reemplazando en gran medida a setup.py y requirements.txt.


9.1 Estructura básica

Un archivo pyproject.toml mínimo suele incluir las siguientes secciones:

[project]
name = "mi_proyecto"
version = "0.1.0"
description = "Descripción breve del proyecto"
authors = [{ name = "Tu Nombre", email = "tu@email.com" }]
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
    "numpy>=2.0.0,<3.0.0",
    "pandas>=2.2.0,<3.0.0",
]

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

Explicación de secciones:

  • [project]: contiene los metadatos del proyecto (nombre, versión, autores, descripción, dependencias).

  • dependencies: lista de dependencias que deben instalarse para usar el proyecto.

  • [build-system]: define las herramientas necesarias para construir e instalar el proyecto, por ejemplo setuptools y wheel.

  • build-backend: indica el backend de construcción que se utilizará, normalmente setuptools.build_meta.

10. Conclusión

Una estructura de proyecto bien diseñada es la base para la reproducibilidad, colaboración y mantenimiento en el desarrollo con Python.

Entre las herramientas modernas, ``uv`` destaca por su velocidad, simplicidad y compatibilidad con los estándares más recientes. En combinación con un manejo ordenado de notebooks, dependencias y datos, proporciona un flujo de trabajo profesional, sostenible y escalable.

En resumen:

  • Usa ``uv`` para gestionar entornos y dependencias.

  • Organiza el código en /src/ y los datos en /data/.

  • Mantén los notebooks en /notebooks/, limpios y bien documentados.

  • Versiona solo lo esencial: código, metadatos y resultados relevantes.


[ ]: