Skip to content

Conversation

@camriddell
Copy link
Contributor

Constructing a new Series with an unspecified datatype/string supertype led to a naive translation of passed floats to strings that was constrained by polars.Config(float_precision=…)

Float64 & Float32 are now handled in the same fashion as PySeries.cast when constructing new Series to preserve as much precision as possible for this style of representation.

Resolves #25257

Constructing a new Series with an unspecified datatype and string
supertype led to a naive translation of passed floats to strings
that was constrained by `polars.Config(float_precision=…)`

Float64 & Float32 are now handled in the same fashion as `PySeries.cast`
when constructing new Series.
@camriddell camriddell changed the title fix: any_value float -> str float_precision fix(Rust): any_value float -> str float_precision Nov 13, 2025
@camriddell camriddell changed the title fix(Rust): any_value float -> str float_precision fix(rust): any_value float -> str float_precision Nov 13, 2025
@codecov
Copy link

codecov bot commented Nov 13, 2025

Codecov Report

❌ Patch coverage is 70.42254% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.04%. Comparing base (0eec829) to head (afae17c).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
crates/polars-core/src/series/any_value.rs 70.42% 21 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #25323      +/-   ##
==========================================
- Coverage   82.05%   82.04%   -0.01%     
==========================================
  Files        1730     1730              
  Lines      241110   241180      +70     
  Branches     3032     3032              
==========================================
+ Hits       197841   197884      +43     
- Misses      42487    42514      +27     
  Partials      782      782              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@camriddell
Copy link
Contributor Author

camriddell commented Nov 13, 2025

I assume that the drop in coverage is likely due to never internally casting to Float32 when digesting PyObjects. If this is always the case shall I remove the AnyValue::Float32 branch?

@coastalwhite coastalwhite changed the title fix(rust): any_value float -> str float_precision fix(rust): Increase precision when constructing float Series Nov 13, 2025
@github-actions github-actions bot added fix Bug fix rust Related to Rust Polars and removed title needs formatting labels Nov 13, 2025
AnyValue::Null => builder.append_null(),
AnyValue::Binary(_) | AnyValue::BinaryOwned(_) => builder.append_null(),
AnyValue::Float64(f) => {
let mut tmp = vec![];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you re-use the buffer like let mut owned is at the start?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be resolved now, let me know if the implementation looks correct- I'm still pretty new to Rust.

@orlp
Copy link
Member

orlp commented Nov 13, 2025

I assume that the drop in coverage is likely due to never internally casting to Float32 when digesting PyObjects. If this is always the case shall I remove the AnyValue::Float32 branch?

No don't worry about it.

@camriddell camriddell requested a review from orlp November 13, 2025 22:03
Copy link
Member

@orlp orlp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation as-is is correct for pure floats, but I think it still goes wrong for nested types which recursively contain floats (like structs and lists).

@camriddell
Copy link
Contributor Author

The implementation as-is is correct for pure floats, but I think it still goes wrong for nested types which recursively contain floats (like structs and lists).

Does this cover the cases you expressed concern about? I just parameterized with a few more cases to test against which all passed locally with out any further source changes.

@camriddell camriddell requested a review from orlp November 14, 2025 18:07
@orlp
Copy link
Member

orlp commented Nov 17, 2025

@camriddell No that doesn't satisfy my concerns because the test case you added doesn't test the mixed string/struct case. This still loses precision:

>>> pl.Series("name", ["a string", {"a": 0.123456789012345}], strict=False, dtype=pl.String)
shape: (2,)
Series: 'name' [str]
[
        "a string"
        "{0.123457}"
]

There needs to be a dedicated path for struct/list/array to handle it recursively, rather than using the Display implementation.

@camriddell
Copy link
Contributor Author

@camriddell No that doesn't satisfy my concerns because the test case you added doesn't test the mixed string/struct case. This still loses precision:

>>> pl.Series("name", ["a string", {"a": 0.123456789012345}], strict=False, dtype=pl.String)
shape: (2,)
Series: 'name' [str]
[
        "a string"
        "{0.123457}"
]

There needs to be a dedicated path for struct/list/array to handle it recursively, rather than using the Display implementation.

Thank you for the clarification and MRE, I'll look into this to recurse through nested data structures.

@camriddell
Copy link
Contributor Author

Hi @orlp I think I have a working solution here. I did a bit of refactoring to keep recursive allocations minimal and added some more tests to cover the cases you highlighted.

The nested data structure formatting code is based on the code in crates/polars-core/src/fmt.rs::{fmt_struct,fmt_list}. Let me know if this seems like the right direction to move in.

Copy link
Member

@orlp orlp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're almost there. Can you add a comment explaining why we do this and not just go through write?

And we very recently added the Float16 type, so I think that also needs a branch here. Sorry to move the goalpost :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Bug fix rust Related to Rust Polars

Projects

None yet

Development

Successfully merging this pull request may close these issues.

polars series truncates digits if reading a number as string

2 participants