Skip to content

fix(masking): validate unmatched columns and support snake_case matching - #406

Merged
kevincostner17 merged 3 commits into
mainfrom
fix/masking-unmatched-columns-251
Sep 15, 2026
Merged

kevincostner17 merged 3 commits into
mainfrom
fix/masking-unmatched-columns-251

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Supersedes #269. This branch carries the original commit by @Voyagerroc-Code (opened as PR #269 by @Voyagerroc-Lab), with authorship preserved, plus review changes on top. Thank you for the fix!

Summary

A masking rule whose columns matched no column did nothing. For example, freshdata clean --mask Email:hash on a frame with an email column wrote the raw values and exited 0. Column resolution now matches by snake_case name, records names that match nothing, and can raise for them.

Behaviour changes

  • A MaskingRule column name masks every column with the same name or the same snake_case form: "First Name" masks first_name, and "email" masks both email and Email.
  • Listed names that match no column are recorded in the new MaskReport.unmatched_columns, which also appears in MaskReport.to_dict().
  • New MaskingRule.strict, default False. With strict=True, or mask_dataframe(..., strict=True), unmatched names raise ValueError naming them. The mask_dataframe argument overrides the rule's setting.
  • freshdata clean --mask COLUMN:STRATEGY rules are strict, so the command exits 1 with a one-line error when COLUMN matches no column.
  • The duplicate-label pre-check in anonymize never raises for absent columns.

Commits

  1. fix(masking): validate unmatched columns and support snake_case matching, by @Voyagerroc-Code (the original from fix(masking): validate unmatched columns and support snake_case matching #269).
  2. fix(masking): non-strict by default, mask every snake_case match, strict CLI --mask. Review changes:
    • non-strict default, so shared rule sets keep working
    • mask every snake_case match instead of only the last one
    • strict CLI rules
    • non-raising pre-check in anonymize
    • E501 fixes, docstrings, changelog
  3. test(masking): cover polars snake_case matching and strict rules in clean_enterprise. Adds tests and moves the changelog entry to Changed.

Tests

  • mask_dataframe:
    • snake_case matching
    • strict mode raises
    • unmatched names recorded by default
    • the strict= argument overrides the rule
    • every snake_case twin masked
    • polars path with snake_case matching
  • fd.anonymize: a shared rule with an absent column; a strict rule alongside duplicated labels elsewhere.
  • clean_enterprise:
    • a strict rule with a missing column raises ValueError naming it
    • a non-strict run completes and reports the column in result.mask_report.unmatched_columns
  • CLI:
    • --mask non_existent:hash exits 1 with a one-line error
    • --mask Email:hash masks email

Verification

Run on main cbd1967 plus these commits:

  • ruff check .: all checks passed
  • mypy src/freshdata: no issues
  • pytest -m "not online and not large", Python 3.12: 5603 passed, 13 skipped
  • pytest -m "not online and not large", Python 3.9 / pandas 1.5: 5599 passed, 17 skipped

Closes #251

Voyagerroc-Code and others added 3 commits September 15, 2026 17:00
…ict CLI --mask

- MaskingRule.strict defaults to False: listed columns that match nothing are
  recorded in MaskReport.unmatched_columns, so shared rule sets keep working in
  fd.anonymize and clean_enterprise. The CLI --mask rules are strict.
- A listed column masks every frame column with the same name or snake_case
  form, instead of only the last one that normalises to it.
- The duplicate-label pre-check in anonymize never raises for absent columns.
- Split the three E501 test lines; add tests, docstrings and a changelog entry.
…lean_enterprise

Move the #251 changelog entry to Changed, since it changes matching, adds
the unmatched_columns report key and makes CLI --mask exit 1.
@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: aec1264b-5911-4cc3-b131-85fcc63defb7


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

FreshData benchmark report — performance

  • freshdata: ?
  • python: ?
  • platform: ?
fixture n_rows n_cols p50 s p95 s peak MB repair % false-repair % preserve % trust monotonic export %

Authored-code reduction (Metric 6)

@kevincostner17
kevincostner17 merged commit e9b5ff9 into main Sep 15, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Masking rules naming a non-existent column mask nothing and exit 0, leaving raw PII

1 participant