omnisus 0.2.0__py3-none-any.whl
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.
- omnisus/__init__.py +643 -0
- omnisus/_loop.py +24 -0
- omnisus/_version.py +1 -0
- omnisus/cli/__init__.py +0 -0
- omnisus/cli/main.py +442 -0
- omnisus/data/__init__.py +0 -0
- omnisus/data/auxiliares-bootstrap.zip +0 -0
- omnisus/data/dicionarios/__init__.py +0 -0
- omnisus/data/dicionarios/aux_cid10.yaml +25 -0
- omnisus/data/dicionarios/aux_municipios.yaml +57 -0
- omnisus/data/dicionarios/aux_ocupacoes.yaml +20 -0
- omnisus/data/dicionarios/aux_paises.yaml +17 -0
- omnisus/data/dicionarios/aux_sigtap_procedimentos.yaml +52 -0
- omnisus/data/dicionarios/aux_uf.yaml +22 -0
- omnisus/data/dicionarios/cnes_dados_complementares.yaml +532 -0
- omnisus/data/dicionarios/cnes_equipamentos.yaml +204 -0
- omnisus/data/dicionarios/cnes_equipes.yaml +616 -0
- omnisus/data/dicionarios/cnes_estabelecimentos.yaml +191 -0
- omnisus/data/dicionarios/cnes_estabelecimentos_ensino.yaml +247 -0
- omnisus/data/dicionarios/cnes_estabelecimentos_filantropicos.yaml +249 -0
- omnisus/data/dicionarios/cnes_gestao_metas.yaml +232 -0
- omnisus/data/dicionarios/cnes_habilitacoes.yaml +234 -0
- omnisus/data/dicionarios/cnes_incentivos.yaml +232 -0
- omnisus/data/dicionarios/cnes_leitos.yaml +294 -0
- omnisus/data/dicionarios/cnes_regras_contratuais.yaml +196 -0
- omnisus/data/dicionarios/cnes_servicos_especializados.yaml +220 -0
- omnisus/data/dicionarios/ibge_populacao.yaml +32 -0
- omnisus/data/dicionarios/sia_apac_acompanhamento_bariatrica.yaml +489 -0
- omnisus/data/dicionarios/sia_apac_acompanhamento_multiprofissional.yaml +168 -0
- omnisus/data/dicionarios/sia_apac_cirurgia_bariatrica.yaml +506 -0
- omnisus/data/dicionarios/sia_apac_fistula_arteriovenosa.yaml +504 -0
- omnisus/data/dicionarios/sia_apac_laudos_diversos.yaml +413 -0
- omnisus/data/dicionarios/sia_apac_medicamentos.yaml +460 -0
- omnisus/data/dicionarios/sia_apac_nefrologia.yaml +610 -0
- omnisus/data/dicionarios/sia_apac_quimioterapia.yaml +499 -0
- omnisus/data/dicionarios/sia_apac_radioterapia.yaml +564 -0
- omnisus/data/dicionarios/sia_apac_tratamento_dialitico.yaml +471 -0
- omnisus/data/dicionarios/sia_atencao_domiciliar.yaml +407 -0
- omnisus/data/dicionarios/sia_bpa_individualizado.yaml +301 -0
- omnisus/data/dicionarios/sia_producao_ambulatorial.yaml +550 -0
- omnisus/data/dicionarios/sia_producao_ambulatorial_1994_2007.yaml +72 -0
- omnisus/data/dicionarios/sia_psicossocial.yaml +382 -0
- omnisus/data/dicionarios/sih_aih_reduzida.yaml +2544 -0
- omnisus/data/dicionarios/sih_aih_reduzida_1992_2007.yaml +462 -0
- omnisus/data/dicionarios/sih_aih_rejeitada.yaml +1671 -0
- omnisus/data/dicionarios/sih_aih_rejeitada_erro.yaml +659 -0
- omnisus/data/dicionarios/sih_servicos_profissionais.yaml +109 -0
- omnisus/data/dicionarios/sim_obitos.yaml +1956 -0
- omnisus/data/dicionarios/sim_obitos_cid9.yaml +236 -0
- omnisus/data/dicionarios/sim_obitos_externos.yaml +1754 -0
- omnisus/data/dicionarios/sim_obitos_fetais.yaml +603 -0
- omnisus/data/dicionarios/sim_obitos_infantis.yaml +1754 -0
- omnisus/data/dicionarios/sim_obitos_maternos.yaml +1754 -0
- omnisus/data/dicionarios/sinan_chagas.yaml +549 -0
- omnisus/data/dicionarios/sinan_hanseniase.yaml +495 -0
- omnisus/data/dicionarios/sinan_tuberculose.yaml +1173 -0
- omnisus/data/dicionarios/sinasc_1994_1995.yaml +76 -0
- omnisus/data/dicionarios/sinasc_nascidos_vivos.yaml +1111 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/Ativ_Ens.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/ESTABENS.CNV +2 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/ESTABFIL.CNV +2 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/Esp_leit.CNV +71 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/Flux_Cli.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/IND_SUS.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/NIVELDEP.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/Srv_Caract.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/TPGESTAO.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/TP_DESAT.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/TP_ESTAB.CNV +46 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/TurnosAt.CNV +9 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/Vinc_SUS.cnv +3 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/motdesat.cnv +12 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/tip1leit.cnv +8 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/tipoeqpC.cnv +65 -0
- omnisus/data/dicionarios/sources/cnv/cnes/CNV/tiposegm.cnv +4 -0
- omnisus/data/dicionarios/sources/cnv/cnes/DadosComplementares.def +443 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Equipamento.def +238 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Equipes.def +521 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Estabel_Ensino.def +196 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Estabel_Filantropico.def +192 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Estabelecimento.def +487 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Gestao_de_Metas.def +193 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Habilitacao.def +201 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Incentivos.def +202 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Leitos_Especialidade.def +195 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Regras_Contratuais.def +195 -0
- omnisus/data/dicionarios/sources/cnv/cnes/Servico_Especializado_200803_.def +200 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Cirurgia_Bariatica.DEF +455 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Confeccao_de_Fistula.DEF +365 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Laudos_Diversos.DEF +438 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Medicamentos.DEF +443 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Nefrologia.DEF +455 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Pos_Cirurgia_Bariatica.def +366 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Quimioterapia.DEF +484 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Radioterapia.DEF +478 -0
- omnisus/data/dicionarios/sources/cnv/sia/APAC_Tratamento_Dialitico.DEF +317 -0
- omnisus/data/dicionarios/sources/cnv/sia/Atencao_Domiciliar.def +408 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/ACES_VASC.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/ALTA.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/CARAT_AT.CNV +12 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/CNCDO.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/COBERTURA.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/COMPLEX.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/CONT_TRAT.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/ENCERRAM.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/ESTADIO.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/FINALID.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/FL_IDADE.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/GESTANTE.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/HBSAG.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/INDICA.cnv +4 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/Invasao.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/LINF_INV.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/LOC_REALIZ.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/MANT_IND.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/MOTSAIPE.CNV +23 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/OBITO.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/PERMANEN.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/RACA_COR.CNV +11 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/REGRA_C.cnv +20 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/SEXO.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/TP_APAC.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/TP_ATEND.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/TP_ESTAB.CNV +43 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/TP_GESTAO.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/TRANSFER.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/TRANSPL.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/destino.cnv +9 -0
- omnisus/data/dicionarios/sources/cnv/sia/CNV/origem.cnv +7 -0
- omnisus/data/dicionarios/sources/cnv/sia/Producao_Ambulatorial.DEF +522 -0
- omnisus/data/dicionarios/sources/cnv/sia/RAAS_Psicossocial.def +337 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/CARATEND.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/COMPLEX2.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/CONTRAC.CNV +14 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/FINANC.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/GESTAO.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/IDENT.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/INSTRU.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/LEITOS.CNV +42 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/MARCAUCI.cnv +5 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/MARCAUTI.CNV +18 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/MORTES.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/NACION3D.CNV +333 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/NATUREZA.CNV +19 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/RACACOR.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/REGCT.cnv +21 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/SAIDAPERM.CNV +29 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/SEXO.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/SIMNAO.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/TP_DIAGSEC.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/TP_VAL.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/VINCPREV.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/motbloqueio.cnv +45 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/sitbloqueio.cnv +5 -0
- omnisus/data/dicionarios/sources/cnv/sih/CNV/sitrejeicao.cnv +3 -0
- omnisus/data/dicionarios/sources/cnv/sih/DBF/MOTERRO.dbf +0 -0
- omnisus/data/dicionarios/sources/cnv/sih/Motivo_de_Erro.DEF +74 -0
- omnisus/data/dicionarios/sources/cnv/sih/RD2008.DEF +532 -0
- omnisus/data/dicionarios/sources/cnv/sih/RJ2008.DEF +489 -0
- omnisus/data/dicionarios/sources/cnv/sih/SP2008.DEF +310 -0
- omnisus/data/dicionarios/sources/cnv/sih_199201_199712/MORTES.CNV +3 -0
- omnisus/data/dicionarios/sources/cnv/sih_199201_199712/RD.DEF +547 -0
- omnisus/data/dicionarios/sources/cnv/sih_199201_199712/VINCPREV.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sih_199801_200307/RD.DEF +550 -0
- omnisus/data/dicionarios/sources/cnv/sih_200308_200712/RD.DEF +549 -0
- omnisus/data/dicionarios/sources/cnv/sim/ACIDTRAB.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sim/ASSMEDIC.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sim/ATESTANT.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sim/CBO2002.CNV +2430 -0
- omnisus/data/dicionarios/sources/cnv/sim/CODIFICA1.cnv +4 -0
- omnisus/data/dicionarios/sources/cnv/sim/DONOVA.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sim/ESCAGR1.CNV +15 -0
- omnisus/data/dicionarios/sources/cnv/sim/ESTCIV.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sim/FONTEINV.CNV +12 -0
- omnisus/data/dicionarios/sources/cnv/sim/FONTINFO.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sim/GRAVIDEZ.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/sim/INSTRUC.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sim/INVESTIG.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sim/LOCOCOR.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sim/OBITOFE1.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sim/OBITOFE2.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sim/OMUFER.CNV +9 -0
- omnisus/data/dicionarios/sources/cnv/sim/Obito_1979_95_CID-09.DEF +217 -0
- omnisus/data/dicionarios/sources/cnv/sim/Obito_1996_CID10.def +1096 -0
- omnisus/data/dicionarios/sources/cnv/sim/PARTO.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sim/RACACOR.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sim/SEMANAS.CNV +9 -0
- omnisus/data/dicionarios/sources/cnv/sim/SERIEFAL.CNV +12 -0
- omnisus/data/dicionarios/sources/cnv/sim/TIPOACID.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sim/TIPOBITO.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sim/TIPOVIOL.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sim/VERSCB.CNV +23 -0
- omnisus/data/dicionarios/sources/cnv/sim/obitoPUE.cnv +7 -0
- omnisus/data/dicionarios/sources/cnv/sim/obitogra.cnv +5 -0
- omnisus/data/dicionarios/sources/cnv/sim/oparto.cnv +7 -0
- omnisus/data/dicionarios/sources/cnv/sinan/AvaliaN.cnv +8 -0
- omnisus/data/dicionarios/sources/cnv/sinan/ChagasNET.def +643 -0
- omnisus/data/dicionarios/sources/cnv/sinan/Escolarnet.cnv +13 -0
- omnisus/data/dicionarios/sources/cnv/sinan/HansNET.def +492 -0
- omnisus/data/dicionarios/sources/cnv/sinan/SAIDAhans.cnv +12 -0
- omnisus/data/dicionarios/sources/cnv/sinan/TuberculNET5_0.def +514 -0
- omnisus/data/dicionarios/sources/cnv/sinan/reacional.cnv +8 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/ANOMAL.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/CONSULT.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/ESC2010.CNV +9 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/ESCAGR1.CNV +15 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/ESTCIV.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/GRAVIDEZ.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/INSTRUC.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/KOTELCHUCK.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/LOCOCOR.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/NASCIDO.def +876 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/ORIGEM.CNV +6 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/PARAPRE.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/PARTO.CNV +5 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/RACA.CNV +8 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/ROBSON.CNV +12 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/SEMANAS.CNV +9 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/SEXO.CNV +4 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/STPARTO.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/TPASSIST.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/TPFUNC.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/TPMETODO.CNV +7 -0
- omnisus/data/dicionarios/sources/cnv/sinasc/idanomal.cnv +6 -0
- omnisus/data/dicionarios/sources/cnv/vinculos.json +1743 -0
- omnisus/data/dicionarios/sources/registry.json +554 -0
- omnisus/data/dicionarios/versoes.json +152 -0
- omnisus/lake/__init__.py +14 -0
- omnisus/lake/_transactions.py +15 -0
- omnisus/lake/catalog.py +107 -0
- omnisus/lake/connection.py +137 -0
- omnisus/lake/locking.py +55 -0
- omnisus/lake/maintenance.py +37 -0
- omnisus/lake/operations.py +633 -0
- omnisus/lake/publication.py +449 -0
- omnisus/lake/schema.py +28 -0
- omnisus/lake/session.py +213 -0
- omnisus/lake/sql.py +17 -0
- omnisus/metadata.py +218 -0
- omnisus/products.py +91 -0
- omnisus/py.typed +0 -0
- omnisus/research.py +406 -0
- omnisus/sources/__init__.py +0 -0
- omnisus/sources/_base.py +179 -0
- omnisus/sources/cnes/__init__.py +0 -0
- omnisus/sources/cnes/importers/__init__.py +0 -0
- omnisus/sources/cnes/importers/master.py +212 -0
- omnisus/sources/datasus_ftp/__init__.py +0 -0
- omnisus/sources/datasus_ftp/_cache.py +144 -0
- omnisus/sources/datasus_ftp/_ftp.py +41 -0
- omnisus/sources/datasus_ftp/_runner.py +604 -0
- omnisus/sources/datasus_ftp/datasets.py +242 -0
- omnisus/sources/datasus_ftp/dbc.py +199 -0
- omnisus/sources/datasus_ftp/dbf_batches.py +172 -0
- omnisus/sources/datasus_ftp/dbf_contract.py +149 -0
- omnisus/sources/datasus_ftp/fetch.py +214 -0
- omnisus/sources/datasus_ftp/filenames.py +96 -0
- omnisus/sources/datasus_ftp/identity.py +75 -0
- omnisus/sources/datasus_ftp/inventory.py +438 -0
- omnisus/sources/datasus_ftp/native.py +40 -0
- omnisus/sources/datasus_ftp/parse.py +87 -0
- omnisus/sources/datasus_ftp/staging.py +242 -0
- omnisus/sources/ibge/__init__.py +0 -0
- omnisus/sources/ibge/fetch.py +140 -0
- omnisus/sources/ibge/importers/__init__.py +0 -0
- omnisus/sources/ibge/importers/pop.py +100 -0
- omnisus/sources/ibge/parse.py +88 -0
- omnisus/sources/ibge/products.py +60 -0
- omnisus/sources/medicamentos/__init__.py +5 -0
- omnisus/sources/medicamentos/horus.py +137 -0
- omnisus/sources/sigtap/__init__.py +172 -0
- omnisus/transforms/__init__.py +0 -0
- omnisus/transforms/age.py +226 -0
- omnisus/transforms/analytics.py +252 -0
- omnisus/transforms/cnv.py +235 -0
- omnisus/transforms/columns.py +113 -0
- omnisus/transforms/dictionaries.py +253 -0
- omnisus-0.2.0.dist-info/METADATA +169 -0
- omnisus-0.2.0.dist-info/RECORD +282 -0
- omnisus-0.2.0.dist-info/WHEEL +4 -0
- omnisus-0.2.0.dist-info/entry_points.txt +2 -0
- omnisus-0.2.0.dist-info/licenses/LICENSE +21 -0
omnisus/__init__.py
ADDED
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
"""omnisus — Brazilian public health database ingestion lib."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import warnings
|
|
6
|
+
from collections.abc import Callable, Iterable, Mapping, Sequence
|
|
7
|
+
from urllib.parse import urlparse
|
|
8
|
+
|
|
9
|
+
import polars as pl
|
|
10
|
+
|
|
11
|
+
from omnisus._loop import run_sync
|
|
12
|
+
from omnisus._version import __version__
|
|
13
|
+
from omnisus.lake import CatalogAttachError, Lake, LakeReader
|
|
14
|
+
from omnisus.lake.catalog import set_lake_dir
|
|
15
|
+
from omnisus.lake.publication import DeletionResult, ImportPolicy, scope_filter
|
|
16
|
+
from omnisus.lake.sql import qualified, quote_identifier
|
|
17
|
+
from omnisus.metadata import describe_dataset
|
|
18
|
+
from omnisus.products import Product, datasets, products
|
|
19
|
+
from omnisus.research import (
|
|
20
|
+
Citation,
|
|
21
|
+
citation_from_publications,
|
|
22
|
+
cite,
|
|
23
|
+
import_research,
|
|
24
|
+
latest_snapshot_id,
|
|
25
|
+
municipality_join_key,
|
|
26
|
+
municipality_join_key_sql,
|
|
27
|
+
reference_join_sql,
|
|
28
|
+
)
|
|
29
|
+
from omnisus.sources._base import (
|
|
30
|
+
ALL_UFS,
|
|
31
|
+
ImportAbortedError,
|
|
32
|
+
ImportReport,
|
|
33
|
+
ImportResult,
|
|
34
|
+
ScopeKey,
|
|
35
|
+
ScopeOutcome,
|
|
36
|
+
)
|
|
37
|
+
from omnisus.sources.datasus_ftp._runner import (
|
|
38
|
+
DEFAULT_BATCH_SIZE,
|
|
39
|
+
DEFAULT_CONCURRENCY,
|
|
40
|
+
)
|
|
41
|
+
from omnisus.sources.datasus_ftp._runner import run_scopes as _run_scopes_ftp
|
|
42
|
+
from omnisus.sources.datasus_ftp.datasets import Dataset, resolve
|
|
43
|
+
from omnisus.sources.datasus_ftp.fetch import (
|
|
44
|
+
DEFAULT_MAX_INFLIGHT_BYTES,
|
|
45
|
+
DEFAULT_MAX_PAYLOAD_BYTES,
|
|
46
|
+
)
|
|
47
|
+
from omnisus.sources.datasus_ftp.inventory import (
|
|
48
|
+
FtpEntry,
|
|
49
|
+
FtpPathNotFound,
|
|
50
|
+
FtpUnavailable,
|
|
51
|
+
available,
|
|
52
|
+
available_releases,
|
|
53
|
+
list_sources,
|
|
54
|
+
)
|
|
55
|
+
from omnisus.sources.datasus_ftp.inventory import crawl as _crawl
|
|
56
|
+
from omnisus.transforms.analytics import (
|
|
57
|
+
AnalyticalProjection,
|
|
58
|
+
DerivedColumn,
|
|
59
|
+
SourceContext,
|
|
60
|
+
UnavailableField,
|
|
61
|
+
analytical_projection,
|
|
62
|
+
)
|
|
63
|
+
from omnisus.transforms.columns import check_columns
|
|
64
|
+
from omnisus.transforms.dictionaries import display_row, label
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def scopes_for(
|
|
68
|
+
dataset: str | Dataset,
|
|
69
|
+
*,
|
|
70
|
+
years: Iterable[int],
|
|
71
|
+
ufs: Sequence[str] | None = None,
|
|
72
|
+
months: Iterable[int] | None = None,
|
|
73
|
+
) -> list[ScopeKey]:
|
|
74
|
+
"""Every scope (UF x year [x month]) of a dataset, without asking the server.
|
|
75
|
+
|
|
76
|
+
Planning is composition: pass the result, or any other list of scopes, to
|
|
77
|
+
:func:`import_dataset`. Scopes DATASUS does not publish are later reported as
|
|
78
|
+
``skipped``; :func:`available` plans only what the server lists.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
dataset: Dataset name, e.g. ``"sim_obitos"``, or a :class:`Dataset`; see
|
|
82
|
+
:func:`datasets`.
|
|
83
|
+
years: Years, e.g. ``[2022, 2023]`` or ``range(2020, 2024)``.
|
|
84
|
+
ufs: UF abbreviations, e.g. ``["RR", "AC"]``. ``None`` (default) means all 27
|
|
85
|
+
(:data:`ALL_UFS`). National datasets (SINAN, SIM subsets) accept only ``None``.
|
|
86
|
+
months: Months 1-12 for monthly datasets (SIH, SIA, CNES); ``None`` (default)
|
|
87
|
+
means all twelve. Ignored for yearly UF datasets; national datasets accept
|
|
88
|
+
only ``None``.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
The scopes, ordered by year, then UF, then month.
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
ValueError: ``dataset`` is unknown, or a national dataset got ``ufs`` or
|
|
95
|
+
``months``.
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
>>> import omnisus as sus
|
|
99
|
+
>>> sus.scopes_for("sih_aih_reduzida", years=[2024], ufs=["RR"], months=[1, 2])
|
|
100
|
+
[ScopeKey(uf='RR', ano=2024, mes=1), ScopeKey(uf='RR', ano=2024, mes=2)]
|
|
101
|
+
>>> sus.scopes_for("sinan_chagas", years=[2023])
|
|
102
|
+
[ScopeKey(uf=None, ano=2023, mes=None)]
|
|
103
|
+
"""
|
|
104
|
+
d = resolve(dataset)
|
|
105
|
+
if d.geography == "national":
|
|
106
|
+
if ufs is not None:
|
|
107
|
+
raise ValueError(
|
|
108
|
+
"national datasets do not accept UF filters; filter records after import"
|
|
109
|
+
)
|
|
110
|
+
if months is not None:
|
|
111
|
+
raise ValueError("national yearly datasets do not accept month filters")
|
|
112
|
+
return [ScopeKey(uf=None, ano=year) for year in years]
|
|
113
|
+
uf_list = tuple(ufs) if ufs is not None else ALL_UFS
|
|
114
|
+
month_list = tuple(months) if months is not None else tuple(range(1, 13))
|
|
115
|
+
scopes: list[ScopeKey] = []
|
|
116
|
+
for year in years:
|
|
117
|
+
for uf in uf_list:
|
|
118
|
+
if d.monthly:
|
|
119
|
+
scopes.extend(ScopeKey(uf=uf, ano=year, mes=m) for m in month_list)
|
|
120
|
+
else:
|
|
121
|
+
scopes.append(ScopeKey(uf=uf, ano=year))
|
|
122
|
+
return scopes
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def browse(path: str, *, depth: int = 1, refresh: bool = False) -> list[FtpEntry]:
|
|
126
|
+
"""List any DATASUS FTP path, including datasets the package does not curate.
|
|
127
|
+
|
|
128
|
+
The open-world counterpart to :func:`available`: it reaches other SINAN agravos,
|
|
129
|
+
CIHA or PCE. Eager, so a huge tree is listed whole; call
|
|
130
|
+
``omnisus.sources.datasus_ftp.inventory.crawl`` for a lazy walk.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
path: Absolute FTP path, e.g. ``"/dissemin/publicos/SINAN/DADOS/FINAIS"``.
|
|
134
|
+
depth: How many directory levels to list; ``1`` (default) lists ``path`` only.
|
|
135
|
+
refresh: ``True`` ignores the local listing cache and asks the server again.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
One :class:`FtpEntry` per file or directory, with size and server time.
|
|
139
|
+
|
|
140
|
+
Raises:
|
|
141
|
+
FtpPathNotFound: the server has no such path.
|
|
142
|
+
FtpUnavailable: the server did not answer after retries.
|
|
143
|
+
|
|
144
|
+
Examples:
|
|
145
|
+
>>> import omnisus as sus
|
|
146
|
+
>>> entries = sus.browse("/dissemin/publicos/SINAN/DADOS/FINAIS") # doctest: +SKIP
|
|
147
|
+
>>> entries[0].name # doctest: +SKIP
|
|
148
|
+
'ACBIBR06.dbc'
|
|
149
|
+
"""
|
|
150
|
+
return list(_crawl(path, depth=depth, refresh=refresh))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
_AFTER_IMPORT: dict[str, Callable[[Lake], object]] = {
|
|
154
|
+
"cnes_estabelecimentos": Lake.ensure_aux_cnes_view,
|
|
155
|
+
}
|
|
156
|
+
"""Behaviour that follows an import, keyed by dataset. It lives here, not on the
|
|
157
|
+
registry row (ADR 0002), and runs whichever function started the import."""
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def import_dataset(
|
|
161
|
+
dataset: str | Dataset,
|
|
162
|
+
*,
|
|
163
|
+
scopes: Sequence[ScopeKey],
|
|
164
|
+
target: str | None = None,
|
|
165
|
+
concurrency: int = DEFAULT_CONCURRENCY,
|
|
166
|
+
batch_size: int = DEFAULT_BATCH_SIZE,
|
|
167
|
+
policy: ImportPolicy = "append",
|
|
168
|
+
run_id: str | None = None,
|
|
169
|
+
max_payload_bytes: int = DEFAULT_MAX_PAYLOAD_BYTES,
|
|
170
|
+
max_inflight_bytes: int = DEFAULT_MAX_INFLIGHT_BYTES,
|
|
171
|
+
) -> ImportReport:
|
|
172
|
+
"""Import the given scopes of a DATASUS FTP dataset into the lake (operator door).
|
|
173
|
+
|
|
174
|
+
The import iterates ``scopes`` and never asks where they came from:
|
|
175
|
+
:func:`scopes_for` plans blindly and :func:`available` asks the server first.
|
|
176
|
+
Every run lists the server once and imports what it lists; callers never choose
|
|
177
|
+
a release or file name. Importing ``cnes_estabelecimentos`` also refreshes the
|
|
178
|
+
``aux_cnes`` view. Works inside a notebook's running event loop.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
dataset: Dataset name, e.g. ``"sia_bpa_individualizado"``, or a
|
|
182
|
+
:class:`Dataset`; see :func:`datasets`.
|
|
183
|
+
scopes: The scopes to import, e.g. from :func:`scopes_for` or :func:`available`.
|
|
184
|
+
target: DuckLake target such as ``"ducklake:/path/omnisus.ducklake"`` or
|
|
185
|
+
``"ducklake:postgresql://…?storage=s3://…"``. ``None`` (default) is
|
|
186
|
+
``data/raw/omnisus.ducklake`` under the working directory, or under
|
|
187
|
+
``$OMNISUS_DATA_DIR``.
|
|
188
|
+
concurrency: Downloads in flight. DATASUS FTP is a shared public server; raise
|
|
189
|
+
it only with reason.
|
|
190
|
+
batch_size: Scopes committed in one DuckLake transaction, hence one snapshot.
|
|
191
|
+
policy: What to do with a scope already in the lake: ``"append"`` (default)
|
|
192
|
+
adds rows again; ``"skip_same"`` skips it when file and parser are
|
|
193
|
+
unchanged, without downloading when the listing shows the same path,
|
|
194
|
+
size and server time; ``"error_if_exists"`` fails that scope;
|
|
195
|
+
``"replace"`` rewrites it. :func:`load` and :func:`import_research` default to ``"skip_same"``.
|
|
196
|
+
run_id: Your identifier for this run, chosen before it starts, to reconcile an
|
|
197
|
+
interrupted commit through ``Lake.publications(run_id=...)``. ``None``
|
|
198
|
+
generates one.
|
|
199
|
+
max_payload_bytes: Largest compressed download accepted per file (512 MiB).
|
|
200
|
+
max_inflight_bytes: Compressed bytes held at once before parsing (1 GiB).
|
|
201
|
+
Neither bounds total memory: a decompressed DBF is held whole.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
One :class:`ScopeOutcome` per scope: ``ok``, ``skipped`` (e.g. the server
|
|
205
|
+
does not list it) or ``failed``, with ``code`` and ``reason``. Inspect
|
|
206
|
+
``report.failed``; later batches continue after a failed scope.
|
|
207
|
+
|
|
208
|
+
Raises:
|
|
209
|
+
ImportAbortedError: the lake transaction failed mid-run; its ``report`` and
|
|
210
|
+
``unresolved`` say what was committed. Inspect before retrying.
|
|
211
|
+
ValueError: ``dataset`` is unknown or ``policy`` is not one of the four values.
|
|
212
|
+
|
|
213
|
+
Examples:
|
|
214
|
+
>>> import omnisus as sus
|
|
215
|
+
>>> scopes = sus.available("sim_obitos", years=[2023], ufs=["RR"]) # doctest: +SKIP
|
|
216
|
+
>>> report = sus.import_dataset("sim_obitos", scopes=scopes) # doctest: +SKIP
|
|
217
|
+
>>> [(str(o.scope), o.status) for o in report.outcomes] # doctest: +SKIP
|
|
218
|
+
[('RR_2023', 'ok')]
|
|
219
|
+
"""
|
|
220
|
+
d = resolve(dataset)
|
|
221
|
+
|
|
222
|
+
async def run() -> ImportReport:
|
|
223
|
+
with Lake.local(target) as lake:
|
|
224
|
+
report = await _run_scopes_ftp(
|
|
225
|
+
d,
|
|
226
|
+
scopes=scopes,
|
|
227
|
+
lake=lake,
|
|
228
|
+
concurrency=concurrency,
|
|
229
|
+
batch_size=batch_size,
|
|
230
|
+
policy=policy,
|
|
231
|
+
run_id=run_id,
|
|
232
|
+
max_payload_bytes=max_payload_bytes,
|
|
233
|
+
max_inflight_bytes=max_inflight_bytes,
|
|
234
|
+
)
|
|
235
|
+
if after_import := _AFTER_IMPORT.get(d.name):
|
|
236
|
+
after_import(lake)
|
|
237
|
+
return report
|
|
238
|
+
|
|
239
|
+
return run_sync(run)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _loadable(dataset: str | Dataset) -> Dataset:
|
|
243
|
+
"""The FTP dataset ``load`` imports; another product's name points to its function."""
|
|
244
|
+
other = {p.name for p in products() if p.dataset is None}
|
|
245
|
+
if dataset in other:
|
|
246
|
+
raise ValueError(
|
|
247
|
+
f"load reads DATASUS FTP datasets; use sus.import_{dataset} for {dataset}"
|
|
248
|
+
)
|
|
249
|
+
return resolve(dataset)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def load(
|
|
253
|
+
dataset: str | Dataset,
|
|
254
|
+
*,
|
|
255
|
+
years: Iterable[int],
|
|
256
|
+
ufs: Sequence[str] | None = None,
|
|
257
|
+
months: Iterable[int] | None = None,
|
|
258
|
+
target: str | None = None,
|
|
259
|
+
policy: ImportPolicy = "skip_same",
|
|
260
|
+
) -> pl.DataFrame:
|
|
261
|
+
"""Download what DATASUS publishes for these scopes and return the rows.
|
|
262
|
+
|
|
263
|
+
The one-call path for a script or notebook cell. It imports into the lake (a
|
|
264
|
+
second call downloads nothing new) and returns the requested scopes' rows with
|
|
265
|
+
codes as DATASUS published them. When every file comes from a validated source
|
|
266
|
+
(see ``describe_dataset(dataset)["analytics"]["validated_sources"]``) it also adds
|
|
267
|
+
the harmonised categories: ``idade_anos_completos``, ``idade_status``,
|
|
268
|
+
``sexo_categoria``, ``sexo_status`` and ``<date>_data`` columns. Otherwise it
|
|
269
|
+
leaves them out and warns once. Readable labels come from :func:`label`.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
dataset: DATASUS FTP dataset name, e.g. ``"sim_obitos"``,
|
|
273
|
+
``"sih_aih_reduzida"``; see :func:`datasets`. IBGE population, SIGTAP and
|
|
274
|
+
CNES names have their own functions (:func:`import_ibge_populacao`,
|
|
275
|
+
:func:`import_sigtap`, :func:`import_cnes_master`).
|
|
276
|
+
years: Years, e.g. ``[2023]`` or ``range(2020, 2024)``.
|
|
277
|
+
ufs: UF abbreviations, e.g. ``["RR"]``. Required for datasets published per
|
|
278
|
+
UF; pass :data:`ALL_UFS` for all of Brazil. National datasets (SINAN,
|
|
279
|
+
SIM subsets) accept only ``None``.
|
|
280
|
+
months: Months 1-12 of monthly datasets (SIH, SIA, CNES), e.g. ``[1, 2]``;
|
|
281
|
+
``None`` (default) means all twelve.
|
|
282
|
+
target: DuckLake target; ``None`` (default) is ``data/raw/omnisus.ducklake``
|
|
283
|
+
under the working directory, or under ``$OMNISUS_DATA_DIR``.
|
|
284
|
+
policy: ``"skip_same"`` (default) reuses scopes already imported from the
|
|
285
|
+
same file; ``"replace"`` rewrites scopes imported from another file or
|
|
286
|
+
dictionary version; ``"append"`` and ``"error_if_exists"`` as in
|
|
287
|
+
:func:`import_dataset`.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
A polars DataFrame with one row per record of the requested scopes.
|
|
291
|
+
|
|
292
|
+
Raises:
|
|
293
|
+
ValueError: ``dataset`` is unknown or not an FTP dataset, ``ufs`` is missing
|
|
294
|
+
for a UF dataset, or given for a national one.
|
|
295
|
+
RuntimeError: a scope failed to import; the message names each one.
|
|
296
|
+
LookupError: DATASUS publishes none of the requested scopes.
|
|
297
|
+
|
|
298
|
+
Warns:
|
|
299
|
+
UserWarning: harmonised categories were left out, and why.
|
|
300
|
+
|
|
301
|
+
Examples:
|
|
302
|
+
>>> import omnisus as sus
|
|
303
|
+
>>> dados = sus.load("sim_obitos", years=[2023], ufs=["RR"]) # doctest: +SKIP
|
|
304
|
+
>>> dados.height # doctest: +SKIP
|
|
305
|
+
3311
|
|
306
|
+
>>> dados = sus.label("sim_obitos", dados, columns=["sexo"]) # doctest: +SKIP
|
|
307
|
+
"""
|
|
308
|
+
d = _loadable(dataset)
|
|
309
|
+
if ufs is None and d.geography != "national":
|
|
310
|
+
raise ValueError(
|
|
311
|
+
f"{d.name} is published per UF: pass ufs=['RR', ...], or ufs=sus.ALL_UFS "
|
|
312
|
+
"for all of Brazil"
|
|
313
|
+
)
|
|
314
|
+
scopes = scopes_for(d, years=years, ufs=ufs, months=months)
|
|
315
|
+
report = import_dataset(d, scopes=scopes, target=target, policy=policy)
|
|
316
|
+
if report.failed:
|
|
317
|
+
reasons = "; ".join(f"{o.scope}: {o.reason}" for o in report.failed)
|
|
318
|
+
raise RuntimeError(
|
|
319
|
+
f"{d.name} import failed ({reasons}). A scope already imported from "
|
|
320
|
+
"another file or parser version is rewritten with policy='replace'."
|
|
321
|
+
)
|
|
322
|
+
rows = _read_with_harmonised(d, scopes, target)
|
|
323
|
+
if rows.is_empty():
|
|
324
|
+
raise LookupError(f"{d.name}: DATASUS publishes none of these scopes: {scopes}")
|
|
325
|
+
return rows
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _read_with_harmonised(
|
|
329
|
+
d: Dataset, scopes: Sequence[ScopeKey], target: str | None
|
|
330
|
+
) -> pl.DataFrame:
|
|
331
|
+
"""The scopes' rows plus the harmonised categories their sources allow (ADR 0003).
|
|
332
|
+
|
|
333
|
+
Rows, schema and source identities come from one pinned snapshot, as
|
|
334
|
+
:func:`analytical_projection` requires. A category the rule leaves out is
|
|
335
|
+
named in one warning; a dataset without rules warns nothing.
|
|
336
|
+
"""
|
|
337
|
+
with LakeReader(target) as latest:
|
|
338
|
+
if d.name not in latest.tables():
|
|
339
|
+
return pl.DataFrame()
|
|
340
|
+
snapshot = latest_snapshot_id(latest)
|
|
341
|
+
predicates = [scope_filter(scope) for scope in scopes]
|
|
342
|
+
where = " OR ".join(f"({sql})" for sql, _ in predicates)
|
|
343
|
+
args = [value for _, values in predicates for value in values]
|
|
344
|
+
with LakeReader(target, snapshot_id=snapshot) as reader:
|
|
345
|
+
con = reader.connect()
|
|
346
|
+
table = qualified(reader.alias, d.name)
|
|
347
|
+
schema = {
|
|
348
|
+
row[0]: row[1] for row in con.execute(f"DESCRIBE SELECT * FROM {table}").fetchall()
|
|
349
|
+
}
|
|
350
|
+
sources = [
|
|
351
|
+
SourceContext.from_publication(row)
|
|
352
|
+
for row in reader.publications()
|
|
353
|
+
if row["dataset"] == d.name and row["active"] and row["scope"] in scopes
|
|
354
|
+
]
|
|
355
|
+
projection = analytical_projection(d.name, observed_schema=schema, scopes=sources)
|
|
356
|
+
derived = "".join(
|
|
357
|
+
f", {column.expression} AS {quote_identifier(column.name)}"
|
|
358
|
+
for column in projection.columns
|
|
359
|
+
)
|
|
360
|
+
rows = con.execute(f"SELECT *{derived} FROM {table} WHERE {where}", args).pl()
|
|
361
|
+
left_out = [u for u in projection.unavailable if u.reason != "unsupported_dataset"]
|
|
362
|
+
if left_out:
|
|
363
|
+
warnings.warn(
|
|
364
|
+
f"{d.name}: harmonised categories left out: "
|
|
365
|
+
+ ", ".join(f"{u.field} ({u.reason})" for u in left_out)
|
|
366
|
+
+ ". They exist only for validated sources (docs/decisions/0003); "
|
|
367
|
+
"labels from sus.label work for any scope.",
|
|
368
|
+
UserWarning,
|
|
369
|
+
stacklevel=3,
|
|
370
|
+
)
|
|
371
|
+
return rows
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def import_ibge_populacao(
|
|
375
|
+
*,
|
|
376
|
+
years: Iterable[int],
|
|
377
|
+
census: bool,
|
|
378
|
+
target: str | None = None,
|
|
379
|
+
) -> list[ImportResult]:
|
|
380
|
+
"""Import IBGE population by municipality: a census or the year's latest estimate.
|
|
381
|
+
|
|
382
|
+
Each population edition is its own publication, identified by the returned
|
|
383
|
+
``publication_id`` in ``ibge_population_manifest``; it never appears in
|
|
384
|
+
``Lake.publications()``. Reconcile an interrupted run through that manifest.
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
years: Years, e.g. ``[2022]``. Censuses exist for 2010 and 2022; an estimate
|
|
388
|
+
is importable only as the aggregate's latest edition, and years without a
|
|
389
|
+
verified territorial universe are refused.
|
|
390
|
+
census: Required, with no default, so nobody gets an estimate thinking it is
|
|
391
|
+
the census. ``True`` imports the census; ``False`` the latest estimate.
|
|
392
|
+
target: DuckLake target; ``None`` (default) is ``data/raw/omnisus.ducklake``
|
|
393
|
+
under the working directory, or under ``$OMNISUS_DATA_DIR``.
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
One :class:`ImportResult` per year, with ``rows`` and ``publication_id``.
|
|
397
|
+
|
|
398
|
+
Raises:
|
|
399
|
+
ValueError: the year has no such edition.
|
|
400
|
+
TypeError: ``census`` was not given.
|
|
401
|
+
|
|
402
|
+
Examples:
|
|
403
|
+
>>> import omnisus as sus
|
|
404
|
+
>>> (censo,) = sus.import_ibge_populacao(years=[2022], census=True) # doctest: +SKIP
|
|
405
|
+
>>> censo.rows # doctest: +SKIP
|
|
406
|
+
5570
|
|
407
|
+
"""
|
|
408
|
+
from omnisus.sources.ibge.importers.pop import import_pop_year
|
|
409
|
+
|
|
410
|
+
edition = "census" if census else "estimate"
|
|
411
|
+
|
|
412
|
+
async def run() -> list[ImportResult]:
|
|
413
|
+
results: list[ImportResult] = []
|
|
414
|
+
with Lake.local(target) as lake:
|
|
415
|
+
for y in years:
|
|
416
|
+
results.append(await import_pop_year(year=y, lake=lake, product=edition))
|
|
417
|
+
return results
|
|
418
|
+
|
|
419
|
+
return run_sync(run)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def import_sigtap(
|
|
423
|
+
*,
|
|
424
|
+
years: Iterable[int],
|
|
425
|
+
months: Iterable[int] | None = None,
|
|
426
|
+
target: str | None = None,
|
|
427
|
+
policy: ImportPolicy = "skip_same",
|
|
428
|
+
) -> ImportReport:
|
|
429
|
+
"""Import SIGTAP procedures, one competência per year x month.
|
|
430
|
+
|
|
431
|
+
Each competência is one national monthly publication from
|
|
432
|
+
``ftp2.datasus.gov.br/public/sistemas/tup/downloads`` into
|
|
433
|
+
``aux_sigtap_procedimentos``. Nothing joins at import: join on
|
|
434
|
+
``co_procedimento`` and the record's competência yourself.
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
years: Years, e.g. ``[2024]``.
|
|
438
|
+
months: Months 1-12, e.g. ``[1, 2]``; ``None`` (default) means all twelve.
|
|
439
|
+
target: DuckLake target; ``None`` (default) is ``data/raw/omnisus.ducklake``
|
|
440
|
+
under the working directory, or under ``$OMNISUS_DATA_DIR``.
|
|
441
|
+
policy: ``"skip_same"`` (default) reports an unchanged zip as
|
|
442
|
+
``skipped``/``unchanged``; ``"append"``, ``"error_if_exists"`` and
|
|
443
|
+
``"replace"`` as in :func:`import_dataset`.
|
|
444
|
+
|
|
445
|
+
Returns:
|
|
446
|
+
One :class:`ScopeOutcome` per competência; one the server does not list is
|
|
447
|
+
``skipped``/``not_listed``. :func:`cite` names each zip.
|
|
448
|
+
|
|
449
|
+
Examples:
|
|
450
|
+
>>> import omnisus as sus
|
|
451
|
+
>>> report = sus.import_sigtap(years=[2024], months=[1]) # doctest: +SKIP
|
|
452
|
+
>>> [(str(o.scope), o.status) for o in report.outcomes] # doctest: +SKIP
|
|
453
|
+
[('national_2024_01', 'ok')]
|
|
454
|
+
"""
|
|
455
|
+
from omnisus.sources.sigtap import import_sigtap as _impl
|
|
456
|
+
|
|
457
|
+
month_list = tuple(months) if months is not None else tuple(range(1, 13))
|
|
458
|
+
wanted = [(year, month) for year in years for month in month_list]
|
|
459
|
+
with Lake.local(target) as lake:
|
|
460
|
+
return _impl(wanted, lake=lake, policy=policy)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def available_sigtap() -> list[tuple[int, int]]:
|
|
464
|
+
"""Every SIGTAP competência the server lists now, oldest first.
|
|
465
|
+
|
|
466
|
+
Returns:
|
|
467
|
+
``(year, month)`` pairs, e.g. ``[(2008, 1), (2008, 2), ...]``.
|
|
468
|
+
|
|
469
|
+
Raises:
|
|
470
|
+
FtpUnavailable: the server did not answer after retries.
|
|
471
|
+
|
|
472
|
+
Examples:
|
|
473
|
+
>>> import omnisus as sus
|
|
474
|
+
>>> sus.available_sigtap()[:2] # doctest: +SKIP
|
|
475
|
+
[(2008, 1), (2008, 2)]
|
|
476
|
+
"""
|
|
477
|
+
from omnisus.sources.sigtap import available_sigtap as _impl
|
|
478
|
+
|
|
479
|
+
return _impl()
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def import_cnes_master(
|
|
483
|
+
*,
|
|
484
|
+
codes: Sequence[str] | None = None,
|
|
485
|
+
target: str | None = None,
|
|
486
|
+
concurrency: int = 5,
|
|
487
|
+
only_missing: bool = True,
|
|
488
|
+
progress: Callable[[int, int], None] | None = None,
|
|
489
|
+
) -> int:
|
|
490
|
+
"""Fetch CNES establishment names from the public API into ``cnes_master``.
|
|
491
|
+
|
|
492
|
+
The CNES-ST DBF has no establishment names; this pulls them from
|
|
493
|
+
``apidadosabertos.saude.gov.br`` and joins them into the ``aux_cnes`` view. It
|
|
494
|
+
is an idempotent upsert, not a publication: no ``run_id``, no ``policy``, no
|
|
495
|
+
manifest row. To finish an interrupted run, run it again.
|
|
496
|
+
|
|
497
|
+
Args:
|
|
498
|
+
codes: 7-digit CNES codes, e.g. ``["2789590"]``. ``None`` (default) takes
|
|
499
|
+
every code in ``cnes_estabelecimentos``.
|
|
500
|
+
target: DuckLake target; ``None`` (default) is ``data/raw/omnisus.ducklake``
|
|
501
|
+
under the working directory, or under ``$OMNISUS_DATA_DIR``.
|
|
502
|
+
concurrency: API requests in flight (default 5).
|
|
503
|
+
only_missing: ``True`` (default) skips codes already in ``cnes_master``, so
|
|
504
|
+
reruns are incremental; ``False`` fetches every code again.
|
|
505
|
+
progress: Optional ``progress(done, total)`` callback after each fetch.
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
The number of records written in this run.
|
|
509
|
+
|
|
510
|
+
Raises:
|
|
511
|
+
ValueError: a code is not seven ASCII digits, or the API returned conflicting
|
|
512
|
+
records for one code.
|
|
513
|
+
|
|
514
|
+
Examples:
|
|
515
|
+
>>> import omnisus as sus
|
|
516
|
+
>>> sus.import_cnes_master(codes=["2789590"]) # doctest: +SKIP
|
|
517
|
+
1
|
|
518
|
+
"""
|
|
519
|
+
from omnisus.sources.cnes.importers.master import (
|
|
520
|
+
import_cnes_master as _impl,
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
return _impl(
|
|
524
|
+
codes=codes,
|
|
525
|
+
target=target,
|
|
526
|
+
concurrency=concurrency,
|
|
527
|
+
only_missing=only_missing,
|
|
528
|
+
progress=progress,
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def outdated(
|
|
533
|
+
dataset: str | Dataset,
|
|
534
|
+
*,
|
|
535
|
+
lake: Lake | LakeReader,
|
|
536
|
+
refresh: bool = False,
|
|
537
|
+
) -> list[ScopeKey]:
|
|
538
|
+
"""Scopes whose imported files differ from what the server lists now.
|
|
539
|
+
|
|
540
|
+
Different means another path (a preliminary year that became final, or a moved
|
|
541
|
+
directory), or the same path with another size or server time (DATASUS
|
|
542
|
+
republished it). Publications without a recorded source are always reported.
|
|
543
|
+
Scopes the server no longer lists are a withdrawal, not returned here.
|
|
544
|
+
Read-only.
|
|
545
|
+
|
|
546
|
+
Args:
|
|
547
|
+
dataset: Dataset name, e.g. ``"sim_obitos"``, or a :class:`Dataset`.
|
|
548
|
+
lake: An open :class:`Lake` or :class:`LakeReader`.
|
|
549
|
+
refresh: ``True`` ignores the local listing cache and asks the server again.
|
|
550
|
+
|
|
551
|
+
Returns:
|
|
552
|
+
The scopes to re-import with :func:`import_dataset` and
|
|
553
|
+
``policy="replace"``, ordered by year, UF and month.
|
|
554
|
+
|
|
555
|
+
Raises:
|
|
556
|
+
ValueError: ``dataset`` is unknown.
|
|
557
|
+
FtpUnavailable: the server did not answer after retries.
|
|
558
|
+
|
|
559
|
+
Examples:
|
|
560
|
+
>>> import omnisus as sus
|
|
561
|
+
>>> with sus.LakeReader() as lake: # doctest: +SKIP
|
|
562
|
+
... stale = sus.outdated("sim_obitos", lake=lake)
|
|
563
|
+
>>> sus.import_dataset( # doctest: +SKIP
|
|
564
|
+
... "sim_obitos", scopes=stale, policy="replace", run_id="refresh-2026-09"
|
|
565
|
+
... )
|
|
566
|
+
"""
|
|
567
|
+
d = resolve(dataset)
|
|
568
|
+
current = list_sources(d, refresh=refresh)
|
|
569
|
+
changed = {
|
|
570
|
+
row["scope"]
|
|
571
|
+
for row in lake.publications()
|
|
572
|
+
if row["dataset"] == d.name
|
|
573
|
+
and row["active"]
|
|
574
|
+
and row["scope"] in current
|
|
575
|
+
and _files_differ(row["sources"], current[row["scope"]].files)
|
|
576
|
+
}
|
|
577
|
+
return sorted(changed, key=lambda s: (s.ano, s.uf or "", s.mes or 0))
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def _files_differ(recorded: Sequence[Mapping[str, object]], listed: Sequence[FtpEntry]) -> bool:
|
|
581
|
+
if [urlparse(str(r["source_uri"])).path for r in recorded] != [e.path for e in listed]:
|
|
582
|
+
return True
|
|
583
|
+
return any(
|
|
584
|
+
(r["source_bytes"] is not None and r["source_bytes"] != e.size_bytes)
|
|
585
|
+
or (
|
|
586
|
+
r["source_modified"] is not None
|
|
587
|
+
and r["source_modified"] != e.modified.strftime("%Y-%m-%dT%H:%M")
|
|
588
|
+
)
|
|
589
|
+
for r, e in zip(recorded, listed, strict=True)
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
__all__ = [
|
|
594
|
+
"ALL_UFS",
|
|
595
|
+
"AnalyticalProjection",
|
|
596
|
+
"CatalogAttachError",
|
|
597
|
+
"Citation",
|
|
598
|
+
"Dataset",
|
|
599
|
+
"DeletionResult",
|
|
600
|
+
"DerivedColumn",
|
|
601
|
+
"FtpEntry",
|
|
602
|
+
"FtpPathNotFound",
|
|
603
|
+
"FtpUnavailable",
|
|
604
|
+
"ImportAbortedError",
|
|
605
|
+
"ImportPolicy",
|
|
606
|
+
"ImportReport",
|
|
607
|
+
"ImportResult",
|
|
608
|
+
"Lake",
|
|
609
|
+
"LakeReader",
|
|
610
|
+
"Product",
|
|
611
|
+
"ScopeKey",
|
|
612
|
+
"ScopeOutcome",
|
|
613
|
+
"SourceContext",
|
|
614
|
+
"UnavailableField",
|
|
615
|
+
"__version__",
|
|
616
|
+
"analytical_projection",
|
|
617
|
+
"available",
|
|
618
|
+
"available_releases",
|
|
619
|
+
"available_sigtap",
|
|
620
|
+
"browse",
|
|
621
|
+
"check_columns",
|
|
622
|
+
"citation_from_publications",
|
|
623
|
+
"cite",
|
|
624
|
+
"datasets",
|
|
625
|
+
"describe_dataset",
|
|
626
|
+
"display_row",
|
|
627
|
+
"import_cnes_master",
|
|
628
|
+
"import_dataset",
|
|
629
|
+
"import_ibge_populacao",
|
|
630
|
+
"import_research",
|
|
631
|
+
"import_sigtap",
|
|
632
|
+
"label",
|
|
633
|
+
"latest_snapshot_id",
|
|
634
|
+
"load",
|
|
635
|
+
"municipality_join_key",
|
|
636
|
+
"municipality_join_key_sql",
|
|
637
|
+
"outdated",
|
|
638
|
+
"products",
|
|
639
|
+
"reference_join_sql",
|
|
640
|
+
"resolve",
|
|
641
|
+
"scopes_for",
|
|
642
|
+
"set_lake_dir",
|
|
643
|
+
]
|
omnisus/_loop.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Run a coroutine from synchronous code, also inside a notebook's running event loop."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import Callable, Coroutine
|
|
7
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def run_sync[T](coroutine: Callable[[], Coroutine[Any, Any, T]]) -> T:
|
|
12
|
+
"""Run ``coroutine()`` to completion, also from inside a running event loop.
|
|
13
|
+
|
|
14
|
+
A marimo or Jupyter cell already runs in an event loop, where
|
|
15
|
+
``asyncio.run`` refuses to start another; there the coroutine gets its own
|
|
16
|
+
loop on a worker thread and the caller blocks until it finishes. Every
|
|
17
|
+
synchronous public function that awaits goes through here.
|
|
18
|
+
"""
|
|
19
|
+
try:
|
|
20
|
+
asyncio.get_running_loop()
|
|
21
|
+
except RuntimeError:
|
|
22
|
+
return asyncio.run(coroutine())
|
|
23
|
+
with ThreadPoolExecutor(max_workers=1) as worker:
|
|
24
|
+
return worker.submit(lambda: asyncio.run(coroutine())).result()
|
omnisus/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0"
|
omnisus/cli/__init__.py
ADDED
|
File without changes
|