Saltar al contenido

Entornos fantásticos y dónde encontrarlos

Este post busca ser una guía de instalación para los entornos que uso en mis cursos de Computación Gráfica (CG) y Visualización de Información (VIS).

¿No basta con tener una instalación de Python?

Digamos que tienes Python instalado en tu sistema. Por ejemplo, en CG y VIS trabajamos con múltiples bibliotecas:

  • En CG: pyglet, numpy, trimesh, scipy…
  • En VIS: matplotlib, geopandas, pyrosm, graph-tool…

Una situación imaginaria (con números de versiones inventados) pero que ilustra el caso base es la siguiente:

    graph LR
    J[Python global del sistema] --> K[pyglet v2.0]
    J --> L[trimesh v3.2]
    J --> M[scipy v1.9]
    J --> N[graph-tool v2.45]
    J --> O[matplotlib v3.5]
    J --> P[pyrosm v0.6]
    J --> Q[geopandas v0.10]
    
    K --> R[Dependencias de pyglet]
    L --> S[Dependencias de trimesh]
    M --> T[Dependencias de scipy]
    N --> U[Dependencias de graph-tool]
    O --> V[Dependencias de matplotlib]
    P --> W[Dependencias de pyrosm]
    Q --> X[Dependencias de geopandas]
    
    R --> Y[Conflictos potenciales\nentre dependencias]
    S --> Y
    T --> Y
    U --> Y
    V --> Y
    W --> Y
    X --> Y
  

Esta situación, donde todo está mezclado con todo, puede generar conflictos. No es raro que debamos hacer cosas como pip install biblioteca para que el módulo biblioteca esté disponible en nuestro sistema (recuerda que pip es un programa que permite instalar bibliotecas de Python). Pero, ¿realmente es posible instalar herramientas heterogéneas y que funcionen bajo el mismo paraguas? La verdad es que no. Podrían pasar cosas como:

  • biblioteca no es compatible con uno de los módulos que ya tengamos instalados.
  • Las dependencias de los módulos que necesito en cada curso no son compatibles. Probablemente al instalar biblioteca se sobreescriben algunas de las dependencias que ya estaban instaladas para otro módulo, y ese módulo deja de funcionar…
  • … o, si funciona, podría dar resultados erróneos en ciertos cálculos (esto puede suceder, por ejemplo, ante cambios en numpy o similares).

Estos conflictos son un gran problema porque la correctitud y reproducibilidad de nuestros resultados está en riesgo.

Una solución es usar entornos o ambientes.

Pero… ¿qué es un entorno o ambiente?

Es una buena pregunta :) Es el conjunto de herramientas que tienes instaladas para tu desarrollo, incluyendo los intérpretes de lenguajes de programación (como Python) y compiladores (para lenguajes como C). De cierto modo, la imagen anterior ilustra un ambiente: el del sistema. ¡Pero eso no implica que no puedas tener ambientes adicionales! Por ejemplo, yo tengo al menos dos entornos: grafica (para CG) y aves (para VIS):

    graph LR
    A[Sistema] --> B[Entorno: grafica]
    A --> C[Entorno: aves]
    
    subgraph "Entorno: grafica"
        B --> D[Python 3.9]
        B --> E[pyglet v2.0]
        B --> F[trimesh v3.2]
        B --> G[scipy v1.9]
        D --> H[Dependencias específicas y compatibles]
        E --> H
        F --> H
        G --> H
    end
    
    subgraph "Entorno: aves"
        C --> K[Python 3.10]
        C --> L[graph-tool v2.45]
        C --> M[matplotlib v3.5]
        C --> N[pyrosm v0.6]
        C --> O[geopandas v0.10]
        K --> P[Dependencias específicas y compatibles]
        L --> P
        M --> P
        N --> P
        O --> P
    end
  

Cada uno de mis ambientes tienen su propia versión de Python y las bibliotecas necesarias para el proyecto en el que trabajo con ese ambiente. Incluso pueden ser versiones diferentes. Así, trabajar con ambientes permite aislar las herramientas de un proyecto para que no interfieran con las de otro, asegurar la compatibilidad entre ellas y trabajar de manera independiente a la configuración del sistema, lo que asegura la reproducibilidad de tu código.

¿Cómo gestiono y configuro entornos?

Utilizar un programa gestor de entornos. En Python, una manera clásica es utilizando virtual env https://docs.python.org/es/3.13/library/venv.html; una moderna, es utilizando uv https://docs.astral.sh/uv/. En ambos casos puedes tener un “entorno virtual” en el que existen versiones independientes de las bibliotecas que necesites, cada uno con su propia versión de Python.

Sin embargo, surgen dificultades cuando tu proyecto tiene requisitos que van más allá de Python. Es común que una biblioteca requiera módulos creados con otros lenguajes de programación o herramientas externas. En esos casos, una solución enfocada en Python a veces no es suficiente: hay que usar un gestor que trabaje con múltiples plataformas.

Desconozco todas las alternativas existentes. Una de ellas, posiblemente la más usada, es conda (parte de Anaconda). conda te permite crear entornos. Tiene su propio repositorio de módulos y herramientas que puedes tener de manera independiente. Yo uso conda, pero con un twist: Anaconda es una “distribución”, es decir, un conjunto sumamente completo de herramientas (incluyendo Python) que incluye el gestor conda. Si instalas Anaconda, tendrás conda y también muchas cosas ya instaladas, sin perjuicio de que puedas crear nuevos entornos. La gracia de esto, es que Anaconda tiene repositorios con bibliotecas y herramientas. En vez de utilizar el programa pip, utilizas conda, que lee de esos repositorios, y así puede saber que una biblioteca en Python puede requerir un programa en Java o un módulo en Rust.

Aunque instalar un paquete (que es más general que biblioteca) se hace de manera similar: conda install paquete, esa no es la manera adecuada de usar conda. Lo ideal es tener un archivo que configura el entorno. Este es el archivo environment.yml de mi entorno grafica:

name: grafica
channels:
  - conda-forge
  - defaults
dependencies:
  - numpy
  - pip
  - pyopengl
  - python
  - mesa>=2.3.0
  - trimesh
  - networkx
  - pillow
  - matplotlib
  - scipy
  - cffi
  - shapely
  - rtree
  - click
  - pip:
    - pyglet>=2.0.0
    - pymunk

Este archivo incluye el nombre del entorno (name: grafica), dice desde dónde se deben descargar los paquetes (channels: ...) y define las dependencias (dependencies: ...). La dependencia mesa define un número de versión (>=2.3.0). En rigor, eso se puede hacer para cada paquete (de hecho, es lo recomendado). Algo interesante sucede: pip es una dependencia también, y, de hecho, se especifican dos paquetes que se deben instalar con pip (y uno con versión). Esto se debe a que los canales de distribución de conda no necesariamente tienen todo lo que está disponible en pip.

El comando conda env create -f environment.yml se encarga de descargar todos los paquetes necesarios para que este entorno funcione. De hecho, hay dependencias que no están declaradas: ¿qué paquetes necesita la biblioteca shapely? Muchos que no aparecen en este archivo. conda se encarga de todo.

Después de unos minutos de descarga y configuración, el comando conda activate grafica activará tu entorno y ejecutar python abrirá el intérprete de la versión que necesitas y no la que tiene el entorno del sistema.

Existen más herramientas de este estilo:

  • Miniconda es una versión de conda que no instala la distribución Anaconda.
  • mamba es una implementación eficiente de la interfaz de conda, es decir, puedes ejecutar los mismos comandos y el resultado será idéntico, pero en menos tiempo y con menos gasto de energía.
  • Micromamba es una versión mínima de mamba: incluye solamente el comando micromamba, que mantiene la interfaz de conda, pero nada más. Ni siquiera instala un entorno base.

Hoy yo uso micromamba. De hecho, tengo configurado mi sistema para que al ejecutar conda en realidad se llame al programa micromamba. El enlace previo lleva a sus instrucciones de instalación.

Si usas Windows, probablemente es más directo instalar Anaconda y utilizar la consola mediante la terminal llamada Anaconda Prompt.

¿Cómo asegurar reproducibilidad?

Una manera sencilla de hacerlo es exportando el entorno. El comando conda list -n grafica --export imprime la lista de paquetes instalados en el entorno grafica con su versión exacta. Aquí hay un ejemplo (lo edité para que no ocupase tanto espacio, porque incluye las dependencias implícitas – las partes que dicen [...] en realidad contienen varios paquetes):

$ conda list -n grafica --export
# This file may be used to create an environment using:
# $ conda create --name <env> --file <this file>
# platform: win-64
_openmp_mutex=4.5=2_gnu
brotli=1.1.0=h2466b09_2
brotli-bin=1.1.0=h2466b09_2
bzip2=1.0.8=h2466b09_7
ca-certificates=2025.2.25=haa95532_0
cairo=1.18.2=h5782bbf_1
cffi=1.17.1=py313ha7868ed_0
click=8.1.8=pyh7428d3b_0
[...]
libbrotlienc=1.1.0=h2466b09_2
libcblas=3.9.0=31_h5e41251_mkl
[...]
llvmlite=0.44.0=py313hb80970b_0
matplotlib=3.10.1=py313hfa70ccb_0
matplotlib-base=3.10.1=py313h81b4f16_0
mesa=3.1.4=pyhd8ed1ab_0
mkl=2024.2.2=h66d3029_15
munkres=1.1.4=pyh9f0ad1d_0
networkx=3.4.2=pyh267e887_2
numba=0.61.0=py313h4ca4f0f_1
numpy=2.1.3=py313hee8cc43_0
openjpeg=2.5.3=h4d64b90_0
[...]
pycparser=2.22=pyh29332c3_1
pyglet=2.1.3=pypi_0
pymunk=6.11.1=pypi_0
pyopengl=3.1.7=pyhd8ed1ab_0
pyparsing=3.2.1=pyhd8ed1ab_0
pyside6=6.8.2=py313h3e3797f_1
python=3.13.2=h261c0b1_101_cp313
[...]
tqdm=4.67.1=pyhd8ed1ab_1
trimesh=4.6.4=pyh7b2049a_0
[...]

Con esta información puedes recrear el entorno de manera exacta.

¿Existen otras alternativas?

Hoy, sobre todo en el mundo del desarrollo y del software en producción, se habla más de contenedores que de entornos. Un ejemplo de tecnología de contenedor es docker. El paradigma de los contenedores es potente, puesto que además de asegurar que esté instalado todo lo que necesita tu entorno con sus versiones correctas, también se encarga de las condiciones del sistema que rodean al entorno, incluyendo sistemas de archivos y acceso a recursos. En resumen, si descargas un contenedor, puedes ejecutarlo directamente y tu código se ejecutará en condiciones que controlar totalmente.

Suena ideal. En el mundo del deployment, lo es.

De hecho, muches estudiantes me entregan sus proyectos de título dockerizados:

Profe, en este repositorio está el código. Levantas el docker y funciona.

(Aquí, “levantar” se refiere a descargar el contenedor y activarlo) ¡Es cierto que funciona! El problema es que le estudiante se encargó de tener funcionando el código en su máquina, creó el contenedor y lo entregó, sin preocuparse de documentar las versiones o siquiera pensar en la documentación del programa. Este esquema facilita tanto el deployment que, en mi opinión, motiva que nos olvidemos de los fundamentos detrás del desarrollo.

Pienso que estas herramientas han abstraído tanto la maquinaria que implica la conexión de múltiples herramientas y módulos, que de repente olvidamos que necesitamos dominar ese aspecto. No solo necesitamos que la arquitectura de nuestro sistema sea robusta. Debemos conocerla y entenderla de modo que podamos trabajar en ella también. Un caso hipótetico: si otra persona llegara a continuar el proyecto de título dockerizado y su trabajo consiste en agregar un nuevo componente, cuyas dependencias no son compatibles con las que están incluidas (sin documentar) en el contenedor. ¿Cuánto tiempo perderá tratando de resolver el problema? ¿Imaginará que es un conflicto de versiones? Tarde o temprano llegará a esa solución. Una solución a un problema que no debía existir en realidad.

En la vida laboral te encontrarás con contenedores, entornos y, también, con software sin ningún tipo de configuración. Solo conociendo los fundamentos podrás desenvolverte bien en todos esos ambientes.