This release is a pre-release and may not be stable for production use.
brinss-public-datasets
Carregamento (com download e cache automáticos) dos datasets abertos do INSS
publicados em dadosabertos.inss.gov.br,
no estilo load_iris() do scikit-learn.
Os dados podem vir do portal do INSS ou do espelho em Parquet no Hugging Face gerado por este mesmo repositório — que é o padrão, por ser muito mais rápido e leve. Veja Fonte dos dados.
Instalação
pip install brinss-public-datasets
Ou, com uv:
uv add brinss-public-datasets
Requer Python 3.12 ou mais novo.
Uso
from brinss.datasets import load_beneficios_concedidos
df = load_beneficios_concedidos() # mês mais recente disponível
df = load_beneficios_concedidos(periodo="2024-06") # um mês específico
df = load_beneficios_concedidos(periodo=("2024-01", "2024-06")) # intervalo de meses
df = load_beneficios_concedidos(periodo="all") # todo o histórico disponível
As colunas vêm como texto por padrão, para não perder os zeros à esquerda dos
códigos do INSS. Para deixar o pandas converter os tipos automaticamente, passe
dtype="infer" — veja Tipos das colunas.
Datasets disponíveis (brinss.datasets.list_datasets()):
| Função | Descrição |
|---|---|
load_beneficios_concedidos |
Benefícios concedidos |
load_beneficios_emitidos |
Benefícios emitidos |
load_beneficios_mantidos_ativos |
Benefícios mantidos ativos |
load_beneficios_mantidos_cessados |
Benefícios mantidos cessados |
load_beneficios_mantidos_suspensos |
Benefícios mantidos suspensos |
load_beneficios_indeferidos |
Benefícios indeferidos |
load_comunicacoes_acidente_trabalho |
Comunicações de Acidente de Trabalho (CAT) |
load_perfil_unidades |
Perfil das unidades do INSS |
Todas aceitam os mesmos parâmetros de load_dataset:
from brinss.datasets import load_dataset
df = load_dataset(
"beneficios_concedidos",
periodo="2024-06",
as_dict=False, # True: dict[str, DataFrame] por período, em vez de concatenar
columns=None, # lista de colunas para carregar só um subconjunto
dtype="str", # "str": tudo como texto (padrão) | "infer": pandas infere os tipos
source="hf", # "hf": espelho Parquet (padrão) | "inss": portal dadosabertos.inss.gov.br
force_download=False, # ignora o cache local e baixa de novo
force_refresh=False, # ignora o cache (24h) do catálogo de períodos disponíveis
cache_dir=None, # sobrescreve o diretório de cache para esta chamada
)
Fonte dos dados
O parâmetro source escolhe de onde os arquivos são baixados:
df = load_beneficios_concedidos(periodo="2024-06") # espelho no Hugging Face (padrão)
df = load_beneficios_concedidos(periodo="2024-06", source="inss") # portal do INSS
source="hf" (padrão) |
source="inss" |
|
|---|---|---|
| Origem | espelho em Parquet no Hugging Face | dadosabertos.inss.gov.br |
| Formato | Parquet zstd, um arquivo por mês | XLSX, ou ZIP com CSV dentro |
| Download | 7,7 MB | 68,6 MB |
| Leitura | 3,3 s | 101,4 s |
columns=[...] |
lido só o que foi pedido, direto do arquivo | arquivo inteiro lido, colunas descartadas depois |
| Atualidade | pode ficar um ciclo de publicação atrás do portal | sempre o mais recente |
| Disponibilidade | não depende da CKAN estar de pé | depende |
Os números de download e leitura são de beneficios_concedidos em junho/2024
(628.457 linhas × 24 colunas), medidos numa mesma máquina — cerca de 9× menos
bytes e 30× menos tempo. A diferença cresce nas famílias pesadas, onde a
alternativa é descompactar gigabytes de CSV.
As duas fontes entregam o mesmo DataFrame. Mesmos nomes de coluna (incluindo
os sufixos de nomes repetidos, APS e APS.1), mesma coluna
periodo_referencia como pandas.Period, mesmo dtype="str" por padrão. Não é
coincidência: o Parquet do espelho é gerado por esta mesma biblioteca lendo o
arquivo do portal (veja
Publicação em Parquet no Hugging Face),
então a linha de título das planilhas, a escolha do membro do ZIP e a detecção
de encoding já vêm resolvidas de lá — resolvidas uma vez, e não a cada leitura.
Há um teste de rede que carrega o mesmo mês pelas duas fontes e compara os
DataFrames.
Vale usar source="inss" quando:
- o mês acabou de ser publicado no portal e ainda não subiu para o espelho —
como o espelho é reconstruído a partir do portal, ele fica para trás por até
um ciclo de publicação. Nesse caso o período aparece como indisponível na
fonte
hf, e a mensagem de erro lembra de tentar a outra; - você quer auditar o espelho contra a origem oficial.
O espelho cobre hoje as 8 famílias, de junho/2023 a julho/2026. Para ver o que
cada fonte tem, list_periods também aceita source:
from brinss.datasets import list_periods
list_periods("beneficios_concedidos") # meses no espelho
list_periods("beneficios_concedidos", source="inss") # meses no portal
Outras funções úteis:
from brinss.datasets import list_datasets, list_periods, get_cache_dir
list_datasets() # chaves de todos os datasets disponíveis
list_periods("beneficios_concedidos") # todos os períodos (meses) disponíveis para um dataset
get_cache_dir() # onde os arquivos baixados estão sendo guardados
Cache local
Os arquivos baixados ficam em cache em disco, na pasta padrão de cache do
sistema operacional (via platformdirs):
- Windows:
%LOCALAPPDATA%\brinss\Cache - Linux:
~/.cache/brinss - macOS:
~/Library/Caches/brinss
Para usar outro diretório, defina a variável de ambiente BRINSS_DATA_HOME
ou passe cache_dir=... em qualquer chamada de load_*/load_dataset.
As duas fontes dividem o mesmo diretório, sem colidir: o Parquet do espelho e o XLSX do portal são arquivos distintos, cada um com sua linha no registro de hashes. Carregar o mesmo mês pelas duas fontes deixa as duas cópias em disco.
O portal não publica checksum dos arquivos; no primeiro download o SHA256 é calculado e guardado localmente, e passa a ser conferido nas chamadas seguintes (detectando automaticamente se o governo trocar o conteúdo de um arquivo sem trocar o nome).
O catálogo de períodos disponíveis também fica em cache por 24h, nas duas
fontes: a resposta da CKAN na fonte inss, o manifest.json na fonte hf.
force_refresh=True ignora esse cache. Se a fonte estiver fora do ar e houver
cache local, ele é usado com um aviso, em vez de a chamada falhar.
Formato dos arquivos
Esta seção é sobre a fonte inss. Na fonte hf nada disso se aplica: é sempre
Parquet, com nomes de coluna e encoding gravados dentro do próprio arquivo. A
biblioteca reconhece o formato pelos primeiros bytes do arquivo baixado, então
nem precisa saber de qual fonte ele veio.
O campo format que a CKAN retorna para cada recurso não é confiável: já foi
visto marcado como CSV para um arquivo que na prática é um ZIP contendo
um único CSV (; como delimitador, encoding Latin-1/cp1252), e marcado
como XLS/XLSX para arquivos que às vezes são XLSX genuíno, às vezes
.xltx, etc. Por isso a biblioteca inspeciona o conteúdo real do arquivo
baixado (em vez de confiar no format) para decidir como ler: ZIP com
planilha OOXML dentro é lido como Excel; ZIP com um único CSV dentro é
descompactado e o CSV é lido com detecção automática de delimitador/encoding;
Excel binário legado (.xls no formato antigo OLE2) é lido via xlrd.
Os recursos da CAT (comunicacoes_acidente_trabalho) vão além: trazem o mesmo
dado três vezes dentro do ZIP, em .csv, .json e .xml. Nesse caso (membros
que só diferem na extensão) a biblioteca lê a versão tabular — o CSV — e registra
no log qual membro foi lido e quais foram ignorados; os outros formatos ficam
intactos dentro do arquivo em cache, sem serem descompactados. Um ZIP com
datasets diferentes dentro continua sendo erro (UnsupportedArchiveError),
já que não haveria como saber qual deles carregar.
Cabeçalho das planilhas
As planilhas de beneficios_concedidos e beneficios_indeferidos abrem com
uma linha de título que preenche uma única célula (ex: DADOS ABERTOS - BENEFÍCIOS CONCEDIDOS - ANO JULHO DE 2026), e os nomes reais das colunas só
vêm na linha seguinte. Lidas ingenuamente, essas planilhas produzem colunas
chamadas Unnamed: 1, Unnamed: 2, etc.
O texto dessa linha muda de mês para mês, então a biblioteca a identifica pela
forma, e não pelo conteúdo: o cabeçalho é a primeira linha que preenche mais de
uma célula. Planilhas que já começam com um cabeçalho de verdade, como as de
perfil_unidades, não são afetadas.
Como o cabeçalho passa a ser o correto, columns=[...] funciona com os nomes
reais dessas famílias ("APS", "Competência concessão", ...) — antes não
havia nome válido para pedir.
Algumas famílias repetem nomes de coluna na origem, em pares de código e
descrição (APS, APS, Espécie, Espécie, ... em beneficios_concedidos;
CBO, CBO, ... na CAT). Esses casos saem com o sufixo padrão do pandas:
APS e APS.1.
Tipos das colunas
Por padrão todas as colunas são carregadas como texto (dtype="str"). Não é
um detalhe de conveniência: os arquivos publicados são texto, e a inferência de
tipos do pandas destrói dados reais desses datasets.
- Zeros à esquerda somem. CID, CBO, CNAE e código IBGE de município vêm como
"01234"na origem e viram1234na inferência — o join com qualquer tabela de referência passa a não casar. - O tipo muda de mês para mês. Um mês em que a coluna vem toda preenchida é
inferido como
int64; outro com células vazias virafloat64. Ao pedir um intervalo de meses, o DataFrame concatenado sai com o tipo dependendo de quais meses foram pedidos.
Para deixar o pandas converter os tipos, como faria um read_csv cru:
df = load_beneficios_concedidos(periodo="2024-06", dtype="infer")
O parâmetro também aceita o enum exportado, se preferir explicitar:
from brinss.datasets import ColumnDtype
df = load_beneficios_concedidos(periodo="2024-06", dtype=ColumnDtype.INFER)
Na fonte hf as colunas já estão gravadas como texto no Parquet, então
dtype="infer" é aplicado depois da leitura, coluna a coluna: a que converte
inteira para número vira número, a que não converte fica texto. O resultado bate
com o da fonte inss nestes datasets — cujas colunas são número ou texto livre
— e perde os zeros à esquerda do mesmo jeito, que é justamente o que
dtype="infer" significa.
Duas observações sobre o modo texto:
- Células vazias continuam saindo como
NaN, e não como""—.isna()segue funcionando normalmente para filtrar linhas incompletas. periodo_referencianão é afetada: é metadado inserido pela biblioteca, e continua comopandas.Periodnos dois modos, para permitir filtros por período direto no DataFrame.
Benefícios mantidos: três datasets, não um
O portal publica três recursos por mês para benefícios mantidos — ativos,
cessados e suspensos — dentro do mesmo pacote, e eles não compartilham as
mesmas colunas: cessados não traz Clientela e repete Sexo., e ativos usa
Motivo Cessação/Suspensão onde os outros dois usam Motivo Cessação/Suspensão Novo. Por isso são três funções separadas, e não uma só
com tudo empilhado.
O mês de referência é lido do nome do recurso, mas quando dois recursos reivindicam o mesmo mês o nome do arquivo na URL desempata — é o que recupera suspensos de maio/2025, que o portal publicou rotulado como "abril 2025".
Arquivos grandes
Alguns meses descompactam para vários gigabytes. Na fonte inss, tamanhos por
mês medidos em maio/2026: beneficios_mantidos_ativos ~891 MB,
beneficios_mantidos_cessados ~786 MB e beneficios_emitidos ~763 MB
compactados — um único mês de beneficios_emitidos chega a ~10 GB
descompactado. beneficios_mantidos_suspensos, em contraste, é leve
(~5 MB/mês).
Na fonte padrão o download encolhe bastante (beneficios_mantidos_ativos fica
em ~385 MB/mês em Parquet) e a leitura deixa de passar por descompactar CSV de
gigabytes. O DataFrame resultante ocupa a mesma RAM, então o cuidado abaixo
continua valendo; o que muda é o custo de chegar até ele. columns=[...] ajuda
mais aqui do que na fonte inss: no Parquet as colunas descartadas não chegam a
ser lidas.
periodo="all" ou intervalos grandes nas famílias pesadas podem exigir bastante
RAM e espaço em disco. Nenhum limite é aplicado
automaticamente nesta versão — prefira pedir um periodo específico e, se
precisar, usar columns=[...] para reduzir o volume carregado em memória.
Nessas famílias pesadas vale lembrar que o padrão dtype="str" costuma ocupar
mais RAM que colunas numéricas; se os códigos com zero à esquerda não importarem
para a sua análise, dtype="infer" reduz o consumo.
Mensagens de progresso
Cada chamada de load_* escreve no stderr o andamento de cada período:
conclusão do download (ou aviso de que o arquivo veio do cache), início e fim
da leitura para o DataFrame, e — quando há mais de um período — a
concatenação final:
Downloading file 'res-06__Benefícios concedidos junho 2024.xlsx' from '...' to '...'.
Download complete: 'res-06__Benefícios concedidos junho 2024.xlsx' (12.4 MB) in 8.3 s.
Reading 'res-06__Benefícios concedidos junho 2024.xlsx' (12.4 MB) into a DataFrame...
DataFrame loaded: 148,203 rows x 17 columns from 'res-06__Benefícios concedidos junho 2024.xlsx' in 4.1 s.
As mensagens saem pelo logger brinss e podem ser silenciadas (ou
redirecionadas) com o logging padrão:
import logging
logging.getLogger("brinss").setLevel(logging.WARNING)
A primeira linha (Downloading file ...) é do
pooch, e se silencia à parte:
import pooch
pooch.get_logger().setLevel("WARNING")
Publicação em Parquet no Hugging Face
O repositório traz um script de manutenção que converte os datasets para Parquet
e publica em
huggingface.co/datasets/agaqueiroz/brinss-public-datasets
— o espelho que a biblioteca lê por padrão. Ele vive em scripts/, fora de
src/brinss, e portanto não faz parte do pacote distribuído — usa a própria
biblioteca para ler os arquivos, herdando de graça o tratamento de banner,
membros de ZIP e encoding. Ele sempre lê da fonte inss, claro: converter o
espelho de volta para ele mesmo publicaria cópia de cópia.
O layout do repositório (data/<família>/<AAAA-MM>.parquet, manifest.json)
está em src/brinss/datasets/_hf.py, importado tanto pelo script que escreve
quanto pelo código que lê. Quem escreve e quem lê não podem divergir sobre onde
um arquivo mora.
uv run --group publish python scripts/publish_to_hf.py # mostra o plano
uv run --group publish python scripts/publish_to_hf.py --push # publica
Dry run é o padrão. Sem --push o script apenas lista o que subiria e o que
seria pulado. Publicar exige um token de escrita, seja em HF_TOKEN seja
guardado em disco por hf auth login.
Cache local dos Parquet
Converter é a metade cara de uma execução: ler um XLSX de centenas de MB com o
openpyxl leva minutos. Os arquivos convertidos ficam em tmp/ (ignorada pelo
git), no mesmo layout do Hub, ao lado de um tmp/build-index.json que registra
de qual origem cada um saiu:
tmp/data/<família>/<AAAA-MM>.parquet
tmp/build-index.json
Uma execução interrompida retoma daí em vez de recomeçar. Um Parquet só é reaproveitado quando o índice confere em três pontos: SHA256 da origem, receita de conversão e tamanho em bytes. O tamanho é o que descarta um arquivo truncado por queda de energia, cujo registro no índice está íntegro mas cujo conteúdo não.
O índice não é o manifesto. O manifesto responde "isto está publicado no Hub"; o índice responde "isto já foi convertido aqui". Confundir os dois foi justamente o que estragou uma carga anterior.
⚠️ O cache cresce. São 291 arquivos numa carga completa, e as famílias
pesadas têm meses de vários GB. O resumo de cada execução mostra quanto tmp/
está ocupando e avisa acima de 5 GB. Para liberar espaço sem perder trabalho
útil, --prune-parquet apaga só os arquivos que o manifesto confirma publicados:
uv run --group publish python scripts/publish_to_hf.py --prune-parquet
Gerar amostras locais
--sample converte só o que já está no cache de downloads, gravando no
mesmo tmp/:
uv run --group publish python scripts/publish_to_hf.py --sample
Ele nunca baixa nada e nunca fala com o Hub — meses ausentes do cache são
reportados e pulados. É a forma barata de conferir o resultado real antes de
encarar uma publicação completa, que são 291 arquivos e dezenas de GB vindos
do portal. Como grava no mesmo cache, também serve para aquecer um --push
posterior: o que o --sample já converteu não é convertido de novo.
Use --parquet-dir para gravar em outro lugar (--sample-dir continua valendo
como apelido) e --force para reconverter o que já está em cache.
Log
Cada execução grava um log em logs/publish-AAAAMMDD-HHMMSS.log (também
ignorada pelo git), em nível DEBUG, com os downloads e leituras da biblioteca
misturados aos passos do script. O console fica em INFO; -v mostra o DEBUG
nele também, --no-log-file desliga o arquivo e --log-dir/--log-file
mudam o destino.
O log abre com o cabeçalho da execução (modo, repositório, famílias, períodos,
receita de conversão, tamanho do manifesto) e fecha com um bloco de resumo:
status explícito — CONCLUIDO COM SUCESSO, CONCLUIDO COM FALHAS ou
INTERROMPIDO —, contagens, bytes convertidos e reaproveitados, commits,
duração, em que mês parou e o erro de cada falha.
A linha iniciando <família>/<período> é gravada antes do trabalho, não
depois, e com fsync. É o que permite descobrir em que mês a máquina desligou:
o último mês concluído não interessa, o que estava em andamento sim.
Um mês que estoura (XLSX corrompido, por exemplo) é registrado e a execução
segue para o próximo, terminando com código de saída 1. Códigos: 0 sucesso,
1 falhas parciais, 2 erro de uso.
Flags úteis
--familia e --periodo (repetíveis) para restringir o escopo, --limite N
para uma primeira carga parcial, --force para reenviar mesmo sem mudança,
--create-repo para criar o repositório no Hub na primeira vez e
--commit-size para ajustar quantos arquivos entram em cada commit.
Layout publicado
data/<família>/<AAAA-MM>.parquet
manifest.json
README.md
Um arquivo por mês, por família — é o que torna o reenvio incremental possível:
se só um mês mudou na origem, só ele sobe. O README.md é gerado com um config
do viewer por família, mas só é escrito quando ainda não existe no Hub, para
não sobrescrever uma edição feita pela interface web. Para regerá-lo de
propósito, use --update-card.
Dados e manifesto no mesmo commit
Os arquivos sobem agrupados: um commit a cada --commit-size arquivos (padrão
25) ou a cada 2 GB, o que vier primeiro, e sempre fechando no fim de cada
família. Um commit por arquivo faria a primeira carga render umas 300 revisões
no Hub, arriscando o rate limit no meio do caminho.
O manifest.json viaja no mesmo commit dos arquivos que ele descreve. Ele
era enviado só no fim da execução, o que abria uma janela — de minutos, numa
carga completa — em que o Hub tinha arquivos que o manifesto desconhecia. Não é
hipotético: um desligamento abrupto da máquina dentro dessa janela deixou 25
meses publicados e não registrados, e toda execução seguinte os reconvertia e
reenviava como novo. Com os dois no mesmo commit esse estado é inalcançável.
Um manifesto ilegível é erro fatal, nunca um manifesto vazio: tratá-lo como
vazio reclassificaria os 291 meses como novo e reenviaria o dataset inteiro.
Reconciliar arquivos órfãos
Sempre que fala com o Hub, o script compara a listagem do repositório com o
manifesto e avisa sobre órfãos — Parquet publicados sem entrada no manifesto,
que seriam reenviados como novo para sempre. Com o commit atômico isso não
deve mais acontecer; quando acontecer, o log conta.
--reconciliar adota esses arquivos no manifesto sem reconverter nem reenviar:
uv run --group publish python scripts/publish_to_hf.py --reconciliar # lista
uv run --group publish python scripts/publish_to_hf.py --reconciliar --push # grava
O SHA da origem vem, nessa ordem, do registry.json do cache de downloads (que
guarda o hash mesmo depois do arquivo de origem ser apagado), do arquivo em
cache, ou de um download. A entrada nasce com rows: null e adopted: true — a
contagem de linhas exigiria reler a origem, que é exatamente o custo que a
reconciliação existe para evitar.
A ressalva: reconciliar assume que o Parquet publicado foi gerado da origem
que está no portal agora. Se o portal trocou o arquivo entre o envio e a
reconciliação, a entrada nasce errada e aquele mês nunca mais se atualiza
sozinho. O adopted: true marca esses casos para uma auditoria futura com
--force.
Como o script evita reenviar o que não mudou
O manifest.json guarda, para cada arquivo publicado, o SHA256 do arquivo de
origem de que ele foi gerado — o mesmo hash que a biblioteca já calcula para o
cache local. Um mês só é reconvertido quando esse hash muda (o portal troca o
conteúdo sem trocar o nome), quando a receita de conversão muda, ou com
--force.
O hash é o do arquivo de origem, e não o do Parquet, de propósito: Parquet não é byte-reproduzível entre versões do pyarrow, então comparar o resultado faria todo mês parecer alterado a cada execução.
Como o portal não publica checksum, saber se um mês mudou exige ter o arquivo
de origem em mãos. O manifesto poupa a parte cara — leitura, conversão e upload
—, não o download. Para não transformar um simples --push-less em dezenas de
GB de tráfego, o dry run não baixa nada: meses ainda ausentes do cache
aparecem como fonte ainda nao baixada.
Tipos no Parquet
As colunas saem como texto, pelo mesmo motivo descrito em
Tipos das colunas. A exceção é periodo_referencia, que
sai como string AAAA-MM em vez de pandas.Period: o Parquet guardaria o
Period como um tipo de extensão do pandas sobre o ordinal do mês (2024-06
vira 653), e todo leitor que não fosse pandas — o viewer do Hugging Face,
DuckDB, polars — mostraria um inteiro sem sentido.
Ao carregar pela fonte hf, a biblioteca descarta essa coluna de texto e insere
de volta o pandas.Period — as duas fontes devolvem a mesma coluna, do mesmo
tipo, na mesma posição. Quem lê o Parquet direto (DuckDB, polars, o viewer do
Hub) continua vendo a string legível.
To-do
- Adicionar tópicos ao repositório no GitHub, para facilitar descoberta.
- Adicionar mensagem quando o download do dataset for concluído
- Adicionar mensagem de início e conclusão do carregamento no dataframe
- Suportar as séries históricas mais antigas (2012–2023), publicadas em
arquivos ZIP com granularidade anual (ex:
beneficios-concedidos-dez-2012-a-nov-2018-...). - Suportar a segunda camada de pacotes legados (
inss-beneficios-*, até mai/2023), com mistura de formatos ZIP/CSV/JSON/XML e múltiplas categorias por mês (ex: ativos/suspensos/cessados em "mantidos"). - Implementar
brinss.ops: funções de transformação/análise sobre os datasets carregados (hoje é só um namespace reservado, vazio). - Rodar os testes de rede (
pytest -m network) periodicamente no CI, num workflow agendado que abra issue ao falhar. Eles ficam fora do CI comum de propósito — dependem do portal e do espelho estarem de pé, e um deles baixa dados de verdade —, mas isso significa que hoje nada avisa quando o INSS muda o layout de um arquivo ou quando as duas fontes deixam de concordar. - Automatizar a atualização do espelho no Hugging Face. Hoje
scripts/publish_to_hf.pyé rodado à mão, então um mês novo no portal só chega à fontehfquando alguém lembra de rodá-lo — é a causa do atraso descrito em Fonte dos dados. - Expor leitura em streaming na API pública.
open_resource_chunksjá existe e é o que permite ao script de publicação converter arquivos de dezenas de GB, mas quem chamaload_*ainda recebe o mês inteiro de uma vez —periodo="all"nas famílias pesadas continua limitado pela RAM. - Medir cobertura de testes:
pytest-covestá no grupodev, mas nenhum comando o usa e não há mínimo configurado. - Refinar
dtype="infer"na fontehf. A conversão pós-leitura só tenta número, então uma coluna que oread_csvinferiria como booleano ou data fica como texto. Não afeta os datasets publicados hoje, mas é uma diferença real entre as duas fontes. - Manter um CHANGELOG. As notas de release saem dos commits, o que serve para acompanhar o desenvolvimento, mas não conta o que muda para quem apenas usa a biblioteca.
Desenvolvimento
uv sync
uv run pytest # suíte completa (sem os testes que precisam de rede)
uv run pytest -m network # inclui os testes que baixam dados de verdade
uv run ruff check .
Os testes marcados com network são desmarcados por padrão (addopts no
pyproject.toml). São três: um download real de cada fonte e uma comparação do
mesmo mês pelas duas, conferindo que entregam DataFrames idênticos.
Publicar uma versão
A publicação é automatizada, mas o gatilho é sempre humano: uma tag vX.Y.Z
constrói e abre a release em rascunho; publicar esse rascunho é o que envia
o pacote ao PyPI.
# 1. bumpar a versão em pyproject.toml, commitar e enviar
git commit -am "Versao 0.2.0" && git push
# 2. taguear e enviar a tag
git tag v0.2.0 && git push origin v0.2.0
A tag dispara release.yml, que confere que a
tag bate com a versão do pyproject.toml, roda ruff e a suíte de testes,
constrói sdist e wheel, valida os metadados com twine check --strict e cria a
release em rascunho com os dois arquivos anexados.
3. Revise as notas geradas em
Releases e
clique em Publish release. Isso dispara
publish-pypi.yml, que baixa os arquivos
anexados à release — os mesmos, byte a byte — e os envia ao PyPI.
O rascunho existe por um motivo específico: o PyPI nunca aceita reenviar uma
versão já publicada. Se 0.2.0 subir quebrada, o conserto é queimar um
0.2.1. O passo manual é a última chance de olhar antes disso.
Autenticação
Por Trusted Publishing (OIDC): não há token guardado no repositório. O PyPI confia neste repositório, neste arquivo de workflow e neste environment, cadastrados em pypi.org/manage/account/publishing:
| Campo | Valor |
|---|---|
| PyPI Project Name | brinss-public-datasets |
| Owner | agaqueiroz |
| Repository name | brinss-public-datasets |
| Workflow name | publish-pypi.yml |
| Environment name | pypi |
Os quatro valores precisam bater exatamente — renomear
.github/workflows/publish-pypi.yml quebra a publicação até o cadastro ser
atualizado. Do lado do GitHub, existe um environment chamado pypi em
Settings → Environments; é onde se coloca uma aprovação manual extra, se
desejado.
Integração contínua
ci.yml roda a cada push no master e em todo pull
request: ruff e a suíte de testes em Linux e Windows, Python 3.12 e 3.13. O
Windows não está ali por simetria — a biblioteca sanitiza nomes de arquivo,
adivinha encoding e controla na mão o tempo de vida dos handles de ZIP.
Os testes de rede continuam fora, ali e no release (veja To-do).
Metadata
Release files for brinss-public-datasets 0.1.0rc1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| brinss_public_datasets-0.1.0rc1.tar.gz | 45.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| brinss_public_datasets-0.1.0rc1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 86.7 kB
Release files / brinss_public_datasets-0.1.0rc1.tar.gz
| Download URL | brinss_public_datasets-0.1.0rc1.tar.gz |
|---|---|
| Size | 45.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5269d4a5dc5d0509c4910a0793af3780f1f904db33121b90b7e57261cb9c14e8
|
|
BLAKE2b-256 checksum How to use checksums |
eac26e83e17ee5d4ea9dfd65e329c4afc8e2dd60238310d3090abb03802081ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / brinss_public_datasets-0.1.0rc1-py3-none-any.whl
| Download URL | brinss_public_datasets-0.1.0rc1-py3-none-any.whl |
|---|---|
| Size | 41.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1db5b49c5e4953b8f6530480d006dc4899fa36604b6ef3d3f0d47f75b41da2e5
|
|
BLAKE2b-256 checksum How to use checksums |
0c9bd7a1401abfdcf98265136c0ee2c4cf7210062cf3763c9eb5cc677a7c5072
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency log