dq-engine 0.3.14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dq-engine might be problematic. Click here for more details.

Files changed (27) hide show
  1. dq_engine-0.3.14/PKG-INFO +307 -0
  2. dq_engine-0.3.14/README.md +295 -0
  3. dq_engine-0.3.14/pyproject.toml +35 -0
  4. dq_engine-0.3.14/setup.cfg +4 -0
  5. dq_engine-0.3.14/src/dq_engine/__init__.py +6 -0
  6. dq_engine-0.3.14/src/dq_engine/config/__init__.py +6 -0
  7. dq_engine-0.3.14/src/dq_engine/config/conventions.py +164 -0
  8. dq_engine-0.3.14/src/dq_engine/execution/__init__.py +25 -0
  9. dq_engine-0.3.14/src/dq_engine/execution/engine.py +782 -0
  10. dq_engine-0.3.14/src/dq_engine/execution/exceptions.py +23 -0
  11. dq_engine-0.3.14/src/dq_engine/execution/outputs.py +166 -0
  12. dq_engine-0.3.14/src/dq_engine/execution/result.py +148 -0
  13. dq_engine-0.3.14/src/dq_engine/execution/rule_compiler.py +245 -0
  14. dq_engine-0.3.14/src/dq_engine/execution/treatment_plan.py +509 -0
  15. dq_engine-0.3.14/src/dq_engine/execution/validator.py +28 -0
  16. dq_engine-0.3.14/src/dq_engine/planning/__init__.py +15 -0
  17. dq_engine-0.3.14/src/dq_engine/planning/models.py +52 -0
  18. dq_engine-0.3.14/src/dq_engine/planning/resolver.py +72 -0
  19. dq_engine-0.3.14/src/dq_engine/registry/__init__.py +6 -0
  20. dq_engine-0.3.14/src/dq_engine/registry/registry.py +82 -0
  21. dq_engine-0.3.14/src/dq_engine/utils/__init__.py +3 -0
  22. dq_engine-0.3.14/src/dq_engine/utils/logging.py +37 -0
  23. dq_engine-0.3.14/src/dq_engine.egg-info/PKG-INFO +307 -0
  24. dq_engine-0.3.14/src/dq_engine.egg-info/SOURCES.txt +25 -0
  25. dq_engine-0.3.14/src/dq_engine.egg-info/dependency_links.txt +1 -0
  26. dq_engine-0.3.14/src/dq_engine.egg-info/requires.txt +5 -0
  27. dq_engine-0.3.14/src/dq_engine.egg-info/top_level.txt +1 -0
@@ -0,0 +1,307 @@
1
+ Metadata-Version: 2.4
2
+ Name: dq-engine
3
+ Version: 0.3.14
4
+ Summary: Framework de validação de qualidade de dados com PySpark
5
+ Author-email: Bruna Cataldo <bruna.cataldo@autoglass.com.br>
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: pyspark>=3.4.0
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
11
+ Requires-Dist: pytest-mock>=3.12.0; extra == "dev"
12
+
13
+ # dq-engine
14
+
15
+ Framework de validação de qualidade de dados com PySpark.
16
+
17
+ Valida tabelas Spark com base em convenções de nomenclatura de colunas, regras declarativas por coluna, padrões de nulos e valores inválidos — gerando relatórios detalhados de inconsistências e sugestões de tratamento automático.
18
+
19
+ ---
20
+
21
+ ## Sumário
22
+
23
+ - [Objetivo](#objetivo)
24
+ - [Estrutura do projeto](#estrutura-do-projeto)
25
+ - [Arquitetura](#arquitetura)
26
+ - [Instalação](#instalação)
27
+ - [Como usar](#como-usar)
28
+ - [Interpretando o output](#interpretando-o-output)
29
+ - [Plano de tratamento](#plano-de-tratamento)
30
+ - [Como adicionar novas regras](#como-adicionar-novas-regras)
31
+ - [Como adicionar novos prefixos](#como-adicionar-novos-prefixos)
32
+ - [Testes](#testes)
33
+
34
+ ---
35
+
36
+ ## Objetivo
37
+
38
+ O `dq-engine` valida tabelas Spark garantindo que os dados estejam de acordo com:
39
+
40
+ - **Convenções de nomenclatura de colunas** — prefixos como `COD_`, `DAT_`, `NOM_` determinam automaticamente o conjunto de regras aplicável a cada coluna
41
+ - **Tipos de regras por coluna** — trimming, upper case, padrões de nulo, regex, domínios enumerados
42
+ - **Convenções de valores nulos** — representações inválidas de nulo são detectadas e sinalizadas por tipo de coluna
43
+ - **Valores de teste** — detecta `TESTE`, `FAKE`, `***` e similares em ambiente de produção
44
+
45
+ ---
46
+
47
+ ## Estrutura do projeto
48
+
49
+ ```
50
+ data-quality-local/
51
+ ├── pyproject.toml
52
+ ├── README.md
53
+ │
54
+ ├── docs/
55
+ │ ├── architecture.md # Arquitetura, fluxo e decisões de design
56
+ │ └── rules.md # Regras de validação e rule sets
57
+ │
58
+ ├── src/
59
+ │ └── dq_engine/
60
+ │ ├── __init__.py # Exportações públicas do pacote
61
+ │ │
62
+ │ ├── config/
63
+ │ │ ├── __init__.py
64
+ │ │ └── conventions.py # Fonte única de verdade: nulos, regras, prefixos, domínios
65
+ │ │
66
+ │ ├── planning/
67
+ │ │ ├── __init__.py
68
+ │ │ ├── models.py # Dataclasses: ValidationTarget, CompiledRule, ColumnTreatmentSpec
69
+ │ │ └── resolver.py # Resolução coluna → rule_set via prefix_mapping
70
+ │ │
71
+ │ ├── registry/
72
+ │ │ ├── __init__.py
73
+ │ │ └── registry.py # RuleRegistry: registro e lookup de builders de regras
74
+ │ │
75
+ │ ├── execution/
76
+ │ │ ├── __init__.py
77
+ │ │ ├── engine.py # DataQualityEngine: orquestração completa
78
+ │ │ ├── rule_compiler.py # SparkRuleCompiler: compila regras em Column expressions
79
+ │ │ ├── treatment_plan.py# Geração de código Spark de tratamento sugerido
80
+ │ │ ├── outputs.py # Builders do DataFrame de resultado
81
+ │ │ ├── result.py # DataQualityResult: contrato de saída
82
+ │ │ ├── validator.py # GenericValidator: validação pontual por coluna
83
+ │ │ └── exceptions.py # Hierarquia de exceções do framework
84
+ │ │
85
+ │ └── utils/
86
+ │ ├── __init__.py
87
+ │ └── logging.py # Logging estruturado
88
+ │
89
+ └── tests/
90
+ ├── __init__.py
91
+ ├── test_resolver.py # Testes do módulo planning/resolver
92
+ ├── test_rule_compiler.py # Testes de cada builder de regra
93
+ ├── test_engine.py # Testes de integração do engine
94
+ └── test_treatment_plan.py # Testes do gerador de código de tratamento
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Arquitetura
100
+
101
+ ```
102
+ DataFrame Spark
103
+ │
104
+ ▼
105
+ planning/resolver.py → identifica colunas elegíveis por prefixo
106
+ │
107
+ ▼
108
+ execution/rule_compiler.py → compila regras declarativas em Column expressions
109
+ │
110
+ ▼
111
+ execution/engine.py → projeta flags de validação (1 select), agrega contagens (1 agg)
112
+ │
113
+ ▼
114
+ execution/outputs.py → gera DataFrame de resultado por coluna
115
+ │
116
+ ▼
117
+ DataQualityResult.output_df → 1 linha por coluna validada
118
+ ```
119
+
120
+ Consulte [`docs/architecture.md`](docs/architecture.md) para detalhes de cada componente e decisões de design.
121
+
122
+ ---
123
+
124
+ ## Instalação
125
+
126
+ ```bash
127
+ pip install -e .
128
+ ```
129
+
130
+ Dependências:
131
+
132
+ - Python >= 3.10
133
+ - PySpark >= 3.4.0
134
+
135
+ ---
136
+
137
+ ## Como usar
138
+
139
+ ### Validação de uma tabela
140
+
141
+ ```python
142
+ from pyspark.sql import SparkSession
143
+ from dq_engine import DataQualityEngine, CONVENTIONS
144
+
145
+ spark = SparkSession.builder.getOrCreate()
146
+
147
+ df = spark.table("meu_lakehouse.tabela_clientes")
148
+
149
+ engine = DataQualityEngine(spark=spark, conventions=CONVENTIONS)
150
+
151
+ result = engine.validate_table(
152
+ df=df,
153
+ table_name="tabela_clientes",
154
+ run_id="2024-01-15",
155
+ )
156
+
157
+ result.output_df.show(truncate=False)
158
+ ```
159
+
160
+ ### Exemplo de output
161
+
162
+ ```
163
+ +------------------+------------------+-------------------+----------+----------+------------+-------------+--------+
164
+ | table_name | column_name | invalid_value |total_rows|valid_rows|invalid_rows|quality_score| status |
165
+ +------------------+------------------+-------------------+----------+----------+------------+-------------+--------+
166
+ | tabela_clientes | NOM_CLIENTE | null | TESTE | 1000 | 985 | 15 | 0.985 | FAILED |
167
+ | tabela_clientes | COD_PRODUTO | | 1000 | 1000 | 0 | 1.0 | PASSED |
168
+ | tabela_clientes | DAT_NASCIMENTO | 0000-00-00 | 1000 | 998 | 2 | 0.998 | FAILED |
169
+ +------------------+------------------+-------------------+----------+----------+------------+-------------+--------+
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Interpretando o output
175
+
176
+ | Coluna | Tipo | Descrição |
177
+ |--------|------|-----------|
178
+ | `table_name` | string | Nome da tabela validada |
179
+ | `column_name` | string | Coluna com inconsistência |
180
+ | `invalid_value` | string | Amostra dos valores inválidos encontrados (até 50 distintos, separados por `\|`) |
181
+ | `total_rows` | long | Total de linhas da tabela |
182
+ | `valid_rows` | long | Linhas que passaram em todas as regras da coluna |
183
+ | `invalid_rows` | long | Linhas que falharam em pelo menos uma regra (deduplificado) |
184
+ | `quality_score` | double | `valid_rows / total_rows` — entre 0.0 e 1.0 |
185
+ | `status` | string | `PASSED` se `invalid_rows == 0`, caso contrário `FAILED` |
186
+
187
+ ---
188
+
189
+ ## Plano de tratamento
190
+
191
+ Além da validação, o engine gera automaticamente o **código Spark de tratamento** sugerido para corrigir as inconsistências encontradas.
192
+
193
+ ```python
194
+ # Opção 1: calcular contexto e gerar código em uma chamada
195
+ treatment_code = engine.render_treatment_code_from_df(
196
+ df=df,
197
+ df_name="df_clientes",
198
+ )
199
+
200
+ # Opção 2: calcular contexto separadamente (evita reprocessamento)
201
+ contexts = engine.get_column_treatment_contexts(df)
202
+ treatment_code = engine.render_treatment_code(df, contexts, df_name="df_clientes")
203
+
204
+ print(treatment_code)
205
+ ```
206
+
207
+ Saída de exemplo:
208
+
209
+ ```python
210
+ df_clientes = df_clientes.select(
211
+ when(col("NOM_CLIENTE").isNull() | upper(trim(col("NOM_CLIENTE").cast("string"))).isin("NULL", "TESTE"),
212
+ lit("N/D")).otherwise(upper(trim(col("NOM_CLIENTE").cast("string")))).alias("NOM_CLIENTE"),
213
+ coalesce(col("COD_PRODUTO").cast("string"), lit("0")).alias("COD_PRODUTO"),
214
+ when(upper(col("DAT_NASCIMENTO").cast("string")).isin("0000-00-00"),
215
+ lit("1800-01-01 00:00:00").cast("timestamp")).otherwise(col("DAT_NASCIMENTO").cast("timestamp")).alias("DAT_NASCIMENTO"),
216
+ )
217
+ ```
218
+
219
+ O código gerado pode ser copiado diretamente para o notebook de tratamento.
220
+
221
+ ---
222
+
223
+ ## Como adicionar novas regras
224
+
225
+ ### 1. Criar o builder em `src/dq_engine/execution/rule_compiler.py`
226
+
227
+ ```python
228
+ def _build_minha_regra(column_name: str, rule: dict, conventions: dict) -> CompiledRule:
229
+ condition = col(column_name).isNull() # sua condição de falha
230
+
231
+ return CompiledRule(
232
+ rule_type="minha_regra",
233
+ error_code="MINHA_REGRA_INVALIDA",
234
+ error_message="Descrição do erro",
235
+ condition=condition,
236
+ suggested_treatment_category="MANUAL_REVIEW",
237
+ suggested_treatment_expression=None,
238
+ manual_review_required=True,
239
+ treatment_note="Orientação de correção.",
240
+ )
241
+ ```
242
+
243
+ ### 2. Registrar no `SparkRuleCompiler._register_default_rules()`
244
+
245
+ ```python
246
+ def _register_default_rules(self) -> None:
247
+ builders = {
248
+ # ... builders existentes ...
249
+ "minha_regra": _build_minha_regra,
250
+ }
251
+ for rule_type, builder in builders.items():
252
+ self.registry.register(rule_type, builder)
253
+ ```
254
+
255
+ ### 3. Referenciar em um rule_set em `src/dq_engine/config/conventions.py`
256
+
257
+ ```python
258
+ "rule_sets": {
259
+ "meu_rule_set": [
260
+ {"type": "string_null_pattern"},
261
+ {"type": "minha_regra"},
262
+ ],
263
+ }
264
+ ```
265
+
266
+ ### 4. Documentar em `docs/rules.md`
267
+
268
+ ---
269
+
270
+ ## Como adicionar novos prefixos
271
+
272
+ Em `src/dq_engine/config/conventions.py`, adicione uma entrada em `prefix_mapping`:
273
+
274
+ ```python
275
+ "prefix_mapping": {
276
+ # ... prefixos existentes ...
277
+ "EMAIL": "email_field",
278
+ }
279
+ ```
280
+
281
+ E defina o rule_set correspondente em `rule_sets`:
282
+
283
+ ```python
284
+ "email_field": [
285
+ {"type": "string_null_pattern"},
286
+ {"type": "regex", "pattern_ref": "email"},
287
+ ],
288
+ ```
289
+
290
+ Prefixos mais longos têm precedência automaticamente — nenhuma configuração extra necessária.
291
+
292
+ ---
293
+
294
+ ## Testes
295
+
296
+ ```bash
297
+ pytest tests/ -v
298
+ ```
299
+
300
+ Os testes cobrem:
301
+
302
+ | Arquivo | Cobertura |
303
+ |---------|-----------|
304
+ | `tests/test_resolver.py` | Resolução de prefixos, precedência, colunas sem match |
305
+ | `tests/test_rule_compiler.py` | Cada builder de regra individualmente |
306
+ | `tests/test_engine.py` | Fluxo completo de validação, quality_score, status |
307
+ | `tests/test_treatment_plan.py` | Geração de expressões e código de tratamento |
@@ -0,0 +1,295 @@
1
+ # dq-engine
2
+
3
+ Framework de validação de qualidade de dados com PySpark.
4
+
5
+ Valida tabelas Spark com base em convenções de nomenclatura de colunas, regras declarativas por coluna, padrões de nulos e valores inválidos — gerando relatórios detalhados de inconsistências e sugestões de tratamento automático.
6
+
7
+ ---
8
+
9
+ ## Sumário
10
+
11
+ - [Objetivo](#objetivo)
12
+ - [Estrutura do projeto](#estrutura-do-projeto)
13
+ - [Arquitetura](#arquitetura)
14
+ - [Instalação](#instalação)
15
+ - [Como usar](#como-usar)
16
+ - [Interpretando o output](#interpretando-o-output)
17
+ - [Plano de tratamento](#plano-de-tratamento)
18
+ - [Como adicionar novas regras](#como-adicionar-novas-regras)
19
+ - [Como adicionar novos prefixos](#como-adicionar-novos-prefixos)
20
+ - [Testes](#testes)
21
+
22
+ ---
23
+
24
+ ## Objetivo
25
+
26
+ O `dq-engine` valida tabelas Spark garantindo que os dados estejam de acordo com:
27
+
28
+ - **Convenções de nomenclatura de colunas** — prefixos como `COD_`, `DAT_`, `NOM_` determinam automaticamente o conjunto de regras aplicável a cada coluna
29
+ - **Tipos de regras por coluna** — trimming, upper case, padrões de nulo, regex, domínios enumerados
30
+ - **Convenções de valores nulos** — representações inválidas de nulo são detectadas e sinalizadas por tipo de coluna
31
+ - **Valores de teste** — detecta `TESTE`, `FAKE`, `***` e similares em ambiente de produção
32
+
33
+ ---
34
+
35
+ ## Estrutura do projeto
36
+
37
+ ```
38
+ data-quality-local/
39
+ ├── pyproject.toml
40
+ ├── README.md
41
+ │
42
+ ├── docs/
43
+ │ ├── architecture.md # Arquitetura, fluxo e decisões de design
44
+ │ └── rules.md # Regras de validação e rule sets
45
+ │
46
+ ├── src/
47
+ │ └── dq_engine/
48
+ │ ├── __init__.py # Exportações públicas do pacote
49
+ │ │
50
+ │ ├── config/
51
+ │ │ ├── __init__.py
52
+ │ │ └── conventions.py # Fonte única de verdade: nulos, regras, prefixos, domínios
53
+ │ │
54
+ │ ├── planning/
55
+ │ │ ├── __init__.py
56
+ │ │ ├── models.py # Dataclasses: ValidationTarget, CompiledRule, ColumnTreatmentSpec
57
+ │ │ └── resolver.py # Resolução coluna → rule_set via prefix_mapping
58
+ │ │
59
+ │ ├── registry/
60
+ │ │ ├── __init__.py
61
+ │ │ └── registry.py # RuleRegistry: registro e lookup de builders de regras
62
+ │ │
63
+ │ ├── execution/
64
+ │ │ ├── __init__.py
65
+ │ │ ├── engine.py # DataQualityEngine: orquestração completa
66
+ │ │ ├── rule_compiler.py # SparkRuleCompiler: compila regras em Column expressions
67
+ │ │ ├── treatment_plan.py# Geração de código Spark de tratamento sugerido
68
+ │ │ ├── outputs.py # Builders do DataFrame de resultado
69
+ │ │ ├── result.py # DataQualityResult: contrato de saída
70
+ │ │ ├── validator.py # GenericValidator: validação pontual por coluna
71
+ │ │ └── exceptions.py # Hierarquia de exceções do framework
72
+ │ │
73
+ │ └── utils/
74
+ │ ├── __init__.py
75
+ │ └── logging.py # Logging estruturado
76
+ │
77
+ └── tests/
78
+ ├── __init__.py
79
+ ├── test_resolver.py # Testes do módulo planning/resolver
80
+ ├── test_rule_compiler.py # Testes de cada builder de regra
81
+ ├── test_engine.py # Testes de integração do engine
82
+ └── test_treatment_plan.py # Testes do gerador de código de tratamento
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Arquitetura
88
+
89
+ ```
90
+ DataFrame Spark
91
+ │
92
+ ▼
93
+ planning/resolver.py → identifica colunas elegíveis por prefixo
94
+ │
95
+ ▼
96
+ execution/rule_compiler.py → compila regras declarativas em Column expressions
97
+ │
98
+ ▼
99
+ execution/engine.py → projeta flags de validação (1 select), agrega contagens (1 agg)
100
+ │
101
+ ▼
102
+ execution/outputs.py → gera DataFrame de resultado por coluna
103
+ │
104
+ ▼
105
+ DataQualityResult.output_df → 1 linha por coluna validada
106
+ ```
107
+
108
+ Consulte [`docs/architecture.md`](docs/architecture.md) para detalhes de cada componente e decisões de design.
109
+
110
+ ---
111
+
112
+ ## Instalação
113
+
114
+ ```bash
115
+ pip install -e .
116
+ ```
117
+
118
+ Dependências:
119
+
120
+ - Python >= 3.10
121
+ - PySpark >= 3.4.0
122
+
123
+ ---
124
+
125
+ ## Como usar
126
+
127
+ ### Validação de uma tabela
128
+
129
+ ```python
130
+ from pyspark.sql import SparkSession
131
+ from dq_engine import DataQualityEngine, CONVENTIONS
132
+
133
+ spark = SparkSession.builder.getOrCreate()
134
+
135
+ df = spark.table("meu_lakehouse.tabela_clientes")
136
+
137
+ engine = DataQualityEngine(spark=spark, conventions=CONVENTIONS)
138
+
139
+ result = engine.validate_table(
140
+ df=df,
141
+ table_name="tabela_clientes",
142
+ run_id="2024-01-15",
143
+ )
144
+
145
+ result.output_df.show(truncate=False)
146
+ ```
147
+
148
+ ### Exemplo de output
149
+
150
+ ```
151
+ +------------------+------------------+-------------------+----------+----------+------------+-------------+--------+
152
+ | table_name | column_name | invalid_value |total_rows|valid_rows|invalid_rows|quality_score| status |
153
+ +------------------+------------------+-------------------+----------+----------+------------+-------------+--------+
154
+ | tabela_clientes | NOM_CLIENTE | null | TESTE | 1000 | 985 | 15 | 0.985 | FAILED |
155
+ | tabela_clientes | COD_PRODUTO | | 1000 | 1000 | 0 | 1.0 | PASSED |
156
+ | tabela_clientes | DAT_NASCIMENTO | 0000-00-00 | 1000 | 998 | 2 | 0.998 | FAILED |
157
+ +------------------+------------------+-------------------+----------+----------+------------+-------------+--------+
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Interpretando o output
163
+
164
+ | Coluna | Tipo | Descrição |
165
+ |--------|------|-----------|
166
+ | `table_name` | string | Nome da tabela validada |
167
+ | `column_name` | string | Coluna com inconsistência |
168
+ | `invalid_value` | string | Amostra dos valores inválidos encontrados (até 50 distintos, separados por `\|`) |
169
+ | `total_rows` | long | Total de linhas da tabela |
170
+ | `valid_rows` | long | Linhas que passaram em todas as regras da coluna |
171
+ | `invalid_rows` | long | Linhas que falharam em pelo menos uma regra (deduplificado) |
172
+ | `quality_score` | double | `valid_rows / total_rows` — entre 0.0 e 1.0 |
173
+ | `status` | string | `PASSED` se `invalid_rows == 0`, caso contrário `FAILED` |
174
+
175
+ ---
176
+
177
+ ## Plano de tratamento
178
+
179
+ Além da validação, o engine gera automaticamente o **código Spark de tratamento** sugerido para corrigir as inconsistências encontradas.
180
+
181
+ ```python
182
+ # Opção 1: calcular contexto e gerar código em uma chamada
183
+ treatment_code = engine.render_treatment_code_from_df(
184
+ df=df,
185
+ df_name="df_clientes",
186
+ )
187
+
188
+ # Opção 2: calcular contexto separadamente (evita reprocessamento)
189
+ contexts = engine.get_column_treatment_contexts(df)
190
+ treatment_code = engine.render_treatment_code(df, contexts, df_name="df_clientes")
191
+
192
+ print(treatment_code)
193
+ ```
194
+
195
+ Saída de exemplo:
196
+
197
+ ```python
198
+ df_clientes = df_clientes.select(
199
+ when(col("NOM_CLIENTE").isNull() | upper(trim(col("NOM_CLIENTE").cast("string"))).isin("NULL", "TESTE"),
200
+ lit("N/D")).otherwise(upper(trim(col("NOM_CLIENTE").cast("string")))).alias("NOM_CLIENTE"),
201
+ coalesce(col("COD_PRODUTO").cast("string"), lit("0")).alias("COD_PRODUTO"),
202
+ when(upper(col("DAT_NASCIMENTO").cast("string")).isin("0000-00-00"),
203
+ lit("1800-01-01 00:00:00").cast("timestamp")).otherwise(col("DAT_NASCIMENTO").cast("timestamp")).alias("DAT_NASCIMENTO"),
204
+ )
205
+ ```
206
+
207
+ O código gerado pode ser copiado diretamente para o notebook de tratamento.
208
+
209
+ ---
210
+
211
+ ## Como adicionar novas regras
212
+
213
+ ### 1. Criar o builder em `src/dq_engine/execution/rule_compiler.py`
214
+
215
+ ```python
216
+ def _build_minha_regra(column_name: str, rule: dict, conventions: dict) -> CompiledRule:
217
+ condition = col(column_name).isNull() # sua condição de falha
218
+
219
+ return CompiledRule(
220
+ rule_type="minha_regra",
221
+ error_code="MINHA_REGRA_INVALIDA",
222
+ error_message="Descrição do erro",
223
+ condition=condition,
224
+ suggested_treatment_category="MANUAL_REVIEW",
225
+ suggested_treatment_expression=None,
226
+ manual_review_required=True,
227
+ treatment_note="Orientação de correção.",
228
+ )
229
+ ```
230
+
231
+ ### 2. Registrar no `SparkRuleCompiler._register_default_rules()`
232
+
233
+ ```python
234
+ def _register_default_rules(self) -> None:
235
+ builders = {
236
+ # ... builders existentes ...
237
+ "minha_regra": _build_minha_regra,
238
+ }
239
+ for rule_type, builder in builders.items():
240
+ self.registry.register(rule_type, builder)
241
+ ```
242
+
243
+ ### 3. Referenciar em um rule_set em `src/dq_engine/config/conventions.py`
244
+
245
+ ```python
246
+ "rule_sets": {
247
+ "meu_rule_set": [
248
+ {"type": "string_null_pattern"},
249
+ {"type": "minha_regra"},
250
+ ],
251
+ }
252
+ ```
253
+
254
+ ### 4. Documentar em `docs/rules.md`
255
+
256
+ ---
257
+
258
+ ## Como adicionar novos prefixos
259
+
260
+ Em `src/dq_engine/config/conventions.py`, adicione uma entrada em `prefix_mapping`:
261
+
262
+ ```python
263
+ "prefix_mapping": {
264
+ # ... prefixos existentes ...
265
+ "EMAIL": "email_field",
266
+ }
267
+ ```
268
+
269
+ E defina o rule_set correspondente em `rule_sets`:
270
+
271
+ ```python
272
+ "email_field": [
273
+ {"type": "string_null_pattern"},
274
+ {"type": "regex", "pattern_ref": "email"},
275
+ ],
276
+ ```
277
+
278
+ Prefixos mais longos têm precedência automaticamente — nenhuma configuração extra necessária.
279
+
280
+ ---
281
+
282
+ ## Testes
283
+
284
+ ```bash
285
+ pytest tests/ -v
286
+ ```
287
+
288
+ Os testes cobrem:
289
+
290
+ | Arquivo | Cobertura |
291
+ |---------|-----------|
292
+ | `tests/test_resolver.py` | Resolução de prefixos, precedência, colunas sem match |
293
+ | `tests/test_rule_compiler.py` | Cada builder de regra individualmente |
294
+ | `tests/test_engine.py` | Fluxo completo de validação, quality_score, status |
295
+ | `tests/test_treatment_plan.py` | Geração de expressões e código de tratamento |
@@ -0,0 +1,35 @@
1
+ # Arquivo : pyproject.toml
2
+ # Caminho : data-quality-local/pyproject.toml
3
+
4
+ [build-system]
5
+ requires = ["setuptools>=68", "wheel"]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "dq-engine"
10
+ version = "0.3.14"
11
+ description = "Framework de validação de qualidade de dados com PySpark"
12
+ readme = "README.md"
13
+ requires-python = ">=3.10"
14
+ authors = [
15
+ { name = "Bruna Cataldo", email = "bruna.cataldo@autoglass.com.br" }
16
+ ]
17
+ dependencies = [
18
+ "pyspark>=3.4.0"
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ dev = [
23
+ "pytest>=8.0.0",
24
+ "pytest-mock>=3.12.0",
25
+ ]
26
+
27
+ [tool.setuptools]
28
+ package-dir = {"" = "src"}
29
+
30
+ [tool.setuptools.packages.find]
31
+ where = ["src"]
32
+
33
+ [tool.pytest.ini_options]
34
+ pythonpath = ["src"]
35
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ # Arquivo : __init__.py
2
+ # Caminho : data-quality-local/src/dq_engine/utils/__init__.py
3
+
4
+ from dq_engine.utils.logging import get_logger
5
+
6
+ __all__ = ["get_logger"]
@@ -0,0 +1,6 @@
1
+ # Arquivo : __init__.py
2
+ # Caminho : data-quality-local/src/dq_engine/config/__init__.py
3
+
4
+ from dq_engine.config.conventions import CONVENTIONS
5
+
6
+ __all__ = ["CONVENTIONS"]