brmunipanel 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.
- brmunipanel-0.1.0/LICENSE +21 -0
- brmunipanel-0.1.0/MANIFEST.in +6 -0
- brmunipanel-0.1.0/PKG-INFO +184 -0
- brmunipanel-0.1.0/README.md +139 -0
- brmunipanel-0.1.0/pyproject.toml +70 -0
- brmunipanel-0.1.0/setup.cfg +4 -0
- brmunipanel-0.1.0/src/brmunipanel/__init__.py +39 -0
- brmunipanel-0.1.0/src/brmunipanel/datasus/__init__.py +1 -0
- brmunipanel-0.1.0/src/brmunipanel/datasus/regioes_saude.py +153 -0
- brmunipanel-0.1.0/src/brmunipanel/datasus/saude.py +309 -0
- brmunipanel-0.1.0/src/brmunipanel/datasus/tabnet.py +234 -0
- brmunipanel-0.1.0/src/brmunipanel/empacotamento.py +317 -0
- brmunipanel-0.1.0/src/brmunipanel/ibge/__init__.py +1 -0
- brmunipanel-0.1.0/src/brmunipanel/ibge/cempre.py +43 -0
- brmunipanel-0.1.0/src/brmunipanel/ibge/pib.py +31 -0
- brmunipanel-0.1.0/src/brmunipanel/ibge/populacao.py +64 -0
- brmunipanel-0.1.0/src/brmunipanel/ibge/sidra.py +112 -0
- brmunipanel-0.1.0/src/brmunipanel/ibge/territorio.py +372 -0
- brmunipanel-0.1.0/src/brmunipanel/inep/__init__.py +9 -0
- brmunipanel-0.1.0/src/brmunipanel/inep/censo_escolar.py +430 -0
- brmunipanel-0.1.0/src/brmunipanel/inep/censo_superior.py +395 -0
- brmunipanel-0.1.0/src/brmunipanel/inep/ideb.py +114 -0
- brmunipanel-0.1.0/src/brmunipanel/ipea/__init__.py +1 -0
- brmunipanel-0.1.0/src/brmunipanel/ipea/pbf.py +160 -0
- brmunipanel-0.1.0/src/brmunipanel/metadata/__init__.py +0 -0
- brmunipanel-0.1.0/src/brmunipanel/metadata/auditoria.py +272 -0
- brmunipanel-0.1.0/src/brmunipanel/metadata/contratos.py +415 -0
- brmunipanel-0.1.0/src/brmunipanel/metadata/dicionario.py +107 -0
- brmunipanel-0.1.0/src/brmunipanel/metadata/variaveis.json +2092 -0
- brmunipanel-0.1.0/src/brmunipanel/nucleo.py +189 -0
- brmunipanel-0.1.0/src/brmunipanel/painel.py +220 -0
- brmunipanel-0.1.0/src/brmunipanel/tesouro/__init__.py +1 -0
- brmunipanel-0.1.0/src/brmunipanel/tesouro/despesa_funcao.py +48 -0
- brmunipanel-0.1.0/src/brmunipanel/tesouro/finbra.py +208 -0
- brmunipanel-0.1.0/src/brmunipanel/tesouro/siconfi.py +305 -0
- brmunipanel-0.1.0/src/brmunipanel.egg-info/PKG-INFO +184 -0
- brmunipanel-0.1.0/src/brmunipanel.egg-info/SOURCES.txt +90 -0
- brmunipanel-0.1.0/src/brmunipanel.egg-info/dependency_links.txt +1 -0
- brmunipanel-0.1.0/src/brmunipanel.egg-info/requires.txt +24 -0
- brmunipanel-0.1.0/src/brmunipanel.egg-info/top_level.txt +1 -0
- brmunipanel-0.1.0/tests/dados/censo_escolar_2006_amostra.csv +11 -0
- brmunipanel-0.1.0/tests/dados/censo_escolar_2006_educprof_amostra.csv +4 -0
- brmunipanel-0.1.0/tests/dados/censo_escolar_2007_amostra.csv +9 -0
- brmunipanel-0.1.0/tests/dados/censo_escolar_2023_amostra.csv +9 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2000_graduacao_amostra.csv +88 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2000_instituicao_amostra.csv +6 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2000_sequencial_amostra.csv +3 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2007_graduacao_amostra.csv +44 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2007_instituicao_amostra.csv +5 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2007_sequencial_amostra.csv +3 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2008_graduacao_amostra.csv +92 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2008_instituicao_amostra.csv +5 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_2008_sequencial_amostra.csv +3 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_cursos_2009_amostra.csv +52 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_cursos_2023_amostra.csv +52 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_ies_2009_amostra.csv +10 -0
- brmunipanel-0.1.0/tests/dados/censo_superior_ies_2023_amostra.csv +12 -0
- brmunipanel-0.1.0/tests/dados/finbra_dsubfuncao_2006_amostra.json +842 -0
- brmunipanel-0.1.0/tests/dados/finbra_dsubfuncao_2010_amostra.json +1107 -0
- brmunipanel-0.1.0/tests/dados/ipea_FAM_PBF_amostra.json +1005 -0
- brmunipanel-0.1.0/tests/dados/ipea_VAL_PBF_amostra.json +830 -0
- brmunipanel-0.1.0/tests/dados/regioes_saude_amostra.json +69 -0
- brmunipanel-0.1.0/tests/dados/siconfi_contas_anuais_2013_amostra.csv +664 -0
- brmunipanel-0.1.0/tests/dados/siconfi_contas_anuais_2022_amostra.csv +923 -0
- brmunipanel-0.1.0/tests/dados/sidra_cempre_amostra.json +1 -0
- brmunipanel-0.1.0/tests/dados/sidra_t1685_2012_amostra.json +514 -0
- brmunipanel-0.1.0/tests/dados/sidra_t5938_2022_amostra.json +450 -0
- brmunipanel-0.1.0/tests/dados/sidra_t6579_amostra.json +1 -0
- brmunipanel-0.1.0/tests/dados/tabnet_com_coluna_amostra.html +69 -0
- brmunipanel-0.1.0/tests/dados/tabnet_sem_coluna_amostra.html +72 -0
- brmunipanel-0.1.0/tests/dados/tabnet_vazio_amostra.html +35 -0
- brmunipanel-0.1.0/tests/test_api.py +99 -0
- brmunipanel-0.1.0/tests/test_auditoria.py +103 -0
- brmunipanel-0.1.0/tests/test_cempre.py +65 -0
- brmunipanel-0.1.0/tests/test_censo_escolar.py +410 -0
- brmunipanel-0.1.0/tests/test_censo_superior.py +662 -0
- brmunipanel-0.1.0/tests/test_dicionario.py +97 -0
- brmunipanel-0.1.0/tests/test_dist_metadata.py +96 -0
- brmunipanel-0.1.0/tests/test_empacotamento.py +173 -0
- brmunipanel-0.1.0/tests/test_finbra.py +395 -0
- brmunipanel-0.1.0/tests/test_ideb.py +221 -0
- brmunipanel-0.1.0/tests/test_ipea_pbf.py +152 -0
- brmunipanel-0.1.0/tests/test_nucleo.py +267 -0
- brmunipanel-0.1.0/tests/test_painel.py +379 -0
- brmunipanel-0.1.0/tests/test_pib.py +71 -0
- brmunipanel-0.1.0/tests/test_populacao.py +101 -0
- brmunipanel-0.1.0/tests/test_regioes_saude.py +135 -0
- brmunipanel-0.1.0/tests/test_saude.py +293 -0
- brmunipanel-0.1.0/tests/test_siconfi.py +325 -0
- brmunipanel-0.1.0/tests/test_sidra.py +133 -0
- brmunipanel-0.1.0/tests/test_tabnet.py +123 -0
- brmunipanel-0.1.0/tests/test_territorio.py +276 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lucas Guesse
|
|
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,184 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: brmunipanel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ETL library for a harmonized panel of socioeconomic, fiscal, health, territorial and educational indicators for Brazilian municipalities (IBGE, Tesouro Nacional, IPEA Data, DATASUS, INEP).
|
|
5
|
+
Author: Lucas Guesse
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/lucasguesse/brmunipanel
|
|
8
|
+
Project-URL: Repository, https://github.com/lucasguesse/brmunipanel
|
|
9
|
+
Project-URL: Issues, https://github.com/lucasguesse/brmunipanel/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/lucasguesse/brmunipanel#readme
|
|
11
|
+
Keywords: brazil,municipalities,panel,etl,indicators,ibge,inep,siconfi,datasus
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: duckdb>=1.0.0
|
|
25
|
+
Requires-Dist: polars>=1.0.0
|
|
26
|
+
Requires-Dist: pyarrow>=16.0.0
|
|
27
|
+
Requires-Dist: pandas>=2.2.0
|
|
28
|
+
Requires-Dist: numpy>=1.26.0
|
|
29
|
+
Requires-Dist: xlrd>=2.0.0
|
|
30
|
+
Requires-Dist: openpyxl>=3.1.0
|
|
31
|
+
Requires-Dist: requests>=2.32.0
|
|
32
|
+
Requires-Dist: tqdm>=4.66.0
|
|
33
|
+
Requires-Dist: access-parser==0.0.6
|
|
34
|
+
Requires-Dist: construct>=2.10.70
|
|
35
|
+
Requires-Dist: tabulate>=0.10.0
|
|
36
|
+
Provides-Extra: plots
|
|
37
|
+
Requires-Dist: matplotlib>=3.9.0; extra == "plots"
|
|
38
|
+
Requires-Dist: seaborn>=0.13.0; extra == "plots"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: tomli>=1.1.0; python_version < "3.11" and extra == "dev"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# BRMuniPanel
|
|
47
|
+
|
|
48
|
+
[](https://github.com/lucasguesse/brmunipanel/actions/workflows/ci.yml)
|
|
49
|
+
|
|
50
|
+
**A Python ETL library and data access tool for the Harmonized Suite of Tables of Socioeconomic, Fiscal, Territorial, Health, and Educational Indicators for Brazilian Municipalities (2006–2023).**
|
|
51
|
+
|
|
52
|
+
## Overview
|
|
53
|
+
`brmunipanel` is an open-source Python library designed to fully automate the extraction, transformation, and loading (ETL) of public administrative records from multiple Brazilian federal agencies. It solves the massive structural burden of dealing with fragmented, historically inconsistent, and undocumented municipal data in Brazil.
|
|
54
|
+
|
|
55
|
+
By standardizing the 7-digit IBGE municipality code as the primary join key and freezing the territorial division to the 2025 canonical grid, this library allows researchers and data scientists to easily build and consume a longitudinal structural database of 5,571 municipalities, structured across six standardized tables: two territorial tables and four longitudinal thematic tables (Demographics/Economy/Social, Public Finances, Health, and Education).
|
|
56
|
+
|
|
57
|
+
This library provides the reproducible scientific protocol and supporting codebase for building the harmonized dataset of Brazilian municipal indicators.
|
|
58
|
+
|
|
59
|
+
## Key Features
|
|
60
|
+
- **Fully Reproducible ETL:** Transparent code that downloads raw data directly from official sources (IBGE, Tesouro Nacional/SICONFI, DATASUS, IPEA Data, INEP) and processes it systematically.
|
|
61
|
+
- **Harmonized Joins:** Automatically aligns historical data (2006–2023) against the most recent and stable territorial division grid (DTB 2025).
|
|
62
|
+
- **Thematic Modularity:** Provides six standardized tables:
|
|
63
|
+
- `municipios`: Canonical territorial crosswalk and municipal metadata (DTB 2025, territorial area in km², coordinates of municipal seat, border and coastal indicators).
|
|
64
|
+
- `demografia_economia_social`: Longitudinal panel covering population estimates, municipal GDP, formal employment from CEMPRE, and Bolsa Família beneficiaries and transfers.
|
|
65
|
+
- `financas_publicas`: Longitudinal panel covering municipal budgetary expenditures by functional classification (28 functions) combining FINBRA (2006–2012) and SICONFI (2013–2023).
|
|
66
|
+
- `saude`: Longitudinal panel covering health infrastructure, human resources, mortality, and live births from DATASUS (CNES, SIM, Sinasc).
|
|
67
|
+
- `municipios_limitrofes`: Adjacency pairs identifying contiguous neighbor municipalities across Brazil.
|
|
68
|
+
- `educacao`: Observed municipal panel aggregating microdata from School Census (Censo Escolar), Higher Education Census (Censo da Educação Superior), and observed public school IDEB scores across primary, lower secondary, and upper secondary education.
|
|
69
|
+
- **Extensive Metadata & Data Dictionaries:** Exposes variables with explicitly documented domain rules, missing value tracking, and schema changes over the years.
|
|
70
|
+
- **Highly Performant:** Built with `duckdb` and `polars`/`pyarrow` for blazing fast in-memory analytics of large municipal microdata.
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
You can install the library directly from PyPI (once published) or from the source repository:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Recommended via pip (once published on PyPI)
|
|
78
|
+
pip install brmunipanel
|
|
79
|
+
|
|
80
|
+
# From the GitHub repository
|
|
81
|
+
pip install git+https://github.com/lucasguesse/brmunipanel.git
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Quick Start (Usage Example)
|
|
85
|
+
|
|
86
|
+
The library exposes version metadata and source namespaces at top level, along with modular ETL and harmonization routines in each submodule:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from pathlib import Path
|
|
90
|
+
import brmunipanel as bmp
|
|
91
|
+
from brmunipanel.ibge import populacao, pib
|
|
92
|
+
from brmunipanel.ipea import pbf
|
|
93
|
+
from brmunipanel.inep import (
|
|
94
|
+
harmonizar_censo_escolar,
|
|
95
|
+
harmonizar_censo_superior,
|
|
96
|
+
harmonizar_ideb,
|
|
97
|
+
)
|
|
98
|
+
from brmunipanel.tesouro import siconfi, finbra
|
|
99
|
+
from brmunipanel.datasus import saude
|
|
100
|
+
|
|
101
|
+
# Package version and source namespaces
|
|
102
|
+
print(bmp.__version__)
|
|
103
|
+
# Available namespaces: bmp.ibge, bmp.tesouro, bmp.ipea, bmp.datasus, bmp.inep
|
|
104
|
+
|
|
105
|
+
# Example: Harmonize population estimates from a local SIDRA raw folder
|
|
106
|
+
# df_pop = populacao.harmonizar(Path("raw/bases-de-dados/ibge/populacao"))
|
|
107
|
+
|
|
108
|
+
# Example: Harmonize Bolsa Família records from an IPEA Data raw folder
|
|
109
|
+
# df_pbf = pbf.harmonizar(Path("raw/bases-de-dados/ipea"))
|
|
110
|
+
|
|
111
|
+
# Example: Harmonize public school IDEB scores with municipal crosswalk
|
|
112
|
+
# df_ideb = harmonizar_ideb(Path("raw/bases-de-dados/ideb"), municipios_df)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Data Sources Handled
|
|
116
|
+
The library currently wraps and harmonizes the following official sources:
|
|
117
|
+
* **IBGE (Instituto Brasileiro de Geografia e Estatística):**
|
|
118
|
+
* Population estimates (SIDRA Table 6579)
|
|
119
|
+
* Municipal GDP (PIB Municipal, SIDRA Table 5938)
|
|
120
|
+
* Central Register of Enterprises (CEMPRE, SIDRA Tables 1685 and 9509)
|
|
121
|
+
* Territorial grids (DTB 2025, Area, Municipal Seat Coordinates, Adjacency matrices)
|
|
122
|
+
* **Tesouro Nacional (STN):**
|
|
123
|
+
* FINBRA (2006–2012, budgetary expenditure by function)
|
|
124
|
+
* SICONFI (2013–2023, budgetary expenditure by function)
|
|
125
|
+
* **IPEA Data (MDS):**
|
|
126
|
+
* Programa Bolsa Família (beneficiaries and financial transfers, FAM_PBF / VAL_PBF)
|
|
127
|
+
* **Ministério da Saúde (DATASUS):**
|
|
128
|
+
* CNES: Hospital beds, ICU capacity, diagnostic imaging equipment, and physicians per municipality
|
|
129
|
+
* SIM: Violent deaths and infant mortality
|
|
130
|
+
* Sinasc: Live births
|
|
131
|
+
* Health Regions and Macro-regions
|
|
132
|
+
* **INEP (Instituto Nacional de Estudos e Pesquisas Educacionais Anísio Teixeira):**
|
|
133
|
+
* Censo Escolar: Active schools, enrollments, and teachers across basic education stages
|
|
134
|
+
* Censo da Educação Superior: In-person higher education institutions and enrollments
|
|
135
|
+
* IDEB: Observed public school scores across primary (anos iniciais), lower secondary (anos finais), and upper secondary (ensino médio) education
|
|
136
|
+
|
|
137
|
+
## Development, Testing, and Building
|
|
138
|
+
To set up the library for local development, run tests, and build verifiable distribution packages according to the Python Packaging User Guide:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# 1. Clone repository and navigate to root
|
|
142
|
+
git clone https://github.com/lucasguesse/brmunipanel.git
|
|
143
|
+
cd brmunipanel
|
|
144
|
+
|
|
145
|
+
# 2. Create and activate a dedicated virtual environment
|
|
146
|
+
python -m venv .venv
|
|
147
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
|
148
|
+
|
|
149
|
+
# 3. Install in editable mode with development dependencies
|
|
150
|
+
pip install -e ".[dev]"
|
|
151
|
+
|
|
152
|
+
# 4. Run the full test suite
|
|
153
|
+
pytest
|
|
154
|
+
|
|
155
|
+
# 5. Build standard distribution artifacts (sdist and wheel)
|
|
156
|
+
# Ensure dist/ is clean before building
|
|
157
|
+
python -m build
|
|
158
|
+
|
|
159
|
+
# 6. Validate distribution artifacts strictly with Twine
|
|
160
|
+
python -m twine check --strict dist/*
|
|
161
|
+
|
|
162
|
+
# 7. Test installation of the built wheel in a separate, clean virtual environment
|
|
163
|
+
python -m venv .venv-clean
|
|
164
|
+
source .venv-clean/bin/activate # On Windows: .venv-clean\Scripts\activate
|
|
165
|
+
pip install --no-deps dist/brmunipanel-0.1.0-py3-none-any.whl
|
|
166
|
+
python -c "import brmunipanel as bmp; print(bmp.__version__)"
|
|
167
|
+
deactivate
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
> **Note on Publishing:** Distribution packages are published to TestPyPI and PyPI via GitHub Actions using PyPA Trusted Publishing (OIDC) without persistent tokens or secrets. Publishing to TestPyPI is triggered manually via `workflow_dispatch`, while official publishing to PyPI is triggered strictly upon a published GitHub Release (`v*`). Version `0.1.0` has been published and validated on TestPyPI, while official publication to PyPI remains pending the first official GitHub Release. Never commit API tokens, credentials, or `.pypirc` files to version control.
|
|
171
|
+
|
|
172
|
+
Full end-to-end pipeline execution and paper reproduction scripts are maintained in the companion research repository.
|
|
173
|
+
|
|
174
|
+
## How to Cite
|
|
175
|
+
If you use this library or its data routines in your research, please cite this software repository and specify the release version used while a definitive academic citation is not yet available:
|
|
176
|
+
|
|
177
|
+
- **Repository:** [https://github.com/lucasguesse/brmunipanel](https://github.com/lucasguesse/brmunipanel)
|
|
178
|
+
- **Release:** Specify the release tag or version used in your analysis.
|
|
179
|
+
|
|
180
|
+
A formal academic citation will be provided here once available.
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
184
|
+
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# BRMuniPanel
|
|
2
|
+
|
|
3
|
+
[](https://github.com/lucasguesse/brmunipanel/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
**A Python ETL library and data access tool for the Harmonized Suite of Tables of Socioeconomic, Fiscal, Territorial, Health, and Educational Indicators for Brazilian Municipalities (2006–2023).**
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
`brmunipanel` is an open-source Python library designed to fully automate the extraction, transformation, and loading (ETL) of public administrative records from multiple Brazilian federal agencies. It solves the massive structural burden of dealing with fragmented, historically inconsistent, and undocumented municipal data in Brazil.
|
|
9
|
+
|
|
10
|
+
By standardizing the 7-digit IBGE municipality code as the primary join key and freezing the territorial division to the 2025 canonical grid, this library allows researchers and data scientists to easily build and consume a longitudinal structural database of 5,571 municipalities, structured across six standardized tables: two territorial tables and four longitudinal thematic tables (Demographics/Economy/Social, Public Finances, Health, and Education).
|
|
11
|
+
|
|
12
|
+
This library provides the reproducible scientific protocol and supporting codebase for building the harmonized dataset of Brazilian municipal indicators.
|
|
13
|
+
|
|
14
|
+
## Key Features
|
|
15
|
+
- **Fully Reproducible ETL:** Transparent code that downloads raw data directly from official sources (IBGE, Tesouro Nacional/SICONFI, DATASUS, IPEA Data, INEP) and processes it systematically.
|
|
16
|
+
- **Harmonized Joins:** Automatically aligns historical data (2006–2023) against the most recent and stable territorial division grid (DTB 2025).
|
|
17
|
+
- **Thematic Modularity:** Provides six standardized tables:
|
|
18
|
+
- `municipios`: Canonical territorial crosswalk and municipal metadata (DTB 2025, territorial area in km², coordinates of municipal seat, border and coastal indicators).
|
|
19
|
+
- `demografia_economia_social`: Longitudinal panel covering population estimates, municipal GDP, formal employment from CEMPRE, and Bolsa Família beneficiaries and transfers.
|
|
20
|
+
- `financas_publicas`: Longitudinal panel covering municipal budgetary expenditures by functional classification (28 functions) combining FINBRA (2006–2012) and SICONFI (2013–2023).
|
|
21
|
+
- `saude`: Longitudinal panel covering health infrastructure, human resources, mortality, and live births from DATASUS (CNES, SIM, Sinasc).
|
|
22
|
+
- `municipios_limitrofes`: Adjacency pairs identifying contiguous neighbor municipalities across Brazil.
|
|
23
|
+
- `educacao`: Observed municipal panel aggregating microdata from School Census (Censo Escolar), Higher Education Census (Censo da Educação Superior), and observed public school IDEB scores across primary, lower secondary, and upper secondary education.
|
|
24
|
+
- **Extensive Metadata & Data Dictionaries:** Exposes variables with explicitly documented domain rules, missing value tracking, and schema changes over the years.
|
|
25
|
+
- **Highly Performant:** Built with `duckdb` and `polars`/`pyarrow` for blazing fast in-memory analytics of large municipal microdata.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
You can install the library directly from PyPI (once published) or from the source repository:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Recommended via pip (once published on PyPI)
|
|
33
|
+
pip install brmunipanel
|
|
34
|
+
|
|
35
|
+
# From the GitHub repository
|
|
36
|
+
pip install git+https://github.com/lucasguesse/brmunipanel.git
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start (Usage Example)
|
|
40
|
+
|
|
41
|
+
The library exposes version metadata and source namespaces at top level, along with modular ETL and harmonization routines in each submodule:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
import brmunipanel as bmp
|
|
46
|
+
from brmunipanel.ibge import populacao, pib
|
|
47
|
+
from brmunipanel.ipea import pbf
|
|
48
|
+
from brmunipanel.inep import (
|
|
49
|
+
harmonizar_censo_escolar,
|
|
50
|
+
harmonizar_censo_superior,
|
|
51
|
+
harmonizar_ideb,
|
|
52
|
+
)
|
|
53
|
+
from brmunipanel.tesouro import siconfi, finbra
|
|
54
|
+
from brmunipanel.datasus import saude
|
|
55
|
+
|
|
56
|
+
# Package version and source namespaces
|
|
57
|
+
print(bmp.__version__)
|
|
58
|
+
# Available namespaces: bmp.ibge, bmp.tesouro, bmp.ipea, bmp.datasus, bmp.inep
|
|
59
|
+
|
|
60
|
+
# Example: Harmonize population estimates from a local SIDRA raw folder
|
|
61
|
+
# df_pop = populacao.harmonizar(Path("raw/bases-de-dados/ibge/populacao"))
|
|
62
|
+
|
|
63
|
+
# Example: Harmonize Bolsa Família records from an IPEA Data raw folder
|
|
64
|
+
# df_pbf = pbf.harmonizar(Path("raw/bases-de-dados/ipea"))
|
|
65
|
+
|
|
66
|
+
# Example: Harmonize public school IDEB scores with municipal crosswalk
|
|
67
|
+
# df_ideb = harmonizar_ideb(Path("raw/bases-de-dados/ideb"), municipios_df)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Data Sources Handled
|
|
71
|
+
The library currently wraps and harmonizes the following official sources:
|
|
72
|
+
* **IBGE (Instituto Brasileiro de Geografia e Estatística):**
|
|
73
|
+
* Population estimates (SIDRA Table 6579)
|
|
74
|
+
* Municipal GDP (PIB Municipal, SIDRA Table 5938)
|
|
75
|
+
* Central Register of Enterprises (CEMPRE, SIDRA Tables 1685 and 9509)
|
|
76
|
+
* Territorial grids (DTB 2025, Area, Municipal Seat Coordinates, Adjacency matrices)
|
|
77
|
+
* **Tesouro Nacional (STN):**
|
|
78
|
+
* FINBRA (2006–2012, budgetary expenditure by function)
|
|
79
|
+
* SICONFI (2013–2023, budgetary expenditure by function)
|
|
80
|
+
* **IPEA Data (MDS):**
|
|
81
|
+
* Programa Bolsa Família (beneficiaries and financial transfers, FAM_PBF / VAL_PBF)
|
|
82
|
+
* **Ministério da Saúde (DATASUS):**
|
|
83
|
+
* CNES: Hospital beds, ICU capacity, diagnostic imaging equipment, and physicians per municipality
|
|
84
|
+
* SIM: Violent deaths and infant mortality
|
|
85
|
+
* Sinasc: Live births
|
|
86
|
+
* Health Regions and Macro-regions
|
|
87
|
+
* **INEP (Instituto Nacional de Estudos e Pesquisas Educacionais Anísio Teixeira):**
|
|
88
|
+
* Censo Escolar: Active schools, enrollments, and teachers across basic education stages
|
|
89
|
+
* Censo da Educação Superior: In-person higher education institutions and enrollments
|
|
90
|
+
* IDEB: Observed public school scores across primary (anos iniciais), lower secondary (anos finais), and upper secondary (ensino médio) education
|
|
91
|
+
|
|
92
|
+
## Development, Testing, and Building
|
|
93
|
+
To set up the library for local development, run tests, and build verifiable distribution packages according to the Python Packaging User Guide:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# 1. Clone repository and navigate to root
|
|
97
|
+
git clone https://github.com/lucasguesse/brmunipanel.git
|
|
98
|
+
cd brmunipanel
|
|
99
|
+
|
|
100
|
+
# 2. Create and activate a dedicated virtual environment
|
|
101
|
+
python -m venv .venv
|
|
102
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
|
103
|
+
|
|
104
|
+
# 3. Install in editable mode with development dependencies
|
|
105
|
+
pip install -e ".[dev]"
|
|
106
|
+
|
|
107
|
+
# 4. Run the full test suite
|
|
108
|
+
pytest
|
|
109
|
+
|
|
110
|
+
# 5. Build standard distribution artifacts (sdist and wheel)
|
|
111
|
+
# Ensure dist/ is clean before building
|
|
112
|
+
python -m build
|
|
113
|
+
|
|
114
|
+
# 6. Validate distribution artifacts strictly with Twine
|
|
115
|
+
python -m twine check --strict dist/*
|
|
116
|
+
|
|
117
|
+
# 7. Test installation of the built wheel in a separate, clean virtual environment
|
|
118
|
+
python -m venv .venv-clean
|
|
119
|
+
source .venv-clean/bin/activate # On Windows: .venv-clean\Scripts\activate
|
|
120
|
+
pip install --no-deps dist/brmunipanel-0.1.0-py3-none-any.whl
|
|
121
|
+
python -c "import brmunipanel as bmp; print(bmp.__version__)"
|
|
122
|
+
deactivate
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> **Note on Publishing:** Distribution packages are published to TestPyPI and PyPI via GitHub Actions using PyPA Trusted Publishing (OIDC) without persistent tokens or secrets. Publishing to TestPyPI is triggered manually via `workflow_dispatch`, while official publishing to PyPI is triggered strictly upon a published GitHub Release (`v*`). Version `0.1.0` has been published and validated on TestPyPI, while official publication to PyPI remains pending the first official GitHub Release. Never commit API tokens, credentials, or `.pypirc` files to version control.
|
|
126
|
+
|
|
127
|
+
Full end-to-end pipeline execution and paper reproduction scripts are maintained in the companion research repository.
|
|
128
|
+
|
|
129
|
+
## How to Cite
|
|
130
|
+
If you use this library or its data routines in your research, please cite this software repository and specify the release version used while a definitive academic citation is not yet available:
|
|
131
|
+
|
|
132
|
+
- **Repository:** [https://github.com/lucasguesse/brmunipanel](https://github.com/lucasguesse/brmunipanel)
|
|
133
|
+
- **Release:** Specify the release tag or version used in your analysis.
|
|
134
|
+
|
|
135
|
+
A formal academic citation will be provided here once available.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
139
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.3"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "brmunipanel"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "ETL library for a harmonized panel of socioeconomic, fiscal, health, territorial and educational indicators for Brazilian municipalities (IBGE, Tesouro Nacional, IPEA Data, DATASUS, INEP)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "Lucas Guesse" }]
|
|
14
|
+
keywords = [
|
|
15
|
+
"brazil",
|
|
16
|
+
"municipalities",
|
|
17
|
+
"panel",
|
|
18
|
+
"etl",
|
|
19
|
+
"indicators",
|
|
20
|
+
"ibge",
|
|
21
|
+
"inep",
|
|
22
|
+
"siconfi",
|
|
23
|
+
"datasus",
|
|
24
|
+
]
|
|
25
|
+
classifiers = [
|
|
26
|
+
"Development Status :: 4 - Beta",
|
|
27
|
+
"Intended Audience :: Science/Research",
|
|
28
|
+
"Operating System :: OS Independent",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",
|
|
34
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
35
|
+
]
|
|
36
|
+
dependencies = [
|
|
37
|
+
"duckdb>=1.0.0",
|
|
38
|
+
"polars>=1.0.0",
|
|
39
|
+
"pyarrow>=16.0.0",
|
|
40
|
+
"pandas>=2.2.0",
|
|
41
|
+
"numpy>=1.26.0",
|
|
42
|
+
"xlrd>=2.0.0",
|
|
43
|
+
"openpyxl>=3.1.0",
|
|
44
|
+
"requests>=2.32.0",
|
|
45
|
+
"tqdm>=4.66.0",
|
|
46
|
+
"access-parser==0.0.6",
|
|
47
|
+
"construct>=2.10.70",
|
|
48
|
+
"tabulate>=0.10.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.optional-dependencies]
|
|
52
|
+
plots = ["matplotlib>=3.9.0", "seaborn>=0.13.0"]
|
|
53
|
+
dev = [
|
|
54
|
+
"build>=1.2.0",
|
|
55
|
+
"pytest>=8.0.0",
|
|
56
|
+
"twine>=5.0.0",
|
|
57
|
+
'tomli>=1.1.0; python_version < "3.11"',
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[project.urls]
|
|
61
|
+
Homepage = "https://github.com/lucasguesse/brmunipanel"
|
|
62
|
+
Repository = "https://github.com/lucasguesse/brmunipanel"
|
|
63
|
+
Issues = "https://github.com/lucasguesse/brmunipanel/issues"
|
|
64
|
+
Documentation = "https://github.com/lucasguesse/brmunipanel#readme"
|
|
65
|
+
|
|
66
|
+
[tool.setuptools.packages.find]
|
|
67
|
+
where = ["src"]
|
|
68
|
+
|
|
69
|
+
[tool.setuptools.package-data]
|
|
70
|
+
brmunipanel = ["metadata/variaveis.json"]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""ETL library for a harmonized panel of Brazilian municipal indicators (IBGE, Tesouro Nacional, IPEA Data, DATASUS, INEP)."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
__version__ = "0.1.0"
|
|
7
|
+
|
|
8
|
+
_SUBMODULES = {
|
|
9
|
+
"datasus",
|
|
10
|
+
"ibge",
|
|
11
|
+
"inep",
|
|
12
|
+
"ipea",
|
|
13
|
+
"tesouro",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"__version__",
|
|
18
|
+
"datasus",
|
|
19
|
+
"ibge",
|
|
20
|
+
"inep",
|
|
21
|
+
"ipea",
|
|
22
|
+
"tesouro",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from brmunipanel import datasus, ibge, inep, ipea, tesouro
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def __getattr__(name: str):
|
|
30
|
+
if name in _SUBMODULES:
|
|
31
|
+
module = importlib.import_module(f"brmunipanel.{name}")
|
|
32
|
+
globals()[name] = module
|
|
33
|
+
return module
|
|
34
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def __dir__():
|
|
38
|
+
return __all__
|
|
39
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Módulos de coleta e harmonização de dados do Ministério da Saúde / DATASUS."""
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Regiões e macrorregiões de saúde por município (API de Dados Abertos do Ministério da Saúde).
|
|
2
|
+
|
|
3
|
+
Endpoint: https://apidadosabertos.saude.gov.br/macrorregiao-e-regiao-de-saude/municipio
|
|
4
|
+
Os códigos de município chegam com 6 dígitos e são convertidos para os 7 dígitos da DTB.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import polars as pl
|
|
15
|
+
import requests
|
|
16
|
+
|
|
17
|
+
from .. import nucleo
|
|
18
|
+
from ..nucleo import Requisicao, RespostaInvalida
|
|
19
|
+
|
|
20
|
+
URL_BASE = "https://apidadosabertos.saude.gov.br/macrorregiao-e-regiao-de-saude/municipio"
|
|
21
|
+
CHAVE_RESPOSTA = "macrorregiao_regiao_saude_municipios"
|
|
22
|
+
LIMITE_PAGINA = 1000
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def validar(conteudo: bytes) -> None:
|
|
26
|
+
"""Valida se o conteúdo é um JSON com o formato esperado da API de regiões de saúde."""
|
|
27
|
+
try:
|
|
28
|
+
dados = json.loads(conteudo)
|
|
29
|
+
if not isinstance(dados, dict):
|
|
30
|
+
raise RespostaInvalida("Resposta não é um objeto JSON")
|
|
31
|
+
itens = dados.get(CHAVE_RESPOSTA)
|
|
32
|
+
if not isinstance(itens, list):
|
|
33
|
+
raise RespostaInvalida(f"Chave '{CHAVE_RESPOSTA}' ausente ou não é uma lista")
|
|
34
|
+
except (json.JSONDecodeError, RespostaInvalida) as erro:
|
|
35
|
+
raise RespostaInvalida(f"Conteúdo inválido da API de regiões de saúde: {erro}") from erro
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def baixar(pasta: Path, **opcoes) -> list[dict]:
|
|
39
|
+
"""Baixa todas as páginas da API de regiões de saúde avançando o offset pelo total de itens recebidos."""
|
|
40
|
+
pasta = Path(pasta)
|
|
41
|
+
offset = 0
|
|
42
|
+
registros = []
|
|
43
|
+
sessao = opcoes.pop("sessao", None) or requests.Session()
|
|
44
|
+
intervalo = opcoes.pop("intervalo", 1.0)
|
|
45
|
+
|
|
46
|
+
while True:
|
|
47
|
+
chave = f"offset{offset:04d}"
|
|
48
|
+
arquivo = f"regioes_saude_offset{offset:04d}.json.gz"
|
|
49
|
+
url = f"{URL_BASE}?limit={LIMITE_PAGINA}&offset={offset}"
|
|
50
|
+
req = Requisicao(chave=chave, url=url, arquivo=arquivo, compactar=True)
|
|
51
|
+
|
|
52
|
+
registro, baixou = nucleo.baixar(req, pasta, sessao=sessao, validar=validar, **opcoes)
|
|
53
|
+
registros.append(registro)
|
|
54
|
+
if baixou and intervalo:
|
|
55
|
+
time.sleep(intervalo)
|
|
56
|
+
|
|
57
|
+
conteudo = nucleo.ler_bruto(pasta, req.arquivo)
|
|
58
|
+
dados = json.loads(conteudo)
|
|
59
|
+
itens = dados.get(CHAVE_RESPOSTA, [])
|
|
60
|
+
if not itens:
|
|
61
|
+
break
|
|
62
|
+
offset += len(itens)
|
|
63
|
+
|
|
64
|
+
return registros
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def processar_itens(
|
|
68
|
+
itens: list[dict[str, Any]],
|
|
69
|
+
municipios: pl.DataFrame,
|
|
70
|
+
) -> tuple[pl.DataFrame, list[dict[str, Any]]]:
|
|
71
|
+
"""Converte os itens da API para tabela harmonizada usando `cod_municipio_6` de `municipios`.
|
|
72
|
+
|
|
73
|
+
Retorna o DataFrame harmonizado e a lista de itens descartados por falta de correspondência na DTB.
|
|
74
|
+
Levanta ValueError se houver código de município repetido entre os itens recebidos.
|
|
75
|
+
"""
|
|
76
|
+
vistos: set[str] = set()
|
|
77
|
+
repetidos: set[str] = set()
|
|
78
|
+
for item in itens:
|
|
79
|
+
cod_6 = str(item.get("codigo_municipio", "")).strip()
|
|
80
|
+
if not cod_6:
|
|
81
|
+
continue
|
|
82
|
+
if cod_6 in vistos:
|
|
83
|
+
repetidos.add(cod_6)
|
|
84
|
+
vistos.add(cod_6)
|
|
85
|
+
|
|
86
|
+
if repetidos:
|
|
87
|
+
raise ValueError(
|
|
88
|
+
f"Códigos de município repetidos encontrados na paginação da API ({len(repetidos)}): {sorted(repetidos)}"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
crosswalk = dict(zip(municipios["cod_municipio_6"].to_list(), municipios["cod_municipio"].to_list()))
|
|
92
|
+
|
|
93
|
+
linhas = []
|
|
94
|
+
descartados = []
|
|
95
|
+
for item in itens:
|
|
96
|
+
cod_6 = str(item.get("codigo_municipio", "")).strip()
|
|
97
|
+
cod_7 = crosswalk.get(cod_6)
|
|
98
|
+
if cod_7 is None:
|
|
99
|
+
descartados.append(item)
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
linhas.append({
|
|
103
|
+
"cod_municipio": cod_7,
|
|
104
|
+
"cod_regiao_saude": str(item.get("codigo_regiao_saude", "")).strip(),
|
|
105
|
+
"nome_regiao_saude": str(item.get("regiao_saude", "")).strip(),
|
|
106
|
+
"cod_macrorregiao_saude": str(item.get("codigo_macrorregiao_saude", "")).strip(),
|
|
107
|
+
"nome_macrorregiao_saude": str(item.get("macrorregiao_saude", "")).strip(),
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
if not linhas:
|
|
111
|
+
df = pl.DataFrame(
|
|
112
|
+
schema={
|
|
113
|
+
"cod_municipio": pl.String,
|
|
114
|
+
"cod_regiao_saude": pl.String,
|
|
115
|
+
"nome_regiao_saude": pl.String,
|
|
116
|
+
"cod_macrorregiao_saude": pl.String,
|
|
117
|
+
"nome_macrorregiao_saude": pl.String,
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
df = pl.DataFrame(linhas, schema_overrides={
|
|
122
|
+
"cod_municipio": pl.String,
|
|
123
|
+
"cod_regiao_saude": pl.String,
|
|
124
|
+
"nome_regiao_saude": pl.String,
|
|
125
|
+
"cod_macrorregiao_saude": pl.String,
|
|
126
|
+
"nome_macrorregiao_saude": pl.String,
|
|
127
|
+
}).sort("cod_municipio")
|
|
128
|
+
|
|
129
|
+
return df, descartados
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def harmonizar(pasta: Path, municipios: pl.DataFrame) -> pl.DataFrame:
|
|
133
|
+
"""Lê os arquivos baixados em `pasta`, extrai todos os registros e harmoniza contra `municipios`."""
|
|
134
|
+
pasta = Path(pasta)
|
|
135
|
+
manifesto = nucleo.ler_manifesto(pasta)
|
|
136
|
+
|
|
137
|
+
arquivos: list[str] = []
|
|
138
|
+
if manifesto:
|
|
139
|
+
for chave in sorted(manifesto.keys()):
|
|
140
|
+
arquivos.append(manifesto[chave]["arquivo"])
|
|
141
|
+
else:
|
|
142
|
+
arquivos = sorted(p.name for p in pasta.glob("regioes_saude_offset*.json.gz"))
|
|
143
|
+
|
|
144
|
+
todos_itens: list[dict[str, Any]] = []
|
|
145
|
+
for arquivo in arquivos:
|
|
146
|
+
conteudo = nucleo.ler_bruto(pasta, arquivo)
|
|
147
|
+
dados = json.loads(conteudo)
|
|
148
|
+
todos_itens.extend(dados.get(CHAVE_RESPOSTA, []))
|
|
149
|
+
|
|
150
|
+
df, descartados = processar_itens(todos_itens, municipios)
|
|
151
|
+
if descartados:
|
|
152
|
+
print(f"Aviso: {len(descartados)} registros da API sem correspondência na DTB descartados.")
|
|
153
|
+
return df
|