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 Fuzzy Matching - Levenshtein distance, Soundex, Jaccard similarity, n-grams, cosine similarity
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.
Metadata
Release files for datacompose 0.5.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| datacompose-0.5.2.tar.gz | 202.3 kB | Without provenance | Details for datacompose-0.5.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| datacompose-0.5.2-py3-none-any.whl | Python 3 | none | any | Details for datacompose-0.5.2-py3-none-any.whl |
Total release size: 283.5 kB
Release files / datacompose-0.5.2.tar.gz
| Download URL | datacompose-0.5.2.tar.gz |
|---|---|
| Size | 202.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1b98fcd012f311536d5fb30b8e2af72337ddb65bec27a2946c312c2a7b32cbbf
|
|
BLAKE2b-256 checksum How to use checksums |
e6a6a3145b67ffaf73383e21e92b6ab9a3fcbc13db2f45092005e6b7f2b2643b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / datacompose-0.5.2-py3-none-any.whl
| Download URL | datacompose-0.5.2-py3-none-any.whl |
|---|---|
| Size | 81.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e60df53799b46bf272160cb533b0cebba0db2dcaa899de41437a0e268b132036
|
|
BLAKE2b-256 checksum How to use checksums |
ec728aadad511a7078bd2d9dbf39dcfdf4a6e60ef51cb768125d87134f2676b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Security for datacompose 0.5.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.