Capítulo 10 — Soporte Python 3.12 y dependencias opcionales
Commits:
acd6ca6,4626351,6fbd832,aa4e5db,0d1360b,3f74c6a(Killian, abril-junio 2024)
¿Qué pasó?
Abril de 2024 fue un período turbulento para aifs. Python 3.12 fue lanzado y unstructured no lo soportaba todavía. Killian tomó una decisión radical: hacer todas las dependencias pesadas opcionales.
El problema: Python 3.12 + unstructured
ERROR: unstructured requires Python >=3.8, <3.12Los usuarios que instalaban aifs con Python 3.12 obtenían un error críptico al importar. Peor: el error no decía nada sobre la versión de Python.
Intento 1: Mensaje de error específico para 3.12
# Commit acd6ca6
import sys
try:
from unstructured.chunking.title import chunk_by_title
from unstructured.partition.auto import partition
except ImportError:
if sys.version_info.major == 3 and sys.version_info.minor == 12:
raise ImportError(
"The 'unstructured' package required by this project does not support Python 3.12. "
"Please downgrade to Python 3.11 to continue."
)
raise ImportError("Please run 'pip install \"unstructured[all-docs]\"' to continue.")Al menos ahora el error era útil. Pero no resolvía el problema.
Intento 2: Ampliar rango de Python en pyproject.toml
# Antes:
python = ">=3.9,<3.12"
# Después (3.12 Support):
python = ">=3.8,<4"Declarar <4 en vez de <3.12 permite que el paquete se instale en Python 3.12, pero si unstructured falla, el error sigue ahí.
Solución final: unstructured como dependencia opcional
# Commit 6fbd832 — La solución elegante
try:
from unstructured.chunking.title import chunk_by_title
from unstructured.partition.auto import partition
def chunk_file(file_path):
elements = partition(filename=file_path)
chunks = chunk_by_title(elements, max_characters=MAX_CHARS_PER_CHUNK)
return [c.text for c in chunks]
except ImportError:
# Fallback: chunking simple por caracteres
def chunk_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
file_text = file.read()
chunks = [file_text[i:i+MAX_CHARS_PER_CHUNK]
for i in range(0, len(file_text), MAX_CHARS_PER_CHUNK)]
return chunksSi unstructured no está instalado (o falla porque es Python 3.12), el código usa un chunking simple: divide el texto cada 500 caracteres. Menos inteligente, pero funciona en cualquier versión.
ChromaDB también se vuelve opcional
# Commit aa4e5db — "Vlite?"
try:
import chromadb
from chromadb.utils.embedding_functions import DefaultEmbeddingFunction as setup_embed
os.environ["TOKENIZERS_PARALLELISM"] = "false"
embed = setup_embed()
except:
pass # shoulda used vliteEl comentario # shoulda used vlite es interesante — Killian estaba considerando migrar el backend de embeddings a vlite, una alternativa más ligera.
La migración nunca se completó, pero el try/except quedó como preparación.
El mensaje silenciado
# Commit 3f74c6a — "Random message"
# ANTES:
print("Please run 'pip install \"unstructured[all-docs]\"' to improve document-reading performance.")
# DESPUÉS:
# print("Please run 'pip install \"unstructured[all-docs]\"' to improve document-reading performance.")Con unstructured ahora siendo opcional y teniendo un fallback silencioso, imprimir un mensaje de "falta instalar algo" cada vez que se importa aifs sería molesto. Se comenta.
La evolución de las dependencias
| Versión | Python | unstructured | chromadb |
|---|---|---|---|
| 0.0.1 | >=3.9,❤️.12 | requerida | requerida |
| 0.0.12 | >=3.8,<4 | requerida (error útil) | requerida |
| final | >=3.8,<4 | opcional (fallback) | opcional (try/except) |
Lección del capítulo
Las dependencias pesadas deben ser opcionales cuando hay un fallback razonable. Un sistema que funciona al 80% es infinitamente mejor que uno que no funciona por falta de una librería.
Siguiente: Cap 11 — Estado final del proyecto