Skip to content

Properly coerce fractions as int #1757

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Properly coerce fractions as int #1757

wants to merge 2 commits into from

Conversation

Viicos
Copy link
Member

@Viicos Viicos commented Jul 18, 2025

Change Summary

Fixes pydantic/pydantic#12063.

Related issue number

Checklist

  • Unit tests for the changes exist
  • Documentation reflects the changes where applicable
  • Pydantic tests pass with this pydantic-core (except for expected changes)
  • My PR is ready to review, please add a comment including the phrase "please review" to assign reviewers

@Viicos Viicos requested a review from davidhewitt July 18, 2025 16:24
Comment on lines 288 to 291
#[cfg(Py_3_11)]
let as_int = self.call_method0("__int__");
#[cfg(not(Py_3_11))]
let as_int = self.call_method0("__trunc__");
Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure if there's a better way: maybe pyo3 can do the coercion directly? I've tried downcasting with no success.

Copy link

codspeed-hq bot commented Jul 18, 2025

CodSpeed Performance Report

Merging #1757 will not alter performance

Comparing vp/fractions-int (711b723) with main (37ec6e7)

Summary

✅ 157 untouched benchmarks

@Viicos Viicos force-pushed the vp/fractions-int branch from 363bb55 to 83b6fba Compare July 20, 2025 08:41
Copy link
Contributor

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

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

Think this needs to check the denominator is 1?

@@ -132,6 +133,7 @@ def test_int_py_and_json(py_and_json: PyAndJson, input_value, expected):
(-i64_max + 1, -i64_max + 1),
(i64_max * 2, i64_max * 2),
(-i64_max * 2, -i64_max * 2),
(Fraction(10_935_244_710_974_505), 10_935_244_710_974_505), # https://github.com/pydantic/pydantic/issues/12063
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should also test for cases when the fraction is not an exact integer, I think in those cases we should fail int validation similar to floats and decimals?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice catch

@Viicos Viicos requested a review from davidhewitt July 21, 2025 10:55
Copy link
Contributor

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM 👍

Comment on lines +288 to +304
#[cfg(Py_3_12)]
let is_integer = self.call_method0("is_integer")?.extract::<bool>()?;
#[cfg(not(Py_3_12))]
let is_integer = self.getattr("denominator")?.extract::<i64>().map_or(false, |d| d == 1);

if is_integer {
#[cfg(Py_3_11)]
let as_int = self.call_method0("__int__");
#[cfg(not(Py_3_11))]
let as_int = self.call_method0("__trunc__");
match as_int {
Ok(i) => Ok(EitherInt::Py(i.as_any().to_owned())),
Err(_) => break 'lax,
}
} else {
Err(ValError::new(ErrorTypeDefaults::IntFromFloat, self))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it might be nice to have this as a fraction_as_int method similar to the other components here.

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

Successfully merging this pull request may close these issues.

Coercion of Fraction to int inconsistent with documentation
2 participants