sidra-fetcher 0.7.2__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.
@@ -0,0 +1,66 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ name: Build distribution
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v5
17
+
18
+ - name: Build sdist and wheel
19
+ run: uv build
20
+
21
+ - name: Upload build artifacts
22
+ uses: actions/upload-artifact@v4
23
+ with:
24
+ name: dist
25
+ path: dist/
26
+
27
+ publish-testpypi:
28
+ name: Publish to TestPyPI
29
+ needs: build
30
+ runs-on: ubuntu-latest
31
+ environment:
32
+ name: testpypi
33
+ url: https://test.pypi.org/p/sidra-fetcher
34
+ permissions:
35
+ id-token: write
36
+ steps:
37
+ - name: Download build artifacts
38
+ uses: actions/download-artifact@v4
39
+ with:
40
+ name: dist
41
+ path: dist/
42
+
43
+ - name: Publish to TestPyPI
44
+ uses: pypa/gh-action-pypi-publish@release/v1
45
+ with:
46
+ repository-url: https://test.pypi.org/legacy/
47
+ skip-existing: true
48
+
49
+ publish-pypi:
50
+ name: Publish to PyPI
51
+ needs: publish-testpypi
52
+ runs-on: ubuntu-latest
53
+ environment:
54
+ name: pypi
55
+ url: https://pypi.org/p/sidra-fetcher
56
+ permissions:
57
+ id-token: write
58
+ steps:
59
+ - name: Download build artifacts
60
+ uses: actions/download-artifact@v4
61
+ with:
62
+ name: dist
63
+ path: dist/
64
+
65
+ - name: Publish to PyPI
66
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,38 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Test (Python ${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.13"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v5
23
+ with:
24
+ enable-cache: true
25
+
26
+ - name: Set up Python ${{ matrix.python-version }}
27
+ run: uv python install ${{ matrix.python-version }}
28
+
29
+ - name: Install dependencies
30
+ run: uv sync --group dev
31
+
32
+ - name: Lint with ruff
33
+ run: |
34
+ uv run ruff check src/ tests/
35
+ uv run ruff format --check src/ tests/
36
+
37
+ - name: Run tests
38
+ run: uv run python -m unittest discover -v tests
@@ -0,0 +1,42 @@
1
+ # Build / packaging
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+
8
+ # Virtual envs e caches do uv
9
+ .venv/
10
+ .uv-cache/
11
+
12
+ # Lockfile — libs não versionam uv.lock
13
+ uv.lock
14
+
15
+ # Caches de teste / lint / tipos
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
19
+
20
+ # Cobertura
21
+ .coverage
22
+ .coverage.*
23
+ htmlcov/
24
+
25
+ # Editor / IDE / OS
26
+ .vscode/
27
+ .idea/
28
+ .DS_Store
29
+ Thumbs.db
30
+ *.swp
31
+
32
+ # Logs e env locais
33
+ *.log
34
+ .env
35
+ .env.local
36
+
37
+ # Claude
38
+ .claude/
39
+
40
+ # Específico do repo
41
+ data/
42
+ *.ini
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ Todas as mudanças notáveis deste projeto serão documentadas neste arquivo.
4
+
5
+ O formato segue [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
6
+ e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/).
7
+
8
+ ## [0.7.2] - 2026-07-16
9
+
10
+ ### Corrigido
11
+
12
+ - Dependência de `quantilica-core` trocada de `git+https://...` para `quantilica-core[cli]>=0.3.1`
13
+ (versão publicada no PyPI, com o extra `cli` que fornece `typer`/`rich` exigidos pelo
14
+ entry point `quantilica.fetchers`, corrigindo um `ModuleNotFoundError: typer` em
15
+ instalações isoladas via `pip install sidra-fetcher`)
16
+ - Instrução de instalação no README (`pip install sidra-fetcher`, em vez de git+https)
17
+
18
+ ### Adicionado
19
+
20
+ - `py.typed` (marcador de pacote tipado, consistente com o classifier `Typing :: Typed`)
21
+ - Primeiro release público no PyPI
@@ -0,0 +1,3 @@
1
+ Use `uv` for python package management and running scripts.
2
+ Follow PEP8 for code style. Use `ruff` for linting and formatting.
3
+ Put imports in alphabetical order (standard library, third-party, local) and at the top of the file.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Quantilica
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,421 @@
1
+ Metadata-Version: 2.4
2
+ Name: sidra-fetcher
3
+ Version: 0.7.2
4
+ Summary: A Python package for fetching data from IBGE's SIDRA and Agregados APIs
5
+ Project-URL: Homepage, https://github.com/Quantilica/sidra-fetcher
6
+ Project-URL: Repository, https://github.com/Quantilica/sidra-fetcher
7
+ Project-URL: Issues, https://github.com/Quantilica/sidra-fetcher/issues
8
+ Author-email: "Komesu, D.K." <daniel@dkko.me>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agregados,api-client,brazil,ibge,open-data,sidra,statistics
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.12
23
+ Requires-Dist: quantilica-core[cli]>=0.3.1
24
+ Description-Content-Type: text/markdown
25
+
26
+ # sidra-fetcher: Cliente Python para a API do IBGE/SIDRA
27
+
28
+ ![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square) ![Python](https://img.shields.io/badge/python-3.13+-blue.svg?style=flat-square)
29
+
30
+ Biblioteca Python para buscar e processar dados e metadados das APIs oficiais do [IBGE](https://www.ibge.gov.br/) — [Agregados v3](https://servicodados.ibge.gov.br/api/docs/agregados?versao=3) e [SIDRA](https://apisidra.ibge.gov.br). Fornece acesso tipado via dataclasses a pesquisas, agregados, períodos, territórios, variáveis e classificações, com clientes síncrono e assíncrono.
31
+
32
+ ---
33
+
34
+ ## Instalação
35
+
36
+ ```bash
37
+ pip install sidra-fetcher
38
+ ```
39
+
40
+ Com [uv](https://github.com/astral-sh/uv):
41
+
42
+ ```bash
43
+ uv add sidra-fetcher
44
+ ```
45
+
46
+ **Requisitos:** Python 3.12+
47
+
48
+ ## Interface de Linha de Comando (CLI)
49
+
50
+ O `sidra-fetcher` inclui uma interface de linha de comando para exploração rápida de metadados.
51
+
52
+ ### Uso Autônomo
53
+
54
+ ```bash
55
+ # Listar todas as pesquisas
56
+ sidra-fetcher list pesquisas
57
+
58
+ # Listar agregados de uma pesquisa (ex: 73)
59
+ sidra-fetcher list agregados 73
60
+
61
+ # Ver metadados detalhados de um agregado (ex: 1612)
62
+ sidra-fetcher info 1612
63
+
64
+ # Listar períodos disponíveis
65
+ sidra-fetcher periods 1612
66
+ ```
67
+
68
+ ### Integração com `quantilica-cli`
69
+
70
+ Se o `quantilica-cli` estiver instalado no mesmo ambiente, o `sidra-fetcher` será detectado automaticamente como um plugin:
71
+
72
+ ```bash
73
+ quantilica sidra info 1612
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Uso Rápido
79
+
80
+ ```python
81
+ from sidra_fetcher.fetcher import SidraClient
82
+
83
+ with SidraClient() as client:
84
+ # Listar todas as pesquisas e seus agregados
85
+ index = client.get_indice_pesquisas_agregados()
86
+ print(index[0].nome, "->", index[0].agregados[0].nome)
87
+
88
+ # Metadados completos do agregado 1705 (IPCA-15)
89
+ agregado = client.get_agregado(1705)
90
+ print(agregado.nome)
91
+ print(f"Períodos: {len(agregado.periodos)}")
92
+ print(f"Localidades: {len(agregado.localidades)}")
93
+ ```
94
+
95
+ ---
96
+
97
+ ## API Python
98
+
99
+ ### `SidraClient` (síncrono)
100
+
101
+ ```python
102
+ from sidra_fetcher.fetcher import SidraClient
103
+
104
+ client = SidraClient(timeout=60)
105
+ ```
106
+
107
+ Todos os métodos abaixo também funcionam via context manager: `with SidraClient() as client:`.
108
+
109
+ #### `get_indice_pesquisas_agregados()`
110
+
111
+ Retorna todas as pesquisas com o índice de agregados aninhado.
112
+
113
+ ```python
114
+ index = client.get_indice_pesquisas_agregados()
115
+ # -> list[IndicePesquisaAgregados]
116
+
117
+ for pesquisa in index:
118
+ print(pesquisa.id, pesquisa.nome)
119
+ for agregado in pesquisa.agregados:
120
+ print(" ", agregado.id, agregado.nome)
121
+ ```
122
+
123
+ #### `get_agregado_metadados(agregado_id)`
124
+
125
+ Retorna os metadados completos de um agregado — variáveis, classificações, níveis territoriais e periodicidade.
126
+
127
+ ```python
128
+ meta = client.get_agregado_metadados(1705)
129
+ # -> Agregado
130
+
131
+ print(meta.id, meta.nome)
132
+ print(meta.periodicidade.frequencia) # ex: "mensal"
133
+ print([v.nome for v in meta.variaveis])
134
+ print([c.nome for c in meta.classificacoes])
135
+ ```
136
+
137
+ #### `get_agregado_periodos(agregado_id)`
138
+
139
+ Retorna os períodos disponíveis de um agregado, com metadados temporais analisados.
140
+
141
+ ```python
142
+ periodos = client.get_agregado_periodos(1705)
143
+ # -> list[Periodo]
144
+
145
+ for p in periodos:
146
+ print(p.id, p.frequencia, p.data_inicio, p.data_fim)
147
+ # ex: "202312 mensal 2023-12-01 2023-12-31"
148
+ ```
149
+
150
+ Veja [Análise de Períodos](#análise-de-períodos) para a lista completa de campos do objeto `Periodo`.
151
+
152
+ #### `get_agregado_localidades(agregado_id, localidades_nivel)`
153
+
154
+ Retorna as localidades filtradas por um ou mais códigos de nível territorial (ex: `"N1"` para Brasil, `"N3"` para estados, `"N6"` para municípios).
155
+
156
+ ```python
157
+ localidades = client.get_agregado_localidades(1705, "N3")
158
+ # -> list[Localidade]
159
+
160
+ for loc in localidades:
161
+ print(loc.id, loc.nome, loc.nivel.id)
162
+ ```
163
+
164
+ #### `get_agregado(agregado_id)`
165
+
166
+ Método de conveniência: busca metadados, períodos e todas as localidades declaradas em uma única chamada.
167
+
168
+ ```python
169
+ agregado = client.get_agregado(1705)
170
+ # -> Agregado (com .periodos e .localidades preenchidos)
171
+ ```
172
+
173
+ #### `get_acervo(acervo)`
174
+
175
+ Busca uma listagem de "acervo" (coleção). Use `AcervoEnum` para selecionar a coleção desejada.
176
+
177
+ ```python
178
+ from sidra_fetcher.agregados import AcervoEnum
179
+
180
+ assuntos = client.get_acervo(AcervoEnum.ASSUNTO)
181
+ variaveis = client.get_acervo(AcervoEnum.VARIAVEL)
182
+ ```
183
+
184
+ Valores disponíveis no `AcervoEnum`:
185
+
186
+ | Membro | Descrição |
187
+ |---------------------|-------------------------|
188
+ | `ASSUNTO` | Tópicos / assuntos |
189
+ | `CLASSIFICACAO` | Classificações |
190
+ | `NIVELTERRITORIAL` | Níveis territoriais |
191
+ | `PERIODO` | Períodos |
192
+ | `PERIODICIDADE` | Periodicidades |
193
+ | `VARIAVEL` | Variáveis |
194
+
195
+ ---
196
+
197
+ ### `AsyncSidraClient` (assíncrono)
198
+
199
+ Equivalente assíncrono do `SidraClient`. Todos os métodos são corrotinas. `get_agregado` busca metadados e períodos concorrentemente via `asyncio.gather`.
200
+
201
+ ```python
202
+ import asyncio
203
+ from sidra_fetcher.fetcher import AsyncSidraClient
204
+
205
+ async def main():
206
+ async with AsyncSidraClient() as client:
207
+ index = await client.get_indice_pesquisas_agregados()
208
+ agregado = await client.get_agregado(1705)
209
+ print(len(agregado.periodos))
210
+
211
+ asyncio.run(main())
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Análise de Períodos
217
+
218
+ `get_agregado_periodos` analisa as strings de período retornadas pela API e as converte em objetos `Periodo` estruturados, com frequência detectada e intervalo de datas calculado automaticamente.
219
+
220
+ ### Campos do objeto `Periodo`
221
+
222
+ | Campo | Tipo | Descrição |
223
+ |---------------|-------------------|--------------------------------------------------------------|
224
+ | `id` | `str` | ID bruto do período da API (ex: `"202312"`) |
225
+ | `literals` | `list[str]` | Representações legíveis (ex: `["dezembro de 2023"]`) |
226
+ | `modificacao` | `dt.date` | Data da última atualização dos dados do período |
227
+ | `frequencia` | `str \| None` | Tipo de frequência detectado (ver tabela abaixo) |
228
+ | `data_inicio` | `dt.date \| None` | Primeiro dia do período |
229
+ | `data_fim` | `dt.date \| None` | Último dia do período |
230
+ | `ano` | `int \| None` | Ano |
231
+ | `mes` | `int \| None` | Mês (1–12); em trimestres móveis, o último mês |
232
+ | `trimestre` | `int \| None` | Número do trimestre (1–4) |
233
+ | `semestre` | `int \| None` | Número do semestre (1–2) |
234
+ | `ano_fim` | `int \| None` | Ano final para períodos plurianuais |
235
+
236
+ ### Tipos de frequência
237
+
238
+ | `frequencia` | Exemplo de literal | Intervalo de datas |
239
+ |---------------------|------------------------------|-------------------------------|
240
+ | `mensal` | `"janeiro de 2023"` | 1 jan – 31 jan |
241
+ | `trimestral` | `"1º trimestre de 2023"` | 1 jan – 31 mar |
242
+ | `trimestre_movel` | `"jan-fev-mar 2023"` | 1 jan – 31 mar |
243
+ | `semestral` | `"1º semestre de 2023"` | 1 jan – 30 jun |
244
+ | `anual` | `"2023"` | 1 jan – 31 dez |
245
+ | `plurianual` | `"2020/2023"` | 1 jan 2020 – 31 dez 2023 |
246
+ | `nao_reconhecida` | *(sem correspondência)* | `None` / `None` |
247
+
248
+ As constantes de frequência também são importáveis:
249
+
250
+ ```python
251
+ from sidra_fetcher.periodos import (
252
+ FREQUENCIA_MENSAL,
253
+ FREQUENCIA_TRIMESTRAL,
254
+ FREQUENCIA_TRIMESTRE_MOVEL,
255
+ FREQUENCIA_SEMESTRAL,
256
+ FREQUENCIA_ANUAL,
257
+ FREQUENCIA_PLURIANUAL,
258
+ FREQUENCIA_NAO_RECONHECIDA,
259
+ )
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Construtor de URL SIDRA
265
+
266
+ A classe `Parametro` constrói e analisa URLs de requisição SIDRA (`/values`).
267
+
268
+ ```python
269
+ from sidra_fetcher.sidra import Parametro, Formato, Precisao
270
+
271
+ params = Parametro(
272
+ agregado="1705",
273
+ territorios={"3": ["all"]}, # todos os estados
274
+ variaveis=["4099"], # taxa de desemprego
275
+ periodos=["202301", "202302"],
276
+ classificacoes={"2": ["6794"]},
277
+ formato=Formato.A,
278
+ decimais={"": Precisao.M},
279
+ )
280
+
281
+ print(params.url())
282
+ # https://apisidra.ibge.gov.br/values/t/1705/n3/all/v/4099/p/202301,202302/c2/6794/h/y/f/a/d/m
283
+ ```
284
+
285
+ ### Parâmetros do `Parametro`
286
+
287
+ | Parâmetro | Tipo | Segmento SIDRA | Exemplo |
288
+ |-----------------|-----------------------------|-------------------|---------------------------------------|
289
+ | `agregado` | `str` | `/t/{id}` | `"1705"` |
290
+ | `territorios` | `dict[str, list[str]]` | `/n{nivel}/{ids}` | `{"3": ["all"]}` → `/n3/all` |
291
+ | `variaveis` | `list[str]` | `/v/{ids}` | `["4099", "4100"]` ou `[]` → `/v/all` |
292
+ | `periodos` | `list[str]` | `/p/{ids}` | `["202301"]` ou `[]` → `/p/all` |
293
+ | `classificacoes`| `dict[str, list[str]]` | `/c{id}/{values}` | `{"2": ["6794"]}` |
294
+ | `cabecalho` | `bool` | `/h/y` ou `/h/n` | `True` |
295
+ | `formato` | `Formato` | `/f/{code}` | `Formato.A` |
296
+ | `decimais` | `dict[str, Precisao]` | `/d/{precisao}` | `{"": Precisao.M}` → `/d/m` |
297
+
298
+ ### Analisar uma URL SIDRA existente
299
+
300
+ ```python
301
+ from sidra_fetcher.sidra import parameter_from_url, parse_url
302
+
303
+ url = "https://apisidra.ibge.gov.br/values/t/1705/n3/all/v/4099/p/all/h/y/f/a/d/m"
304
+
305
+ params = parameter_from_url(url)
306
+ print(params.agregado) # "1705"
307
+ print(params.territorios) # {"3": ["all"]}
308
+
309
+ parsed = parse_url(url)
310
+ print(parsed["aggregate"]) # "1705"
311
+ print(parsed["territories"]) # {"3": ["all"]}
312
+ print(parsed["periods"]) # ["all"]
313
+ ```
314
+
315
+ ---
316
+
317
+ ## Utilitários de Leitura e Achatamento
318
+
319
+ ### Salvar e carregar metadados de agregados
320
+
321
+ ```python
322
+ from sidra_fetcher.reader import save_agregado, load_agregado
323
+
324
+ # Salvar em JSON
325
+ save_agregado(agregado, "agregado_1705.json")
326
+
327
+ # Carregar do JSON (períodos são reanalisados automaticamente)
328
+ agregado = load_agregado("agregado_1705.json")
329
+ ```
330
+
331
+ ### Achatar metadados para análise
332
+
333
+ `flatten_aggregate_metadata` transforma a estrutura hierárquica variável × classificação em uma sequência de dicts — uma linha por combinação única de variável + categoria:
334
+
335
+ ```python
336
+ from sidra_fetcher.reader import flatten_aggregate_metadata
337
+
338
+ raw_meta = client.get("https://servicodados.ibge.gov.br/api/v3/agregados/1705/metadados")
339
+
340
+ for row in flatten_aggregate_metadata(raw_meta):
341
+ print(row["agregado"], row["D4N"], row.get("C5N"), row["MN"])
342
+ ```
343
+
344
+ Cada linha contém:
345
+
346
+ | Chave | Descrição |
347
+ |----------------|---------------------------------------------|
348
+ | `agregado` | Nome do agregado |
349
+ | `pesquisa` | Nome da pesquisa |
350
+ | `assunto` | Assunto / tópico |
351
+ | `frequencia` | Frequência do agregado |
352
+ | `url_agregado` | URL do agregado |
353
+ | `D4C`/`D4N` | ID / nome da variável |
354
+ | `D5C`/`D5N` | ID / nome da primeira classificação |
355
+ | `C5C`/`C5N` | ID / nome da primeira categoria |
356
+ | `MN` | Unidade de medida |
357
+ | `nivel` | Nível hierárquico da categoria |
358
+
359
+ `flatten_surveys_metadata` achata o índice de pesquisas em uma lista de dicts `{pesquisa_id, pesquisa, agregado_id, agregado}`:
360
+
361
+ ```python
362
+ from sidra_fetcher.reader import flatten_surveys_metadata
363
+
364
+ raw_index = client.get("https://servicodados.ibge.gov.br/api/v3/agregados")
365
+ rows = flatten_surveys_metadata(raw_index)
366
+ ```
367
+
368
+ ---
369
+
370
+ ## Utilitários de Tamanho e Estatísticas
371
+
372
+ ```python
373
+ from sidra_fetcher.stats import calculate_aggregate
374
+
375
+ stats = calculate_aggregate(agregado)
376
+ print(stats)
377
+ # {
378
+ # "pesquisa_id": "...",
379
+ # "agregado_id": 1705,
380
+ # "n_localidades": 27,
381
+ # "n_variaveis": 1,
382
+ # "n_classificacoes": 1,
383
+ # "n_dimensoes": 2,
384
+ # "n_periodos": 84,
385
+ # "period_size": 54, # linhas por período
386
+ # "total_size": 4536, # total estimado de linhas
387
+ # ...
388
+ # }
389
+ ```
390
+
391
+ ---
392
+
393
+ ## Estrutura do Projeto
394
+
395
+ ```
396
+ src/sidra_fetcher/
397
+ ├── __init__.py — logger do pacote
398
+ ├── agregados.py — dataclasses e construtores de URL para a API Agregados
399
+ ├── fetcher.py — SidraClient e AsyncSidraClient
400
+ ├── periodos.py — análise de strings de período e detecção de frequência
401
+ ├── reader.py — parsers JSON → dataclass e achatamento de metadados
402
+ ├── sidra.py — construtor de URL SIDRA (Parametro) e parsers
403
+ └── stats.py — estatísticas de tamanho e dimensões
404
+ ```
405
+
406
+ ---
407
+
408
+ ## Desenvolvimento
409
+
410
+ ```bash
411
+ git clone https://github.com/Quantilica/sidra-fetcher.git
412
+ cd sidra-fetcher
413
+ uv sync --extra dev
414
+ uv run ruff check src/ tests/
415
+ uv run ruff format src/ tests/
416
+ uv run python -m unittest discover -v tests
417
+ ```
418
+
419
+ ## Licença
420
+
421
+ MIT — veja [LICENSE](LICENSE).