DataWeave
Declarative Data Pipeline Framework -- Define ETL workflows in YAML. Transform, validate, profile, and load data with zero configuration.
Why I Built This
Every data team I have worked with ends up writing the same boilerplate: load CSV, filter rows, compute columns, validate quality, dump results. The logic is simple but the wiring is tedious, and it scatters across Jupyter notebooks that nobody wants to maintain.
DataWeave replaces that boilerplate with a single YAML file. You declare what should happen to your data -- filter, transform, aggregate, validate -- and the framework handles the how. Think of it as Great Expectations meets dbt, but lightweight enough to pip-install and run in five minutes.
I wanted to build something that:
- Eliminates copy-paste ETL -- define once in YAML, run anywhere.
- Catches data quality issues early -- null checks, outlier detection, pattern matching built in.
- Generates human-readable reports -- hand the HTML profile to a stakeholder, no notebook required.
- Stays small -- no Spark cluster, no Airflow DAG, no cloud dependency. Just pandas and a YAML file.
Quick Demo (60-Second Walkthrough)
# Install
pip install -e .
# Run a pipeline
dataweave run samples/pipeline.yaml -v
# Profile your data
dataweave profile samples/sales_data.csv
# Validate against rules
dataweave validate samples/sales_data.csv samples/validation_rules.yaml -v
What just happened:
runloaded 25 sales records, filtered out cancelled orders, computed revenue, sorted by date, and wrote cleaned output.profileanalyzed every column -- types, nulls, outliers, distributions -- and generated an HTML report.validatechecked 8 quality rules (not-null, unique, min/max, regex patterns) and reported pass/fail.
Architecture
flowchart TD
A[YAML Config] -->|loader.py| B[PipelineConfig Model]
B -->|engine.py| C[PipelineEngine]
D[CSV / JSON / Parquet] -->|pandas| C
C --> E{Step Loop}
E -->|filter| F[FilterOperator]
E -->|transform| G[TransformOperator]
E -->|aggregate| H[AggregateOperator]
E -->|join| I[JoinOperator]
E -->|validate| J[ValidateOperator]
E -->|sort / select / rename / dedup / fill_na| K[Other Operators]
F & G & H & I & J & K --> L[Transformed DataFrame]
L -->|output| M[CSV / JSON / Parquet]
L -->|profiler.py| N[DataProfile]
N -->|report.py + Jinja2| O[HTML Report]
style A fill:#e3f2fd,stroke:#1565c0
style C fill:#e8f5e9,stroke:#2e7d32
style O fill:#fff3e0,stroke:#e65100
Component Overview
| Module | Responsibility |
|---|---|
models.py |
Pydantic models for YAML config validation |
loader.py |
Parse YAML into typed PipelineConfig |
engine.py |
Execute steps in sequence, collect timing |
operators/ |
Pluggable operator implementations |
schema.py |
Automatic type detection and schema inference |
profiler.py |
Column-level statistics and anomaly detection |
report.py |
Jinja2-powered HTML report generation |
cli.py |
Click-based command-line interface |
Installation
# From source
git clone https://github.com/sonimaharshi1999/dataweave.git
cd dataweave
pip install -e ".[dev]"
# Run tests
python -m pytest tests/ -v
Usage
Define a Pipeline in YAML
name: sales_etl
description: "Clean and transform sales data"
source:
path: data/sales.csv
format: csv
steps:
- name: remove_cancelled
operator: filter
params:
column: status
op: ne
value: cancelled
- name: compute_revenue
operator: transform
params:
expressions:
revenue: "quantity * unit_price"
- name: validate_quality
operator: validate
validations:
- column: order_id
check: not_null
severity: error
- column: quantity
check: min
value: 1
severity: error
- name: aggregate_by_region
operator: aggregate
params:
group_by: region
aggregations:
revenue: sum
quantity: sum
output:
path: output/summary.csv
format: csv
Available Operators
| Operator | Description | Key Params |
|---|---|---|
filter |
Keep rows matching a condition | column, op, value |
transform |
Add/modify columns with expressions | expressions, drop |
aggregate |
Group-by aggregation | group_by, aggregations |
join |
Merge with another dataset | join.right_source, join.on, join.how |
validate |
Run data quality checks | validations[] |
select |
Keep only listed columns | columns |
rename |
Rename columns | columns (old -> new map) |
sort |
Sort by column(s) | by, ascending |
deduplicate |
Remove duplicate rows | subset, keep |
fill_na |
Fill missing values | columns, strategy |
Filter Operators
Supported comparison operators for filter:
eq,ne-- equals, not equalsgt,ge,lt,le-- numeric comparisonsin,not_in-- membership testscontains-- substring match
Transform Expressions
expressions:
upper_name: "upper(customer_name)" # String functions
revenue: "quantity * unit_price" # Arithmetic
name_length: "len(customer_name)" # Length
Programmatic API
from dataweave.loader import load_pipeline
from dataweave.engine import PipelineEngine
from dataweave.profiler import profile_dataframe
config = load_pipeline("pipeline.yaml")
engine = PipelineEngine(config)
# Run and get results
result = engine.run()
print(f"Success: {result.success}, Rows: {result.final_row_count}")
# Or get the DataFrame directly
df = engine.run_to_dataframe()
# Profile any DataFrame
profile = profile_dataframe(df)
print(f"Outliers in price: {profile.columns[2].outlier_count}")
Performance / Benchmarks
Measured on a 2023 MacBook Pro (M3, 16 GB RAM) with synthetic CSV data:
| Dataset Size | Columns | Pipeline Steps | Duration |
|---|---|---|---|
| 1,000 rows | 10 | 5 (filter + transform + sort + dedup + validate) | ~15 ms |
| 100,000 rows | 10 | 5 | ~120 ms |
| 1,000,000 rows | 10 | 5 | ~1.2 s |
| 1,000,000 rows | 10 | Profile (all columns) | ~3.5 s |
Key takeaways:
- Sub-second for datasets under 500K rows with typical pipelines.
- Profiling is the most expensive operation due to per-column statistics and outlier detection.
- Memory usage scales linearly with row count -- roughly 80 bytes/row for a 10-column dataset.
What I Would Do Differently
-
Expression engine -- The current transform expressions use string parsing with regex. A proper AST-based expression evaluator (or even a safe subset of Python's
evalwith restricted globals) would support nested functions and complex arithmetic without fragile string splitting. -
Streaming execution -- Right now every operator materializes the full DataFrame. For very large files, a chunked/streaming mode that processes N rows at a time would cut peak memory usage significantly.
-
Operator composition -- The step-by-step model is clean but forces intermediate DataFrames. A lazy evaluation approach (like Polars or Spark) that fuses operations before executing would improve performance on long pipelines.
-
Plugin system -- Operators are registered at import time. A proper entry-point-based plugin system would let users add custom operators without forking the package.
-
Incremental profiling -- The profiler scans every column every time. For append-only data sources, maintaining running statistics (count, mean, variance via Welford's algorithm) would make re-profiling near-instant.
Scaling Considerations
- Vertical scaling: DataWeave rides on pandas, which is single-threaded. For datasets beyond ~10M rows, swap the pandas backend for Polars (drop-in for most operations) or Dask for out-of-core parallel processing.
- Horizontal scaling: The YAML config is portable. Wrap
PipelineEngine.run()in an Airflow/Prefect task to distribute across workers. Each pipeline is stateless -- no shared state to coordinate. - Data formats: CSV is the default, but Parquet support is built in. Switching to Parquet for large datasets cuts I/O time by 5-10x and enables predicate pushdown if you add a Polars backend.
- Validation at scale: The validate operator checks every row. For billion-row tables, sample-based validation (check a random 1% and extrapolate) would keep quality assurance practical.
- Caching: Intermediate step results could be cached to disk (keyed by step config hash) so re-running a modified pipeline skips unchanged upstream steps.
Project Structure
dataweave/
pyproject.toml
README.md
.gitignore
.github/workflows/test.yml
src/dataweave/
__init__.py
__version__.py
py.typed
models.py # Pydantic config models
loader.py # YAML -> PipelineConfig
engine.py # Pipeline execution engine
schema.py # Schema inference & type detection
profiler.py # Column profiling & anomaly detection
report.py # HTML report generation (Jinja2)
cli.py # Click CLI (run, profile, validate)
operators/
__init__.py
base.py # Operator ABC & registry
core.py # All built-in operators
samples/
sales_data.csv # Sample dataset (25 rows)
pipeline.yaml # Sample pipeline config
validation_rules.yaml
tests/
conftest.py
test_models.py
test_schema.py
test_operators.py
test_engine.py
test_profiler.py
test_cli.py
Sample Input / Output
Project Overview
Reports
- HTML Report - interactive report
- PDF Report - downloadable PDF
- TXT Report - plain text
License
MIT License -- Maharshi Soni
Metadata
Release files for dataweave-lib 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dataweave_lib-0.1.1.tar.gz | 30.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dataweave_lib-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.3 kB
Release files / dataweave_lib-0.1.1.tar.gz
| Download URL | dataweave_lib-0.1.1.tar.gz |
|---|---|
| Size | 30.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f6dd6df6e554610f624d619dbbeb202b7d5b791a4174b24c22a0689c8987252b
|
|
BLAKE2b-256 checksum How to use checksums |
bafbb99bd8cab57cd6f276bfe1b22b3a08ff23da1d2f4dc40cbec2a7c8e33f48
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / dataweave_lib-0.1.1-py3-none-any.whl
| Download URL | dataweave_lib-0.1.1-py3-none-any.whl |
|---|---|
| Size | 24.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d359f4ecf003add34f92d705586f8eb6460abd5f772886bca8a3edfff964ade3
|
|
BLAKE2b-256 checksum How to use checksums |
b1e082a81153b1f9826e104ab17494818459d10efa92460c7652fe4ddedd23de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|