scherlok 0.1.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.
- scherlok-0.1.0/.github/workflows/ci.yml +27 -0
- scherlok-0.1.0/.github/workflows/release.yml +35 -0
- scherlok-0.1.0/.gitignore +39 -0
- scherlok-0.1.0/CONTRIBUTING.md +52 -0
- scherlok-0.1.0/LICENSE +21 -0
- scherlok-0.1.0/PKG-INFO +235 -0
- scherlok-0.1.0/README.md +205 -0
- scherlok-0.1.0/pyproject.toml +57 -0
- scherlok-0.1.0/src/scherlok/__init__.py +3 -0
- scherlok-0.1.0/src/scherlok/alerter/__init__.py +1 -0
- scherlok-0.1.0/src/scherlok/alerter/console.py +73 -0
- scherlok-0.1.0/src/scherlok/alerter/exitcode.py +11 -0
- scherlok-0.1.0/src/scherlok/alerter/slack.py +52 -0
- scherlok-0.1.0/src/scherlok/cli.py +351 -0
- scherlok-0.1.0/src/scherlok/config.py +59 -0
- scherlok-0.1.0/src/scherlok/connectors/__init__.py +32 -0
- scherlok-0.1.0/src/scherlok/connectors/base.py +41 -0
- scherlok-0.1.0/src/scherlok/connectors/bigquery.py +160 -0
- scherlok-0.1.0/src/scherlok/connectors/postgres.py +131 -0
- scherlok-0.1.0/src/scherlok/detector/__init__.py +1 -0
- scherlok-0.1.0/src/scherlok/detector/anomaly.py +81 -0
- scherlok-0.1.0/src/scherlok/detector/cardinality.py +57 -0
- scherlok-0.1.0/src/scherlok/detector/distribution_shift.py +50 -0
- scherlok-0.1.0/src/scherlok/detector/freshness.py +56 -0
- scherlok-0.1.0/src/scherlok/detector/nullability.py +55 -0
- scherlok-0.1.0/src/scherlok/detector/schema_drift.py +55 -0
- scherlok-0.1.0/src/scherlok/detector/severity.py +46 -0
- scherlok-0.1.0/src/scherlok/profiler/__init__.py +1 -0
- scherlok-0.1.0/src/scherlok/profiler/distribution.py +26 -0
- scherlok-0.1.0/src/scherlok/profiler/freshness.py +26 -0
- scherlok-0.1.0/src/scherlok/profiler/schema.py +13 -0
- scherlok-0.1.0/src/scherlok/profiler/volume.py +18 -0
- scherlok-0.1.0/src/scherlok/store/__init__.py +1 -0
- scherlok-0.1.0/src/scherlok/store/remote.py +166 -0
- scherlok-0.1.0/src/scherlok/store/sqlite.py +143 -0
- scherlok-0.1.0/tests/__init__.py +0 -0
- scherlok-0.1.0/tests/test_alerter.py +77 -0
- scherlok-0.1.0/tests/test_bigquery.py +106 -0
- scherlok-0.1.0/tests/test_cli.py +53 -0
- scherlok-0.1.0/tests/test_config.py +62 -0
- scherlok-0.1.0/tests/test_connector.py +37 -0
- scherlok-0.1.0/tests/test_detector.py +294 -0
- scherlok-0.1.0/tests/test_profiler.py +97 -0
- scherlok-0.1.0/tests/test_store.py +91 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
python-version: ["3.10", "3.12"]
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: ${{ matrix.python-version }}
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: |
|
|
21
|
+
pip install -e ".[dev]"
|
|
22
|
+
|
|
23
|
+
- name: Lint
|
|
24
|
+
run: ruff check src/ tests/
|
|
25
|
+
|
|
26
|
+
- name: Test
|
|
27
|
+
run: pytest tests/ -v
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- run: ruff check src/ tests/
|
|
21
|
+
- run: pytest tests/ -v
|
|
22
|
+
|
|
23
|
+
publish:
|
|
24
|
+
needs: test
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
permissions:
|
|
27
|
+
id-token: write # trusted publishing
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
- run: pip install build
|
|
34
|
+
- run: python -m build
|
|
35
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
*.egg
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
ENV/
|
|
17
|
+
|
|
18
|
+
# IDE
|
|
19
|
+
.idea/
|
|
20
|
+
.vscode/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
|
|
24
|
+
# Environment
|
|
25
|
+
.env
|
|
26
|
+
.env.local
|
|
27
|
+
|
|
28
|
+
# Testing
|
|
29
|
+
.pytest_cache/
|
|
30
|
+
.coverage
|
|
31
|
+
htmlcov/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
# Scherlok local data
|
|
38
|
+
docs/
|
|
39
|
+
scripts/claude/tmp/
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Contributing to Scherlok
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing to Scherlok!
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Clone the repo
|
|
9
|
+
git clone https://github.com/rbmuller/scherlok.git
|
|
10
|
+
cd scherlok
|
|
11
|
+
|
|
12
|
+
# Create virtual environment
|
|
13
|
+
python -m venv .venv
|
|
14
|
+
source .venv/bin/activate
|
|
15
|
+
|
|
16
|
+
# Install in development mode
|
|
17
|
+
pip install -e ".[dev]"
|
|
18
|
+
|
|
19
|
+
# Run tests
|
|
20
|
+
pytest tests/ -v
|
|
21
|
+
|
|
22
|
+
# Run linter
|
|
23
|
+
ruff check src/ tests/
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Code Standards
|
|
27
|
+
|
|
28
|
+
- Python 3.10+ with type hints on all function signatures
|
|
29
|
+
- Docstrings on all public functions
|
|
30
|
+
- Use `pathlib` for file paths
|
|
31
|
+
- Use `rich` for terminal output
|
|
32
|
+
- Follow conventional commits for commit messages
|
|
33
|
+
|
|
34
|
+
## Adding a New Connector
|
|
35
|
+
|
|
36
|
+
1. Create a new module in `src/scherlok/connectors/`
|
|
37
|
+
2. Extend `BaseConnector` from `connectors/base.py`
|
|
38
|
+
3. Register the scheme in `connectors/__init__.py`
|
|
39
|
+
4. Add tests in `tests/test_connector.py`
|
|
40
|
+
|
|
41
|
+
## Adding a New Alerter
|
|
42
|
+
|
|
43
|
+
1. Create a new module in `src/scherlok/alerter/`
|
|
44
|
+
2. Follow the pattern from `alerter/slack.py` or `alerter/console.py`
|
|
45
|
+
3. Add tests
|
|
46
|
+
|
|
47
|
+
## Pull Requests
|
|
48
|
+
|
|
49
|
+
- Create a branch from `main`
|
|
50
|
+
- Write tests for new functionality
|
|
51
|
+
- Make sure `pytest` and `ruff check` pass
|
|
52
|
+
- Open a PR with a clear description
|
scherlok-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robson Bayer Müller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
scherlok-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scherlok
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A detective for your data. Zero-config data quality monitoring.
|
|
5
|
+
Project-URL: Homepage, https://github.com/rbmuller/scherlok
|
|
6
|
+
Project-URL: Repository, https://github.com/rbmuller/scherlok
|
|
7
|
+
Project-URL: Issues, https://github.com/rbmuller/scherlok/issues
|
|
8
|
+
Author-email: Robson Muller <robson@tbdcdata.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: anomaly-detection,data-engineering,data-quality,monitoring
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Database
|
|
17
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: psycopg2-binary>=2.9.0
|
|
20
|
+
Requires-Dist: requests>=2.28.0
|
|
21
|
+
Requires-Dist: rich>=13.0.0
|
|
22
|
+
Requires-Dist: typer>=0.9.0
|
|
23
|
+
Provides-Extra: bigquery
|
|
24
|
+
Requires-Dist: google-cloud-bigquery>=3.0.0; extra == 'bigquery'
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
<div align="center">
|
|
32
|
+
|
|
33
|
+
<img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=white" alt="Python 3.10+">
|
|
34
|
+
<img src="https://img.shields.io/pypi/v/scherlok?color=green" alt="PyPI">
|
|
35
|
+
<img src="https://img.shields.io/github/license/rbmuller/scherlok" alt="MIT License">
|
|
36
|
+
<a href="https://github.com/rbmuller/scherlok/actions/workflows/ci.yml"><img src="https://github.com/rbmuller/scherlok/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
37
|
+
|
|
38
|
+
<br><br>
|
|
39
|
+
|
|
40
|
+
<h1>Scherlok</h1>
|
|
41
|
+
|
|
42
|
+
<p><strong>Your data broke in production. Again.</strong><br>
|
|
43
|
+
Scherlok makes sure it doesn't happen next time.</p>
|
|
44
|
+
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install scherlok
|
|
49
|
+
scherlok connect postgres://localhost/mydb
|
|
50
|
+
scherlok investigate
|
|
51
|
+
scherlok watch
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
<div align="center">
|
|
55
|
+
|
|
56
|
+
**Zero config. Zero YAML. Zero rules to write.**<br>
|
|
57
|
+
Scherlok learns what "normal" looks like, then tells you when something changes.
|
|
58
|
+
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## The Problem
|
|
64
|
+
|
|
65
|
+
Every data team has the same nightmare:
|
|
66
|
+
|
|
67
|
+
> A source API silently changes from **dollars to cents**. Revenue dashboards show wrong numbers for **3 weeks** before anyone notices.
|
|
68
|
+
>
|
|
69
|
+
> A column starts returning **NULLs**. A table stops updating. Row counts drop **40% on a Tuesday**. Nobody knows until the CEO asks why the report looks weird.
|
|
70
|
+
|
|
71
|
+
Current tools (Great Expectations, Soda, dbt tests) require you to **define what "correct" looks like** before you can detect what's wrong. Hundreds of rules. Dozens of YAML files. And you still miss things — because you can't write rules for problems you haven't imagined yet.
|
|
72
|
+
|
|
73
|
+
## The Solution
|
|
74
|
+
|
|
75
|
+
Scherlok takes the opposite approach: **learn first, then detect.**
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
scherlok connect postgres://user:pass@host/db # connect once
|
|
79
|
+
scherlok investigate # learn your data
|
|
80
|
+
scherlok watch # detect anomalies
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Three commands. Five minutes. Done.
|
|
84
|
+
|
|
85
|
+
## What It Catches
|
|
86
|
+
|
|
87
|
+
| Anomaly | What Happened | Severity |
|
|
88
|
+
|---------|---------------|----------|
|
|
89
|
+
| **Volume drop** | Row count dropped 40% overnight | CRITICAL |
|
|
90
|
+
| **Volume spike** | 3x more rows than normal | WARNING |
|
|
91
|
+
| **Freshness alert** | Table hasn't updated in 12h (normally every 2h) | CRITICAL |
|
|
92
|
+
| **Schema drift** | Column removed or type changed | CRITICAL |
|
|
93
|
+
| **NULL surge** | NULL rate jumped from 2% to 45% | WARNING |
|
|
94
|
+
| **Distribution shift** | Column mean shifted 5+ standard deviations | WARNING |
|
|
95
|
+
| **Cardinality explosion** | Status column went from 5 values to 500 | CRITICAL |
|
|
96
|
+
|
|
97
|
+
Every anomaly is auto-scored: **INFO**, **WARNING**, or **CRITICAL**. No thresholds to configure.
|
|
98
|
+
|
|
99
|
+
## How It Works
|
|
100
|
+
|
|
101
|
+
### 1. `investigate` — Learn the patterns
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
$ scherlok investigate
|
|
105
|
+
|
|
106
|
+
Profiling 12 tables...
|
|
107
|
+
✓ users — 45,231 rows, 8 columns
|
|
108
|
+
✓ orders — 1,203,847 rows, 15 columns
|
|
109
|
+
✓ products — 892 rows, 12 columns
|
|
110
|
+
...
|
|
111
|
+
Done. Profiles saved.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Scherlok profiles every table: row counts, column types, NULL rates, value distributions, freshness cadence, cardinality. Stores everything locally in SQLite.
|
|
115
|
+
|
|
116
|
+
### 2. `watch` — Detect anomalies
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
$ scherlok watch
|
|
120
|
+
|
|
121
|
+
Checking 12 tables against learned profiles...
|
|
122
|
+
|
|
123
|
+
🔴 CRITICAL orders volume_drop Row count dropped 52% (1,203,847 → 578,412)
|
|
124
|
+
🟡 WARNING users null_increase Column "email": NULL rate 2.1% → 18.7%
|
|
125
|
+
🔵 INFO products distribution Column "price": mean shifted 3.2σ
|
|
126
|
+
|
|
127
|
+
3 anomalies detected. Exit code: 1
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. Alert — Slack, CI/CD, or both
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Slack alerts
|
|
134
|
+
scherlok watch --slack https://hooks.slack.com/services/...
|
|
135
|
+
|
|
136
|
+
# CI/CD gate (fails pipeline on CRITICAL)
|
|
137
|
+
scherlok watch --exit-code --fail-on critical
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## CI/CD Integration
|
|
141
|
+
|
|
142
|
+
Use Scherlok as a data quality gate:
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
# GitHub Actions
|
|
146
|
+
- name: Data quality check
|
|
147
|
+
run: |
|
|
148
|
+
pip install scherlok
|
|
149
|
+
scherlok connect ${{ secrets.DATABASE_URL }}
|
|
150
|
+
scherlok watch --exit-code --fail-on critical
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
If Scherlok detects a critical anomaly, the pipeline fails. Bad data never reaches production.
|
|
154
|
+
|
|
155
|
+
## Connectors
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# PostgreSQL
|
|
159
|
+
scherlok connect postgres://user:pass@host:5432/db
|
|
160
|
+
|
|
161
|
+
# BigQuery
|
|
162
|
+
pip install scherlok[bigquery]
|
|
163
|
+
scherlok connect bigquery://project-id/dataset-name
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
| Database | Status |
|
|
167
|
+
|----------|--------|
|
|
168
|
+
| PostgreSQL | Available |
|
|
169
|
+
| BigQuery | Available |
|
|
170
|
+
| Snowflake | Coming soon |
|
|
171
|
+
| MySQL | Coming soon |
|
|
172
|
+
| DuckDB | Planned |
|
|
173
|
+
|
|
174
|
+
## Remote Storage
|
|
175
|
+
|
|
176
|
+
Share profiles across CI runs and team members:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# AWS S3
|
|
180
|
+
scherlok config --store s3://my-bucket/scherlok/profiles.db
|
|
181
|
+
|
|
182
|
+
# Google Cloud Storage
|
|
183
|
+
scherlok config --store gs://my-bucket/scherlok/profiles.db
|
|
184
|
+
|
|
185
|
+
# Azure Blob Storage
|
|
186
|
+
scherlok config --store az://my-container/scherlok/profiles.db
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Why Not [Other Tool]?
|
|
190
|
+
|
|
191
|
+
| | Great Expectations | Soda | Monte Carlo | **Scherlok** |
|
|
192
|
+
|---|---|---|---|---|
|
|
193
|
+
| Setup time | Hours | 30 min | Weeks | **5 minutes** |
|
|
194
|
+
| Config required | Hundreds of rules | YAML checks | Dashboard setup | **None** |
|
|
195
|
+
| Anomaly detection | Manual thresholds | Paid feature | Yes | **Yes, free** |
|
|
196
|
+
| Self-hosted | Yes | Limited | No (SaaS) | **Yes** |
|
|
197
|
+
| CI/CD gate | Yes | Yes | No | **Yes** |
|
|
198
|
+
| Price | Free | Freemium | $50-200K/yr | **Free, forever** |
|
|
199
|
+
|
|
200
|
+
## CLI Reference
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
scherlok connect <url> Connect to a database
|
|
204
|
+
scherlok investigate Profile all tables (learn patterns)
|
|
205
|
+
scherlok watch Detect anomalies and alert
|
|
206
|
+
scherlok status Quick health dashboard
|
|
207
|
+
scherlok report Detailed profile summary
|
|
208
|
+
scherlok history [--days N] Timeline of past anomalies
|
|
209
|
+
scherlok config --store <url> Set remote storage
|
|
210
|
+
scherlok version Show version
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Install
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
pip install scherlok
|
|
217
|
+
|
|
218
|
+
# With BigQuery support
|
|
219
|
+
pip install scherlok[bigquery]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Requires Python 3.10+.
|
|
223
|
+
|
|
224
|
+
## Contributing
|
|
225
|
+
|
|
226
|
+
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
227
|
+
|
|
228
|
+
We're especially looking for:
|
|
229
|
+
- New database connectors (Snowflake, MySQL, DuckDB)
|
|
230
|
+
- Anomaly detection improvements
|
|
231
|
+
- Documentation and examples
|
|
232
|
+
|
|
233
|
+
## License
|
|
234
|
+
|
|
235
|
+
[MIT](LICENSE) — Developed by [Robson Bayer Müller](https://github.com/rbmuller)
|
scherlok-0.1.0/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=white" alt="Python 3.10+">
|
|
4
|
+
<img src="https://img.shields.io/pypi/v/scherlok?color=green" alt="PyPI">
|
|
5
|
+
<img src="https://img.shields.io/github/license/rbmuller/scherlok" alt="MIT License">
|
|
6
|
+
<a href="https://github.com/rbmuller/scherlok/actions/workflows/ci.yml"><img src="https://github.com/rbmuller/scherlok/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
7
|
+
|
|
8
|
+
<br><br>
|
|
9
|
+
|
|
10
|
+
<h1>Scherlok</h1>
|
|
11
|
+
|
|
12
|
+
<p><strong>Your data broke in production. Again.</strong><br>
|
|
13
|
+
Scherlok makes sure it doesn't happen next time.</p>
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install scherlok
|
|
19
|
+
scherlok connect postgres://localhost/mydb
|
|
20
|
+
scherlok investigate
|
|
21
|
+
scherlok watch
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
<div align="center">
|
|
25
|
+
|
|
26
|
+
**Zero config. Zero YAML. Zero rules to write.**<br>
|
|
27
|
+
Scherlok learns what "normal" looks like, then tells you when something changes.
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## The Problem
|
|
34
|
+
|
|
35
|
+
Every data team has the same nightmare:
|
|
36
|
+
|
|
37
|
+
> A source API silently changes from **dollars to cents**. Revenue dashboards show wrong numbers for **3 weeks** before anyone notices.
|
|
38
|
+
>
|
|
39
|
+
> A column starts returning **NULLs**. A table stops updating. Row counts drop **40% on a Tuesday**. Nobody knows until the CEO asks why the report looks weird.
|
|
40
|
+
|
|
41
|
+
Current tools (Great Expectations, Soda, dbt tests) require you to **define what "correct" looks like** before you can detect what's wrong. Hundreds of rules. Dozens of YAML files. And you still miss things — because you can't write rules for problems you haven't imagined yet.
|
|
42
|
+
|
|
43
|
+
## The Solution
|
|
44
|
+
|
|
45
|
+
Scherlok takes the opposite approach: **learn first, then detect.**
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
scherlok connect postgres://user:pass@host/db # connect once
|
|
49
|
+
scherlok investigate # learn your data
|
|
50
|
+
scherlok watch # detect anomalies
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Three commands. Five minutes. Done.
|
|
54
|
+
|
|
55
|
+
## What It Catches
|
|
56
|
+
|
|
57
|
+
| Anomaly | What Happened | Severity |
|
|
58
|
+
|---------|---------------|----------|
|
|
59
|
+
| **Volume drop** | Row count dropped 40% overnight | CRITICAL |
|
|
60
|
+
| **Volume spike** | 3x more rows than normal | WARNING |
|
|
61
|
+
| **Freshness alert** | Table hasn't updated in 12h (normally every 2h) | CRITICAL |
|
|
62
|
+
| **Schema drift** | Column removed or type changed | CRITICAL |
|
|
63
|
+
| **NULL surge** | NULL rate jumped from 2% to 45% | WARNING |
|
|
64
|
+
| **Distribution shift** | Column mean shifted 5+ standard deviations | WARNING |
|
|
65
|
+
| **Cardinality explosion** | Status column went from 5 values to 500 | CRITICAL |
|
|
66
|
+
|
|
67
|
+
Every anomaly is auto-scored: **INFO**, **WARNING**, or **CRITICAL**. No thresholds to configure.
|
|
68
|
+
|
|
69
|
+
## How It Works
|
|
70
|
+
|
|
71
|
+
### 1. `investigate` — Learn the patterns
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
$ scherlok investigate
|
|
75
|
+
|
|
76
|
+
Profiling 12 tables...
|
|
77
|
+
✓ users — 45,231 rows, 8 columns
|
|
78
|
+
✓ orders — 1,203,847 rows, 15 columns
|
|
79
|
+
✓ products — 892 rows, 12 columns
|
|
80
|
+
...
|
|
81
|
+
Done. Profiles saved.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Scherlok profiles every table: row counts, column types, NULL rates, value distributions, freshness cadence, cardinality. Stores everything locally in SQLite.
|
|
85
|
+
|
|
86
|
+
### 2. `watch` — Detect anomalies
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
$ scherlok watch
|
|
90
|
+
|
|
91
|
+
Checking 12 tables against learned profiles...
|
|
92
|
+
|
|
93
|
+
🔴 CRITICAL orders volume_drop Row count dropped 52% (1,203,847 → 578,412)
|
|
94
|
+
🟡 WARNING users null_increase Column "email": NULL rate 2.1% → 18.7%
|
|
95
|
+
🔵 INFO products distribution Column "price": mean shifted 3.2σ
|
|
96
|
+
|
|
97
|
+
3 anomalies detected. Exit code: 1
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3. Alert — Slack, CI/CD, or both
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Slack alerts
|
|
104
|
+
scherlok watch --slack https://hooks.slack.com/services/...
|
|
105
|
+
|
|
106
|
+
# CI/CD gate (fails pipeline on CRITICAL)
|
|
107
|
+
scherlok watch --exit-code --fail-on critical
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## CI/CD Integration
|
|
111
|
+
|
|
112
|
+
Use Scherlok as a data quality gate:
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
# GitHub Actions
|
|
116
|
+
- name: Data quality check
|
|
117
|
+
run: |
|
|
118
|
+
pip install scherlok
|
|
119
|
+
scherlok connect ${{ secrets.DATABASE_URL }}
|
|
120
|
+
scherlok watch --exit-code --fail-on critical
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
If Scherlok detects a critical anomaly, the pipeline fails. Bad data never reaches production.
|
|
124
|
+
|
|
125
|
+
## Connectors
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# PostgreSQL
|
|
129
|
+
scherlok connect postgres://user:pass@host:5432/db
|
|
130
|
+
|
|
131
|
+
# BigQuery
|
|
132
|
+
pip install scherlok[bigquery]
|
|
133
|
+
scherlok connect bigquery://project-id/dataset-name
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| Database | Status |
|
|
137
|
+
|----------|--------|
|
|
138
|
+
| PostgreSQL | Available |
|
|
139
|
+
| BigQuery | Available |
|
|
140
|
+
| Snowflake | Coming soon |
|
|
141
|
+
| MySQL | Coming soon |
|
|
142
|
+
| DuckDB | Planned |
|
|
143
|
+
|
|
144
|
+
## Remote Storage
|
|
145
|
+
|
|
146
|
+
Share profiles across CI runs and team members:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# AWS S3
|
|
150
|
+
scherlok config --store s3://my-bucket/scherlok/profiles.db
|
|
151
|
+
|
|
152
|
+
# Google Cloud Storage
|
|
153
|
+
scherlok config --store gs://my-bucket/scherlok/profiles.db
|
|
154
|
+
|
|
155
|
+
# Azure Blob Storage
|
|
156
|
+
scherlok config --store az://my-container/scherlok/profiles.db
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Why Not [Other Tool]?
|
|
160
|
+
|
|
161
|
+
| | Great Expectations | Soda | Monte Carlo | **Scherlok** |
|
|
162
|
+
|---|---|---|---|---|
|
|
163
|
+
| Setup time | Hours | 30 min | Weeks | **5 minutes** |
|
|
164
|
+
| Config required | Hundreds of rules | YAML checks | Dashboard setup | **None** |
|
|
165
|
+
| Anomaly detection | Manual thresholds | Paid feature | Yes | **Yes, free** |
|
|
166
|
+
| Self-hosted | Yes | Limited | No (SaaS) | **Yes** |
|
|
167
|
+
| CI/CD gate | Yes | Yes | No | **Yes** |
|
|
168
|
+
| Price | Free | Freemium | $50-200K/yr | **Free, forever** |
|
|
169
|
+
|
|
170
|
+
## CLI Reference
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
scherlok connect <url> Connect to a database
|
|
174
|
+
scherlok investigate Profile all tables (learn patterns)
|
|
175
|
+
scherlok watch Detect anomalies and alert
|
|
176
|
+
scherlok status Quick health dashboard
|
|
177
|
+
scherlok report Detailed profile summary
|
|
178
|
+
scherlok history [--days N] Timeline of past anomalies
|
|
179
|
+
scherlok config --store <url> Set remote storage
|
|
180
|
+
scherlok version Show version
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Install
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
pip install scherlok
|
|
187
|
+
|
|
188
|
+
# With BigQuery support
|
|
189
|
+
pip install scherlok[bigquery]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Requires Python 3.10+.
|
|
193
|
+
|
|
194
|
+
## Contributing
|
|
195
|
+
|
|
196
|
+
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
197
|
+
|
|
198
|
+
We're especially looking for:
|
|
199
|
+
- New database connectors (Snowflake, MySQL, DuckDB)
|
|
200
|
+
- Anomaly detection improvements
|
|
201
|
+
- Documentation and examples
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
[MIT](LICENSE) — Developed by [Robson Bayer Müller](https://github.com/rbmuller)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "scherlok"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A detective for your data. Zero-config data quality monitoring."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Robson Muller", email = "robson@tbdcdata.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["data-quality", "monitoring", "anomaly-detection", "data-engineering"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Database",
|
|
22
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"typer>=0.9.0",
|
|
26
|
+
"rich>=13.0.0",
|
|
27
|
+
"psycopg2-binary>=2.9.0",
|
|
28
|
+
"requests>=2.28.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
bigquery = [
|
|
33
|
+
"google-cloud-bigquery>=3.0.0",
|
|
34
|
+
]
|
|
35
|
+
dev = [
|
|
36
|
+
"pytest>=7.0.0",
|
|
37
|
+
"pytest-cov>=4.0.0",
|
|
38
|
+
"ruff>=0.1.0",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
scherlok = "scherlok.cli:app"
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/rbmuller/scherlok"
|
|
46
|
+
Repository = "https://github.com/rbmuller/scherlok"
|
|
47
|
+
Issues = "https://github.com/rbmuller/scherlok/issues"
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
target-version = "py310"
|
|
51
|
+
line-length = 100
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = ["E", "F", "I", "N", "W", "UP"]
|
|
55
|
+
|
|
56
|
+
[tool.pytest.ini_options]
|
|
57
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Alerting modules for Scherlok."""
|