Rule-based data anonymization and sanitization for CLI, Django, Pandas, and SQL dumps.
Project description
py-data-cloak
py-data-cloak is a rule-based data anonymization engine for Python. It works
on JSON, NDJSON, CSV, and SQL dumps from the command line, integrates with the
Django ORM for safe dumpdata exports, and plugs into Pandas for data-science
workflows.
It keeps referential integrity (user_id=42 always masks to the same value
within a session — or across runs with a persistent vault), streams large files
without loading them into memory, and can auto-detect PII from a sample to
generate a starter rules file for you.
Install
pip install py-data-cloak
# Optional extras
pip install "py-data-cloak[django]" # Django dumpdata_masked command + mixin
pip install "py-data-cloak[pandas]" # mask_dataframe helper
pip install "py-data-cloak[vault]" # encrypted persistent vaults
pip install "py-data-cloak[all]" # all of the above
Quick start
# privacy_rules.yaml
email: faker:email
ssn: mask_all_but_last_4
password: fixed:***REDACTED***
notes: clear
credit_card: format_preserve:luhn
salary: noise:5000
dob: shift_date:365
user_id: hash:sha256:mysalt
'*_email': faker:email # glob: any column ending in _email
're:.*_secret$': redact # regex
'user.profile.phone': format_preserve # nested JSON path
pycloak process users.json --rules privacy_rules.yaml --output safe.json
pycloak process huge.jsonl --rules privacy_rules.yaml --output safe.jsonl
pycloak process export.csv --rules privacy_rules.yaml --output safe.csv
pycloak process dump.sql --rules privacy_rules.yaml --output safe.sql
pycloak process input.json --rules privacy_rules.yaml --dry-run
Don't know what to mask? Let pycloak guess:
pycloak scan users.json --output starter_rules.yaml
Rules reference
| Rule | Effect |
|---|---|
faker:<provider>[:<arg>...] |
Replace with a Faker value (faker:email, faker:name, ...). |
fixed:<value> |
Replace with a static string. |
clear |
Replace with null. |
redact[:<placeholder>] |
Replace with [REDACTED] or a custom string. |
mask_all_but_last_<n> |
Keep the last N chars, replace the rest with *. |
partial:<start>:<end>[:<mask_char>] |
Keep N leading and M trailing chars (john@x.com -> j***@x.com). |
format_preserve[:luhn] |
Keep the shape (digits/letters/separators). With :luhn, the digit sequence is Luhn-valid. |
hash[:<algo>[:<salt>]] |
Deterministic hex digest. Default sha256. |
noise:<sigma> |
Gaussian noise added to a numeric value. |
shift_date:<days> |
Shift a date by a random number of days within ±days. |
custom:<module.path>:<function> |
Call your own fn(value, ctx) -> masked. |
Field matching
- Exact —
"email","user.profile.phone"(nested JSON path) - Glob —
"*_email","user.*","address.[lc]ine?" - Regex — prefix the pattern with
re:, e.g."re:^.*_secret$"
Exact rules are checked first; glob and regex follow in declaration order, so put specific patterns above broader catch-alls.
Python API
from pycloak import Anonymizer, Vault, load_rules
rules = load_rules("privacy_rules.yaml")
vault = Vault("masked.vault", passphrase="hunter2") # optional
anonymizer = Anonymizer(rules, seed=42, locale="en_US", vault=vault)
masked = anonymizer.process_record({"email": "alice@example.com", "salary": 95000})
anonymizer.save() # persist the vault for the next run
Custom rules
from pycloak import register_rule
from pycloak.rules import Rule
@register_rule
class UppercaseRule(Rule):
@classmethod
def matches(cls, spec): return spec == "upper"
@classmethod
def parse(cls, spec): return cls()
def apply(self, value, ctx): return str(value).upper()
Or use custom:my.module:my_func directly in YAML:
# my_module.py
def my_func(value, ctx):
return f"<masked:{ctx.field_name}>"
some_field: custom:my_module:my_func
Pandas
from pycloak.pandas_helper import mask_dataframe
masked_df = mask_dataframe(df, rules)
Django
Add to INSTALLED_APPS:
INSTALLED_APPS = [..., "pycloak.django"]
PY_DATA_CLOAK_MASKING_RULES = "privacy_rules.yaml" # path or dict
PY_DATA_CLOAK_SAFE_REPR = True # optional: safer repr for logs
Stream-friendly masked dump:
python manage.py dumpdata_masked auth.User --output safe_users.json --chunk-size 5000
Per-instance access via the mixin:
from pycloak.django.mixins import MaskedModelMixin
class User(MaskedModelMixin, models.Model):
...
User.objects.first().masked_data()
Versioning
0.2.0 introduces streaming, consistency, SQL/NDJSON support, PII detection, vaults, Pandas/Django streaming, and the rule registry. The pre-1.0 API may still evolve; 1.0.0 will lock the public surface.
License
MIT.
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 py_data_cloak-0.2.0.tar.gz.
File metadata
- Download URL: py_data_cloak-0.2.0.tar.gz
- Upload date:
- Size: 28.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
906b5239561c4ba82199d963354820fc111dadcb65f7444d117cf92ac07a7432
|
|
| MD5 |
ce04756e86229013f7a42637703927f1
|
|
| BLAKE2b-256 |
f575e689973ffeb0f0a2d6a8e0cf4fbc534210a7f71baed5ab6f3a7e30ed8172
|
File details
Details for the file py_data_cloak-0.2.0-py3-none-any.whl.
File metadata
- Download URL: py_data_cloak-0.2.0-py3-none-any.whl
- Upload date:
- Size: 29.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
333e98a8c93d75e8ee002ce49f4cc05bb1fa82c7efb156fc11dcbf3916e789d4
|
|
| MD5 |
7920cf3b533bbc3836dfbbeeb044323d
|
|
| BLAKE2b-256 |
3e6e0b652d7fecf488c81afa7fcbf8cdf6c79e019dff6d37d15cea62219cd74a
|