Copy-pasteable data transformation primitives for PySpark. Inspired by shadcn-svelte.
Project description
DataCompose
PySpark transformations you can actually own and modify. No black boxes.
Before vs After
# Before: Regex nightmare for addresses
df = df.withColumn("state_clean",
F.when(F.col("address").rlike(".*\\b(NY|N\\.Y\\.|New York|NewYork|Newyork)\\b.*"), "NY")
.when(F.col("address").rlike(".*\\b(CA|Cal\\.|Calif\\.|California)\\b.*"), "CA")
.when(F.col("address").rlike(".*\\b(IL|Ill\\.|Illinois|Illinios)\\b.*"), "IL")
.when(F.upper(F.col("address")).contains("NEW YORK"), "NY")
.when(F.regexp_extract(F.col("address"), ",\\s*([A-Z]{2})\\s+\\d{5}", 1) == "NY", "NY")
.when(F.regexp_extract(F.col("address"), "\\s+([A-Z]{2})\\s*$", 1) == "NY", "NY")
# ... handle "N.Y 10001" vs "NY, 10001" vs "New York 10001"
# ... handle misspellings like "Californai" or "Illnois"
# ... 50 more states × 10 variations each
)
# After: One line
from builders.transformers.addresses import addresses
df = df.withColumn("state", addresses.standardize_state(F.col("address")))
Installation
pip install datacompose
How It Works
# Copy transformers into YOUR repo
datacompose add phones
datacompose add addresses
datacompose add emails
# Use them like any Python module - this is your code now
from transformers.pyspark.addresses import addresses
df = (df
.withColumn("street_number", addresses.extract_street_number(F.col("address")))
.withColumn("street_name", addresses.extract_street_name(F.col("address")))
.withColumn("city", addresses.extract_city(F.col("address")))
.withColumn("state", addresses.standardize_state(F.col("address")))
.withColumn("zip", addresses.extract_zip_code(F.col("address")))
)
# Result:
+----------------------------------------+-------------+------------+-----------+-----+-------+
|address |street_number|street_name |city |state|zip |
+----------------------------------------+-------------+------------+-----------+-----+-------+
|123 Main St, New York, NY 10001 |123 |Main |New York |NY |10001 |
|456 Oak Ave Apt 5B, Los Angeles, CA 90001|456 |Oak |Los Angeles|CA |90001 |
|789 Pine Blvd, Chicago, IL 60601 |789 |Pine |Chicago |IL |60601 |
+----------------------------------------+-------------+------------+-----------+-----+-------+
The code lives in your repo. Modify it. Delete what you don't need. No external dependencies.
Why Copy-to-Own?
- Your data is weird - Phone numbers with "ask for Bob"? We can't predict that. You can fix it.
- No breaking changes - Library updates can't break your pipeline at 2 AM
- Actually debuggable - Stack traces point to YOUR code, not site-packages
- No dependency hell - It's just PySpark. If Spark runs, this runs.
Available Transformers
Phones - Standardize formats, extract from text, validate, handle extensions
Addresses - Parse components, standardize states, validate zips, detect PO boxes
Emails - Validate, extract domains, fix typos (gmial→gmail), standardize
More coming based on what you need.
Real Example
# Messy customer data
df = spark.createDataFrame([
("(555) 123-4567 ext 89", "john.doe@gmial.com", "123 Main St Apt 4B"),
("555.987.6543", "JANE@COMPANY.COM", "456 Oak Ave, NY, NY 10001")
])
# Clean it
clean_df = (df
.withColumn("phone", phones.standardize_phone(F.col("phone")))
.withColumn("email", emails.fix_common_typos(F.col("email")))
.withColumn("street", addresses.extract_street_address(F.col("address")))
)
The Philosophy
█████████████ 60% - Already clean
████████ 30% - Common patterns (formatting, typos)
██ 8% - Edge cases (weird but fixable)
▌ 2% - Complete chaos (that's what interns are for)
We handle the 38% with patterns. You handle the 2% chaos.
Documentation
Full docs at datacompose.io
Key Features
- Zero dependencies - Just PySpark code that runs anywhere Spark runs
- Fully modifiable - It's in your repo. Change whatever you need
- Battle-tested patterns - Built from real production data cleaning challenges
- Composable functions - Chain simple operations into complex pipelines
- No breaking changes - You control when and how to update
License
MIT - It's your code now.
Inspired by shadcn/ui and Svelte's approach to components - copy, don't install.
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 datacompose-0.3.0.tar.gz.
File metadata
- Download URL: datacompose-0.3.0.tar.gz
- Upload date:
- Size: 195.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d9cab7d1253a51f827d248f9d65dea8ae56e83b2476da1286c750aee5c40305
|
|
| MD5 |
0ba33b11ccb9338575b34a73158f24cc
|
|
| BLAKE2b-256 |
1981ddf93961689744c71e755d1db13ffdf81f86c08268158b51f9b3f50de30c
|
File details
Details for the file datacompose-0.3.0-py3-none-any.whl.
File metadata
- Download URL: datacompose-0.3.0-py3-none-any.whl
- Upload date:
- Size: 72.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03973c27d4f9edecd5ab84fb28c60d6a4003ba6f0f76fe71151ff96bfae71210
|
|
| MD5 |
01a5abfb6ba51003bcfb09bcff36ca83
|
|
| BLAKE2b-256 |
3d0f00742794b24077273d74c5fc7c47e047e56ffa6bcdeae40d4e7c686e55e7
|