test(dtypes): pin the silent-coercion thresholds - #502
Merged
Merged
Conversation
The last of four mutation lanes on steps/dtypes.py. 19 tests, killing all 19 mutants that survived the full suite. No equivalence claim was needed. These are the thresholds that decide when a column's type is silently rewritten, and how much collateral damage that is allowed to cause: the parse share required to convert, the contamination-share floor, the bad-cell budget before a conversion is abandoned, the coerced-cells report cap, the post-semantic retry, and the datetime screens. Each is pinned at the value, just below it and just above it -- 3 bad cells in 10 warns while 4 stays silent, exactly the cap is not "truncated" while cap+1 is. One worth naming: len(nonnull) > 0 could become >= 0, and .all() on an empty series is True, so an all-null column would have been called integral. 22 mutants were candidates; the full suite killed 3 of them, which got no tests. The lane had drafted and verified kills for all three before Stage 1 finished and removed them once the confirmation showed they were already covered. Sample-vs-column screens compute their drawn positions at runtime through sample_series rather than hard-coding indices, so a pandas RNG change adapts instead of breaking. Also pins a defect, not fixed: a column whose values carry different UTC offsets is reported as target="datetime" while the result is object dtype, and the audit record reads "converted to object" -- a description that, read plainly, says no conversion happened. It also silently disarms the day/month ambiguity note, which is gated on is_datetime64_any_dtype. Verified on py3.12/pandas 2.3.3 (19 passed) and py3.9/pandas 1.5.3 (16 passed, 3 skipped behind PANDAS_MAJOR >= 2, matching the source branch's own gate). Ordering swept over 8 pytest-randomly seeds against all four dtypes test files together: 105 passed each. Full suite 7389 passed. Tests only; no src change.
Contributor
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 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. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The last of four mutation lanes on
steps/dtypes.py. 19 tests, killing all 19 mutants that survived the full suite. No equivalence claim was needed.The 3 already-covered mutants got no tests. The lane had drafted and verified kills for all three before stage 1 finished, then removed them once the confirmation showed they were covered.
Why these matter
These are the thresholds that decide when a column's type is silently rewritten, and how much collateral damage that is allowed to cause:
cmp#10,#13,#24)cmp#30,#31)cmp#32,#36)cmp#33)cmp#34,#35)bool#12,#14,#15,#16)Each is pinned at the value, just below it and just above it — 3 bad cells in 10 warns while 4 stays silent; exactly
COERCED_CELLS_CAPis not reported as truncated while cap+1 is.One worth naming on its own:
len(nonnull) > 0could become>= 0, and.all()on an empty series isTrue— so an all-null column would have been called integral. Now pinned bytest_a_column_with_no_parsed_values_is_never_called_integral.A defect pinned, not fixed
A column whose values carry different UTC offsets is reported as a successful datetime conversion that did not happen:
Values with differing offsets cannot share one tz-aware
datetime64, so pandas returns an object-dtype Series ofTimestamps and_try_datetimeaccepts it. Three problems in one: the declared target is not the delivered result; the audit record contradicts itself — "converted to object" read plainly says no conversion happened, which is squarely the audit-completeness contract; and_record_coerced's day/month ambiguity note, gated onis_datetime64_any_dtype, can never fire for such a column.pd.to_datetime(..., utc=True)yields a realdatetime64[ns, UTC]. The right behaviour is to convert withutc=Trueand say so, or decline the column — claiming"datetime"and deliveringobjectis not defensible. Pinned astest_mixed_utc_offsets_are_reported_as_a_conversion_to_object, marked as recording rather than endorsing.Verification
PANDAS_MAJOR >= 2, matching the source branch's own gatepytest-randomlyseeds with all fourdtypestest files together — 105 passed on each. An order-dependent test nearly landed earlier in this series, so this is checked rather than assumed.ruff check .cleanSample-vs-column screens compute their drawn positions at runtime through
sample_seriesrather than hard-coding indices, so a pandas RNG change adapts instead of breaking.Scope
Tests only — no
src/change. No behaviour change, no changelog entry, no compatibility impact.