dq-engine
Framework PySpark para validacao e tratamento de qualidade de dados.
O que faz
- Resolve rule_set por nome de coluna
- Compila regras declarativas em expressoes Spark
- Gera score e status por coluna
- Aplica tratamento em lote (inclui colapso de espacos internos em texto DSC_)
- Executa pipeline antes/depois com comparativo
- Detecta avisos (informativos, nao alteram o score):
- cardinalidade IDT_ fora do padrao;
- similaridade categorica DSC_/TPO_ — mesma categoria com grafia diferente, por pontuacao/espacos (ex.: "S.A" vs "S/A");
- nulos padronizados (
N/D/0/1800-01-01) por coluna, marcando[DROP?]quando sao maioria.
- Registra em
dq_historico.xlsx(abas Historico com% Colunas Aprovadas, Relatorio comCausa/Acao Sugerida, e Avisos) - Suporta modo producao (valida o DataFrame ja tratado e marca situacao CORRIGIDO)
Requisitos
- Python 3.10+
- PySpark 3.4+
Instalacao
pip install -e .
Uso rapido
from pyspark.sql import SparkSession
from dq_engine import DataQualityEngine
from dq_engine.config.conventions import CONVENTIONS
spark = SparkSession.builder.getOrCreate()
engine = DataQualityEngine(spark=spark, conventions=CONVENTIONS)
df = spark.table("lakehouse.clientes")
result = engine.validate_table(df=df, table_name="CLIENTES", run_id="2026-07-02")
result.output_df.orderBy("column_name").show(truncate=False)
Dois modos de uso
| Modo | Quando usar | O que faz |
|---|---|---|
| Simulacao (padrao) | Antes de levar o tratamento para o ETL | Valida o dado bruto, aplica o tratamento, valida de novo e compara ANTES x DEPOIS. Imprime o trecho de ETL (treat_*) para copiar e colar. |
Producao (producao=True) |
Depois que o ETL real ja aplicou o data clean | Valida uma unica vez o dado ja tratado (nao re-trata) e marca a situacao como CORRIGIDO, ou PENDENTE_FONTE se sobrar falha. |
Simulacao
df_tratado, result_before, result_after = engine.run_dq_pipeline(
df=df,
table_name="CLIENTES",
output_dir="/mnt/dq_output", # opcional: sem ele nada e gravado em arquivo
)
Producao
df_validado, result, _ = engine.run_dq_pipeline(
df=df_ja_tratado,
table_name="CLIENTES",
output_dir="/mnt/dq_output",
producao=True,
ignore_columns_from_score=[], # lista de colunas a tirar do score (veja abaixo)
)
Ignorar colunas no score (ignore_columns_from_score)
Para uma particularidade ja conhecida e nao corrigivel agora (ex.: IDT_X que na verdade
deveria ser TPO_X), informe o nome exato da coluna:
df_validado, result, _ = engine.run_dq_pipeline(
df=df_ja_tratado,
table_name="CLIENTES",
output_dir="/mnt/dq_output",
producao=True,
ignore_columns_from_score=["IDT_SITUACAO", "IDT_SUBCATEGORIA"],
)
- So tem efeito com
producao=True(em simulacao e ignorado). - A coluna continua sendo validada; apenas fica fora do
quality_score/indicador da tabela e do diagnostico de falha residual. Nao e manipular score, e priorizar. - O estado real da coluna e mostrado no console/
.txt(subsecao "COLUNAS MONITORADAS") e gravado na abaAvisosdo Excel (Tipo Aviso = COLUNA_MONITORADA) para ajuste posterior. [](ou omitir) = todas as colunas entram no score.
Via main.py: python main.py --table ... --producao --ignore-columns-producao IDT_X
(flag repetivel), ou no .env: DQ_PRODUCAO=true e DQ_IGNORE_COLUMNS_PRODUCAO=IDT_X,IDT_Y.
Como ler o output
O output tem dois blocos de aviso:
- PONTO DE ATENCAO — nao reduz o score. Um bloco unico, em subsecoes:
IDT_fora do padrao de dominio (mais de 2 valores distintos alem deN/D: provavel erro de prefixo, deveria serTPO_/DSC_);- regras WARNING (ex.: ano suspeito em datas, campos estritos como CPF/CNPJ/placa/chassi),
sempre com exemplos dos valores que dispararam a regra. Colunas
DSC_(campo aberto) nao validamencoding_corruption; - categorias duplicadas por grafia (
S.AxS/A); - colunas monitoradas (fora do score).
- FALHA RESIDUAL — reduz o score. Colunas que seguem com falha apos o tratamento: corrigir na fonte.
Tudo isso vai tambem para o Excel (aba Avisos), com coluna, regra, categoria, quantidade e
mensagem (incluindo exemplos).
Regras de tratamento de texto
Todo tratamento de string converte para MAIUSCULAS, remove acentos e trata nulos
(N/D), exceto:
COD_— soupper+trim, preservando pontuacao (nulo vira"0");- colunas
DSC_comPATH/BUCKET/CAMINHO(treat_dsc_path) — preservam o caminho e usam minusculas.
Datas (DAT_/DTH_) sao sempre timestamp (padrao das tabelas trusted TRU_): treat_date
e treat_datetime devolvem TimestampType, preservam a hora e, para data sem hora, usam
00:00:00. Nulo/invalido vira 1800-01-01 00:00:00. Tabelas REP_/REF_ (colunas date)
nao tem tratamento especifico no dq-engine.
DSC_ de baixa cardinalidade (<= dsc_cardinality_threshold) sao reclassificadas como
dsc_category e tratadas com treat_dsc_category; as demais usam treat_dsc (preserva
espacos e pontuacao interna). DSC_ capturadas por nome (ex.: DSC_PLACA) mantem o tratamento
especifico mesmo com baixa cardinalidade.
- Placeholders em
DSC_:X,TESTEe sequencia de zeros (0,000000) viramN/D. - Ruido nas bordas de
DSC_:treat_dscremove simbolos soltos no inicio/fim ("SUZANO *"->SUZANO), mas preserva parenteses/colchetes/chaves ("... (GASOLINA / FLEX)"mantem o)final). STR_usatreat_str(igual atreat_dsc, sem a troca de placeholders de DSC_).
Tipos numericos
| Prefixo | Tipo | Tratamento |
|---|---|---|
VAL_ |
float | treat_float |
NUM_, QTD_ |
int | treat_int (decimais sao truncados; coluna com casas decimais deve ser VAL_) |
Excecoes pelo nome continuam com a regra propria: NUM_APOLICE/NUM_DOCUMENTO (texto),
NUM_TELEFONE, NUM_CHASSI, NUM_CPF.../NUM_CNPJ.... Atencao: int vai ate
2.147.483.647 — colunas NUM_ com mais digitos (protocolos, notas fiscais) estouram.
Campos estritos: so aviso, valor invalido mantido
CPF, CNPJ, CEP, UF, telefone, placa e chassi (resolvidos pelo nome da coluna) nao afetam o
score — todas as regras sao WARNING e aparecem na aba Avisos. No tratamento:
- nulo disfarcado (
VAZIO,0,TESTE,000.000.000-00, vazio) ->N/D; - valor valido -> forma padronizada (sem mascara; telefone como
(XX) XXXXX-XXXX); - valor invalido -> mantido como veio, com aviso "valor mantido; corrigir na origem" (ex.: CNPJ incompleto continua incompleto).
Avisos especificos, alem de formato/nulo:
| Aviso | Quando |
|---|---|
cpf_check_digit / cnpj_check_digit |
digito verificador invalido ou digitos repetidos |
chassi_check_digit |
chassi com formato valido mas digito verificador (ISO 3779) divergente |
telefone_ddd |
DDD inexistente na Anatel |
placa_padrao_antigo |
placa ABC1234 — nao e convertida para Mercosul |
domain (UF) |
nome por extenso ou codigo IBGE — nao e convertido para sigla |
No modo simulacao, problemas que o tratamento corrigiu (ex.: nulo disfarcado -> N/D) tambem
continuam na aba Avisos, com a indicacao "trocado(s) por N/D no tratamento".
Onde os arquivos sao salvos
Quando output_dir e informado, o DqOutputSaver grava:
{output_dir}/
├── table_output/
│ └── {TABELA}_{TIMESTAMP}.txt # relatorio detalhado de cada execucao
└── output_consolidado/
└── dq_historico_v2.xlsx # historico acumulado (nome via historico_filename)
Abas do Excel: Historico (indicador/score por execucao), Relatorio (diagnostico por coluna),
Avisos (todos os avisos acima) e Distribuicao (opcional, include_distribution=True).
No main.py a configuracao e:
| Item | Flag / .env |
Default |
|---|---|---|
| Pasta de saida | --output-dir / DQ_OUTPUT_DIR |
\KIRIBATI.autoglass.com.br\Departamento$\Célula de Dados e Implantação\Engenharia\Outputs_Data_Quality |
| Nome do Excel | --historico-filename / DQ_HISTORICO_FILENAME |
dq_historico_v2.xlsx |
| Tabelas ja processadas | --processed-file / DQ_PROCESSED_FILE |
state/processed_tables.yaml |
| Tabelas com falha | --failed-file / DQ_FAILED_FILE |
state/failed_tables.yaml |
Se o Excel estiver aberto, o save avisa e nao grava o registro: feche e rode de novo.
Leitura via Snowflake (opcional)
O engine sempre recebe um DataFrame Spark comum — a origem dos dados e desacoplada. Para descobrir e ler tabelas do Snowflake por schema, instale o extra snowflake:
pip install -e ".[snowflake]"
from dq_engine.sources.snowflake_source import SnowflakeReader, discover_tables
reader = SnowflakeReader() # credenciais via variaveis de ambiente (.env)
table_names = discover_tables(reader, schema_like="%NOME_DO_SCHEMA%")
df = reader.read(spark, table_names[0])
result = engine.validate_table(df=df, table_name=table_names[0], run_id="2026-07-14")
O script main.py automatiza o fluxo (descobre tabelas do schema -> roda dq-engine -> salva consolidado/historico) e pode ser agendado no Sonata:
python main.py --schema-like "%NOME_DO_SCHEMA%"
O padrao LIKE tambem pode vir do .env (variavel TABLE_SCHEMA), dispensando --schema-like em toda chamada.
Tambem e possivel rodar uma lista fixa de tabelas em vez de (ou combinada com) o schema, via --table (repetivel) ou pela variavel TABLE_LIST no .env (nomes completos DATABASE.SCHEMA.TABELA separados por virgula):
python main.py --table TRUSTED.MAX_APOLICE.TABELA_1 --table TRUSTED.MAX_APOLICE.TABELA_2
Tambem e possivel apontar um YAML com lista simples de tabelas (como to_process.yaml) usando --tables-yaml ou a variavel TABLE_LIST_FILE no .env:
python main.py --tables-yaml to_process.yaml
Sem --schema-like/TABLE_SCHEMA, o main.py roda so as tabelas informadas (--table, TABLE_LIST ou --tables-yaml), sem descoberta via INFORMATION_SCHEMA; com os dois informados, a lista filtra o resultado da descoberta.
Tabelas processadas com sucesso ficam registradas em processed_tables.yaml (arquivo temporario, desacoplado do dq-engine) e sao puladas nas proximas execucoes; use --rerun-processed para forcar tudo de novo.
API principal
- DataQualityEngine.validate_table
- DataQualityEngine.apply_treatment
- DataQualityEngine.run_dq_pipeline
- DataQualityEngine.get_column_treatment_contexts
- DataQualityResult.table_summary
- DataQualityResult.failed_columns
Configuracao
Arquivo central de convencoes:
- src/dq_engine/config/conventions.py
Documentacao
- docs/architecture.md
- docs/rules.md
Metadata
Release files for dq-engine 0.7.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dq_engine-0.7.4.tar.gz | 81.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dq_engine-0.7.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 164.7 kB
Release files / dq_engine-0.7.4.tar.gz
| Download URL | dq_engine-0.7.4.tar.gz |
|---|---|
| Size | 81.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f6f62e38bf2757c4f35ae19fb88327acc09ff8edbf9f30cd23b98b5973c0ee20
|
|
BLAKE2b-256 checksum How to use checksums |
3dac5d1ebe43fd3c7d3e83d1f02e8bae2d3f587313e090232e80c0653cb685fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.0
|
Release files / dq_engine-0.7.4-py3-none-any.whl
| Download URL | dq_engine-0.7.4-py3-none-any.whl |
|---|---|
| Size | 83.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ab93e13a4a37140d665110bf854f22946f40fa9da3ef18c6c43878cf07911cc7
|
|
BLAKE2b-256 checksum How to use checksums |
d62a50ca3f23f3628c884725252bacfd44f0520d13a2d2cfebf67573587498c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.0
|