nini-datacomp
Compara duas tabelas grandes linha a linha, dentro de um orçamento de memória. Diz quais linhas existem só de um lado, quais divergem, em que colunas e com exemplos, num relatório em texto, Markdown, HTML ou JSON.
É a reescrita do datacompolars: o mesmo resultado (os testes conferem os casos de borda contra ele, amostra por amostra), com a comparação em kernels C++ que leem as colunas do Polars sem cópia.
- Memória sob controle: a comparação anda em janelas pela chave, do tamanho que cabe no
memory_limit("auto"= 1/4 da RAM livre, até 2 GB). Tabelas maiores que a memória são comparadas sem problema. - Rápida: 10 milhões de linhas x 300 colunas em 32 s com 1 GB, onde o datacompolars levava 50 s e usava quase 2 GB (números).
- Sem surpresas: igualdade exata pelo hash de linha (com
verify_hash=Truepara conferir célula a célula), tolerâncias absolutas e relativas com a aritmética do Polars, texto sem caixa e sem espaços, nulos e NaN como no datacompolars. - Lê o que você tem: Parquet, CSV, JSON, Arrow, Avro, Excel e os arquivos do SAS (.sas7bdat, .xpt), do Stata (.dta) e do SPSS (.sav, .zsav, .por), estes pelo ReadStat compilado na própria biblioteca: nenhum pacote a mais.
- Leve: só
polars,numpyepydantic; wheels prontos para Linux, Windows e macOS (x86-64 e ARM), sem compilador.
Instalação
pip install nini-datacomp
Python 3.10 ou mais novo e Polars 1.30 ou mais novo.
Uso
import nini_datacomp as dc # importe antes do Polars (veja Memória)
result = dc.compare(
"sas/tops_adm.parquet", # arquivo, pasta, glob, pl.DataFrame ou pl.LazyFrame
"lake/tops_adm/",
on=["id", "competencia"], # a chave: uma coluna ou várias
abs_tol={"valor": 0.005}, # tolerância numa coluna (ou um número para todas)
memory_limit="2GB",
)
result.is_match # False
result.rows.mismatched # linhas em comum com algum valor diferente
result.columns["valor"].mismatches # divergências nessa coluna
result.columns["valor"].samples # pl.DataFrame: id, competencia, valor (left), valor (right)
print(result.report()) # o relatório em texto
result.report(path="relatorio.html") # ou em HTML (o formato sai da extensão)
As opções vão como argumentos nomeados, como acima, ou num dc.CompareOptions(...) passado em options=.
Formatos
O formato sai da extensão; uma pasta vira uma fonte só (com as subpastas; arquivos que começam com . ou _ ficam
de fora). Tudo o que não é Parquet é convertido uma vez para Parquet numa pasta temporária, aos pedaços (cada um com
~1/16 do memory_limit), e a pasta some no fim da comparação.
| formato | extensões | como é lido |
|---|---|---|
| Parquet | .parquet, .pq |
direto |
| CSV | .csv, .tsv |
aos pedaços (pl.scan_csv); outra codificação é convertida para UTF-8 antes |
| NDJSON, Arrow IPC | .ndjson, .jsonl, .arrow, .ipc, .feather |
aos pedaços |
| JSON, Avro | .json, .avro |
inteiro na memória (o Polars só lê assim) |
| Excel | .xlsx, .xlsm, .xlsb, .xls, .ods |
inteiro; precisa do pacote fastexcel |
| SAS | .sas7bdat, .xpt |
aos pedaços, pelo ReadStat |
| Stata | .dta |
idem |
| SPSS | .sav, .zsav, .por |
idem |
read=dc.ReadOptions(...) muda a leitura, para os dois lados ou um par (esquerda, direita):
dc.compare(
"sas/tops_adm.sas7bdat",
"lake/tops_adm/",
on="id",
cast="right", # no SAS todo número é real (Float64); no lake o id costuma ser inteiro
read=(dc.ReadOptions(encoding="wlatin1"), dc.ReadOptions()),
)
| opção | padrão | o que faz |
|---|---|---|
format |
pela extensão | força o formato ("csv", "sas", ...) |
encoding |
do arquivo | CSV: a codificação ("latin1", "cp1252"); SAS/Stata/SPSS: no lugar da que o arquivo declara (o .xpt não declara); aceita os nomes do SAS ("wlatin1") |
blank_strings_as_null |
True |
SAS/Stata/SPSS: texto vazio vira nulo, que é como o SAS grava texto ausente |
convert_dates |
True |
SAS/Stata/SPSS: colunas com formato de data, data e hora ou hora (DATE9., DATETIME20., %td, ADATE10...) viram Date, Datetime("us") e Time |
separator, has_header, decimal_comma, null_values |
CSV padrão | CSV (.tsv usa tabulação) |
infer_schema_length, schema_overrides |
10.000 linhas | CSV/JSON/Excel: como deduzir os tipos, ou os tipos de algumas colunas |
sheet |
a primeira | Excel: nome ou número da planilha |
csv_options |
{} |
CSV: outros argumentos de pl.scan_csv |
recursive |
True |
pasta: procura também nas subpastas |
temp_dir |
o do sistema | onde fica o Parquet temporário |
Para ler fora da comparação: dc.read_sas, dc.read_stata e dc.read_spss devolvem um pl.DataFrame;
dc.scan_sas, dc.scan_stata e dc.scan_spss, um pl.LazyFrame lido aos pedaços quando a consulta roda (cada
collect lê o arquivo de novo).
O resultado
| atributo | o que traz |
|---|---|
is_match |
os dois lados são iguais: mesmas linhas, mesmos valores, mesmas colunas e tipos |
rows |
left_total, right_total, common, left_only, right_only, mismatched, matched, mismatch_rate |
columns |
mapeamento por nome das colunas comparadas (dtype, mismatches, rate, samples, tolerance), mais left_only, right_only, type_mismatches e mismatched() (da que mais diverge para a que menos) |
errors, aborted |
erros fatais (chave que falta, chave de tipos diferentes, chave repetida): ficam aqui, sem exceção |
warnings |
avisos (nenhuma coluna além da chave, tolerância para uma coluna que não existe) |
execution |
janelas, grupos de colunas, memória, tempo por etapa, versões |
report(...), to_dict(), to_json() |
o relatório e a forma serializável |
O relatório
result.report(format=None, path=None, *, width=100, style="auto", max_columns=20, max_sample_columns=10, print_output=False), nos formatos "text", "markdown", "html" e "json". Sem format, o formato sai da
extensão de path (.md, .html, .json, .txt); com path, o relatório também é salvo. Texto e Markdown
mostram até max_columns colunas com divergência; HTML e JSON trazem tudo.
┌──────────────────────────────────────────────────────────────────────────────┐
│ ✘ DIFFERENCES FOUND │
│ 2 of 3 common rows differ (66.67%); 1 rows only in sas; 1 rows only in lake. │
└──────────────────────────────────────────────────────────────────────────────┘
DIFFERENCES BY COLUMN
─────────────────────
┌────────┬─────────┬─────────────┬─────────────┬──────────────┐
│ Column │ Type │ Differences │ % of common │ │
├────────┼─────────┼─────────────┼─────────────┼──────────────┤
│ valor │ Float64 │ 2 │ 66.67% │ ████████░░░░ │
└────────┴─────────┴─────────────┴─────────────┴──────────────┘
SAMPLE DIFFERING ROWS
─────────────────────
valor: 2 differing rows, showing 2
┌────┬─────────────┬─────────────┬──────────────┐
│ id │ competencia │ valor (sas) │ valor (lake) │
├────┼─────────────┼─────────────┼──────────────┤
│ 2 │ 2026-01 │ 10 │ 10.5 │
│ 3 │ 2026-01 │ 7.25 │ null │
└────┴─────────────┴─────────────┴──────────────┘
Opções
| opção | padrão | o que faz |
|---|---|---|
names |
("left", "right") |
os rótulos dos dois lados nas amostras e no relatório |
case_sensitive_columns |
False |
False: os nomes das colunas são comparados em minúsculas |
cast |
"none" |
colunas de tipos diferentes: "left" converte a direita, "right" a esquerda, "none" só as lista |
abs_tol, rel_tol |
0.0 |
tolerâncias nas colunas numéricas (um número ou um por coluna): igual se |l - r| <= abs_tol + rel_tol * |r| |
ignore_whitespace, ignore_case |
False |
texto comparado sem espaços em branco e/ou em minúsculas |
details |
True |
divergências por coluna e amostras (False: só as contagens de linhas) |
samples |
5 |
linhas divergentes guardadas por coluna, na ordem da chave |
memory_limit |
"auto" |
orçamento de memória: bytes ou texto ("512MB", "2GB", "1.5GiB") |
window_rows |
None |
avançado: linhas por janela, no lugar do cálculo pelo memory_limit |
threads |
None |
threads dos kernels C++ (padrão: todos os núcleos) |
verify_hash |
False |
confere as colunas exatas célula a célula em todos os pares, além do hash |
Uma opção com nome errado é erro (extra="forbid"), em vez de ser ignorada.
Tipos
Inteiros, reais, booleano, texto (String, e Categorical e Enum comparados como texto), Date, Datetime, Duration,
Time e Decimal. List e Struct ainda não: uma coluna de tipo não suportado levanta UnsupportedTypeError.
Desempenho
O caminho exato (hash de linha) contra o datacompolars 0.4.4, com memory_limit="1GB" (954 MiB), num Windows 11 com
16 threads e 15,7 GB. Média de 5 execuções, cada uma num processo novo; a razão vem com o IC de 95%, e um caso é ok
se o intervalo inteiro fica em até 1,10. As contagens (linhas e divergências por coluna) conferem em todos.
| linhas x colunas | nini-datacomp | pico | datacompolars | pico | razão (IC 95%) |
|---|---|---|---|---|---|
| 1M x 10 | 0,11 s | 406 MiB | 0,22 s | 698 MiB | 0,51 (0,46–0,56) |
| 1M x 50 | 0,37 s | 682 MiB | 0,43 s | 1070 MiB | 0,85 (0,82–0,89) |
| 1M x 300 | 3,20 s | 561 MiB | 3,35 s | 1709 MiB | 0,95 (0,85–1,06) |
| 10M x 10 | 0,76 s | 734 MiB | 1,16 s | 1631 MiB | 0,66 (0,63–0,68) |
| 10M x 50 | 4,77 s | 633 MiB | 4,26 s | 1679 MiB | 1,12 (0,98–1,26), inconclusivo |
| 10M x 300 | 31,9 s | 674 MiB | 50,0 s | 1929 MiB | 0,64 (0,62–0,65) |
O nini-datacomp fica dentro do memory_limit em todos os casos; o datacompolars não tem orçamento e usa até o dobro.
Os detalhes, com o caminho coluna a coluna (com tolerância), estão em
docs/benchmarks/.
Memória
Importe o nini_datacomp antes do Polars. No import, ele configura o alocador do Polars (MIMALLOC_PURGE_DELAY=10
e MIMALLOC_RESET_DELAY=10) para devolver em 10 ms a memória que libera: sem isso, numa comparação grande no Windows
o pico chega a ~1,9x; devolvendo na hora, cada janela pede de novo ao sistema a memória da anterior (até ~30% mais
lento). Se o Polars já tiver sido importado, não dá mais para configurar e o pacote avisa com AllocatorWarning; dá
para definir as variáveis antes de iniciar o Python, ou silenciar com NINI_DATACOMP_ALLOCATOR=0.
Vindo do datacompolars
Mesma semântica; mudam os nomes, e o que era ajuste interno do motor vira um orçamento de memória.
| datacompolars 0.4.4 | nini-datacomp | observação |
|---|---|---|
compare(left, right, settings) |
compare(left, right, on=..., options=...) |
on sai das opções; opções também como argumentos nomeados |
CompareSettings |
CompareOptions |
pydantic, extra="forbid" (nome errado é erro) |
join_columns |
on |
uma coluna (texto) ou várias |
left_name, right_name |
names=("left", "right") |
|
lowercase_columns=True |
case_sensitive_columns=False |
mesmo padrão, nome positivo |
casting |
cast |
"none", "left" ou "right" |
abs_tol, rel_tol |
abs_tol, rel_tol |
número ou um por coluna (dict) |
ignore_spaces, ignore_case |
ignore_whitespace, ignore_case |
|
check_duplicate_keys |
— | chave repetida sempre aborta (a checagem não custa nada) |
column_details, sample_count |
details, samples |
|
window_rows, cache_windows, prefetch_windows, columns_per_batch |
memory_limit="auto" (+ window_rows) |
o motor escolhe janelas e grupos de colunas pelo orçamento; "auto" = 1/4 da RAM livre, até 2 GB |
| — | threads, verify_hash |
threads dos kernels C++; conferir o hash de linha célula a célula |
common_keys_only |
— | fase 6 |
custom_comparators |
— | fase 6 |
SourceOptions |
read=ReadOptions(...) |
também um por lado; o SAS sem o extra [sas] (o ReadStat vem compilado) |
result.fatal_errors |
result.errors |
|
result.column_stats |
result.columns.mismatched() |
mesma ordem: da coluna que mais diverge para a que menos |
result.samples (lista de SampleTable) |
result.columns["c"].samples |
pl.DataFrame, mesmos cabeçalhos |
result.columns.compared |
result.columns.compared |
result.columns também é um mapeamento por nome |
result.report(ReportSettings(...)) |
result.report(format=None, path=None, width=100, ...) |
os mesmos 4 formatos; não imprime sozinho (print_output=True imprime) |
result.to_json(), model_dump() |
result.to_json(), result.to_dict() |
o resultado é uma dataclass, não pydantic |
Desenvolvimento
Precisa de Python ≥ 3.10, uv, CMake ≥ 3.20 e um compilador C++17 (no Windows, o Visual Studio com as ferramentas de C++; os wheels publicados usam o clang-cl).
uv sync # compila o C++ e instala o pacote no ambiente
uv run python tools/check.py # formata, lint, tipos e testes, parando no primeiro que falhar
uv run python tools/check.py --then bench_hash # ... e, se tudo passar, um benchmark
uv run python tools/gen_bindings.py # depois de mudar a assinatura de uma função C++
Ferramentas (tools/):
| comando | o que faz |
|---|---|
uv run python tools/make_data.py --rows 1000000 --cols 50 |
gera um par de tabelas com o resultado esperado (data/bench/) |
uv run python tools/make_golden.py |
regrava os gabaritos dos casos de borda (tests/golden/) com o datacompolars 0.4.4 |
uv run python tools/bench_baseline.py |
mede a linha de base (datacompolars 0.4.4) e escreve docs/benchmarks/baseline.md |
uv run python tools/bench_hash.py |
mede o nini-datacomp nos mesmos casos (--mode columnwise para o caminho com tolerância) e escreve docs/benchmarks/fase2.md / fase3.md |
uv run python tools/diag_profile.py --case 1000000x50 |
onde vai o tempo de uma comparação (cProfile e o planejamento por partes) |
No Windows, para compilar como os wheels: $env:DC_CLANGCL = "1" antes do uv sync (precisa dos componentes
"C++ Clang Compiler for Windows" e "MSBuild support for LLVM (clang-cl) toolset" no Visual Studio Installer).
| variável | efeito |
|---|---|
NINI_DATACOMP_LIB |
caminho de uma biblioteca compilada à mão (ex. com sanitizers) |
NINI_DATACOMP_THREADS |
número de threads (padrão: todas as CPUs disponíveis) |
NINI_DATACOMP_POOL=0 |
desliga o pool de memória do C++ (só para comparar) |
Licença
Metadata
Release files for nini-datacomp 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_datacomp-0.2.0.tar.gz | 425.9 kB | With provenance | Details for nini_datacomp-0.2.0.tar.gz |
Built distributions (wheels)
Total release size: 4.5 MB
Release files / nini_datacomp-0.2.0.tar.gz
| Download URL | nini_datacomp-0.2.0.tar.gz |
|---|---|
| Size | 425.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ff71455bd99ee80537cdd57d2723dab5bcfe65d5d83e938726cfd4e93e0e4284
|
|
BLAKE2b-256 checksum How to use checksums |
18b6778b7a7b0d353e200fbf9d883a18923322f46ade6fa3acabf894b01e0d60
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-win_arm64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-win_arm64.whl |
|---|---|
| Size | 314.1 kB |
| Tags | Python 3 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
2b907ff1d852ea3ce9e3ff5a6a9e557573f5994b4a10974e060d7b3d2765207e
|
|
BLAKE2b-256 checksum How to use checksums |
10928a8d4d503c720da5d11b75c8621caf4778206a8900afee5c90fe3ac6753b
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-win_amd64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-win_amd64.whl |
|---|---|
| Size | 349.5 kB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
066ac661dc260f2025729bfecb9c399a433439295d5a00bd8802ba2f6feec8d2
|
|
BLAKE2b-256 checksum How to use checksums |
900155fc269f17db29fdcf1b21426f10cd946b804e56a75315eb6edf64ba8a0a
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-musllinux_1_2_x86_64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.3 MB |
| Tags | Linux musl 1.2+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
c77c82c50f98cc4f401f76ced00183c021647ff03e5652fcc001fbfb853fcfa9
|
|
BLAKE2b-256 checksum How to use checksums |
19c23561da1a7739e0411aa05405dcff4c50efe36eacbe35ce6adad63a7ade1c
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-musllinux_1_2_aarch64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Linux musl 1.2+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
3209842e6d62cb24d201c37d4f7bbb4d2bf077b12b7672ee03ed3db0f0a2358f
|
|
BLAKE2b-256 checksum How to use checksums |
b7e70768ccab1abbf2c8b080c2debc4b2c65930281d57d2427dab781a5e4e852
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 248.7 kB |
| Tags | Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
c0d34cc957596d625a2c91eb01044c69a8fc188e41b705f5e8b37beb68c8ae7b
|
|
BLAKE2b-256 checksum How to use checksums |
1eb2e3d9f439b43f4d6c12045e888833bb3db0d1a80899104058fd39a3b41817
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 236.6 kB |
| Tags | Linux glibc 2.24+ ARM64 Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
3fe7078f73ca06a5dde574668647ee8628b8400918ac0ce0f583cf64a61008e0
|
|
BLAKE2b-256 checksum How to use checksums |
eadc459b070e93a782693420673186af6172a69ad87e43c92e26ae84dd446ae0
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-macosx_11_0_x86_64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-macosx_11_0_x86_64.whl |
|---|---|
| Size | 225.4 kB |
| Tags | Python 3 macOS 11.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
674d4727366ee968d1ad27dcb6450c0f965c0370981c7903f24da7d7f40e8dea
|
|
BLAKE2b-256 checksum How to use checksums |
6ebf3697cc778fb43e7ba4511bb3bd44016605835472c85ce6bb5a38836204a8
|
| 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 3, 2026.
Transparency logRelease files / nini_datacomp-0.2.0-py3-none-macosx_11_0_arm64.whl
| Download URL | nini_datacomp-0.2.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 213.7 kB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
21d3d88ca451929e5400b162020522b7a78e39c849fcf362054207271218a93a
|
|
BLAKE2b-256 checksum How to use checksums |
b249b6d651efa01364652e6f78b911749b408be2cafb856ac9a44ee3183553a6
|
| 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 3, 2026.
Transparency logSecurity for nini-datacomp 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 9 files in this release have been uploaded with provenance metadata.
Attestation for nini_datacomp-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 3, 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.