Skip to content

gh-67790: Support basic formatting for Fraction #111320

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

Merged
merged 15 commits into from
Dec 16, 2023

Conversation

mdickinson
Copy link
Member

@mdickinson mdickinson commented Oct 25, 2023

PR #100161 added fancy float-style formatting for the Fraction type, but left us in a state where basic formatting for fractions (alignment, fill, thousands separators) still wasn't supported. For example, we can't currently specify a minimum width for a formatted fraction:

>>> format(Fraction(3, 2), '20')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/fractions.py", line 427, in __format__
    raise ValueError(
ValueError: Invalid format specifier '20' for object of type 'Fraction'

This PR adds that basic formatting support, aiming for compatibility with int formatting. The basic formatting is active either with presentation type d, or with no explicit presentation type. For example, on this branch:

>>> x = Fraction(103993, 33102)
>>> f"{x:.<20}"  # minimum width, fill and alignment
'103993/33102........'
>>> f"{x:_}"  # thousands separators
'103_993/33_102'
>>> f"{x:+}"  # sign specification
'+103993/33102'
>>> f"{x:+d}"  # explicit 'd' presentation type
'+103993/33102'
>>> y = Fraction(22)
>>> f"{y}"
'22'
>>> f"{y:#}"  # alternate flag '#' forces an explicit denominator
'22/1'

All of the above except f"{y}" currently give ValueError on main.

Some details:

  • Minimum width, fill character, alignment, the sign flag, and thousands separators are supported in the obvious way.
  • The zero-fill flag 0 is not supported (though it's still fine to use 0 as a fill character in the normal way): it's not 100% clear what the semantics should be (should both the numerator and denominator be padded? Just the numerator?) or what value it would provide, so until someone comes up with valid use-cases that can help inform the semantics, I'm leaving this unsupported.
  • The alternate flag # forces a slash and denominator in the formatted output, even when the output is integer-valued. By default, the slash and denominator are left off for integer-valued fractions.

Pinging @ericvsmith for awareness.


📚 Documentation preview 📚: https://cpython-previews--111320.org.readthedocs.build/

@mdickinson mdickinson changed the title gh-67790: Support basic formatting in Fraction.__format__ gh-67790: Support basic formatting for Fraction Oct 25, 2023
@mdickinson
Copy link
Member Author

@serhiy-storchaka @ericvsmith Would either of you be interested in reviewing?

@serhiy-storchaka
Copy link
Member

serhiy-storchaka commented Oct 25, 2023

float.__format__ does not support d. On other hand, %d in printf-like formatting accept float, but truncate it. Would not it cause confusion? Users may (wrongly) suppose that the d format specifier always format a number as a decimal integer.

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

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

It is perhaps out of the scope of this PR or this issue, but it may be useful to provide options for:

  • output as improper fraction: 3/2 as 1 1/2.
  • always output a fraction slash: 3/1 as 3/1. (already possible with the # modifier)
  • specify different symbol for fraction slash, e.g. :, ÷ (U+00F7), (U+2044), (U+2215), (U+2236).

@mdickinson
Copy link
Member Author

mdickinson commented Oct 25, 2023

@serhiy-storchaka Thank you for reviewing!

float.__format__ does not support d. On other hand, %d in printf-like formatting accept float, but truncate it. Would not it cause confusion?

Hmm, possibly. Now that I look at it, we're adding two ways to do exactly the same thing (that is, format(f, s) and format(f, s + 'd') do exactly the same thing where s is a format specifier without a presentation type). That seems unnecessary.

What do you think about simply dropping the d support for now? So for example format(f, '>.10') would still work but format(f, '>.10d') wouldn't. Then we can still add support for a d presentation type in the future if that looks useful.

it may be useful to provide options for [...]

Yes, I think I'd rather leave these to a separate PR.

@serhiy-storchaka
Copy link
Member

What do you think about simply dropping the d support for now?

Looks fine to me.

Copy link
Member

@ericvsmith ericvsmith left a comment

Choose a reason for hiding this comment

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

LGTM

@ericvsmith
Copy link
Member

What do you think about simply dropping the d support for now? So for example format(f, '>.10') would still work but format(f, '>.10d') wouldn't. Then we can still add support for a d presentation type in the future if that looks useful.

Actually, I think I'd require the "d", just in case we want to do somethings else entirely without it. But I don't feel strongly about it.

OTOH, note that for ints, the 'd' has no effect.

@serhiy-storchaka
Copy link
Member

@mdickinson It LGTM if drop 'd' and "integer-like".

@mdickinson
Copy link
Member Author

Thanks @serhiy-storchaka and @ericvsmith for feedback.

@ericvsmith

Actually, I think I'd require the "d", just in case we want to do somethings else entirely without it.

Yes, I can see a case both ways, and part of me wants to require a presentation type for all non-trivial formatting. I think this is close enough to the obvious one way to do formatting for Fractions that I'm happy for it to be the "default" formatting, so not require a "d". I'll make that change.

Copy link
Member

@ericvsmith ericvsmith left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks, Mark!

@mdickinson mdickinson merged commit fe479fb into python:main Dec 16, 2023
@mdickinson mdickinson deleted the fraction-format-d-presentation-type branch December 16, 2023 10:58
scoder added a commit to scoder/quicktions that referenced this pull request Jan 10, 2024
bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull request Jan 21, 2024
https://build.opensuse.org/request/show/1140281
by user dirkmueller + anag+factory
- update to 1.16:
  * Formatting support was improved, following CPython 3.13a3 as
    of python/cpython#111320
  * Add support for Python 3.13 by using Cython 3.0.8 and calling
    math.gcd().
bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull request Feb 7, 2024
https://build.opensuse.org/request/show/1140281
by user dirkmueller + anag+factory
- update to 1.16:
  * Formatting support was improved, following CPython 3.13a3 as
    of python/cpython#111320
  * Add support for Python 3.13 by using Cython 3.0.8 and calling
    math.gcd().
bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull request Feb 7, 2024
https://build.opensuse.org/request/show/1140281
by user dirkmueller + anag+factory
- update to 1.16:
  * Formatting support was improved, following CPython 3.13a3 as
    of python/cpython#111320
  * Add support for Python 3.13 by using Cython 3.0.8 and calling
    math.gcd().
aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
PR python#100161 added fancy float-style formatting for the Fraction type,
but left us in a state where basic formatting for fractions (alignment,
fill, minimum width, thousands separators) still wasn't supported.

This PR adds that support.

---------

Co-authored-by: Serhiy Storchaka <[email protected]>
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
PR python#100161 added fancy float-style formatting for the Fraction type,
but left us in a state where basic formatting for fractions (alignment,
fill, minimum width, thousands separators) still wasn't supported.

This PR adds that support.

---------

Co-authored-by: Serhiy Storchaka <[email protected]>
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