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.
Files changed (35) hide show
  1. datos_mexico-0.1.0/.gitignore +72 -0
  2. datos_mexico-0.1.0/CITATION.cff +21 -0
  3. datos_mexico-0.1.0/LICENSE +21 -0
  4. datos_mexico-0.1.0/PKG-INFO +153 -0
  5. datos_mexico-0.1.0/README.md +108 -0
  6. datos_mexico-0.1.0/pyproject.toml +113 -0
  7. datos_mexico-0.1.0/src/datos_mexico/__init__.py +35 -0
  8. datos_mexico-0.1.0/src/datos_mexico/_cache.py +114 -0
  9. datos_mexico-0.1.0/src/datos_mexico/_constants.py +18 -0
  10. datos_mexico-0.1.0/src/datos_mexico/_helpers.py +89 -0
  11. datos_mexico-0.1.0/src/datos_mexico/_http.py +446 -0
  12. datos_mexico-0.1.0/src/datos_mexico/_namespace.py +81 -0
  13. datos_mexico-0.1.0/src/datos_mexico/_version.py +3 -0
  14. datos_mexico-0.1.0/src/datos_mexico/client.py +148 -0
  15. datos_mexico-0.1.0/src/datos_mexico/endpoints/__init__.py +1 -0
  16. datos_mexico-0.1.0/src/datos_mexico/endpoints/cdmx.py +360 -0
  17. datos_mexico-0.1.0/src/datos_mexico/endpoints/comparativo.py +139 -0
  18. datos_mexico-0.1.0/src/datos_mexico/endpoints/consar.py +706 -0
  19. datos_mexico-0.1.0/src/datos_mexico/endpoints/demo.py +50 -0
  20. datos_mexico-0.1.0/src/datos_mexico/endpoints/enigh.py +203 -0
  21. datos_mexico-0.1.0/src/datos_mexico/endpoints/export.py +101 -0
  22. datos_mexico-0.1.0/src/datos_mexico/endpoints/nombramientos.py +62 -0
  23. datos_mexico-0.1.0/src/datos_mexico/endpoints/personas.py +62 -0
  24. datos_mexico-0.1.0/src/datos_mexico/exceptions.py +192 -0
  25. datos_mexico-0.1.0/src/datos_mexico/models/__init__.py +313 -0
  26. datos_mexico-0.1.0/src/datos_mexico/models/base.py +69 -0
  27. datos_mexico-0.1.0/src/datos_mexico/models/cdmx.py +313 -0
  28. datos_mexico-0.1.0/src/datos_mexico/models/comparativo.py +264 -0
  29. datos_mexico-0.1.0/src/datos_mexico/models/consar.py +918 -0
  30. datos_mexico-0.1.0/src/datos_mexico/models/demo.py +75 -0
  31. datos_mexico-0.1.0/src/datos_mexico/models/enigh.py +293 -0
  32. datos_mexico-0.1.0/src/datos_mexico/models/export.py +13 -0
  33. datos_mexico-0.1.0/src/datos_mexico/models/nombramientos.py +36 -0
  34. datos_mexico-0.1.0/src/datos_mexico/models/personas.py +26 -0
  35. 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"})