A Python/PySpark library for data quality checks and validation
Project description
pipeDQ
A comprehensive, metadata-driven Python library for data quality checks and validation.
pipeDQ is built to scale from your local laptop to massive distributed clusters. It dynamically detects your environment and intelligently routes execution to the fastest available backend:
- PySpark: For distributed processing over massive datasets using Spark SQL.
- DuckDB: For lightning-fast, zero-JVM execution over local Pandas DataFrames, Parquet, and CSV files.
- SQLite (Fallback): If DuckDB isn't installed but you provide a Pandas or Polars DataFrame,
pipeDQseamlessly falls back to Python's built-in SQLite engine to evaluate your SQL rules in-memory.
Features
- Multi-Engine Architecture: Write once, run anywhere. Seamlessly switch between PySpark and DuckDB without changing your code.
- SQL-Driven Validation: Define your business rules using standard boolean SQL
WHEREclauses. - Single-Pass Evaluation:
pipeDQoptimizes rule execution by grouping checks and evaluating them in a single pass over your data. - Threshold Support: Define acceptable passing percentages to distinguish between minor data anomalies and critical failures.
- Bad Record Extraction: Optionally capture and store the exact rows that fail validation.
- Auto-Bootstrapping: Easily create your metadata schema, Rules table, and Results sink with a single function call.
Installation
# Install with basic dependencies (DuckDB will be used as the local engine)
pip install pipedq
# If you intend to use it in a PySpark environment, PySpark will be auto-detected!
Quickstart
import duckdb
from pipedq.sql.models import SqlRule
from pipedq.sql.factory import get_sql_engine
from pipedq.sql.config import create_metadata_tables
# 1. Connect to your database or SparkSession
conn = duckdb.connect(':memory:')
# conn = SparkSession.builder.getOrCreate() # Auto-detected by pipeDQ!
# 2. Get the optimal engine for your environment
engine = get_sql_engine(conn=conn)
# 3. Bootstrap metadata tables (Optional)
create_metadata_tables(engine, schema_name="pipedq")
# 4. Create dummy data
conn.execute("CREATE TABLE users (id INT, age INT, email VARCHAR)")
conn.execute("INSERT INTO users VALUES (1, 25, 'test@example.com'), (2, 15, NULL)")
# 5. Define Data Quality Rules
rules = [
SqlRule(rule_id="R1", table_name="users", sql_where_clause="age >= 18", is_mandatory=True),
SqlRule(rule_id="R2", table_name="users", sql_where_clause="email IS NOT NULL")
]
# 6. Execute!
results = engine.execute_rules(rules)
for res in results:
print(f"[{res.rule_id}] Passed: {res.is_passed} ({res.passed_pct}%)")
Rule Cookbook (25+ Common Examples)
pipeDQ rules use standard SQL boolean expressions. Here are 30 commonly used rule patterns you can drop directly into the sql_where_clause field of your SqlRule.
1. Completeness & Null Checks
| Rule ID | Description | SQL Where Clause |
|---|---|---|
NUL-01 |
Column is not null | first_name IS NOT NULL |
NUL-02 |
Neither of two columns is null | first_name IS NOT NULL AND last_name IS NOT NULL |
NUL-03 |
At least one of two columns is populated | email IS NOT NULL OR phone IS NOT NULL |
NUL-04 |
Avoid empty strings (along with nulls) | TRIM(status) != '' AND status IS NOT NULL |
2. Range & Boundary Checks
| Rule ID | Description | SQL Where Clause |
|---|---|---|
RNG-01 |
Positive integer check | age > 0 |
RNG-02 |
Within a specific range (Inclusive) | credit_score BETWEEN 300 AND 850 |
RNG-03 |
Percentage bounds | discount_rate >= 0.0 AND discount_rate <= 1.0 |
RNG-04 |
Upper bound threshold | salary <= 1000000 |
3. String Patterns & Formatting
| Rule ID | Description | SQL Where Clause |
|---|---|---|
STR-01 |
Valid Email Format (Basic) | email LIKE '%_@__%.__%' |
STR-02 |
Starts with specific prefix | order_id LIKE 'ORD-%' |
STR-03 |
Exact length check | LENGTH(ssn) = 9 |
STR-04 |
Minimum length | LENGTH(password) >= 8 |
STR-05 |
String contains no spaces | username NOT LIKE '% %' |
STR-06 |
Alpha-numeric characters only (Regex) | REGEXP_MATCHES(user_code, '^[a-zA-Z0-9]+$') * |
STR-07 |
Capitalized first letter | SUBSTRING(first_name, 1, 1) = UPPER(SUBSTRING(first_name, 1, 1)) |
* Note: Regex functions may vary slightly by engine (RLIKE in Spark, REGEXP_MATCHES in DuckDB).
4. Categorical & Set Membership
| Rule ID | Description | SQL Where Clause |
|---|---|---|
CAT-01 |
Value exists in strict ENUM set | status IN ('PENDING', 'ACTIVE', 'CLOSED') |
CAT-02 |
Value does NOT exist in exclusion list | country NOT IN ('ZZ', 'UNKNOWN') |
CAT-03 |
Valid boolean strings | UPPER(is_active) IN ('TRUE', 'FALSE', 'T', 'F', 'YES', 'NO') |
5. Date & Time Validations
| Rule ID | Description | SQL Where Clause |
|---|---|---|
DAT-01 |
Date is not in the future | transaction_date <= CURRENT_DATE |
DAT-02 |
Logical chronological order | end_date >= start_date |
DAT-03 |
Age logic (Over 18 based on DOB) | dob <= CURRENT_DATE - INTERVAL 18 YEAR |
DAT-04 |
Occurs during business week | EXTRACT(DOW FROM event_date) BETWEEN 1 AND 5 |
DAT-05 |
Timestamps within last 24 hours | created_at >= CURRENT_TIMESTAMP - INTERVAL 24 HOUR |
6. Cross-Column Logical Rules
| Rule ID | Description | SQL Where Clause |
|---|---|---|
XCL-01 |
Conditional nulls (If active, must have email) | status != 'ACTIVE' OR email IS NOT NULL |
XCL-02 |
Value consistency | total_amount = (subtotal + tax_amount) |
XCL-03 |
Shipping constraints | shipping_date IS NULL OR shipping_date >= order_date |
XCL-04 |
Mutually exclusive flags | NOT (is_student = TRUE AND is_retired = TRUE) |
7. Complex Business Logic
| Rule ID | Description | SQL Where Clause |
|---|---|---|
BIZ-01 |
Tier-based discounts | (tier = 'VIP' AND discount <= 0.3) OR (tier = 'STD' AND discount <= 0.1) |
BIZ-02 |
Valid currency codes for amounts | amount = 0 OR currency_code IN ('USD', 'EUR', 'GBP') |
BIZ-03 |
Valid product/category hierarchy | (category='ELEC' AND type IN ('TV','PC')) OR (category!='ELEC') |
BIZ-04 |
Custom status transitions | previous_status = 'PENDING' OR current_status != 'ACTIVE' |
BIZ-05 |
Data type parsing bounds (Safe Cast) | CAST(age_string AS INT) >= 0 (Engine will fail row if cast fails) |
Configuration Reference: SqlRule
When instantiating a SqlRule, you have several parameters to fine-tune the execution:
rule_id(str): Your internal identifier for the rule (e.g.RQ-104).table_name(str): The name of the table or view to query.sql_where_clause(str): The boolean condition that must evaluate toTRUEfor a row to pass.column_name(Optional[str]): A metadata tag to indicate which column this rule primarily targets.threshold_pct(float, default100.0): What percentage of rows must pass for the entire rule to be marked asPASSED.store_failed_rows(bool, defaultFalse): If true, all rows that evaluate toFALSEorNULLwill be extracted and saved to your configuredfailed_rows_table.is_mandatory(bool, defaultTrue): If false, this rule acts as a "warning" and won't necessarily break downstream pipelines.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pipedq-0.1.0.tar.gz.
File metadata
- Download URL: pipedq-0.1.0.tar.gz
- Upload date:
- Size: 10.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28304e2dc5eb7af6121059f9816a959a7e4e9e55ac8c067e5dda786f9cd99ea0
|
|
| MD5 |
a6b2b16fbf751130d327d40b28007b7a
|
|
| BLAKE2b-256 |
af2a10130e63e597b639a43c81f5d6af942d950d4342090aa1f88a4f9f63a4ee
|
File details
Details for the file pipedq-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pipedq-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44b76477196d10aa837bf7837df0185b79c4aae1636e9daf10f93d450534aa8c
|
|
| MD5 |
4503717c6566e186d284a872f699e52d
|
|
| BLAKE2b-256 |
733cfa3684954c4f9f270eafa5c1566ce2b04a1d2c07676db3a8655dbf5e6e8e
|