nini-datagen
Dados sintéticos realistas do Brasil, em escala: CPF, CNPJ (inclusive alfanumérico), nomes com a distribuição real do
IBGE, endereços do CNEFE, telefones, e-mails, textos e mais. Os geradores são kernels C++ que escrevem direto na
memória do Polars (Arrow string_view), sem passar string por string pelo Python.
Guia completo em docs/guia.md, números em docs/desempenho.md, exemplos em examples/ e mudanças no CHANGELOG.
Uso
import nini_datagen as dg
dg.first_name(5, seed=42) # pl.Series String com nomes na frequência do Censo
dg.integer(1_000_000, low=1, high=6) # sem seed: semente nova a cada chamada
g = dg.DataGen(seed=42) # semente, locale e threads fixos
sexo = g.sex(1_000_000) # "F"/"M", 51,5% de mulheres
nome = g.first_name(1_000_000, sex=sexo) # nomes coerentes com o sexo de cada linha
idade = g.age(1_000_000) # pirâmide etária aproximada do Brasil
plano = g.choice(1_000_000, ["bronze", "prata", "ouro"], weights=[6, 3, 1], null_fraction=0.05)
Toda configuração é um modelo Pydantic imutável. Dá para passar o objeto, um dict ou kwargs; nome de parâmetro
errado ou valor inválido vira ValidationError:
cfg = dg.IntegerConfig(low=18, high=90, null_fraction=0.1)
g.integer(1000, cfg)
g.integer(1000, cfg, high=65) # kwargs sobrescrevem campos
g.integer(1000, hihg=65) # ValidationError: Extra inputs are not permitted
| gerador | configuração | tipo |
|---|---|---|
integer |
IntegerConfig(low, high, dtype) |
Int32 / Int64 |
uniform |
UniformConfig(low, high, dtype) |
Float64 / Float32 |
normal, lognormal |
NormalConfig(mean, std), LognormalConfig(mean, sigma) |
Float64 |
boolean |
BooleanConfig(p) |
Boolean |
date, datetime |
DateConfig(start, end), DatetimeConfig(start, end, unit) |
Date / Datetime |
choice |
ChoiceConfig(values, weights) |
String, Int64, Float64 ou Boolean |
sex |
SexConfig(p_female, labels) |
String |
age |
AgeConfig(low, high, weights) |
Int32 |
first_name, last_name |
FirstNameConfig(sex), LastNameConfig() |
String |
full_name |
FullNameConfig(sex, compound, two_surnames) |
String |
cpf |
CPFConfig(formatted, unique) |
String |
cnpj |
CNPJConfig(alphanumeric, branch, formatted, unique) |
String |
pis, voter_id, rg |
PISConfig(formatted), VoterIDConfig(formatted), RGConfig(formatted) |
String |
cnh, iban, ean13 |
CNHConfig(), IBANConfig(), EAN13Config() |
String |
license_plate |
LicensePlateConfig(style) ("mercosul" ou "old") |
String |
credit_card |
CreditCardConfig(brand, formatted) |
String |
uuid, ipv6, mac, url |
UUIDConfig(), IPv6Config(), MACConfig(), URLConfig() |
String |
ipv4 |
IPv4Config(private) |
String |
phone |
PhoneConfig(style, mobile, uf) |
String |
email, username |
EmailConfig(domains, domain_weights, style_weights), UsernameConfig(style_weights) |
String |
company, occupation |
CompanyConfig(), OccupationConfig(zipf) |
String |
vehicle |
VehicleConfig(year_low, year_high) |
Struct {brand, model, year} |
cep |
CepConfig(formatted, uf, source) |
String |
address |
AddressConfig(uf, complement, phone, coords, full, source) |
Struct {street, number, complement, neighborhood, city, state, cep, ...} |
city, state |
CityConfig(uf, with_state), StateConfig(weighted) |
String |
sentence, paragraph |
SentenceConfig(theme, templates, slots), ParagraphConfig(..., sentences) |
String |
birthdate |
BirthdateConfig(on) + coluna age |
Date |
correlated |
CorrelatedConfig(rho, mean, std, lognormal, center, scale) + coluna other |
Float64 |
choice_by |
ChoiceByConfig(options, default) + coluna by |
String |
Todos aceitam name (nome da coluna) e null_fraction (fração de nulos).
Os documentos saem com dígitos verificadores corretos (não são documentos reais de ninguém), e dg.validators confere
textos de qualquer origem:
g.cpf(1_000_000, unique=True) # sem repetição (até 10^9)
g.cnpj(10, alphanumeric=True, formatted=True) # "HI.EJT.HBE/0001-69", o formato novo da Receita
dg.validators.cpf("529.982.247-25") # True
Frases saem de uma gramática com concordância (temas atendimento, saude, entrega, avaliacao, cadastro ou
geral), ou de modelos próprios:
g.sentence(3, theme="saude") # "Reembolso de R$ 964,22 liberado para pagamento."
g.paragraph(3, sentences=(2, 4))
g.sentence(3, templates=["Pedido {cod} enviado {prazo}.", ("Sem observações.", 3)], slots={"cod": ["{d}{d}{d}"]})
g.vehicle(5).struct.unnest() # colunas brand, model, year
Endereços são reais, do CNEFE do IBGE (Censo 2022): rua, bairro, cidade, UF e CEP existem juntos, sorteados pelo número de endereços. O pacote traz uma base leve (1% dos endereços de cada município, todos os 5.570 municípios); a completa (~55 MB, com a faixa real de números de cada rua) é baixada uma vez e fica em cache:
g.address(5, full=True).struct.unnest() # street, number, complement, neighborhood, city, state, cep, full
g.cep(5, uf="SP")
dg.datasets.download("cnefe") # depois disso, source="auto" usa a base completa
Tabelas e LazyFrame
Um Schema descreve a tabela: cada coluna é um gerador com parâmetros, uma referência a outra coluna (dg.ref) para
os geradores que dependem de dados, ou uma expressão do Polars. Ele é validado e compilado uma vez:
import polars as pl
schema = dg.Schema(
{
"id": ("cpf", {"unique": True, "formatted": True}),
"sexo": "sex",
"nome": ("full_name", {"sex": dg.ref("sexo")}), # nome coerente com o sexo da linha
"idade": ("age", {"low": 18, "high": 90}),
"nascimento": ("birthdate", {"age": dg.ref("idade"), "on": "2026-01-01"}),
"renda": ("correlated", {"other": dg.ref("idade"), "rho": 0.4, "mean": 8, "std": 0.6, "lognormal": True}),
"area": (
"choice_by",
{"by": dg.ref("sexo"), "options": {"F": ["Saúde", "Educação"], "M": ["Engenharia", "Comércio"]}},
),
"cliente": dg.CPFConfig(formatted=True), # também vale o objeto de configuração
"meses": pl.col("idade") * 12,
}
)
df = g.table(1_000_000, schema) # pl.DataFrame
lf = g.scan(10**9, schema) # pl.LazyFrame: nada é gerado até o collect
lf.filter(pl.col("idade") >= 60).select("nome", "renda").head(10).collect() # gera só o necessário
table preenche as colunas bloco a bloco (65.536 linhas), todas as colunas de um bloco de uma vez, com os blocos em
paralelo: até colunas baratas, como inteiros e booleanos, entram no paralelismo. scan registra o schema como fonte
do Polars: ele recebe as colunas pedidas, o filtro e o limite, e gera em lotes só o que foi pedido. Cada coluna sai igual
a g.generate(tipo, n, name=coluna, ...), e scan(n, schema).collect() é igual a table(n, schema). No scan, as
expressões são avaliadas lote a lote: use expressões linha a linha (sem mean(), rank() etc.).
Dados sujos, duplicatas e arquivos grandes
schema = dg.Schema(
{
"cpf": ("cpf", {"formatted": True, "dirty": {"unmask": 0.3, "whitespace": 0.02}}),
"nome": ("full_name", {"dirty": {"typo": 0.02, "case": 0.01, "accents": 0.05}}),
"valor": ("lognormal", {"mean": 5, "sigma": 1, "dirty": {"outliers": 0.001, "sentinel": [(-1, 0.01)]}}),
"uf": "state",
}
)
df = g.table(100_000, schema)
com_dups = g.add_duplicates(df, 0.05, dirty={"nome": {"typo": 0.5}}) # row_id e dup_of são o gabarito
g.write_parquet_dataset("saida/", 50_000_000, schema, partition_by="uf", rows_per_file=1_000_000)
Os defeitos seguem as mesmas regras de reprodutibilidade dos dados: cada um tem seu fluxo, e a coluna suja sai igual
em table, scan e write_parquet_dataset. Os arquivos gravados juntos são exatamente table(n, schema), para
qualquer batch_rows.
Desempenho
Os geradores são kernels C++ que escrevem direto na memória do Polars, em blocos de 65.536 linhas, em paralelo. Na máquina de desenvolvimento (Windows, 16 threads), com 1 thread: CPF ~10 ns/linha, nome ~5, e-mail ~30, frase ~60, endereço completo do CNEFE ~100; a tabela de 20 colunas do benchmark sai a ~300 ns/linha com 1 thread e ~110 com 16 (1 milhão de linhas em ~0,1 s). Detalhes, método e comparação com Faker, Mimesis e dataforge em docs/desempenho.md.
Reprodutibilidade
A partir da 0.2.0, a mesma seed dá sempre a mesma saída, em qualquer sistema e com qualquer número de threads, e
n=1_000 dá exatamente as primeiras linhas de n=1_000_000. Cada coluna tem seu próprio fluxo de números aleatórios,
identificado pelo nome (name, que por padrão é o tipo do gerador): colunas com nomes diferentes não saem
correlacionadas, e a mesma coluna sai sempre igual (g.integer(10) duas vezes dá o mesmo resultado). Os nulos têm
fluxo próprio: mudar null_fraction não muda os valores das linhas que continuam preenchidas.
Instalação
pip install nini-datagen # ou: uv add nini-datagen
Os wheels já trazem a biblioteca C++ compilada (Linux, Windows e macOS; x86-64 e ARM64) e funcionam com qualquer Python ≥ 3.11.
Desenvolvimento
Precisa de uv e de um compilador C++17 (GCC, Clang ou MSVC). CMake e Ninja vêm sozinhos pelo scikit-build-core.
uv sync # cria o ambiente e compila o C++
uv run pytest # testes
uv run pytest -m bench -s # benchmarks contra o MVP (fora da suíte padrão)
uv run python tools/bench.py # tabela completa de ns/linha
uv run python tools/samples.py # amostras de cada gerador
uv run python tools/profile_table.py # onde vai o tempo da tabela e dos endereços
uv run --isolated --python 3.14 --group bench python tools/compare.py # contra Faker, Mimesis e dataforge
uv run ruff check . && uv run pyright # qualidade
uv run python tools/gen_bindings.py # depois de mudar a assinatura de uma função DG_EXPORT
uv sync / uv run recompilam sozinhos quando um arquivo de cpp/ muda (ou as variáveis abaixo).
DG_CLANGCL=1(Windows): compila com clang-cl em vez do MSVC, como os wheels publicados; bem mais rápido nos kernels. Precisa dos componentes "C++ Clang Compiler for Windows" e "MSBuild support for LLVM (clang-cl) toolset" do Visual Studio Installer.DG_NATIVE=ON: compila para as instruções da sua CPU (-march=native), só para medir; os wheels usam x86-64-v2. O resultado não muda: o código não depende de FMA nem da biblioteca matemática do sistema.
Estrutura
cpp/ kernels C++ (ABI em C, prefixo dg_), um arquivo por domínio
src/nini_datagen/
__init__.py, api.py funções soltas (dg.integer, dg.table...) e exportações
generator.py DataGen: semente, locale e threads; um método por gerador
registry.py registro dos geradores por nome e montagem das configurações
config/ modelos Pydantic (um por gerador, mais DirtyConfig)
providers/ um gerador por tipo: plan() aloca, Job.fill() preenche cada bloco, Job.finish() entrega
schema/ Schema (colunas, ref, expressões, níveis), table e scan (fonte do Polars)
transforms/ dados sujos e duplicatas
io/ write_parquet_dataset
datasets/ download com cache (CNEFE completo)
locales/pt_BR/ dados e regras do Brasil (data/)
core/ sementes e fluxos, blocos e threads, views do Arrow, tabelas alias e vocabulários
_native.py carrega a biblioteca C++ e confere a versão da ABI
tests/ pytest; tests/golden/ guarda os gabaritos da v0.2.0
tools/ bindings, benchmarks, diagnóstico, comparação, amostras, base do CNEFE
docs/, examples/ guia, desempenho e exemplos
Gerador novo: uma configuração em config/, um provider com @registry.register em providers/ e um atalho em
generator.py/api.py; o resto (blocos, threads, nulos, semente) vem do roteiro comum em providers/base.py.
Licença
Código: MIT (LICENSE). Dados: fontes abertas do IBGE e do TSE, com créditos em DATA_LICENSES.md.
Metadata
Release files for nini-datagen 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nini_datagen-0.2.0.tar.gz | 74.9 MB | With provenance | Details for nini_datagen-0.2.0.tar.gz |
Built distributions (wheels)
Total release size: 81.3 MB
Release files / nini_datagen-0.2.0.tar.gz
| Download URL | nini_datagen-0.2.0.tar.gz |
|---|---|
| Size | 74.9 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c06f4499d34e8a1d5fb60f5712f86f890c01dbd218b34e8a2e01e8109f2aa4d5
|
|
BLAKE2b-256 checksum How to use checksums |
9d27f24c8367b6982284db7cab21251a478cad3b17b8ba84d0ce091afdfafb3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logRelease files / nini_datagen-0.2.0-py3-none-win_amd64.whl
| Download URL | nini_datagen-0.2.0-py3-none-win_amd64.whl |
|---|---|
| Size | 650.0 kB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
e2c479e931f3f88303cd925e2fc030cfa2f7872a35f4d4252353db0f82939dc8
|
|
BLAKE2b-256 checksum How to use checksums |
81cd6c754b665d85a770f9c897bd1fe831a72486489733b5a8741671dec63384
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logRelease files / nini_datagen-0.2.0-py3-none-musllinux_1_2_x86_64.whl
| Download URL | nini_datagen-0.2.0-py3-none-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | Linux musl 1.2+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
da7f14b5e67ac15eea0c05691d029f1c3ff4dfa782b92689901b23a76406181a
|
|
BLAKE2b-256 checksum How to use checksums |
57a92a25a54c01aeb8bd5d6ef2c952c35f5fffbbdcc4a1f4d1a238065e019b31
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logRelease files / nini_datagen-0.2.0-py3-none-musllinux_1_2_aarch64.whl
| Download URL | nini_datagen-0.2.0-py3-none-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | Linux musl 1.2+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
fa75565d11699854689bdd76bad2795c144594f4804c7a73a883eea1bbcd67f5
|
|
BLAKE2b-256 checksum How to use checksums |
147ee9bd378eb624e4ae9533bc072eeaeda01e7c1cad4462fa7df8e5fbc5bf17
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logRelease files / nini_datagen-0.2.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nini_datagen-0.2.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 613.6 kB |
| Tags | Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
48102c880c37c8c91488ac976b432b5efe912ff99b73437d91b6200901be5ba3
|
|
BLAKE2b-256 checksum How to use checksums |
409151e41c07fd1425485495d766584565a1191cbe200ab8ca443a9cc180b144
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logRelease files / nini_datagen-0.2.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nini_datagen-0.2.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 615.7 kB |
| Tags | Linux glibc 2.24+ ARM64 Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
8ea0397bca30b90f5355d1cc1fdeec3565d12674d6b1cbe0d4863f853266cff0
|
|
BLAKE2b-256 checksum How to use checksums |
6e36b054e0c2d0d7f719a7aa6f5ef5c53a96e4879c9c51cc535ac901b04b4d01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logRelease files / nini_datagen-0.2.0-py3-none-macosx_11_0_x86_64.whl
| Download URL | nini_datagen-0.2.0-py3-none-macosx_11_0_x86_64.whl |
|---|---|
| Size | 596.7 kB |
| Tags | Python 3 macOS 11.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
e7ea37166a4dae4ab53917641af514ef57311fa2ee3338e9bf579cba72832d4a
|
|
BLAKE2b-256 checksum How to use checksums |
928ec5124571873456cae5238c8569efbb4f570d372ecd587240a65a75dce43a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logRelease files / nini_datagen-0.2.0-py3-none-macosx_11_0_arm64.whl
| Download URL | nini_datagen-0.2.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 596.3 kB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
9bd5133b6d4a7299f4dfb2d5a2501c8b8653414cc41116da636bc417053985f8
|
|
BLAKE2b-256 checksum How to use checksums |
5cd61077296efa25fd4253d21c0ca635669440c2800e0fb751ce257583cccc5f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 1, 2026.
Transparency logSecurity for nini-datagen 0.2.0
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.
Full provenance
All 8 files in this release have been uploaded with provenance metadata.
Attestation for nini_datagen-0.2.0.tar.gz
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 Nov 1, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.