Skip to main content

FakeNumDetect

FakeNumDetect é uma biblioteca Python, em desenvolvimento, para apontar indícios de dados numéricos fabricados ou manipulados, combinando testes estatísticos de forense numérica e modelos de Machine Learning.

Projeto de Trabalho de Conclusão de Curso (TCC2, SENAC). O TCC1 definiu a proposta e a fundamentação; o TCC2 é a etapa de implementação e validação experimental.

Importante: um resultado "suspeito" da FakeNumDetect é um indício estatístico que merece investigação, e não uma prova de fraude ou fabricação.

Status do projeto

Em desenvolvimento. o que ja tem hoje:

Parte Situação
Testes estatísticos: Benford (1º e 2º dígito), GRIM, SPRITE, entropia de Shannon, terminação de dígitos ✅ implementados e testados
Machine Learning: Isolation Forest e Sparse Autoencoder ✅ implementados, calibrados e avaliados em 4 datasets reais
Score de suspeição unificado por registro (0 a 100, pesos calibrados por regressão logística L2) ✅ implementado (combina Isolation Forest, Sparse Autoencoder e Benford)
Análise por coluna com correção de múltiplas comparações (Bonferroni e Benjamini-Hochberg) ✅ implementada
Consistência do arredondamento entre colunas comparáveis (comparar_arredondamento) ✅ implementada; indica que colunas não combinam, mas não qual delas é a fabricada
Avaliação: métricas, validação cruzada, Wilcoxon, bootstrap, Friedman ✅ implementada
Relatório em HTML com gráficos (registros e colunas) ✅ implementado; o PDF é gerado pelo "Imprimir > Salvar como PDF" do navegador
API única no estilo scikit-learn (fit/detect/report, classe FakeNumDetect) ✅ implementada; encadeia os módulos no mesmo caminho da validação cruzada
Empacotamento e integração contínua (pyproject.toml, GitHub Actions em Python 3.10 e 3.13, cobertura mínima de 90%) ✅ configurados; pacote validado com twine check e testado instalado fora do repositório
Publicação no PyPI ⏳ pacote pronto; falta o envio pela conta da autora

Como a biblioteca analisa os dados

A FakeNumDetect trabalha em dois níveis:

  1. Por registro (linha): o score de suspeição unificado combina Isolation Forest, Sparse Autoencoder e um score de Benford por registro. Responde quais linhas são suspeitas.
  2. Por coluna: Benford e terminação de dígitos são aplicados a cada coluna, com correção para múltiplas comparações. Responde quais colunas parecem ter valores fabricados.

GRIM e SPRITE ficam disponíveis como funções independentes: eles verificam médias e desvios-padrão reportados (por exemplo, numa tabela de um artigo), e não dados brutos. Com as médias publicadas em três artigos de pizza do Cornell Food and Brand Lab, o GRIM concordou com o julgamento de especialistas (van der Zee, Anaya e Brown, 2017) em 96 de 97 médias, e o SPRITE recusou os 13 desvios-padrão que eles apontaram como impossíveis. Num cenário sintético com verdade matemática conhecida (escala de 1 a 5, n de 10 a 50), nenhum dos 400 casos honestos foi acusado, e as duas técnicas pegaram todas as 170 estatísticas retocadas à mão que ficaram impossíveis (85% das 200 simuladas).

A terminação de dígitos também tem um score por registro (terminacao_record_suspicion_score), que compara o último dígito de cada valor com a frequência observada nos dados de referência. Ele não entra no score unificado; foi avaliado à parte e só ajudou nos dados do seguro (ver Principais resultados).

Estrutura do repositório

FakeNumDetect/
├── fakenumdetect/            # código-fonte da biblioteca
│   ├── estatisticas/         # Benford, GRIM, SPRITE, Shannon, terminação de dígitos, análise por coluna
│   ├── ml/                   # Isolation Forest e Sparse Autoencoder
│   ├── preprocessamento/     # DatasetBundle, divisões treino/validação/teste, k-fold, carregadores dos datasets
│   ├── pontuacao/            # score de suspeição unificado e ensembles
│   ├── avaliacao/            # métricas, comparação estatística, correção de múltiplas comparações
│   ├── relatorio/            # geração do relatório em HTML
│   ├── api/                  # classe FakeNumDetect (fit, detect, report)
│   └── ModuleExcecoes.py     # erros com nome próprio da biblioteca
├── tests/                    # testes automatizados (pytest), com dados reais em tests/fixtures/
├── experiments/              # scripts que reproduzem os experimentos do TCC2 (e o download verificado dos dados)
├── exemplos/                 # notebook de uso (Google Colab ou Jupyter)
├── results/                  # resultados dos experimentos (.jsonl)
├── .github/workflows/        # integração contínua (testes e cobertura mínima de 90%)
├── pyproject.toml            # empacotamento da biblioteca (versões mínimas)
├── requirements.txt          # ambiente exato dos resultados (versões fixas)
└── README.md

As pastas datasets/ e models/ existem localmente e ficam fora do Git.

Instalação

Requer Python 3.10 ou superior (desenvolvido com 3.13).

Depois da publicação no PyPI:

pip install fakenumdetect

Instalação (ambiente de desenvolvimento)

Requer Python 3.10 ou superior (desenvolvido com 3.13).

git clone https://github.com/GiPaiva/FakeNumDetect.git
cd FakeNumDetect
python -m venv venv
source venv/bin/activate      # Windows: venv\Scripts\activate
pip install -r requirements.txt

O requirements.txt fixa as versões exatas do ambiente em que os testes e os resultados de results/ foram gerados (Python 3.13.7), incluindo o PyOD, usado só num experimento. O pyproject.toml, usado por pip install fakenumdetect, aceita versões mais novas, para a biblioteca não entrar em conflito com outros pacotes do projeto de quem a usa.

Para rodar os testes:

python -m pytest -q

Para medir a cobertura de testes da biblioteca (linhas e ramos):

python -m pytest -q --cov=fakenumdetect --cov-branch --cov-report=term-missing

Cobertura atual: 97% (354 testes, medida com o comando acima).

Exemplos de uso

Os exemplos usam arquivos reais que já estão em tests/fixtures/.

Uso rápido: fit, detect e report

from fakenumdetect import FakeNumDetect
from fakenumdetect.preprocessamento.ModuleLoaderADBench import load_adbench

bundle = load_adbench("tests/fixtures/4_breastw.npz")
det = FakeNumDetect().fit(bundle.X_train)   # referência: só registros genuínos
res = det.detect(bundle.X_test)

print(res.registros.head(3))                # scores 0 a 100 por técnica, score unificado e sinalização
print(res.registros["sinalizado"].sum(), "de", len(res.registros), "registros sinalizados")   # 227 de 328
print(res.colunas["colunas_suspeitas"])     # []
det.report(res, "relatorio.html")
  • fit(X) recebe dados de referência que você acredita serem genuínos (matriz ou DataFrame, sem valores ausentes). Ele treina o Isolation Forest (com os valores do artigo original: 100 árvores, subamostra de até 256 registros e contamination="auto") e o Sparse Autoencoder, a normalização de cada técnica e o limiar (percentil 95 do score unificado numa parte da referência separada para validação).
  • Por padrão, as técnicas são combinadas pela média simples. Se você tiver dados rotulados (1 = fabricado, com as duas classes), fit(X, X_cal=..., y_cal=...) calibra os pesos por regressão logística.
  • detect(X) devolve registros (um DataFrame com o mesmo índice da entrada), limiar, colunas (análise por coluna) e, com colunas_comparaveis=[["col_a", "col_b"]], arredondamento (consistência do arredondamento entre essas colunas).
  • report(res, caminho) gera o relatório em HTML.
  • res.laudo["tabela"]: o laudo do lote com as 7 técnicas. Cada uma diz quanto suspeita do lote inteiro (0 a 100) ou por que não se aplica, e a linha "Juntas" combina as que opinaram (correção de Simes). GRIM e SPRITE entram com det.detect(dados, estatisticas_publicadas=tabela) (colunas media, n, dp, minimo, maximo; média e DP como texto). Dois botões de 0 a 5: confianca_referencia (5 = comparar com os dados de referência; 0 = com a Lei de Benford e finais uniformes) e rigor (5 = aceita 5% de alarme falso; 0 = 0,1%). Escolha os dois antes de olhar o resultado. No experimento (run_laudo.py), o laudo separou sem erro a fabricação real do seguro, mas não superou a melhor técnica individual nas fabricações simuladas do JarFraud e, com valores inventados, ficou significativamente abaixo do teste de Benford.
  • Erros de dado têm nome próprio (EmptyDataError, InsufficientDataError, InvalidDataTypeError, BenfordInapplicableError, NoApplicableTechniqueError), importáveis de fakenumdetect. Todos herdam de FakeNumDetectError (e de ValueError): except FakeNumDetectError trata qualquer problema no dado.
  • Opcional: FakeNumDetect(regras_aplicabilidade=True) tira da nota por registro as técnicas que não se aplicam ao tipo de dado (regra do TCC1): o Benford só usa as colunas cujos números variam pelo menos 2 ordens de grandeza, e o Autoencoder exige 2 colunas ou mais. O resultado informa as técnicas usadas e as excluídas (res.tecnicas), e o relatório também. Na validação cruzada, a regra não melhorou a nota em nenhum dos 4 datasets e piorou a média ponderada no AcademicAnomaly; por isso é opção, e não padrão.

Para usar no Google Colab ou no Jupyter, abra o notebook exemplos/uso_fakenumdetect.ipynb: ele instala a biblioteca, roda os três passos com um conjunto de dados real que já vem no scikit-learn, mostra o relatório dentro do notebook e traz uma seção para enviar o seu próprio CSV.

Cuidados, vindos dos experimentos: a referência precisa ser genuína (registros fabricados no treino prejudicam muito o autoencoder); o limiar do percentil 95 sinaliza, por construção, cerca de 5% dos registros genuínos; e os testes de dígitos indicam desvio de uma distribuição de referência, não fabricação.

Teste de Benford em uma coluna

import numpy as np
from fakenumdetect.estatisticas.ModuleBenford import analyze_first_digit

dados = np.load("tests/fixtures/jarfraud_colunas_amostra.npz")
vendas = dados["X"][:, list(dados["feature_names"]).index("sale")]

r = analyze_first_digit(vendas)
print(r["p_value"], r["mad"], r["conformity"])   # p ~0.09, MAD ~0.0035, "close conformity"
print(r["digitos_desviantes"])                   # estatística Z por dígito: [{"digito": 7, "direcao": "excesso", ...}]

Análise por coluna com correção de múltiplas comparações

import numpy as np
from fakenumdetect.estatisticas.ModuleAnaliseColunas import analisar_colunas

dados = np.load("tests/fixtures/jarfraud_colunas_amostra.npz")
r = analisar_colunas(dados["X"], list(dados["feature_names"]), correcao="bh")

print(r["colunas_suspeitas"])        # [] : dados contábeis reais seguem Benford
for c in r["colunas"]:
    print(c["nome"], c["benford"]["conformidade"], c["suspeita"])

Por padrão, uma coluna só é sinalizada quando o p-valor corrigido é significativo e o MAD indica desvio relevante (faixas de Nigrini). Isso evita sinalizar colunas genuínas em amostras grandes, onde o qui-quadrado rejeita desvios minúsculos. Quando o Benford se aplica, o resultado também lista os dígitos que se afastam do esperado (c["benford"]["digitos_desviantes"], estatística Z de Nigrini com correção BH entre os dígitos); essa lista explica o desvio, mas não decide a suspeita. Cada teste só é aplicado quando faz sentido para a coluna (por exemplo, Benford exige valores que cubram pelo menos duas ordens de grandeza).

Score de suspeição de um registro com Isolation Forest

from fakenumdetect.preprocessamento.ModuleLoaderADBench import load_adbench
from fakenumdetect.ml.ModuleIsolationForest import calibrate_isolation_forest, raw_suspicion_score

bundle = load_adbench("tests/fixtures/4_breastw.npz")
modelo = calibrate_isolation_forest(bundle.X_train, bundle.X_val)["model"]
scores = raw_suspicion_score(modelo, bundle.X_test)   # quanto maior, mais suspeito

O fluxo completo do score unificado (normalização de cada técnica para 0 a 100, calibração de pesos e limiar) é o que a classe FakeNumDetect faz; a versão usada na validação cruzada está em experiments/run_kfold_comparacao.py.

Relatório em HTML

import numpy as np
from fakenumdetect.estatisticas.ModuleAnaliseColunas import analisar_colunas
from fakenumdetect.relatorio.ModuleRelatorio import gerar_relatorio_html

dados = np.load("tests/fixtures/jarfraud_colunas_amostra.npz")
analise = analisar_colunas(dados["X"], list(dados["feature_names"]))
gerar_relatorio_html("relatorio.html", analise_colunas=analise)

O relatório também aceita o score unificado de cada registro (scores_registros, escala 0 a 100) e o limiar (limiar_registros). O resultado é um único arquivo HTML, com os gráficos embutidos, que abre em qualquer navegador. Para ver o fluxo inteiro sobre um dataset real (treinar os modelos, calcular o score, analisar as colunas e gerar o relatório):

python experiments/run_relatorio_exemplo.py 4_breastw

O relatório é salvo em results/relatorios/.

Datasets usados nos experimentos

Dataset Origem Onde fica
4_breastw ADBench (Han et al., 2022) tests/fixtures/4_breastw.npz
AcademicAnomaly macrOData tests/fixtures/AcademicAnomaly.npz
FakeData Bradshaw e Payne (2021), GitHub MSBradshaw/FakeData baixado para a pasta temporária do sistema
JarFraud Bao et al. (2020), GitHub JarFraud/FraudDetection baixado para a pasta temporária do sistema
Seguro (Shu et al., 2012) Data Colada #98, ResearchBox #336 (CC BY 4.0) datasets/seguro_shu2012/ (amostra de 400 linhas em tests/fixtures/shu2012_amostra.xlsx)

O dataset do seguro é o único com fabricação real e verdade conhecida por coluna: o artigo foi retratado em 2021, e o Data Colada mostrou quais valores foram fabricados (a fonte do Excel separa os registros originais das cópias). Ele é uma validação à parte e não entra no Friedman nem na correção múltipla do estudo principal. Baixe DrivingdataAll with font.xlsx de https://researchbox.org/336 para datasets/seguro_shu2012/.

FakeData e JarFraud são baixados das fontes oficiais automaticamente, na primeira vez em que um experimento precisa deles (experiments/ModuleCacheDados.py). Antes de reaproveitar o arquivo da pasta temporária, o script confere o SHA-256 com o dos arquivos que geraram results/: se o arquivo estiver incompleto, ele é baixado de novo; se o arquivo de origem tiver mudado, o script para com erro, em vez de rodar com outro dado.

Reproduzindo os experimentos

Os scripts gravam resultados em results/*.jsonl acrescentando linhas. Para refazer um experimento do zero, apague antes o .jsonl correspondente. A ordem importa, porque alguns scripts leem resultados de outros:

  1. Divisão única: run_isolation_forest_<dataset>.py e run_autoencoder_<dataset>.py
  2. Escolha da esparsidade do autoencoder: run_escolha_esparsidade.py <dataset>
  3. Validação cruzada: run_kfold_comparacao.py <dataset> para os 4 datasets e depois run_kfold_comparacao.py friedman e run_kfold_comparacao.py correcao (Benjamini-Hochberg e Bonferroni sobre as 32 comparações) Regra de aplicabilidade por registro (opcional): run_kfold_comparacao.py aplicabilidade <dataset> para os 4 datasets e depois run_kfold_comparacao.py resumo_aplicabilidade. Validação cruzada repetida com 10 sementes (F1, PR-AUC, MCC e especificidade): run_kfold_comparacao.py sementes <dataset> para os 4 datasets e depois run_kfold_comparacao.py resumo_sementes.
  4. Sensibilidade (usam os pesos do passo 3): run_sensibilidade_pesos.py <dataset> e run_sensibilidade_limiar.py <dataset>; sensibilidade do autoencoder à contaminação do treino: run_sensibilidade_contaminacao_ae.py <dataset> e, em seguida, as estratégias de mitigação: run_mitigacao_contaminacao_ae.py <dataset> (só 4_breastw e AcademicAnomaly)
  5. Análise por coluna: run_analise_colunas.py descritivo, run_analise_colunas.py injecao e run_analise_colunas.py z (estatística Z por dígito); aplicabilidade das 7 técnicas em cada base: run_analise_colunas.py tecnicas; checagem do artefato de precisão do FakeData: run_artefato_precisao_fakedata.py
  6. Relatório de exemplo (usa os pesos do passo 3): run_relatorio_exemplo.py <dataset>
  7. Validação com fabricação real (seguro): run_seguro_shu2012.py colunas e run_seguro_shu2012.py registro; consistência do arredondamento: run_consistencia_arredondamento.py seguro, alarme_falso e poder
  8. GRIM e SPRITE com estatísticas publicadas: run_grim_sprite_pizza.py (lê tests/fixtures/grim_pizza_wansink.csv, não precisa baixar nada)
  9. Laudo do lote com as 7 técnicas: run_laudo.py seguro e run_laudo.py jarfraud
  10. Terminação de dígitos por registro: run_terminacao_registro.py <dataset> (aceita também shu2012) e depois run_terminacao_registro.py resumo
  11. GRIM e SPRITE em cenário sintético: run_grim_sprite_sintetico.py (não precisa baixar nada)
  12. Custo do critério de escolha da arquitetura do autoencoder: run_sensibilidade_arquitetura_ae.py <dataset> para os 4 datasets e depois run_sensibilidade_arquitetura_ae.py resumo
  13. Referências de comparação (acaso, z-score e PyOD) nos mesmos folds: run_baselines.py <dataset> para os 4 datasets, run_baselines.py pyod_ae <dataset> (autoencoder do PyOD), run_baselines.py temporal (JarFraud com divisão temporal) e depois run_baselines.py resumo. O PyOD só é usado nesse experimento e não é dependência da biblioteca (está no requirements.txt, mas não no pyproject.toml)

Os nomes de dataset aceitos são 4_breastw, AcademicAnomaly, fakedata_real_experiment e jarfraud_full_experiment_clean.

Principais resultados até agora

  • Nenhuma técnica isolada funciona bem em todos os domínios: o F1 médio da melhor técnica vai de cerca de 0,93 (breastw) a 0,03 (JarFraud).
  • O score unificado ponderado teve o maior F1 médio em 2 dos 4 datasets e ficou ligeiramente abaixo da melhor técnica nos outros 2, mas não superou a melhor técnica individual com significância estatística em nenhum deles. No nível de registro, a hipótese central do TCC recebe apoio parcial, e não confirmação. A conclusão se manteve ao repetir a validação cruzada com 10 sementes.
  • A forma de combinar importa: a média ponderada com pesos calibrados foi melhor que a média simples em todos os datasets.
  • Na análise por coluna, as regras de aplicabilidade evitam que 100% das colunas sejam sinalizadas por serem de um tipo inadequado, e o critério combinado de p-valor e MAD reduz os falsos positivos para menos de 10%.
  • A terminação de dígitos por registro só se aplica a dados com valores grandes (≥ 1000). Nos dados do seguro, onde o sinal da fabricação é a falta do arredondamento humano, ela separou os registros fabricados acima do acaso (PR-AUC 0,334 contra 0,250); no JarFraud, a diferença foi irrelevante, e no breastw e no FakeData ela não se aplica.

A discussão completa, com tabelas e limitações, está no texto do TCC2.

Limitações conhecidas

  • A análise foi validada em 4 datasets; em nenhum deles há rótulo de fabricação por coluna, então a análise por coluna foi validada com fabricação simulada sobre dados reais.
  • No arquivo do FakeData, as amostras reais têm 2 casas decimais e as fabricadas têm precisão cheia, o que por si só separa as classes. Isolation Forest e Autoencoder não dependem disso (o F1 não muda com os fabricados arredondados), mas o artefato impede validar a análise por coluna com esses rótulos.
  • Na única validação com fabricação real e verdade conhecida por coluna (dados do seguro de Shu et al., 2012), os testes de dígitos sinalizaram todas as colunas genuínas e só 5 das 12 fabricadas: os dados genuínos têm arredondamento humano, e os fabricados, gerados por computador, têm dígitos uniformes. No nível de registro, nenhuma técnica distinguiu as cópias (PR-AUC igual ao do acaso). Os testes detectam desvio de uma distribuição de referência, o que não é o mesmo que detectar fabricação. O teste de consistência do arredondamento entre colunas, criado a partir desse caso (e por isso validado em outros dados: alarme falso de 2,3%), pega esse tipo de inconsistência, mas não diz qual coluna é a fabricada e não vê nada quando todas foram fabricadas do mesmo jeito.
  • Fabricações pequenas (poucos por cento dos valores de uma coluna) são difíceis de detectar pelos testes de dígitos.
  • O SPRITE é uma busca heurística: "não encontrei uma amostra" é indício, e não prova. Nos artigos de pizza, ele não encontrava amostra para um desvio-padrão que uma verificação exata mostrou ser possível; a causa era um defeito no sorteio da busca, já corrigido, e agora ele encontra amostra para os 34 desvios-padrão possíveis. O GRIM arredonda empates exatos (como 2,675) para cima ou para o par, e por isso acusa uma média que os especialistas, mais conservadores, aceitaram.
  • Uma coluna inteiramente inventada com valores uniformes pode ser declarada "não aplicável" para Benford e escapar da análise por coluna.
  • Na divisão única, a prevalência do teste fica acima da prevalência da base (todas as anomalias vão para o teste), o que infla F1 e PR-AUC; as comparações entre técnicas usam a validação cruzada, que preserva a prevalência.
  • Um z-score univariado igualou o score combinado no FakeData, e, no JarFraud com divisão temporal (treino até 2001, teste de 2003 a 2008), nenhuma técnica superou o acaso (run_baselines.py).
  • O autoencoder padrão do PyOD superou o autoencoder da FakeNumDetect nas 4 bases e, sozinho, igualou ou superou o score combinado no AcademicAnomaly e no FakeData; a revisão do autoencoder fica como trabalho futuro.
  • No FakeData, a validação de cada fold tem só 4 registros, e o limiar no percentil 95 fica instável; ali, o PR-AUC é a métrica confiável.
  • A arquitetura e a esparsidade do autoencoder foram calibradas uma vez e reutilizadas em todos os folds da validação cruzada. O Isolation Forest usa os valores do artigo original (100 árvores, subamostra de até 256 registros); uma versão anterior escolhia esses valores e a contamination por um critério sem relação com a detecção, e a troca não mudou nenhuma conclusão.
  • A arquitetura do autoencoder é escolhida pela menor perda de reconstrução na validação, critério que não mede a detecção e tende a premiar redes maiores. Com as grades usadas, o custo foi desprezível: a diferença média de PR-AUC para a melhor arquitetura da grade ficou abaixo de 0,005 nos 4 datasets (run_sensibilidade_arquitetura_ae.py).
  • O autoencoder pode ser muito sensível a registros fabricados que entrem no treino: no AcademicAnomaly, 5% de contaminação derrubou o F1 em 36,5%. As mitigações previstas no TCC1 (mais regularização e ensemble de autoencoders por votação majoritária, disponível em treinar_ensemble_autoencoders) foram testadas e não resolveram o problema: nenhuma superou o autoencoder original com o treino contaminado. O aparamento iterativo do treino (treinar_autoencoder_aparado, fora do TCC1) foi o melhor com 5% de contaminação (F1 0,453 contra 0,392), mas também ficou longe do critério, porque remove cerca de 9% do treino mesmo quando ele está limpo e custa desempenho no caso sem contaminação (F1 0,617 para 0,491).

Autora

Giovanna Paiva Alves. Desenvolvido como Trabalho de Conclusão de Curso no SENAC.

Licença

MIT. Veja o arquivo LICENSE.

Metadata

Release files for fakenumdetect 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fakenumdetect 0.1.0
File Size Uploaded Provenance Actions
fakenumdetect-0.1.0.tar.gz 130.1 kB Without provenance Details for fakenumdetect-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fakenumdetect 0.1.0
File Interpreter ABI Platform Actions
fakenumdetect-0.1.0-py3-none-any.whl Python 3 none any Details for fakenumdetect-0.1.0-py3-none-any.whl

Total release size: 222.9 kB

Release files / fakenumdetect-0.1.0.tar.gz

Download URL fakenumdetect-0.1.0.tar.gz
Size 130.1 kB
Tags Source
SHA-256 checksum
How to use checksums
81326b56c342ec121905aecb3ca5acdb99748b6f2284d1d84b0d63af8eb1be7f
BLAKE2b-256 checksum
How to use checksums
133fa6f5497f924de7b32e46a5a15d7f8a09ebe96b86bcb7bdd0d9fb2dc6d1df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Release files / fakenumdetect-0.1.0-py3-none-any.whl

Download URL fakenumdetect-0.1.0-py3-none-any.whl
Size 92.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d81df1b09cb805e84af5395894199fae18706bb1109dec1b683cc11cae8bc69b
BLAKE2b-256 checksum
How to use checksums
e616e10198d4376336e4b3d36682cc77d3e1263e40e7cb37a352318d0298f1ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Security for fakenumdetect 0.1.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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A 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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page