datos-mexico 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datos_mexico-0.1.0/.gitignore +72 -0
- datos_mexico-0.1.0/CITATION.cff +21 -0
- datos_mexico-0.1.0/LICENSE +21 -0
- datos_mexico-0.1.0/PKG-INFO +153 -0
- datos_mexico-0.1.0/README.md +108 -0
- datos_mexico-0.1.0/pyproject.toml +113 -0
- datos_mexico-0.1.0/src/datos_mexico/__init__.py +35 -0
- datos_mexico-0.1.0/src/datos_mexico/_cache.py +114 -0
- datos_mexico-0.1.0/src/datos_mexico/_constants.py +18 -0
- datos_mexico-0.1.0/src/datos_mexico/_helpers.py +89 -0
- datos_mexico-0.1.0/src/datos_mexico/_http.py +446 -0
- datos_mexico-0.1.0/src/datos_mexico/_namespace.py +81 -0
- datos_mexico-0.1.0/src/datos_mexico/_version.py +3 -0
- datos_mexico-0.1.0/src/datos_mexico/client.py +148 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/__init__.py +1 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/cdmx.py +360 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/comparativo.py +139 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/consar.py +706 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/demo.py +50 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/enigh.py +203 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/export.py +101 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/nombramientos.py +62 -0
- datos_mexico-0.1.0/src/datos_mexico/endpoints/personas.py +62 -0
- datos_mexico-0.1.0/src/datos_mexico/exceptions.py +192 -0
- datos_mexico-0.1.0/src/datos_mexico/models/__init__.py +313 -0
- datos_mexico-0.1.0/src/datos_mexico/models/base.py +69 -0
- datos_mexico-0.1.0/src/datos_mexico/models/cdmx.py +313 -0
- datos_mexico-0.1.0/src/datos_mexico/models/comparativo.py +264 -0
- datos_mexico-0.1.0/src/datos_mexico/models/consar.py +918 -0
- datos_mexico-0.1.0/src/datos_mexico/models/demo.py +75 -0
- datos_mexico-0.1.0/src/datos_mexico/models/enigh.py +293 -0
- datos_mexico-0.1.0/src/datos_mexico/models/export.py +13 -0
- datos_mexico-0.1.0/src/datos_mexico/models/nombramientos.py +36 -0
- datos_mexico-0.1.0/src/datos_mexico/models/personas.py +26 -0
- datos_mexico-0.1.0/src/datos_mexico/py.typed +0 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
|
|
25
|
+
# Testing
|
|
26
|
+
htmlcov/
|
|
27
|
+
.tox/
|
|
28
|
+
.nox/
|
|
29
|
+
.coverage
|
|
30
|
+
.coverage.*
|
|
31
|
+
.cache
|
|
32
|
+
nosetests.xml
|
|
33
|
+
coverage.xml
|
|
34
|
+
*.cover
|
|
35
|
+
*.py,cover
|
|
36
|
+
.hypothesis/
|
|
37
|
+
.pytest_cache/
|
|
38
|
+
cover/
|
|
39
|
+
|
|
40
|
+
# Environments
|
|
41
|
+
.env
|
|
42
|
+
.venv
|
|
43
|
+
env/
|
|
44
|
+
venv/
|
|
45
|
+
ENV/
|
|
46
|
+
env.bak/
|
|
47
|
+
venv.bak/
|
|
48
|
+
|
|
49
|
+
# IDE
|
|
50
|
+
.vscode/
|
|
51
|
+
.idea/
|
|
52
|
+
*.swp
|
|
53
|
+
*.swo
|
|
54
|
+
|
|
55
|
+
# OS
|
|
56
|
+
.DS_Store
|
|
57
|
+
Thumbs.db
|
|
58
|
+
|
|
59
|
+
# Notebooks
|
|
60
|
+
.ipynb_checkpoints/
|
|
61
|
+
|
|
62
|
+
# Documentation builds
|
|
63
|
+
docs/_build/
|
|
64
|
+
site/
|
|
65
|
+
|
|
66
|
+
# Type checking
|
|
67
|
+
.mypy_cache/
|
|
68
|
+
.pyre/
|
|
69
|
+
.pytype/
|
|
70
|
+
|
|
71
|
+
# Ruff
|
|
72
|
+
.ruff_cache/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it using the following metadata."
|
|
3
|
+
title: "datos-mexico-py: Cliente Python para la API del Observatorio Datos México"
|
|
4
|
+
abstract: "Cliente Python oficial para acceder programáticamente a los datos públicos mexicanos curados por el Observatorio Datos México. Provee acceso tipado a microdatos del SAR (CONSAR), ENIGH (INEGI) y servidores públicos de la Ciudad de México."
|
|
5
|
+
authors:
|
|
6
|
+
- name: "Equipo de Datos México"
|
|
7
|
+
website: "https://datosmexico.org"
|
|
8
|
+
email: "equipo@datosmexico.org"
|
|
9
|
+
version: 0.1.0
|
|
10
|
+
date-released: 2026-05-04
|
|
11
|
+
license: MIT
|
|
12
|
+
repository-code: "https://github.com/datos-mexico/datos-mexico-py"
|
|
13
|
+
url: "https://datosmexico.org"
|
|
14
|
+
keywords:
|
|
15
|
+
- "datos abiertos"
|
|
16
|
+
- "México"
|
|
17
|
+
- "open data"
|
|
18
|
+
- "INEGI"
|
|
19
|
+
- "CONSAR"
|
|
20
|
+
- "ENIGH"
|
|
21
|
+
- "SAR"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Datos México
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: datos-mexico
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Cliente Python oficial para la API del Observatorio Datos México
|
|
5
|
+
Project-URL: Homepage, https://datosmexico.org
|
|
6
|
+
Project-URL: Documentation, https://github.com/datos-mexico/datos-mexico-py#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/datos-mexico/datos-mexico-py
|
|
8
|
+
Project-URL: Issues, https://github.com/datos-mexico/datos-mexico-py/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/datos-mexico/datos-mexico-py/releases
|
|
10
|
+
Author-email: David Fernando Ávila Díaz <df.avila.diaz@gmail.com>
|
|
11
|
+
Maintainer-email: Equipo de Datos México <pypi@datosmexico.org>
|
|
12
|
+
License: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: afore,api-client,cdmx,consar,datos-abiertos,enigh,inegi,mexico,open-data,pensiones,sar,transparencia
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
|
+
Requires-Dist: httpx>=0.27.0
|
|
30
|
+
Requires-Dist: pydantic>=2.6.0
|
|
31
|
+
Requires-Dist: tenacity>=8.2.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
34
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: respx>=0.21.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
39
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
40
|
+
Provides-Extra: examples
|
|
41
|
+
Requires-Dist: jupyter>=1.0; extra == 'examples'
|
|
42
|
+
Requires-Dist: matplotlib>=3.7; extra == 'examples'
|
|
43
|
+
Requires-Dist: pandas>=2.0; extra == 'examples'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# datos-mexico-py
|
|
47
|
+
|
|
48
|
+
Cliente Python oficial para la API del [Observatorio Datos México](https://datosmexico.org).
|
|
49
|
+
|
|
50
|
+
Acceso programático a microdatos públicos mexicanos curados, validados al peso contra fuentes oficiales, y documentados con sus salvedades metodológicas.
|
|
51
|
+
|
|
52
|
+
## Datasets disponibles
|
|
53
|
+
|
|
54
|
+
- **CDMX servidores públicos**: 246,831 servidores · 75 sectores · padrón vigente del Gobierno de la Ciudad de México
|
|
55
|
+
- **CONSAR / SAR**: serie histórica 1998–2025 · 11 AFOREs · recursos administrados, composición, comisiones, traspasos
|
|
56
|
+
- **ENIGH 2024 Nueva Serie**: 91,414 hogares en muestra · 38.8M expandidos · ingresos, gastos, demografía
|
|
57
|
+
|
|
58
|
+
Próximamente: tipos comparativos cross-dataset.
|
|
59
|
+
|
|
60
|
+
## Instalación
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install datos-mexico
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Requiere Python 3.10 o superior.
|
|
67
|
+
|
|
68
|
+
## Uso rápido
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from datos_mexico import DatosMexico
|
|
72
|
+
|
|
73
|
+
client = DatosMexico()
|
|
74
|
+
|
|
75
|
+
# CDMX servidores públicos
|
|
76
|
+
stats = client.cdmx.dashboard_stats()
|
|
77
|
+
print(f"{stats['totalServidores']:,} servidores públicos")
|
|
78
|
+
|
|
79
|
+
# SAR composición
|
|
80
|
+
sar = client.consar.recursos_totales()
|
|
81
|
+
print(f"Última fecha: {sar['fecha_max']}")
|
|
82
|
+
|
|
83
|
+
# ENIGH hogares
|
|
84
|
+
hogares = client.enigh.hogares_summary()
|
|
85
|
+
print(f"{hogares['n_hogares_expandido']:,} hogares estimados")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
El directorio [`examples/`](examples/) contiene 5 notebooks Jupyter ejecutables que muestran flujos típicos del SDK con datos reales contra `https://api.datos-itam.org`:
|
|
91
|
+
|
|
92
|
+
- [`01_quickstart.ipynb`](examples/01_quickstart.ipynb) — onboarding en 10 minutos
|
|
93
|
+
- [`02_cdmx_servidores_publicos.ipynb`](examples/02_cdmx_servidores_publicos.ipynb) — análisis del padrón CDMX (distribuciones, top sectores, brecha por edad)
|
|
94
|
+
- [`03_sar_composicion.ipynb`](examples/03_sar_composicion.ipynb) — composición del Sistema de Ahorro para el Retiro (serie histórica, AFOREs, componentes, IMSS vs ISSSTE)
|
|
95
|
+
- [`04_enigh_hogares_desigualdad.ipynb`](examples/04_enigh_hogares_desigualdad.ipynb) — desigualdad de ingreso por decil ENIGH 2024 NS (composición de gasto D1 vs D10, validaciones INEGI)
|
|
96
|
+
- [`05_paper_amafore_workflow.ipynb`](examples/05_paper_amafore_workflow.ipynb) — workflow específico para investigación de pensiones (cross-dataset, paper Amafore-ITAM 2026)
|
|
97
|
+
|
|
98
|
+
Para ejecutarlos:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install datos-mexico[examples]
|
|
102
|
+
jupyter notebook examples/
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Cada notebook se renderiza en GitHub con outputs visibles (gráficas y cifras reales).
|
|
106
|
+
|
|
107
|
+
## Documentación
|
|
108
|
+
|
|
109
|
+
- **Quickstart**: [docs/quickstart.md](docs/quickstart.md)
|
|
110
|
+
- **API completa**: [docs/api/](docs/api/)
|
|
111
|
+
- **Ejemplos en notebooks**: [examples/](examples/)
|
|
112
|
+
- **Documentación de la API HTTP**: https://api.datos-itam.org/docs
|
|
113
|
+
|
|
114
|
+
## Salvedades metodológicas
|
|
115
|
+
|
|
116
|
+
El cliente reproduce los datos tal como los publica la API del observatorio. La API a su vez reprocesa fuentes oficiales (INEGI, CONSAR, Datos Abiertos CDMX) sin alterar microdatos. Cada endpoint documenta sus límites de cobertura, fechas de corte, y validaciones contra fuente primaria.
|
|
117
|
+
|
|
118
|
+
Para precisiones técnicas profundas sobre cualquier dataset, consultar las fuentes primarias enlazadas en [docs/sources.md](docs/sources.md).
|
|
119
|
+
|
|
120
|
+
## Cómo citar
|
|
121
|
+
|
|
122
|
+
Si usas este cliente en una investigación o publicación académica, por favor cita el proyecto:
|
|
123
|
+
|
|
124
|
+
```bibtex
|
|
125
|
+
@software{datos_mexico_py,
|
|
126
|
+
author = {{Equipo de Datos México}},
|
|
127
|
+
title = {datos-mexico-py: Cliente Python para la API del Observatorio Datos México},
|
|
128
|
+
year = {2026},
|
|
129
|
+
publisher = {Datos México},
|
|
130
|
+
url = {https://github.com/datos-mexico/datos-mexico-py},
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
GitHub también ofrece exportación BibTeX/APA automática desde el botón "Cite this repository" en la página del repo.
|
|
135
|
+
|
|
136
|
+
## Contribuir
|
|
137
|
+
|
|
138
|
+
Ver [docs/contributing.md](docs/contributing.md). Pull requests, issues, y reportes de errores en datos son bienvenidos.
|
|
139
|
+
|
|
140
|
+
## Licencia
|
|
141
|
+
|
|
142
|
+
MIT — ver [LICENSE](LICENSE).
|
|
143
|
+
|
|
144
|
+
## Contacto
|
|
145
|
+
|
|
146
|
+
- Sitio: https://datosmexico.org
|
|
147
|
+
- Email general: equipo@datosmexico.org
|
|
148
|
+
- Reportes de errores en datos: errores@datosmexico.org
|
|
149
|
+
- Prensa y medios: prensa@datosmexico.org
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
*Datos México es un observatorio independiente formado por estudiantes y egresados del Instituto Tecnológico Autónomo de México (ITAM).*
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# datos-mexico-py
|
|
2
|
+
|
|
3
|
+
Cliente Python oficial para la API del [Observatorio Datos México](https://datosmexico.org).
|
|
4
|
+
|
|
5
|
+
Acceso programático a microdatos públicos mexicanos curados, validados al peso contra fuentes oficiales, y documentados con sus salvedades metodológicas.
|
|
6
|
+
|
|
7
|
+
## Datasets disponibles
|
|
8
|
+
|
|
9
|
+
- **CDMX servidores públicos**: 246,831 servidores · 75 sectores · padrón vigente del Gobierno de la Ciudad de México
|
|
10
|
+
- **CONSAR / SAR**: serie histórica 1998–2025 · 11 AFOREs · recursos administrados, composición, comisiones, traspasos
|
|
11
|
+
- **ENIGH 2024 Nueva Serie**: 91,414 hogares en muestra · 38.8M expandidos · ingresos, gastos, demografía
|
|
12
|
+
|
|
13
|
+
Próximamente: tipos comparativos cross-dataset.
|
|
14
|
+
|
|
15
|
+
## Instalación
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install datos-mexico
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requiere Python 3.10 o superior.
|
|
22
|
+
|
|
23
|
+
## Uso rápido
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from datos_mexico import DatosMexico
|
|
27
|
+
|
|
28
|
+
client = DatosMexico()
|
|
29
|
+
|
|
30
|
+
# CDMX servidores públicos
|
|
31
|
+
stats = client.cdmx.dashboard_stats()
|
|
32
|
+
print(f"{stats['totalServidores']:,} servidores públicos")
|
|
33
|
+
|
|
34
|
+
# SAR composición
|
|
35
|
+
sar = client.consar.recursos_totales()
|
|
36
|
+
print(f"Última fecha: {sar['fecha_max']}")
|
|
37
|
+
|
|
38
|
+
# ENIGH hogares
|
|
39
|
+
hogares = client.enigh.hogares_summary()
|
|
40
|
+
print(f"{hogares['n_hogares_expandido']:,} hogares estimados")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
El directorio [`examples/`](examples/) contiene 5 notebooks Jupyter ejecutables que muestran flujos típicos del SDK con datos reales contra `https://api.datos-itam.org`:
|
|
46
|
+
|
|
47
|
+
- [`01_quickstart.ipynb`](examples/01_quickstart.ipynb) — onboarding en 10 minutos
|
|
48
|
+
- [`02_cdmx_servidores_publicos.ipynb`](examples/02_cdmx_servidores_publicos.ipynb) — análisis del padrón CDMX (distribuciones, top sectores, brecha por edad)
|
|
49
|
+
- [`03_sar_composicion.ipynb`](examples/03_sar_composicion.ipynb) — composición del Sistema de Ahorro para el Retiro (serie histórica, AFOREs, componentes, IMSS vs ISSSTE)
|
|
50
|
+
- [`04_enigh_hogares_desigualdad.ipynb`](examples/04_enigh_hogares_desigualdad.ipynb) — desigualdad de ingreso por decil ENIGH 2024 NS (composición de gasto D1 vs D10, validaciones INEGI)
|
|
51
|
+
- [`05_paper_amafore_workflow.ipynb`](examples/05_paper_amafore_workflow.ipynb) — workflow específico para investigación de pensiones (cross-dataset, paper Amafore-ITAM 2026)
|
|
52
|
+
|
|
53
|
+
Para ejecutarlos:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install datos-mexico[examples]
|
|
57
|
+
jupyter notebook examples/
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Cada notebook se renderiza en GitHub con outputs visibles (gráficas y cifras reales).
|
|
61
|
+
|
|
62
|
+
## Documentación
|
|
63
|
+
|
|
64
|
+
- **Quickstart**: [docs/quickstart.md](docs/quickstart.md)
|
|
65
|
+
- **API completa**: [docs/api/](docs/api/)
|
|
66
|
+
- **Ejemplos en notebooks**: [examples/](examples/)
|
|
67
|
+
- **Documentación de la API HTTP**: https://api.datos-itam.org/docs
|
|
68
|
+
|
|
69
|
+
## Salvedades metodológicas
|
|
70
|
+
|
|
71
|
+
El cliente reproduce los datos tal como los publica la API del observatorio. La API a su vez reprocesa fuentes oficiales (INEGI, CONSAR, Datos Abiertos CDMX) sin alterar microdatos. Cada endpoint documenta sus límites de cobertura, fechas de corte, y validaciones contra fuente primaria.
|
|
72
|
+
|
|
73
|
+
Para precisiones técnicas profundas sobre cualquier dataset, consultar las fuentes primarias enlazadas en [docs/sources.md](docs/sources.md).
|
|
74
|
+
|
|
75
|
+
## Cómo citar
|
|
76
|
+
|
|
77
|
+
Si usas este cliente en una investigación o publicación académica, por favor cita el proyecto:
|
|
78
|
+
|
|
79
|
+
```bibtex
|
|
80
|
+
@software{datos_mexico_py,
|
|
81
|
+
author = {{Equipo de Datos México}},
|
|
82
|
+
title = {datos-mexico-py: Cliente Python para la API del Observatorio Datos México},
|
|
83
|
+
year = {2026},
|
|
84
|
+
publisher = {Datos México},
|
|
85
|
+
url = {https://github.com/datos-mexico/datos-mexico-py},
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
GitHub también ofrece exportación BibTeX/APA automática desde el botón "Cite this repository" en la página del repo.
|
|
90
|
+
|
|
91
|
+
## Contribuir
|
|
92
|
+
|
|
93
|
+
Ver [docs/contributing.md](docs/contributing.md). Pull requests, issues, y reportes de errores en datos son bienvenidos.
|
|
94
|
+
|
|
95
|
+
## Licencia
|
|
96
|
+
|
|
97
|
+
MIT — ver [LICENSE](LICENSE).
|
|
98
|
+
|
|
99
|
+
## Contacto
|
|
100
|
+
|
|
101
|
+
- Sitio: https://datosmexico.org
|
|
102
|
+
- Email general: equipo@datosmexico.org
|
|
103
|
+
- Reportes de errores en datos: errores@datosmexico.org
|
|
104
|
+
- Prensa y medios: prensa@datosmexico.org
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
*Datos México es un observatorio independiente formado por estudiantes y egresados del Instituto Tecnológico Autónomo de México (ITAM).*
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "datos-mexico"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Cliente Python oficial para la API del Observatorio Datos México"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "David Fernando Ávila Díaz", email = "df.avila.diaz@gmail.com" }
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{ name = "Equipo de Datos México", email = "pypi@datosmexico.org" }
|
|
17
|
+
]
|
|
18
|
+
keywords = [
|
|
19
|
+
"mexico",
|
|
20
|
+
"datos-abiertos",
|
|
21
|
+
"open-data",
|
|
22
|
+
"consar",
|
|
23
|
+
"sar",
|
|
24
|
+
"afore",
|
|
25
|
+
"enigh",
|
|
26
|
+
"inegi",
|
|
27
|
+
"cdmx",
|
|
28
|
+
"transparencia",
|
|
29
|
+
"api-client",
|
|
30
|
+
"pensiones",
|
|
31
|
+
]
|
|
32
|
+
classifiers = [
|
|
33
|
+
"Development Status :: 4 - Beta",
|
|
34
|
+
"Intended Audience :: Developers",
|
|
35
|
+
"Intended Audience :: Science/Research",
|
|
36
|
+
"License :: OSI Approved :: MIT License",
|
|
37
|
+
"Operating System :: OS Independent",
|
|
38
|
+
"Programming Language :: Python :: 3",
|
|
39
|
+
"Programming Language :: Python :: 3.10",
|
|
40
|
+
"Programming Language :: Python :: 3.11",
|
|
41
|
+
"Programming Language :: Python :: 3.12",
|
|
42
|
+
"Programming Language :: Python :: 3.13",
|
|
43
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
44
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
45
|
+
"Typing :: Typed",
|
|
46
|
+
]
|
|
47
|
+
dependencies = [
|
|
48
|
+
"httpx>=0.27.0",
|
|
49
|
+
"pydantic>=2.6.0",
|
|
50
|
+
"tenacity>=8.2.0",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[project.optional-dependencies]
|
|
54
|
+
dev = [
|
|
55
|
+
"pytest>=8.0",
|
|
56
|
+
"pytest-cov>=5.0",
|
|
57
|
+
"ruff>=0.6",
|
|
58
|
+
"mypy>=1.10",
|
|
59
|
+
"build>=1.2",
|
|
60
|
+
"twine>=5.0",
|
|
61
|
+
"respx>=0.21.0",
|
|
62
|
+
]
|
|
63
|
+
examples = [
|
|
64
|
+
"jupyter>=1.0",
|
|
65
|
+
"pandas>=2.0",
|
|
66
|
+
"matplotlib>=3.7",
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
[project.urls]
|
|
70
|
+
Homepage = "https://datosmexico.org"
|
|
71
|
+
Documentation = "https://github.com/datos-mexico/datos-mexico-py#readme"
|
|
72
|
+
Repository = "https://github.com/datos-mexico/datos-mexico-py"
|
|
73
|
+
Issues = "https://github.com/datos-mexico/datos-mexico-py/issues"
|
|
74
|
+
Changelog = "https://github.com/datos-mexico/datos-mexico-py/releases"
|
|
75
|
+
|
|
76
|
+
[tool.hatch.version]
|
|
77
|
+
path = "src/datos_mexico/_version.py"
|
|
78
|
+
|
|
79
|
+
[tool.hatch.build.targets.wheel]
|
|
80
|
+
packages = ["src/datos_mexico"]
|
|
81
|
+
include = ["src/datos_mexico/py.typed"]
|
|
82
|
+
|
|
83
|
+
[tool.hatch.build.targets.sdist]
|
|
84
|
+
include = [
|
|
85
|
+
"src/datos_mexico",
|
|
86
|
+
"README.md",
|
|
87
|
+
"LICENSE",
|
|
88
|
+
"CITATION.cff",
|
|
89
|
+
"pyproject.toml",
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
[tool.ruff]
|
|
93
|
+
line-length = 100
|
|
94
|
+
target-version = "py310"
|
|
95
|
+
extend-exclude = ["examples"]
|
|
96
|
+
|
|
97
|
+
[tool.ruff.lint]
|
|
98
|
+
select = ["E", "F", "I", "N", "UP", "B", "SIM", "RUF"]
|
|
99
|
+
ignore = []
|
|
100
|
+
|
|
101
|
+
[tool.pytest.ini_options]
|
|
102
|
+
testpaths = ["tests"]
|
|
103
|
+
python_files = "test_*.py"
|
|
104
|
+
addopts = "-v --tb=short"
|
|
105
|
+
markers = [
|
|
106
|
+
"integration: integration tests against the live API; gated by DATOS_MEXICO_INTEGRATION_TESTS=1",
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
[tool.mypy]
|
|
110
|
+
python_version = "3.10"
|
|
111
|
+
strict = true
|
|
112
|
+
warn_return_any = true
|
|
113
|
+
warn_unused_configs = true
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""datos-mexico: Cliente Python para la API del Observatorio Datos México."""
|
|
2
|
+
|
|
3
|
+
from datos_mexico._version import __version__
|
|
4
|
+
from datos_mexico.client import DatosMexico
|
|
5
|
+
from datos_mexico.exceptions import (
|
|
6
|
+
ApiError,
|
|
7
|
+
AuthenticationError,
|
|
8
|
+
AuthorizationError,
|
|
9
|
+
BadRequestError,
|
|
10
|
+
ConfigurationError,
|
|
11
|
+
DatosMexicoError,
|
|
12
|
+
NetworkError,
|
|
13
|
+
NotFoundError,
|
|
14
|
+
RateLimitError,
|
|
15
|
+
ServerError,
|
|
16
|
+
TimeoutError,
|
|
17
|
+
ValidationError,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"ApiError",
|
|
22
|
+
"AuthenticationError",
|
|
23
|
+
"AuthorizationError",
|
|
24
|
+
"BadRequestError",
|
|
25
|
+
"ConfigurationError",
|
|
26
|
+
"DatosMexico",
|
|
27
|
+
"DatosMexicoError",
|
|
28
|
+
"NetworkError",
|
|
29
|
+
"NotFoundError",
|
|
30
|
+
"RateLimitError",
|
|
31
|
+
"ServerError",
|
|
32
|
+
"TimeoutError",
|
|
33
|
+
"ValidationError",
|
|
34
|
+
"__version__",
|
|
35
|
+
]
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Cache en memoria con TTL configurable.
|
|
2
|
+
|
|
3
|
+
Implementa una caché thread-safe basada en un diccionario con timestamps
|
|
4
|
+
de expiración. El usuario del paquete normalmente no instancia ``TTLCache``
|
|
5
|
+
directamente: el ``HttpClient`` lo usa internamente para cachear respuestas
|
|
6
|
+
``GET``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import threading
|
|
12
|
+
import time
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TTLCache:
|
|
17
|
+
"""Caché thread-safe con expiración por TTL.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
ttl_seconds: Tiempo de vida de las entradas en segundos. Si es ``0``
|
|
21
|
+
la caché queda deshabilitada: ``set`` no almacena nada y ``get``
|
|
22
|
+
siempre devuelve ``None``. Debe ser ``>= 0``.
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
ValueError: Si ``ttl_seconds`` es negativo.
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
>>> cache = TTLCache(ttl_seconds=60)
|
|
29
|
+
>>> cache.set("key", {"value": 1})
|
|
30
|
+
>>> cache.get("key")
|
|
31
|
+
{'value': 1}
|
|
32
|
+
>>> cache_disabled = TTLCache(ttl_seconds=0)
|
|
33
|
+
>>> cache_disabled.set("key", "value")
|
|
34
|
+
>>> cache_disabled.get("key") is None
|
|
35
|
+
True
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, ttl_seconds: int) -> None:
|
|
39
|
+
if ttl_seconds < 0:
|
|
40
|
+
raise ValueError(f"ttl_seconds must be >= 0, got {ttl_seconds}")
|
|
41
|
+
self._ttl = ttl_seconds
|
|
42
|
+
self._store: dict[str, tuple[float, Any]] = {}
|
|
43
|
+
self._lock = threading.Lock()
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def ttl_seconds(self) -> int:
|
|
47
|
+
"""TTL configurado, en segundos."""
|
|
48
|
+
return self._ttl
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def enabled(self) -> bool:
|
|
52
|
+
"""True si la caché está activa (``ttl_seconds > 0``)."""
|
|
53
|
+
return self._ttl > 0
|
|
54
|
+
|
|
55
|
+
def get(self, key: str) -> Any | None:
|
|
56
|
+
"""Recupera el valor asociado a ``key`` si no expiró.
|
|
57
|
+
|
|
58
|
+
Si la entrada expiró, se elimina y se devuelve ``None``.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
key: Clave a consultar.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Valor cacheado, o ``None`` si no existe o expiró.
|
|
65
|
+
"""
|
|
66
|
+
if not self.enabled:
|
|
67
|
+
return None
|
|
68
|
+
now = time.monotonic()
|
|
69
|
+
with self._lock:
|
|
70
|
+
entry = self._store.get(key)
|
|
71
|
+
if entry is None:
|
|
72
|
+
return None
|
|
73
|
+
expires_at, value = entry
|
|
74
|
+
if expires_at <= now:
|
|
75
|
+
del self._store[key]
|
|
76
|
+
return None
|
|
77
|
+
return value
|
|
78
|
+
|
|
79
|
+
def set(self, key: str, value: Any) -> None:
|
|
80
|
+
"""Almacena ``value`` bajo ``key`` con expiración relativa al TTL.
|
|
81
|
+
|
|
82
|
+
Si la caché está deshabilitada (``ttl_seconds == 0``), la operación
|
|
83
|
+
es un no-op.
|
|
84
|
+
"""
|
|
85
|
+
if not self.enabled:
|
|
86
|
+
return
|
|
87
|
+
expires_at = time.monotonic() + self._ttl
|
|
88
|
+
with self._lock:
|
|
89
|
+
self._store[key] = (expires_at, value)
|
|
90
|
+
|
|
91
|
+
def clear(self) -> None:
|
|
92
|
+
"""Elimina todas las entradas de la caché."""
|
|
93
|
+
with self._lock:
|
|
94
|
+
self._store.clear()
|
|
95
|
+
|
|
96
|
+
def clear_expired(self) -> int:
|
|
97
|
+
"""Elimina las entradas expiradas y devuelve cuántas se eliminaron."""
|
|
98
|
+
if not self.enabled:
|
|
99
|
+
return 0
|
|
100
|
+
now = time.monotonic()
|
|
101
|
+
with self._lock:
|
|
102
|
+
expired = [k for k, (exp, _) in self._store.items() if exp <= now]
|
|
103
|
+
for k in expired:
|
|
104
|
+
del self._store[k]
|
|
105
|
+
return len(expired)
|
|
106
|
+
|
|
107
|
+
def __len__(self) -> int:
|
|
108
|
+
with self._lock:
|
|
109
|
+
return len(self._store)
|
|
110
|
+
|
|
111
|
+
def __contains__(self, key: object) -> bool:
|
|
112
|
+
if not isinstance(key, str):
|
|
113
|
+
return False
|
|
114
|
+
return self.get(key) is not None
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Constantes compartidas del cliente datos-mexico."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datos_mexico._version import __version__
|
|
6
|
+
|
|
7
|
+
DEFAULT_BASE_URL: str = "https://api.datos-itam.org"
|
|
8
|
+
DEFAULT_TIMEOUT_SECONDS: float = 30.0
|
|
9
|
+
DEFAULT_CACHE_TTL_SECONDS: int = 300
|
|
10
|
+
DEFAULT_MAX_RETRIES: int = 3
|
|
11
|
+
DEFAULT_RETRY_BACKOFF_BASE: float = 1.0
|
|
12
|
+
DEFAULT_RETRY_BACKOFF_MAX: float = 30.0
|
|
13
|
+
|
|
14
|
+
USER_AGENT: str = f"datos-mexico-py/{__version__} (https://datosmexico.org)"
|
|
15
|
+
|
|
16
|
+
RETRYABLE_STATUS_CODES: frozenset[int] = frozenset({408, 425, 429, 500, 502, 503, 504})
|
|
17
|
+
|
|
18
|
+
RETRYABLE_METHODS: frozenset[str] = frozenset({"GET", "HEAD", "OPTIONS"})
|