qualipilot 2.0.0__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.
Files changed (50) hide show
  1. qualipilot-2.0.0/.gitignore +68 -0
  2. qualipilot-2.0.0/LICENSE +5 -0
  3. qualipilot-2.0.0/PKG-INFO +301 -0
  4. qualipilot-2.0.0/README.md +222 -0
  5. qualipilot-2.0.0/pyproject.toml +181 -0
  6. qualipilot-2.0.0/src/qualipilot/__init__.py +16 -0
  7. qualipilot-2.0.0/src/qualipilot/checker.py +195 -0
  8. qualipilot-2.0.0/src/qualipilot/checks/__init__.py +28 -0
  9. qualipilot-2.0.0/src/qualipilot/checks/base.py +61 -0
  10. qualipilot-2.0.0/src/qualipilot/checks/cardinality.py +42 -0
  11. qualipilot-2.0.0/src/qualipilot/checks/duplicates.py +28 -0
  12. qualipilot-2.0.0/src/qualipilot/checks/freshness.py +77 -0
  13. qualipilot-2.0.0/src/qualipilot/checks/linkage.py +73 -0
  14. qualipilot-2.0.0/src/qualipilot/checks/missing.py +43 -0
  15. qualipilot-2.0.0/src/qualipilot/checks/outliers.py +67 -0
  16. qualipilot-2.0.0/src/qualipilot/checks/ranges.py +63 -0
  17. qualipilot-2.0.0/src/qualipilot/checks/types.py +25 -0
  18. qualipilot-2.0.0/src/qualipilot/cli.py +434 -0
  19. qualipilot-2.0.0/src/qualipilot/engines/__init__.py +95 -0
  20. qualipilot-2.0.0/src/qualipilot/engines/base.py +118 -0
  21. qualipilot-2.0.0/src/qualipilot/engines/cudf_engine.py +147 -0
  22. qualipilot-2.0.0/src/qualipilot/engines/dask_engine.py +152 -0
  23. qualipilot-2.0.0/src/qualipilot/engines/duckdb_engine.py +283 -0
  24. qualipilot-2.0.0/src/qualipilot/engines/pandas_engine.py +139 -0
  25. qualipilot-2.0.0/src/qualipilot/engines/polars_engine.py +203 -0
  26. qualipilot-2.0.0/src/qualipilot/engines/spark_engine.py +245 -0
  27. qualipilot-2.0.0/src/qualipilot/lakehouse.py +116 -0
  28. qualipilot-2.0.0/src/qualipilot/lambda_handler.py +95 -0
  29. qualipilot-2.0.0/src/qualipilot/linking/__init__.py +27 -0
  30. qualipilot-2.0.0/src/qualipilot/linking/blocking.py +127 -0
  31. qualipilot-2.0.0/src/qualipilot/linking/cluster.py +54 -0
  32. qualipilot-2.0.0/src/qualipilot/linking/comparisons.py +133 -0
  33. qualipilot-2.0.0/src/qualipilot/linking/config.py +63 -0
  34. qualipilot-2.0.0/src/qualipilot/linking/duckdb_linker.py +248 -0
  35. qualipilot-2.0.0/src/qualipilot/linking/em.py +212 -0
  36. qualipilot-2.0.0/src/qualipilot/linking/linker.py +261 -0
  37. qualipilot-2.0.0/src/qualipilot/llm/__init__.py +46 -0
  38. qualipilot-2.0.0/src/qualipilot/llm/base.py +23 -0
  39. qualipilot-2.0.0/src/qualipilot/llm/bedrock.py +105 -0
  40. qualipilot-2.0.0/src/qualipilot/llm/null_provider.py +14 -0
  41. qualipilot-2.0.0/src/qualipilot/llm/ollama.py +72 -0
  42. qualipilot-2.0.0/src/qualipilot/llm/openai_compat.py +76 -0
  43. qualipilot-2.0.0/src/qualipilot/logging_setup.py +89 -0
  44. qualipilot-2.0.0/src/qualipilot/models/__init__.py +1 -0
  45. qualipilot-2.0.0/src/qualipilot/models/config.py +145 -0
  46. qualipilot-2.0.0/src/qualipilot/models/results.py +101 -0
  47. qualipilot-2.0.0/src/qualipilot/py.typed +0 -0
  48. qualipilot-2.0.0/src/qualipilot/reporting/__init__.py +6 -0
  49. qualipilot-2.0.0/src/qualipilot/reporting/html.py +84 -0
  50. qualipilot-2.0.0/src/qualipilot/reporting/markdown.py +77 -0
@@ -0,0 +1,68 @@
1
+ # bytecode
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # build/dist
8
+ build/
9
+ dist/
10
+ *.egg-info/
11
+ .eggs/
12
+ pip-wheel-metadata/
13
+
14
+ # venv
15
+ .env
16
+ .venv/
17
+ venv/
18
+ ENV/
19
+
20
+ # editors
21
+ .vscode/
22
+ .idea/
23
+ *.swp
24
+
25
+ # os
26
+ .DS_Store
27
+ Thumbs.db
28
+
29
+ # tests / coverage
30
+ .cache/
31
+ .pytest_cache/
32
+ .coverage
33
+ .coverage.*
34
+ coverage.xml
35
+ htmlcov/
36
+ .tox/
37
+ .hypothesis/
38
+
39
+ # type checkers
40
+ .mypy_cache/
41
+ .ruff_cache/
42
+ .pyre/
43
+
44
+ # notebooks
45
+ .ipynb_checkpoints
46
+
47
+ # local artefacts
48
+ results.json
49
+ data_quality_results.json
50
+ *.log
51
+ reports/
52
+ .local/
53
+
54
+ # secrets
55
+ .env.*
56
+ !.env.example
57
+ *.pem
58
+ *.key
59
+
60
+ # terraform
61
+ .terraform/
62
+ *.tfstate
63
+ *.tfstate.*
64
+ *.tfvars
65
+ !example.tfvars
66
+
67
+ # docker
68
+ .docker/
@@ -0,0 +1,5 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
2
+
3
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
4
+
5
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,301 @@
1
+ Metadata-Version: 2.4
2
+ Name: qualipilot
3
+ Version: 2.0.0
4
+ Summary: Production-grade data quality checks with pluggable LLM reporting (AWS Bedrock, Ollama, OpenAI-compatible).
5
+ Project-URL: Homepage, https://github.com/Sarvesh-GanesanW/dataqualitychecker
6
+ Project-URL: Repository, https://github.com/Sarvesh-GanesanW/dataqualitychecker
7
+ Project-URL: Issues, https://github.com/Sarvesh-GanesanW/dataqualitychecker/issues
8
+ Author-email: Sarvesh Ganesan <sarveshganesan99@gmail.com>
9
+ License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ License-File: LICENSE
15
+ Keywords: bedrock,dask,data-quality,data-validation,ollama,pandas,polars
16
+ Classifier: Development Status :: 5 - Production/Stable
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering
25
+ Classifier: Topic :: Software Development :: Quality Assurance
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.11
28
+ Requires-Dist: httpx>=0.27
29
+ Requires-Dist: pandas>=2.2
30
+ Requires-Dist: polars>=1.12
31
+ Requires-Dist: pyarrow>=17.0
32
+ Requires-Dist: pydantic-settings>=2.5
33
+ Requires-Dist: pydantic>=2.9
34
+ Requires-Dist: pyyaml>=6.0
35
+ Requires-Dist: rich>=13.8
36
+ Requires-Dist: tenacity>=9.0
37
+ Requires-Dist: typer>=0.12
38
+ Provides-Extra: all
39
+ Requires-Dist: boto3>=1.35; extra == 'all'
40
+ Requires-Dist: botocore>=1.35; extra == 'all'
41
+ Requires-Dist: dask[dataframe]>=2024.8; extra == 'all'
42
+ Requires-Dist: duckdb>=1.5; extra == 'all'
43
+ Requires-Dist: matplotlib>=3.9; extra == 'all'
44
+ Requires-Dist: numpy>=2.0; extra == 'all'
45
+ Requires-Dist: openai>=1.50; extra == 'all'
46
+ Requires-Dist: pyiceberg>=0.9; extra == 'all'
47
+ Requires-Dist: rapidfuzz>=3.9; extra == 'all'
48
+ Provides-Extra: bedrock
49
+ Requires-Dist: boto3>=1.35; extra == 'bedrock'
50
+ Requires-Dist: botocore>=1.35; extra == 'bedrock'
51
+ Provides-Extra: dask
52
+ Requires-Dist: dask[dataframe]>=2024.8; extra == 'dask'
53
+ Provides-Extra: dev
54
+ Requires-Dist: hypothesis>=6.112; extra == 'dev'
55
+ Requires-Dist: moto>=5.0; extra == 'dev'
56
+ Requires-Dist: mypy>=1.11; extra == 'dev'
57
+ Requires-Dist: pre-commit>=3.8; extra == 'dev'
58
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
59
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
60
+ Requires-Dist: pytest>=8.3; extra == 'dev'
61
+ Requires-Dist: ruff>=0.6; extra == 'dev'
62
+ Requires-Dist: types-pyyaml; extra == 'dev'
63
+ Provides-Extra: duckdb
64
+ Requires-Dist: duckdb>=1.5; extra == 'duckdb'
65
+ Provides-Extra: iceberg
66
+ Requires-Dist: pyarrow>=17; extra == 'iceberg'
67
+ Requires-Dist: pyiceberg>=0.9; extra == 'iceberg'
68
+ Provides-Extra: linking
69
+ Requires-Dist: numpy>=2.0; extra == 'linking'
70
+ Requires-Dist: rapidfuzz>=3.9; extra == 'linking'
71
+ Provides-Extra: ollama
72
+ Provides-Extra: openai
73
+ Requires-Dist: openai>=1.50; extra == 'openai'
74
+ Provides-Extra: spark
75
+ Requires-Dist: pyspark>=3.5; extra == 'spark'
76
+ Provides-Extra: viz
77
+ Requires-Dist: matplotlib>=3.9; extra == 'viz'
78
+ Description-Content-Type: text/markdown
79
+
80
+ # qualipilot
81
+
82
+ Production-grade data quality checker for Python. Runs structural and
83
+ statistical checks on any tabular dataset (CSV / Parquet / JSON / Pandas /
84
+ Polars / Dask / cuDF) and, optionally, asks an LLM — **AWS Bedrock**,
85
+ **Ollama**, or any OpenAI-compatible endpoint — to narrate the findings.
86
+
87
+ * swap engines with one flag (Polars default, Pandas/Dask/cuDF on demand)
88
+ * swap LLM providers the same way (`--llm bedrock|ollama|openai|none`)
89
+ * one-click install, docker-compose for local runs, terraform for Lambda
90
+ * typed Pydantic results, deterministic JSON output, exit-code severity
91
+ gate for CI pipelines
92
+
93
+ ---
94
+
95
+ ## Install
96
+
97
+ ### One-click (recommended)
98
+
99
+ ```bash
100
+ # macOS / Linux
101
+ ./install.sh --all # core + every optional extra
102
+ ./install.sh --bedrock # core + boto3
103
+ ./install.sh --dev # editable + dev + pre-commit
104
+
105
+ # Windows PowerShell
106
+ .\install.ps1 -Extras all
107
+ ```
108
+
109
+ ### Manual
110
+
111
+ ```bash
112
+ pip install qualipilot # core
113
+ pip install "qualipilot[bedrock]" # + boto3 for AWS Bedrock
114
+ pip install "qualipilot[ollama]" # + httpx (already core)
115
+ pip install "qualipilot[dask]" # + dask[dataframe]
116
+ pip install "qualipilot[all]" # everything except cuDF
117
+ ```
118
+
119
+ cuDF (GPU) needs the RAPIDS conda channel — see
120
+ [docs.rapids.ai/install](https://docs.rapids.ai/install).
121
+
122
+ ---
123
+
124
+ ## Quickstart (CLI)
125
+
126
+ ```bash
127
+ qualipilot check data.csv \
128
+ --engine polars \
129
+ --range amount=0,100000 \
130
+ --output reports/data.quality.html \
131
+ --llm bedrock \
132
+ --model anthropic.claude-3-5-haiku-20241022-v1:0 \
133
+ --region us-east-1 \
134
+ --fail-on warn
135
+ ```
136
+
137
+ * `--output` can be `.json`, `.html`, or `.md`; format is inferred.
138
+ * `--fail-on {ok,warn,error}` decides when the CLI returns a non-zero
139
+ exit code — wire it straight into CI.
140
+ * All flags have `--config` equivalents; see `examples/config.yaml`.
141
+
142
+ ## Quickstart (Python)
143
+
144
+ ```python
145
+ import pandas as pd
146
+ from qualipilot import DataQualityChecker, QualipilotConfig
147
+ from qualipilot.models.config import CheckConfig, ColumnRange, LLMConfig
148
+
149
+ df = pd.read_csv("orders.csv")
150
+
151
+ config = QualipilotConfig(
152
+ engine="polars",
153
+ checks=CheckConfig(
154
+ column_ranges={"amount": ColumnRange(min=0, max=100_000)},
155
+ ),
156
+ llm=LLMConfig(
157
+ provider="bedrock",
158
+ model="anthropic.claude-3-5-haiku-20241022-v1:0",
159
+ region="us-east-1",
160
+ ),
161
+ )
162
+
163
+ report = DataQualityChecker(df, config).run()
164
+ print(report.to_json())
165
+ print(report.llm_report)
166
+ ```
167
+
168
+ ---
169
+
170
+ ## What it checks
171
+
172
+ | Check | Default | Description |
173
+ |---|---|---|
174
+ | `missing_values` | on | per-column null counts + percentage |
175
+ | `duplicates` | on | global duplicate rows (subset-aware) |
176
+ | `data_types` | on | dtype rollup per column |
177
+ | `outliers` | on | IQR rule, Q1/Q3 computed in one pass |
178
+ | `ranges` | on | user-supplied `[min, max]` per column |
179
+ | `cardinality` | on | distinct count + top-10 values |
180
+ | `freshness` | off | max-timestamp vs `freshness_max_age_hours` |
181
+
182
+ Each check returns a typed `CheckResult` with severity `ok / warn /
183
+ error`, a duration, a JSON-safe payload, and any captured exception.
184
+
185
+ ---
186
+
187
+ ## Engines
188
+
189
+ | Engine | When to use |
190
+ |---|---|
191
+ | `polars` (default) | in-memory data up to ~10 GB — 8× faster than pandas |
192
+ | `pandas` | legacy integrations that need pandas-native output |
193
+ | `dask` | larger-than-memory data or multi-worker clusters |
194
+ | `cudf` | single-node GPU acceleration (RAPIDS required) |
195
+
196
+ `--engine auto` inspects the input object and picks the fastest safe
197
+ backend (Polars for single-node, Dask for already-Dask frames, cuDF
198
+ when a GPU frame is handed in).
199
+
200
+ ---
201
+
202
+ ## LLM providers
203
+
204
+ | Provider | `--llm` | Required |
205
+ |---|---|---|
206
+ | None (default) | `none` | nothing |
207
+ | AWS Bedrock (Converse API) | `bedrock` | `boto3`, IAM `bedrock:Converse` |
208
+ | Ollama | `ollama` | running ollama server |
209
+ | OpenAI-compatible | `openai` | base URL + API key |
210
+
211
+ Bedrock uses the **Converse API**, so the same code path works for
212
+ Anthropic Claude, Meta Llama, Mistral, Cohere, etc. — you just change
213
+ `model=...`.
214
+
215
+ ---
216
+
217
+ ## Deploy
218
+
219
+ ### Docker (local Ollama stack)
220
+
221
+ ```bash
222
+ docker compose -f docker/docker-compose.yml up --build
223
+ ```
224
+
225
+ This brings up `ollama` and a `qualipilot` container wired to it, and
226
+ runs the sample check end-to-end.
227
+
228
+ ### AWS Lambda (container image)
229
+
230
+ ```bash
231
+ cd deploy/terraform
232
+ terraform init
233
+ terraform apply -var project=qualipilot -var aws_profile=sre-tea
234
+
235
+ # build + push the image to the ECR repo terraform just made
236
+ aws ecr get-login-password | docker login --username AWS --password-stdin \
237
+ $(terraform output -raw ecr_repository_url | cut -d/ -f1)
238
+ docker build -f ../../docker/Dockerfile.lambda -t qualipilot-lambda:latest ../..
239
+ docker tag qualipilot-lambda:latest "$(terraform output -raw ecr_repository_url):latest"
240
+ docker push "$(terraform output -raw ecr_repository_url):latest"
241
+
242
+ aws lambda update-function-code \
243
+ --function-name qualipilot \
244
+ --image-uri "$(terraform output -raw ecr_repository_url):latest"
245
+ ```
246
+
247
+ Invoke with:
248
+
249
+ ```bash
250
+ aws lambda invoke \
251
+ --function-name qualipilot \
252
+ --payload '{"s3_uri":"s3://my-bucket/events.parquet"}' \
253
+ response.json
254
+ ```
255
+
256
+ Report lands at `s3://my-bucket/reports/events.quality.json`.
257
+
258
+ ---
259
+
260
+ ## Development
261
+
262
+ ```bash
263
+ ./install.sh --dev
264
+ make lint typecheck test
265
+ ```
266
+
267
+ * Ruff for lint + format, MyPy in strict mode, pytest with coverage.
268
+ * Pre-commit runs the same locally before every commit.
269
+ * `pytest -m integration` runs tests that need real AWS/Bedrock credentials.
270
+
271
+ ---
272
+
273
+ ## Record linkage / probabilistic dedup
274
+
275
+ Beyond exact duplicates, qualipilot ships an in-house Fellegi-Sunter
276
+ linker — no external splink dependency. Polars blocking, rapidfuzz
277
+ string distance, numpy EM. 1M rows in ~10 s on a laptop.
278
+
279
+ ```bash
280
+ qualipilot link customers.csv \
281
+ --id customer_id \
282
+ --compare "name:fuzzy:0.92,0.75" \
283
+ --compare "postcode:exact" \
284
+ --block "postcode" \
285
+ --threshold 0.9
286
+ ```
287
+
288
+ Full details: [`docs/LINKING.md`](docs/LINKING.md).
289
+
290
+ ## Docs
291
+
292
+ * [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — module layout + data flow
293
+ * [`docs/LINKING.md`](docs/LINKING.md) — probabilistic dedup / linkage
294
+ * [`docs/DEEP_DIVE.md`](docs/DEEP_DIVE.md) — audit of the v1 codebase
295
+ * [`docs/DEPLOY.md`](docs/DEPLOY.md) — cloud + on-prem deployment notes
296
+ * [`docs/MIGRATION.md`](docs/MIGRATION.md) — upgrading from v1.x
297
+ * [`docs/RUST_CONVERSION.md`](docs/RUST_CONVERSION.md) — should we port to Rust? (tldr: hybrid, not rewrite)
298
+
299
+ ## License
300
+
301
+ MIT.
@@ -0,0 +1,222 @@
1
+ # qualipilot
2
+
3
+ Production-grade data quality checker for Python. Runs structural and
4
+ statistical checks on any tabular dataset (CSV / Parquet / JSON / Pandas /
5
+ Polars / Dask / cuDF) and, optionally, asks an LLM — **AWS Bedrock**,
6
+ **Ollama**, or any OpenAI-compatible endpoint — to narrate the findings.
7
+
8
+ * swap engines with one flag (Polars default, Pandas/Dask/cuDF on demand)
9
+ * swap LLM providers the same way (`--llm bedrock|ollama|openai|none`)
10
+ * one-click install, docker-compose for local runs, terraform for Lambda
11
+ * typed Pydantic results, deterministic JSON output, exit-code severity
12
+ gate for CI pipelines
13
+
14
+ ---
15
+
16
+ ## Install
17
+
18
+ ### One-click (recommended)
19
+
20
+ ```bash
21
+ # macOS / Linux
22
+ ./install.sh --all # core + every optional extra
23
+ ./install.sh --bedrock # core + boto3
24
+ ./install.sh --dev # editable + dev + pre-commit
25
+
26
+ # Windows PowerShell
27
+ .\install.ps1 -Extras all
28
+ ```
29
+
30
+ ### Manual
31
+
32
+ ```bash
33
+ pip install qualipilot # core
34
+ pip install "qualipilot[bedrock]" # + boto3 for AWS Bedrock
35
+ pip install "qualipilot[ollama]" # + httpx (already core)
36
+ pip install "qualipilot[dask]" # + dask[dataframe]
37
+ pip install "qualipilot[all]" # everything except cuDF
38
+ ```
39
+
40
+ cuDF (GPU) needs the RAPIDS conda channel — see
41
+ [docs.rapids.ai/install](https://docs.rapids.ai/install).
42
+
43
+ ---
44
+
45
+ ## Quickstart (CLI)
46
+
47
+ ```bash
48
+ qualipilot check data.csv \
49
+ --engine polars \
50
+ --range amount=0,100000 \
51
+ --output reports/data.quality.html \
52
+ --llm bedrock \
53
+ --model anthropic.claude-3-5-haiku-20241022-v1:0 \
54
+ --region us-east-1 \
55
+ --fail-on warn
56
+ ```
57
+
58
+ * `--output` can be `.json`, `.html`, or `.md`; format is inferred.
59
+ * `--fail-on {ok,warn,error}` decides when the CLI returns a non-zero
60
+ exit code — wire it straight into CI.
61
+ * All flags have `--config` equivalents; see `examples/config.yaml`.
62
+
63
+ ## Quickstart (Python)
64
+
65
+ ```python
66
+ import pandas as pd
67
+ from qualipilot import DataQualityChecker, QualipilotConfig
68
+ from qualipilot.models.config import CheckConfig, ColumnRange, LLMConfig
69
+
70
+ df = pd.read_csv("orders.csv")
71
+
72
+ config = QualipilotConfig(
73
+ engine="polars",
74
+ checks=CheckConfig(
75
+ column_ranges={"amount": ColumnRange(min=0, max=100_000)},
76
+ ),
77
+ llm=LLMConfig(
78
+ provider="bedrock",
79
+ model="anthropic.claude-3-5-haiku-20241022-v1:0",
80
+ region="us-east-1",
81
+ ),
82
+ )
83
+
84
+ report = DataQualityChecker(df, config).run()
85
+ print(report.to_json())
86
+ print(report.llm_report)
87
+ ```
88
+
89
+ ---
90
+
91
+ ## What it checks
92
+
93
+ | Check | Default | Description |
94
+ |---|---|---|
95
+ | `missing_values` | on | per-column null counts + percentage |
96
+ | `duplicates` | on | global duplicate rows (subset-aware) |
97
+ | `data_types` | on | dtype rollup per column |
98
+ | `outliers` | on | IQR rule, Q1/Q3 computed in one pass |
99
+ | `ranges` | on | user-supplied `[min, max]` per column |
100
+ | `cardinality` | on | distinct count + top-10 values |
101
+ | `freshness` | off | max-timestamp vs `freshness_max_age_hours` |
102
+
103
+ Each check returns a typed `CheckResult` with severity `ok / warn /
104
+ error`, a duration, a JSON-safe payload, and any captured exception.
105
+
106
+ ---
107
+
108
+ ## Engines
109
+
110
+ | Engine | When to use |
111
+ |---|---|
112
+ | `polars` (default) | in-memory data up to ~10 GB — 8× faster than pandas |
113
+ | `pandas` | legacy integrations that need pandas-native output |
114
+ | `dask` | larger-than-memory data or multi-worker clusters |
115
+ | `cudf` | single-node GPU acceleration (RAPIDS required) |
116
+
117
+ `--engine auto` inspects the input object and picks the fastest safe
118
+ backend (Polars for single-node, Dask for already-Dask frames, cuDF
119
+ when a GPU frame is handed in).
120
+
121
+ ---
122
+
123
+ ## LLM providers
124
+
125
+ | Provider | `--llm` | Required |
126
+ |---|---|---|
127
+ | None (default) | `none` | nothing |
128
+ | AWS Bedrock (Converse API) | `bedrock` | `boto3`, IAM `bedrock:Converse` |
129
+ | Ollama | `ollama` | running ollama server |
130
+ | OpenAI-compatible | `openai` | base URL + API key |
131
+
132
+ Bedrock uses the **Converse API**, so the same code path works for
133
+ Anthropic Claude, Meta Llama, Mistral, Cohere, etc. — you just change
134
+ `model=...`.
135
+
136
+ ---
137
+
138
+ ## Deploy
139
+
140
+ ### Docker (local Ollama stack)
141
+
142
+ ```bash
143
+ docker compose -f docker/docker-compose.yml up --build
144
+ ```
145
+
146
+ This brings up `ollama` and a `qualipilot` container wired to it, and
147
+ runs the sample check end-to-end.
148
+
149
+ ### AWS Lambda (container image)
150
+
151
+ ```bash
152
+ cd deploy/terraform
153
+ terraform init
154
+ terraform apply -var project=qualipilot -var aws_profile=sre-tea
155
+
156
+ # build + push the image to the ECR repo terraform just made
157
+ aws ecr get-login-password | docker login --username AWS --password-stdin \
158
+ $(terraform output -raw ecr_repository_url | cut -d/ -f1)
159
+ docker build -f ../../docker/Dockerfile.lambda -t qualipilot-lambda:latest ../..
160
+ docker tag qualipilot-lambda:latest "$(terraform output -raw ecr_repository_url):latest"
161
+ docker push "$(terraform output -raw ecr_repository_url):latest"
162
+
163
+ aws lambda update-function-code \
164
+ --function-name qualipilot \
165
+ --image-uri "$(terraform output -raw ecr_repository_url):latest"
166
+ ```
167
+
168
+ Invoke with:
169
+
170
+ ```bash
171
+ aws lambda invoke \
172
+ --function-name qualipilot \
173
+ --payload '{"s3_uri":"s3://my-bucket/events.parquet"}' \
174
+ response.json
175
+ ```
176
+
177
+ Report lands at `s3://my-bucket/reports/events.quality.json`.
178
+
179
+ ---
180
+
181
+ ## Development
182
+
183
+ ```bash
184
+ ./install.sh --dev
185
+ make lint typecheck test
186
+ ```
187
+
188
+ * Ruff for lint + format, MyPy in strict mode, pytest with coverage.
189
+ * Pre-commit runs the same locally before every commit.
190
+ * `pytest -m integration` runs tests that need real AWS/Bedrock credentials.
191
+
192
+ ---
193
+
194
+ ## Record linkage / probabilistic dedup
195
+
196
+ Beyond exact duplicates, qualipilot ships an in-house Fellegi-Sunter
197
+ linker — no external splink dependency. Polars blocking, rapidfuzz
198
+ string distance, numpy EM. 1M rows in ~10 s on a laptop.
199
+
200
+ ```bash
201
+ qualipilot link customers.csv \
202
+ --id customer_id \
203
+ --compare "name:fuzzy:0.92,0.75" \
204
+ --compare "postcode:exact" \
205
+ --block "postcode" \
206
+ --threshold 0.9
207
+ ```
208
+
209
+ Full details: [`docs/LINKING.md`](docs/LINKING.md).
210
+
211
+ ## Docs
212
+
213
+ * [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — module layout + data flow
214
+ * [`docs/LINKING.md`](docs/LINKING.md) — probabilistic dedup / linkage
215
+ * [`docs/DEEP_DIVE.md`](docs/DEEP_DIVE.md) — audit of the v1 codebase
216
+ * [`docs/DEPLOY.md`](docs/DEPLOY.md) — cloud + on-prem deployment notes
217
+ * [`docs/MIGRATION.md`](docs/MIGRATION.md) — upgrading from v1.x
218
+ * [`docs/RUST_CONVERSION.md`](docs/RUST_CONVERSION.md) — should we port to Rust? (tldr: hybrid, not rewrite)
219
+
220
+ ## License
221
+
222
+ MIT.