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. Cada regra aparece
separada, com o que significa, quantas linhas, exemplos daquela regra e a acao:
- "o tratamento corrige" (nulo fora do padrao, placeholder, maiusculas...): se aparece em producao, a tabela nao foi reprocessada com o data_clean atual;
- "o tratamento NAO corrige" (texto so com numero, encoding, dominio, formato): corrigir na fonte ou rever o prefixo da coluna.
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_— mantem o texto como veio (sotrim): sem upper, preserva pontuacao, acentos e minusculas — codigos/chaves nao mudam. O nulo deCOD_e sempre"0"(nuncaN/D), inclusive emCOD_com regra propria pelo nome (COD_CHASSI,COD_UF,COD_CPF...), que mantem a validacao/avisos do campo mas devolvem"0"no nulo;- colunas com
PATHouLINKno nome (qualquer prefixo) eDSC_comBUCKET/CAMINHO(treat_dsc_path) — nao passam para maiusculas: preservam o caminho/link 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, assim como datas com ano abaixo de
suspicious_year_min (default 1900, ex.: 0001-01-01). Datas futuras sao mantidas e so geram
aviso (ano suspeito). Tabelas REP_/REF_ (colunas date) nao tem tratamento especifico no
dq-engine.
DSC_ (texto livre ou categorica, de baixa cardinalidade) e STR_ usam a mesma funcao,
treat_dsc. DSC_ capturadas por nome (ex.: DSC_PLACA) mantem o tratamento especifico mesmo
com baixa cardinalidade.
- Simbolos em qualquer posicao:
treat_dscmantem letras, numeros, espaco e a pontuacao. , ; : - / ( ) [ ] ' " ? ! % & + = @ _; o resto (* # | ~ ^ $ < >, emojis...) e removido tambem no meio do texto ("EVENTO** RELATO"->EVENTO RELATO). - Ruido nas bordas: simbolos soltos no inicio/fim saem (
"SUZANO *"->SUZANO,"UBERABA."->UBERABA), mas(/[no inicio e)/]/%no fim ficam ("... (GASOLINA / FLEX)"mantem o)final). - Placeholders:
X,TESTEe sequencia de zeros (0,000000) viramN/D.
Funcoes treat_* do trecho de ETL sao sempre as mesmas desde a 0.7.2 — ajustes novos mudam o
comportamento dessas funcoes, sem criar nomes novos. Para os ajustes valerem nos ETLs que ja
estao em producao (que chamam a funcao gravada no trecho da epoca), cada treat_* aplica a
regra da familia pelo nome da coluna:
| Chamada no ETL | Coluna | Regra aplicada |
|---|---|---|
treat_string / treat_dsc / treat_dsc_path |
COD_* (ex.: COD_APOLICE, COD_DOCUMENTO, COD_LINK) |
treat_cod (texto mantido, nulo "0") |
treat_string / treat_dsc |
nome com PATH/LINK |
treat_dsc_path |
treat_string |
DSC_* / STR_* |
treat_dsc |
treat_float |
NUM_* / QTD_* |
treat_int |
COD_ com campo estrito (COD_CHASSI, COD_UF, COD_CPF...) continua com a validacao do campo,
mas o nulo e "0".
Tipos numericos
| Prefixo | Tipo | Tratamento |
|---|---|---|
VAL_, PERC_ |
float | treat_float (treat_string em VAL_/PERC_ tambem vira 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.5
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.5.tar.gz | 85.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dq_engine-0.7.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 173.3 kB
Release files / dq_engine-0.7.5.tar.gz
| Download URL | dq_engine-0.7.5.tar.gz |
|---|---|
| Size | 85.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4b0168d5a556a6af955f2635bc395bb4ef04184ee6a085bc6391a15ca4ede892
|
|
BLAKE2b-256 checksum How to use checksums |
8115e90bad54fe81733f7227dc92f45cb47e40642b4e988ab4f0a524b1af4088
|
| 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.5-py3-none-any.whl
| Download URL | dq_engine-0.7.5-py3-none-any.whl |
|---|---|
| Size | 87.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c0a867ce27128cdf477446a2cebd26ad8bf792129cde9fdb8f08da0fa321539a
|
|
BLAKE2b-256 checksum How to use checksums |
c99114f60a6369311bdf6add184533dd6536183e477e639a7ba07c364bfb786c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.0
|