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
Espelho 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")
Espelho em Parquet no Hugging Face
A fonte padrão da biblioteca é o espelho em huggingface.co/datasets/agaqueiroz/brinss-public-datasets, gerado por uma ferramenta à parte, no repositório br_public_datasets_publisher: ela lê os arquivos do portal através desta biblioteca — herdando de graça o tratamento de banner, membros de ZIP e encoding —, converte para Parquet e publica. Este repositório é só o lado que lê.
O layout do espelho está em src/brinss/datasets/_hf.py, importado tanto por quem
escreve quanto por quem lê. Quem escreve e quem lê não podem divergir sobre onde um
arquivo mora:
data/<família>/<AAAA-MM>.parquet
manifest.json
README.md
Um arquivo por mês, por família — é o que permite à biblioteca baixar só os meses
pedidos, e ao publicador reenviar só o que mudou. O manifest.json guarda, de cada
arquivo publicado, o SHA256 do arquivo de origem de que ele foi gerado.
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. - Expor leitura em streaming na API pública.
open_resource_chunksjá existe e é o que permite ao publicador 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.0rc2
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.0rc2.tar.gz | 32.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| brinss_public_datasets-0.1.0rc2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 70.8 kB
Release files / brinss_public_datasets-0.1.0rc2.tar.gz
| Download URL | brinss_public_datasets-0.1.0rc2.tar.gz |
|---|---|
| Size | 32.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e92ed496ddf341c2ae79282c9fcd57871f3b00f2045b1443f2fc422ff44afc3a
|
|
BLAKE2b-256 checksum How to use checksums |
1837a8dd9c719d1e39aa5e0daff8ce69df8534fc58b0fb164a2a0ef6224e4bd7
|
| 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 30, 2026.
Transparency logRelease files / brinss_public_datasets-0.1.0rc2-py3-none-any.whl
| Download URL | brinss_public_datasets-0.1.0rc2-py3-none-any.whl |
|---|---|
| Size | 38.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
085df12e7f18b8b7993f8e950d2fcf274eba7aebcda171849526749fad4339fa
|
|
BLAKE2b-256 checksum How to use checksums |
7cc6fcf3e6b2e8478ee95242cf9dc1babbc090bbbb2af4212732ea305542d2c4
|
| 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 30, 2026.
Transparency log