Skip to content

fix(dtypes,strings): never abort cleaning on an unusual object cell - #453

Merged
kevincostner17 merged 1 commit into
mainfrom
fix/pipeline-object-cells
Sep 16, 2026
Merged

kevincostner17 merged 1 commit into
mainfrom
fix/pipeline-object-cells

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Summary

Three crashes on the default fd.clean path, found by fuzzing. Each aborts the whole call on data that arrives routinely from databases, JSON and spreadsheets.

They share one assumption: that every cell of an object column is scalar text.

Root cause

Behaviour change

  • Bytes cells: text inspection falls back to a view that keeps str cells and ignores everything else, so an undecodable cell is left exactly as it was, on both pandas versions. ASCII bytes are unaffected.
  • Container cells: repair counts are computed only over positions holding a real str. Lists, dicts, sets and tuples are never rewritten and never counted, and the reported repair count no longer includes cells the pipeline did not touch.
  • Booleans with NaT: missing cells are normalized to NaN before the boolean cast, so the real booleans still convert and the missing cells stay missing.

Default-output changes

None for frames that already cleaned successfully.

  • Frames that previously raised now return a cleaned frame. The unusual cell is passed through untouched, and the rest of the column is cleaned as usual.
  • Repair counts in the report are unchanged for columns of scalar text. They only differ where a column also holds a container cell, which previously raised.
  • Golden suites are unchanged (tests/test_golden.py passes untouched).

Tests

  • tests/test_dtypes.py: an undecodable bytes cell survives while the rest of the frame cleans; ASCII bytes columns are unchanged; booleans mixed with NaT clean both with and without a second column (the inference-order trigger); ordinary boolean columns still convert.
  • tests/test_strings.py: pd.NA beside a list cell cleans; list, dict, set and tuple cells are passed through while ordinary text is still stripped; repair counts exclude untouched container cells.

Verification

  • ruff check and mypy src/freshdata: clean.
  • All three campaign repros exit 0 on py3.12 / pandas 2.3.3 and py3.9 / pandas 1.5.3; each fails on main.
  • tests/test_dtypes.py, tests/test_strings.py and tests/test_golden.py: 111 passed on py3.12, 108 passed / 3 skipped on py3.9.
  • Full not online and not large lanes: py3.12 6514 passed, 17 skipped; py3.9 6485 passed, 21 skipped.

Three crashes on the default fd.clean path, all from code that assumed
every cell in an object column is scalar text:

* non-UTF-8 bytes: dtype inference cast a sample with astype("string"),
  and pandas 2 decodes bytes when casting to StringDtype, so a BLOB read
  out of a database raised UnicodeDecodeError. pandas 1.5 returned the
  frame with the cell untouched. Text inspection now falls back to a view
  that keeps str cells and ignores the rest, so both versions leave the
  cell alone.
* pd.NA beside a list or dict: the strip and case passes counted repairs
  with stripped.ne(s), whose flex comparison hands object columns to
  NumPy, which calls bool() on pd.NA != pd.NA and raises "boolean value
  of NA is ambiguous". Only str cells can change, so the comparison is
  restricted to those positions.
* booleans mixed with pd.NaT: BooleanArray accepts only None/NaN as a
  missing value, so [None, None, NaT, False] raised TypeError("Need to
  pass bool-like values") -- but only when the frame had another column,
  because that changed inference order. Missing cells are normalized to
  NaN before the boolean cast.

Closes #447
Closes #448
Closes #451
@coderabbitai

coderabbitai Bot commented Sep 16, 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: 119c48bc-62d4-4a1c-9fb3-3c16d08d214f


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 3683bb3 into main Sep 16, 2026
22 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

1 participant