Skip to content

fix(freshcore): fall back for non-scalar dtypes and wide ints, restore integer dtypes, keep non-string labels - #389

Merged
kevincostner17 merged 1 commit into
mainfrom
fix/freshcore-dtype-fidelity
Sep 15, 2026
Merged

kevincostner17 merged 1 commit into
mainfrom
fix/freshcore-dtype-fidelity

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Summary

FreshCore's native arrays only carry float, bool and string columns, and the adapter rebuilt results from plain lists keyed by str(label). That silently changed dtypes and labels. This PR:

  • Falls back for datetime (naive and tz-aware), timedelta, categorical, period and interval columns, which used to come back as strings.
  • Falls back for integer columns holding a value beyond ±2**53, which float64 cannot represent exactly.
  • Restores integer dtypes (int64, nullable Int64, other widths) when every returned value is integral and in range. Missing values are allowed only for nullable dtypes. Otherwise the column stays float64 and the change is recorded in report.backend_differences (step "dtypes").
  • Falls back when distinct column labels collide once stringified, before or after renaming (1 and "1", 1 and " 1 "). Previously one column silently overwrote the other.
  • Maps non-colliding non-string labels (e.g. 0, 1 from a headerless CSV) back to the original labels.

All new fallbacks use the existing fallback path, so fallback_policy="error" raises FallbackError. docs/fallback-matrix.md, docs/backends.md and docs/freshcore.md list the new triggers.

Not changed here: bool columns still come back as nullable boolean, and float32 / nullable Float64 still come back as float64.

Tests

New tests/test_execution/test_freshcore_dtype_fidelity.py uses a fake native module:

  • Each fallback (datetime, tz-aware datetime, categorical, timedelta, period, interval, several kinds at once, wide Int64/int64/uint64, colliding labels before and after renaming) gives pandas-equal output, dtypes and actions, with the recorded reason. Each also raises FallbackError under fallback_policy="error".
  • The FreshCore engine returns datetime/category columns as strings and ints as float64 #262 reproduction frame matches the pandas engine's dtypes, and big[0] == 2**53 + 1.
  • int64, Int64, Int8 and uint16 round-trip through the native path with their dtype and match the pandas engine.
  • Values that are non-integral, missing from a non-nullable int column, or out of range stay float64 and are recorded in backend_differences.
  • Integer, RangeIndex and mixed renamed/non-string labels round-trip and match the pandas engine.
  • Supported shapes (ints at exactly ±2**53, all-NA Int64, distinct mixed labels) stay native.

Verification

Closes #262
Refs #232 (part 2)

…e integer dtypes, map non-string labels

The FreshCore native arrays only carry float, bool and string values, and the
adapter rebuilt results from plain lists keyed by str(label). That silently
changed dtypes and column labels:

- Datetime (naive and tz-aware), timedelta, categorical, period and interval
  columns were sent as str(v) and came back as object columns of strings.
  _unsupported_reason() now falls back for them, naming the columns and dtype
  kinds, so the run goes through the pandas reference path (and
  fallback_policy="error" raises FallbackError).
- Integer columns holding a value beyond +/-2**53 were rounded by the float64
  round-trip. They now fall back too.
- int64, nullable Int64 and other integer widths came back as float64.
  _frame_from_native() now casts each integer input column back to its input
  dtype when every returned value is integral and in range (missing values
  only for nullable dtypes). Otherwise the column stays float64 and the change
  is recorded in report.backend_differences (step "dtypes").
- Distinct labels whose str() collides, before or after column-name
  normalization (1 and "1", or 1 and " 1 "), collapsed into one native column
  with no record. They now fall back. Non-colliding non-string labels (for
  example 0 and 1 from a headerless CSV) are mapped back to the original
  labels instead of coming back stringified.

Docs: new rows in docs/fallback-matrix.md and matching notes in
docs/backends.md and docs/freshcore.md.

Tests: tests/test_execution/test_freshcore_dtype_fidelity.py covers each
fallback (identical pandas output, recorded reason, FallbackError under
fallback_policy="error"), integer dtype restoration, recorded dtype
differences, and non-string label round-trips with a fake native module.

Closes #262
Refs #232 (part 2)
@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: c1a9fe3c-72f5-4af4-a967-0ffa89c4419b


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 50431cd into main Sep 15, 2026
32 of 33 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.

FreshCore engine returns datetime/category columns as strings and ints as float64

1 participant