🇨🇴 Colombia Open
Datasets públicos de Colombia, curados, normalizados y validados, para que cualquiera los use desde Python sin lidiar con los portales, APIs y Excels inconsistentes de cada institución oficial.
from colombia_open import ColombiaOpen
hub = ColombiaOpen()
municipios = hub.load_polars("municipios")
departamentos = hub.load_polars("departamentos")
Proyecto en MVP activo. Tres fuentes están implementadas (DIVIPOLA: departamentos + municipios, DANE; demografía: proyecciones de población municipal, DANE; y educación: directorio de establecimientos, MEN). GitHub Releases publicados y landing page en vivo en davidcasr.com/colombia-open. No publicado en PyPI todavía — ver Estado del proyecto.
Por qué existe
Los datos públicos de Colombia existen, son abiertos, y están dispersos en decenas de portales con formatos, convenciones de código y calidad de API distintas (DANE, IDEAM, ICFES, DNP, Banco de la República, XM...). El trabajo real casi nunca es "¿existe el dato?" sino "¿cuánto tiempo me toma normalizarlo, validarlo, y confiar en que no tiene errores silenciosos (ej. un código de municipio que perdió el cero inicial en Excel)?"
colombia-open hace ese trabajo una vez, por fuente, y lo distribuye como
tablas Polars/Parquet listas para usar — con su fuente
oficial, licencia y fecha de actualización siempre visibles.
Instalación
pip install colombia-open # próximamente — ver "Estado del proyecto"
Para correr el pipeline localmente (extraer datos en vivo, no solo leerlos):
git clone https://github.com/davidcasr/colombia-open.git
cd colombia-open
make bootstrap # crea .venv e instala con extras pipeline+dev
make build # extract -> normalize -> validate -> data/normalized/
make test
Uso
from colombia_open import ColombiaOpen
hub = ColombiaOpen()
hub.list_datasets()
# ["departamentos", "municipios", "demografia", "educacion_establecimientos"]
municipios = hub.load_polars("municipios")
municipios.filter(municipios["cod_dpto"] == "05") # municipios de Antioquia
hub.resolve_municipios(["Medellín", "cali", "BOGOTA"])
# resuelve nombres a código DIVIPOLA, sin fuzzy matching (coincidencia exacta
# normalizada: sin tildes, minúsculas)
hub.cross_view(["municipios", "departamentos"], on="cod_dpto")
# join listo entre dos datasets que comparten una clave territorial
hub.provenance("municipios")
# {"source_name": "DANE — DIVIPOLA...", "source_url": "...", "source_mode": "live", ...}
CLI equivalente:
colombia-open list
colombia-open show municipios
colombia-open path municipios --output parquet
colombia-open example municipios --kind python
colombia-open validate municipios
Datasets disponibles
| Dataset | Descripción | Fuente | Filas | Licencia |
|---|---|---|---|---|
departamentos |
Departamentos: código DIVIPOLA (2 dígitos) + nombre | DANE, vía datos.gov.co | 33 | CC BY-SA 4.0 |
municipios |
Municipios: código DIVIPOLA (5 dígitos), nombre, departamento, centroide lon/lat | DANE, vía datos.gov.co | ~1122 | CC BY-SA 4.0 |
demografia |
Proyecciones de población municipal por área geográfica, 2018-2042 | DANE (descarga directa) | ~84225 | Términos DANE (público) |
educacion_establecimientos |
Directorio único de establecimientos educativos, 2015-2025 | MEN, vía datos.gov.co | ~606206 | CC BY-SA 4.0 |
Ver docs/roadmap/roadmap.md para las ~14 fuentes mapeadas (implementadas y
pendientes) y docs/licenses/data_licenses.md para el detalle legal de cada una.
Instalación con extras
| Extra | Para qué | Incluye |
|---|---|---|
| (base) | Solo leer datos ya publicados | polars, pyarrow, requests, platformdirs |
pipeline |
Correr extract→build→validate localmente | duckdb, pandas, openpyxl, tenacity, structlog |
scraping |
Fuentes sin API/descarga directa (entorno aparte) | curl_cffi, beautifulsoup4, defusedxml |
geo |
Lookups geoespaciales (polígonos, cuando existan) | geopandas, shapely |
validation |
Validación estricta de esquema (Frictionless) | frictionless |
mcp |
Servidor MCP para que agentes de IA consulten el catálogo | mcp |
pip install "colombia-open[pipeline]"
Filosofía: una fuente por fin de semana
Este proyecto no se construye de golpe. Cada fuente nueva se implementa
de punta a punta (extractor + builder + validación + registro + tests +
docs) antes de empezar la siguiente. El resto de las fuentes candidatas
quedan mapeadas en docs/roadmap/roadmap.md con su dificultad de acceso, sin
implementar, hasta que les toque su turno.
La razón de ingeniería: la prioridad #1 no es "cuántas fuentes tenemos" sino
"qué tan fácil es agregar la fuente número N+1 sin releer todo el código
cada vez" — por eso existe la skill .claude/skills/new-source/ y el
comando /next-source. Ver CLAUDE.md para el detalle completo.
Arquitectura
src/
├── colombia_open/ # librería pública (pip install), deps livianas
├── extractors/ # uno por fuente institucional — fetch + fallback + raw snapshot
├── builders/ # staging -> normalizado (parquet/json) + catálogo
├── validation/ # reglas por dominio, funciones puras
└── registry/ # qué datasets existen, su esquema y su licencia
data/
├── raw/ # snapshots crudos, write-once (no se edita después)
├── staging/ # CSV normalizado + metadata.json por extractor
├── normalized/ # parquet/json finales + dataset_catalog.json (lo que lee la librería)
└── registry/ # datasets.json — fuente de verdad estática del registro
La librería pública (colombia_open/) nunca importa código de pipeline
(extractors/, builders/, validation/) — así pip install colombia-open
se mantiene liviano. El primer uso descarga y cachea el bundle de datos
publicado en GitHub Releases (con verificación SHA256); en desarrollo, lee
directamente data/normalized/ si ya corriste make build.
Estado del proyecto
- ✅ Patrón extractor/builder/validación/registro probado con tres fuentes (DIVIPOLA, demografía y educación) de dominios distintos (API Socrata pequeña, descarga directa de Excel, API Socrata grande y paginada).
- ✅ GitHub Releases
publicados (último:
v0.3.0, bundle de datos con SHA256, incluye las tres fuentes) —ColombiaOpen()ya puede descargar y cachear el bundle automáticamente sin tener que correr el pipeline localmente (verdata_manager.py). Convención de versionado:.claude/rules/releases.md. - ⬜ Todavía no se publica en PyPI. El mecanismo ya está listo y verificado
end-to-end (
.github/workflows/publish.yml, trusted publishing sin token): build en limpio, venv aislado, descarga real del bundle desde GitHub Releases y carga de los 4 datasets confirmados el 2026-10-18. Falta configurar el trusted publisher en pypi.org y correr el primer publish. Mientras tanto, la instalación es víagit clone+make bootstrap, o consumiendo el bundle del Release directamente. - ✅ Landing page (
site/, verdocs/brand/design-system.md) deployada en davidcasr.com/colombia-open. - Ver
docs/roadmap/roadmap.mdpara qué sigue.
Legal
El código es MIT (LICENSE). Cada dataset conserva la licencia de su fuente
original — ver docs/licenses/data_licenses.md antes de redistribuir cualquier dataset
fuera de este paquete.
Contribuir
Hecho por David Castro. El flujo de trabajo
está pensado para sesiones de Claude Code recurrentes — ver CLAUDE.md si
vas a contribuir con un agente de IA.
Metadata
Release files for colombia-open 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| colombia_open-0.3.0.tar.gz | 77.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| colombia_open-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 93.2 kB
Release files / colombia_open-0.3.0.tar.gz
| Download URL | colombia_open-0.3.0.tar.gz |
|---|---|
| Size | 77.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
227d2dd9c0c7790b6efac2a9b1dacc452cca9cd2a356c11469712add666cafe8
|
|
BLAKE2b-256 checksum How to use checksums |
0928799e931e4bbb4174e83b2f21aefc1387697de74f61bc1c9d705908476107
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / colombia_open-0.3.0-py3-none-any.whl
| Download URL | colombia_open-0.3.0-py3-none-any.whl |
|---|---|
| Size | 16.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb119170a2e94bd4105cce7c3538d9d68ab02219d1727b3a229234ccff403805
|
|
BLAKE2b-256 checksum How to use checksums |
07e10cc4782257c1072f7720fca62a32436ba8eefad27f26b9a146347eb60a8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logSecurity for colombia-open 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for colombia_open-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.