Skip to content

Conversation

@CloseChoice
Copy link
Contributor

@CloseChoice CloseChoice commented Oct 23, 2025

Change Summary

Add validation and serialization for fractions.Fraction, heavily inspired by how this is done for Decimal.

Related issue number

supports pydantic/pydantic#12286
This PR works in conjuction with:
pydantic/pydantic#12442

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

Open todos:

  • open pydantic PR
  • decide on how to handle le, ge, lt, gt
  • should we support multiple_of as for Decimal?

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.

Thanks very much for this, overall looks great.

A bunch of comments. Also please be aware that we're considering moving pydantic-core into the pydantic tree (pydantic/pydantic#12436) to make this sort of development of large features easier to write, document and test in one shot.

Depending on the rate of progress you might need to import this PR onto the pydantic repo PR, probably with git subtree pull or similar, we can work that out together.

Comment on lines +814 to +818
type: Required[Literal['decimal']]
le: Decimal
ge: Decimal
lt: Decimal
gt: Decimal
Copy link
Contributor

Choose a reason for hiding this comment

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

Think some decimal -> fraction replacement needed here.

Comment on lines +87 to +93
// let mut is_nan: Option<bool> = None;
// let mut is_nan = || -> PyResult<bool> {
// match is_nan {
// Some(is_nan) => Ok(is_nan),
// None => Ok(*is_nan.insert(decimal.call_method0(intern!(py, "is_nan"))?.extract()?)),
// }
// };
Copy link
Contributor

Choose a reason for hiding this comment

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

nan is presumably not relevant here.

// }
// };

// if let Some(le) = &self.le {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should implement all these (and add tests for validation).

) -> PyResult<Py<PyAny>> {
let _py = value.py();
match extra.ob_type_lookup.is_type(value, ObType::Fraction) {
IsType::Exact | IsType::Subclass => infer_to_python_known(ObType::Fraction, value, include, exclude, extra),
Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunately to avoid breaking changes in pydantic v2 we will need a config flag for the change of Python serialization. (Users can then opt-in to the fixed behaviour and config flag can be deprecated / removed in v3.)

Copy link
Member

Choose a reason for hiding this comment

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

I would say a config flag is probably too much for this use case (no one reported this -- pydantic/pydantic#12286 was created by my when rewriting the types documentation), and users can define a custom serializer until v3.

) -> ValResult<EitherInt<'py>> {
let py = fraction.py();

// as_integer_ratio was added in Python 3.8, so this should be fine
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// as_integer_ratio was added in Python 3.8, so this should be fine

I don't think it's necessary to mention addition of such methods, as we don't support 3.8 anyway.

) -> PyResult<Py<PyAny>> {
let _py = value.py();
match extra.ob_type_lookup.is_type(value, ObType::Fraction) {
IsType::Exact | IsType::Subclass => infer_to_python_known(ObType::Fraction, value, include, exclude, extra),
Copy link
Member

Choose a reason for hiding this comment

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

I would say a config flag is probably too much for this use case (no one reported this -- pydantic/pydantic#12286 was created by my when rewriting the types documentation), and users can define a custom serializer until v3.

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.

3 participants