From 130c717a099aaaafa43e7949cab9b8b147c98365 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 25 Oct 2023 11:48:03 +0100 Subject: [PATCH 01/13] gh-67790: Add integer-style formatting for Fraction type --- Doc/whatsnew/3.13.rst | 7 +++ Lib/fractions.py | 87 +++++++++++++++++++++++++++++--------- Lib/test/test_fractions.py | 58 ++++++++++++++++++++++--- 3 files changed, 127 insertions(+), 25 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index a514659e383e4b..dbc23f7972d507 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -171,6 +171,13 @@ doctest :attr:`doctest.TestResults.skipped` attributes. (Contributed by Victor Stinner in :gh:`108794`.) +fractions +--------- + +* Objects of type :class:`fractions.Fraction` now support integer-style + formatting with the ``d`` presentation type. (Contributed by Mark Dickinson + in :gh:`?????`) + io -- diff --git a/Lib/fractions.py b/Lib/fractions.py index c95db0730e5b6d..c51bba4411d4c9 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -139,6 +139,26 @@ def _round_to_figures(n, d, figures): return sign, significand, exponent +# Pattern for matching int-style format specifications; +# supports 'd' presentation type (and missing presentation type, interpreted +# as equivalent to 'd'). +_INT_FORMAT_SPECIFICATION_MATCHER = re.compile(r""" + (?: + (?P.)? + (?P[<>=^]) + )? + (?P[-+ ]?) + # Alt flag forces a slash and denominator in the output, even for + # integer-valued Fraction objects. + (?P\#)? + # We don't implement the zeropad flag since there's no single obvious way + # to interpret it. + (?P0|[1-9][0-9]*)? + (?P[,_])? + (?Pd?) +""", re.DOTALL | re.VERBOSE).fullmatch + + # Pattern for matching float-style format specifications; # supports 'e', 'E', 'f', 'F', 'g', 'G' and '%' presentation types. _FLOAT_FORMAT_SPECIFICATION_MATCHER = re.compile(r""" @@ -414,27 +434,39 @@ def __str__(self): else: return '%s/%s' % (self._numerator, self._denominator) - def __format__(self, format_spec, /): - """Format this fraction according to the given format specification.""" - - # Backwards compatiblility with existing formatting. - if not format_spec: - return str(self) + def _format_int_style(self, match): + """Helper method for __format__; handles 'd' presentation type.""" # Validate and parse the format specifier. - match = _FLOAT_FORMAT_SPECIFICATION_MATCHER(format_spec) - if match is None: - raise ValueError( - f"Invalid format specifier {format_spec!r} " - f"for object of type {type(self).__name__!r}" - ) - elif match["align"] is not None and match["zeropad"] is not None: - # Avoid the temptation to guess. - raise ValueError( - f"Invalid format specifier {format_spec!r} " - f"for object of type {type(self).__name__!r}; " - "can't use explicit alignment when zero-padding" - ) + fill = match["fill"] or " " + align = match["align"] or ">" + pos_sign = "" if match["sign"] == "-" else match["sign"] + alternate_form = bool(match["alt"]) + minimumwidth = int(match["minimumwidth"] or "0") + thousands_sep = match["thousands_sep"] or '' + + # Determine the body and sign representation. + n, d = self._numerator, self._denominator + if d > 1 or alternate_form: + body = f"{abs(n):{thousands_sep}}/{d:{thousands_sep}}" + else: + body = f"{abs(n):{thousands_sep}}" + sign = '-' if n < 0 else pos_sign + + # Pad with fill character if necessary and return. + padding = fill * (minimumwidth - len(sign) - len(body)) + if align == ">": + return padding + sign + body + elif align == "<": + return sign + body + padding + elif align == "^": + half = len(padding) // 2 + return padding[:half] + sign + body + padding[half:] + else: # align == "=" + return sign + padding + body + + def _format_float_style(self, match): + """Helper method for __format__; handles float presentation types.""" fill = match["fill"] or " " align = match["align"] or ">" pos_sign = "" if match["sign"] == "-" else match["sign"] @@ -530,6 +562,23 @@ def __format__(self, format_spec, /): else: # align == "=" return sign + padding + body + def __format__(self, format_spec, /): + """Format this fraction according to the given format specification.""" + + if match := _INT_FORMAT_SPECIFICATION_MATCHER(format_spec): + return self._format_int_style(match) + + if match := _FLOAT_FORMAT_SPECIFICATION_MATCHER(format_spec): + # Refuse the temptation to guess if both alignment _and_ + # zero padding are specified. + if match["align"] is None or match["zeropad"] is None: + return self._format_float_style(match) + + raise ValueError( + f"Invalid format specifier {format_spec!r} " + f"for object of type {type(self).__name__!r}" + ) + def _operator_fallbacks(monomorphic_operator, fallback_operator): """Generates forward and reverse operators given a purely-rational operator and a function from the operator module. diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 499e3b6e656faa..cc0deb05430ec7 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -848,17 +848,57 @@ def denominator(self): self.assertEqual(type(f.numerator), myint) self.assertEqual(type(f.denominator), myint) - def test_format_no_presentation_type(self): - # Triples (fraction, specification, expected_result) + def test_format_d_presentation_type(self): + # Triples (fraction, specification, expected_result). We test both + # with and without a trailing 'd' on the specification. testcases = [ - (F(1, 3), '', '1/3'), - (F(-1, 3), '', '-1/3'), - (F(3), '', '3'), - (F(-3), '', '-3'), + # Explicit sign handling + (F(2, 3), '+', '+2/3'), + (F(-2, 3), '+', '-2/3'), + (F(3), '+', '+3'), + (F(-3), '+', '-3'), + (F(2, 3), ' ', ' 2/3'), + (F(-2, 3), ' ', '-2/3'), + (F(3), ' ', ' 3'), + (F(-3), ' ', '-3'), + (F(2, 3), '-', '2/3'), + (F(-2, 3), '-', '-2/3'), + (F(3), '-', '3'), + (F(-3), '-', '-3'), + # Padding + (F(0), '5', ' 0'), + (F(2, 3), '5', ' 2/3'), + (F(-2, 3), '5', ' -2/3'), + (F(2, 3), '0', '2/3'), + (F(2, 3), '1', '2/3'), + (F(2, 3), '2', '2/3'), + # Alignment + (F(2, 3), '<5', '2/3 '), + (F(2, 3), '>5', ' 2/3'), + (F(2, 3), '^5', ' 2/3 '), + (F(2, 3), '=5', ' 2/3'), + (F(-2, 3), '<5', '-2/3 '), + (F(-2, 3), '>5', ' -2/3'), + (F(-2, 3), '^5', '-2/3 '), + (F(-2, 3), '=5', '- 2/3'), + # Fill + (F(2, 3), 'X>5', 'XX2/3'), + (F(-2, 3), '.<5', '-2/3.'), + (F(-2, 3), '\n^6', '\n-2/3\n'), + # Thousands separators + (F(1234, 5679), ',', '1,234/5,679'), + (F(-1234, 5679), '_', '-1_234/5_679'), + (F(1234567), '_', '1_234_567'), + (F(-1234567), ',', '-1,234,567'), + # Alternate form forces a slash in the output + (F(123), '#', '123/1'), + (F(-123), '#', '-123/1'), + (F(0), '#', '0/1'), ] for fraction, spec, expected in testcases: with self.subTest(fraction=fraction, spec=spec): self.assertEqual(format(fraction, spec), expected) + self.assertEqual(format(fraction, spec + 'd'), expected) def test_format_e_presentation_type(self): # Triples (fraction, specification, expected_result) @@ -1218,6 +1258,12 @@ def test_invalid_formats(self): '.%', # Z instead of z for negative zero suppression 'Z.2f' + # D instead of d for integer-style formatting + '10D', + # z flag not supported for integer-style formatting + 'zd', + # zero padding not supported for integer-style formatting + '05d', ] for spec in invalid_specs: with self.subTest(spec=spec): From 13a60d7839d1ac557eee2321bbe489fbaf82aa1e Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 25 Oct 2023 12:44:10 +0100 Subject: [PATCH 02/13] Add docs --- Doc/library/fractions.rst | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 509c63686f5a7f..39d7bf0dbc3e84 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -106,6 +106,10 @@ another rational number, or from a string. presentation types ``"e"``, ``"E"``, ``"f"``, ``"F"``, ``"g"``, ``"G"`` and ``"%""``. + .. versionchanged:: 3.13 + :class:`Fraction` instances now support integer-style formatting, with + presentation type ``"d"`` or missing presentation type. + .. attribute:: numerator Numerator of the Fraction in lowest term. @@ -204,10 +208,14 @@ another rational number, or from a string. Provides support for float-style formatting of :class:`Fraction` instances via the :meth:`str.format` method, the :func:`format` built-in function, or :ref:`Formatted string literals `. The - presentation types ``"e"``, ``"E"``, ``"f"``, ``"F"``, ``"g"``, ``"G"`` - and ``"%"`` are supported. For these presentation types, formatting for a - :class:`Fraction` object ``x`` follows the rules outlined for - the :class:`float` type in the :ref:`formatspec` section. + presentation types ``"d"``, ``"e"``, ``"E"``, ``"f"``, ``"F"``, ``"g"``, + ``"G"`` and ``"%"`` are supported. For presentation types other than + ``"d"``, formatting for a :class:`Fraction` object follows the + rules outlined for the :class:`float` type in the :ref:`formatspec` + section. For presentation type ``"d"``, formatting follows the rules for + the :class:`int` type, except that the zero-fill flag is not supported. + If no presentation type is given, the rules are identical to those for + presentation type ``"d"``. Here are some examples:: @@ -221,7 +229,10 @@ another rational number, or from a string. >>> old_price, new_price = 499, 672 >>> "{:.2%} price increase".format(Fraction(new_price, old_price) - 1) '34.67% price increase' - + >>> format(Fraction(103993, 33102), '_d') + '103_993/33_102' + >>> format(Fraction(1, 7), '.^+10') + '...+1/7...' .. seealso:: From 751211a950fee768105e03af91e238c36e42127e Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 25 Oct 2023 13:08:03 +0100 Subject: [PATCH 03/13] Add news entry --- .../next/Library/2023-10-25-13-07-53.gh-issue-67790.jMn9Ad.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-10-25-13-07-53.gh-issue-67790.jMn9Ad.rst diff --git a/Misc/NEWS.d/next/Library/2023-10-25-13-07-53.gh-issue-67790.jMn9Ad.rst b/Misc/NEWS.d/next/Library/2023-10-25-13-07-53.gh-issue-67790.jMn9Ad.rst new file mode 100644 index 00000000000000..44c5702a6551b0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-25-13-07-53.gh-issue-67790.jMn9Ad.rst @@ -0,0 +1,2 @@ +Implement basic formatting support (minimum width, alignment, fill) for +:class:`fractions.Fraction`. From 51aa87e0a825b5d2cc011a3e51a955661cf724bc Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 25 Oct 2023 13:14:34 +0100 Subject: [PATCH 04/13] Add PR number --- Doc/whatsnew/3.13.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index dbc23f7972d507..9313728e4086d8 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -176,7 +176,7 @@ fractions * Objects of type :class:`fractions.Fraction` now support integer-style formatting with the ``d`` presentation type. (Contributed by Mark Dickinson - in :gh:`?????`) + in :gh:`111320`) io -- From 5c7ac04d2305fb5ac9f14edffd5ce03799d4e1a2 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 25 Oct 2023 13:18:29 +0100 Subject: [PATCH 05/13] Restore original line spacing in docs --- Doc/library/fractions.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 39d7bf0dbc3e84..f5c8cdeeea443e 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -234,6 +234,7 @@ another rational number, or from a string. >>> format(Fraction(1, 7), '.^+10') '...+1/7...' + .. seealso:: Module :mod:`numbers` From 3e7b6b61015f1ddf6616aad90d0fdab61cf03bcf Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 25 Oct 2023 15:16:55 +0100 Subject: [PATCH 06/13] Remove 'float-style', since it's now too specific --- Doc/library/fractions.rst | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index f5c8cdeeea443e..00221037ab1dd4 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -205,17 +205,16 @@ another rational number, or from a string. .. method:: __format__(format_spec, /) - Provides support for float-style formatting of :class:`Fraction` - instances via the :meth:`str.format` method, the :func:`format` built-in - function, or :ref:`Formatted string literals `. The - presentation types ``"d"``, ``"e"``, ``"E"``, ``"f"``, ``"F"``, ``"g"``, - ``"G"`` and ``"%"`` are supported. For presentation types other than - ``"d"``, formatting for a :class:`Fraction` object follows the - rules outlined for the :class:`float` type in the :ref:`formatspec` - section. For presentation type ``"d"``, formatting follows the rules for - the :class:`int` type, except that the zero-fill flag is not supported. - If no presentation type is given, the rules are identical to those for - presentation type ``"d"``. + Provides support for formatting of :class:`Fraction` instances via the + :meth:`str.format` method, the :func:`format` built-in function, or + :ref:`Formatted string literals `. The presentation types + ``"d"``, ``"e"``, ``"E"``, ``"f"``, ``"F"``, ``"g"``, ``"G"`` and ``"%"`` + are supported. For presentation types other than ``"d"``, formatting for + a :class:`Fraction` object follows the rules outlined for the + :class:`float` type in the :ref:`formatspec` section. For presentation + type ``"d"``, formatting follows the rules for the :class:`int` type, + except that the zero-fill flag is not supported. If no presentation type + is given, the rules are identical to those for presentation type ``"d"``. Here are some examples:: From acfa57c3f0dc17e6ed810e2a9d8bcea1e0a53907 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 25 Oct 2023 15:19:25 +0100 Subject: [PATCH 07/13] Tighten doc wording --- Doc/library/fractions.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 00221037ab1dd4..ef60ea322db897 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -210,11 +210,11 @@ another rational number, or from a string. :ref:`Formatted string literals `. The presentation types ``"d"``, ``"e"``, ``"E"``, ``"f"``, ``"F"``, ``"g"``, ``"G"`` and ``"%"`` are supported. For presentation types other than ``"d"``, formatting for - a :class:`Fraction` object follows the rules outlined for the - :class:`float` type in the :ref:`formatspec` section. For presentation - type ``"d"``, formatting follows the rules for the :class:`int` type, - except that the zero-fill flag is not supported. If no presentation type - is given, the rules are identical to those for presentation type ``"d"``. + :class:`Fraction` follows the rules outlined for the :class:`float` type + in the :ref:`formatspec` section. For presentation type ``"d"``, + formatting follows the rules for the :class:`int` type, except that the + zero-fill flag is not supported. If no presentation type is given, the + rules are identical to those for presentation type ``"d"``. Here are some examples:: From 82281821b461569286a979d35441eca7f20538a3 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 3 Dec 2023 09:55:27 +0000 Subject: [PATCH 08/13] Remove support for 'd' presentation type; don't refer to integer-style --- Doc/library/fractions.rst | 39 ++++++++++++++++++++++++-------------- Doc/whatsnew/3.13.rst | 5 +++-- Lib/fractions.py | 18 +++++++++--------- Lib/test/test_fractions.py | 6 ++---- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index ef60ea322db897..3ea223e7a807d2 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -107,8 +107,8 @@ another rational number, or from a string. and ``"%""``. .. versionchanged:: 3.13 - :class:`Fraction` instances now support integer-style formatting, with - presentation type ``"d"`` or missing presentation type. + Formatting of :class:`Fraction` instances without a presentation type + now supports fill, alignment, sign handling, minimum width and grouping. .. attribute:: numerator @@ -207,18 +207,33 @@ another rational number, or from a string. Provides support for formatting of :class:`Fraction` instances via the :meth:`str.format` method, the :func:`format` built-in function, or - :ref:`Formatted string literals `. The presentation types - ``"d"``, ``"e"``, ``"E"``, ``"f"``, ``"F"``, ``"g"``, ``"G"`` and ``"%"`` - are supported. For presentation types other than ``"d"``, formatting for - :class:`Fraction` follows the rules outlined for the :class:`float` type - in the :ref:`formatspec` section. For presentation type ``"d"``, - formatting follows the rules for the :class:`int` type, except that the - zero-fill flag is not supported. If no presentation type is given, the - rules are identical to those for presentation type ``"d"``. + :ref:`Formatted string literals `. + + If the ``format_spec`` format specification string does not end with one + of the presentation types ``'e'``, ``'E'``, ``'f'``, ``'F'``, ``'g'``, + ``'G'`` and ``'%'`` then formatting follows the general rules for fill, + alignment, sign handling, minimum width, and grouping as described in the + :ref:`format specification mini-language `. The "alternate + form" flag ``'#'`` is supported: if present, it forces the output string to + always include an explicit denominator, even when the value being + formatted is an exact integer. The zero-fill flag `'0'` is not supported. + + If the ``format_spec`` format specification string does end with one of + the presentation types ``'e'``, ``'E'``, ``'f'``, ``'F'``, ``'g'``, + ``'G'`` and ``'%'`` then formatting follows the rules outlined for the + :class:`float` type in the :ref:`formatspec` section. Here are some examples:: >>> from fractions import Fraction + >>> format(Fraction(103993, 33102), '_') + '103_993/33_102' + >>> format(Fraction(1, 7), '.^+10') + '...+1/7...' + >>> format(Fraction(3, 1), '') + '3' + >>> format(Fraction(3, 1), '#') + '3/1' >>> format(Fraction(1, 7), '.40g') '0.1428571428571428571428571428571428571429' >>> format(Fraction('1234567.855'), '_.2f') @@ -228,10 +243,6 @@ another rational number, or from a string. >>> old_price, new_price = 499, 672 >>> "{:.2%} price increase".format(Fraction(new_price, old_price) - 1) '34.67% price increase' - >>> format(Fraction(103993, 33102), '_d') - '103_993/33_102' - >>> format(Fraction(1, 7), '.^+10') - '...+1/7...' .. seealso:: diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index fbe852a172d93e..e172f80611f49a 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -195,8 +195,9 @@ doctest fractions --------- -* Objects of type :class:`fractions.Fraction` now support integer-style - formatting with the ``d`` presentation type. (Contributed by Mark Dickinson +* Formatting for objects of type :class:`fractions.Fraction` now supports + the standard format specification mini-language rules for fill, alignment, + sign handling, minimum width and grouping. (Contributed by Mark Dickinson in :gh:`111320`) glob diff --git a/Lib/fractions.py b/Lib/fractions.py index c51bba4411d4c9..6532d5d54e3c35 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -139,10 +139,8 @@ def _round_to_figures(n, d, figures): return sign, significand, exponent -# Pattern for matching int-style format specifications; -# supports 'd' presentation type (and missing presentation type, interpreted -# as equivalent to 'd'). -_INT_FORMAT_SPECIFICATION_MATCHER = re.compile(r""" +# Pattern for matching non-float-style format specifications. +_GENERAL_FORMAT_SPECIFICATION_MATCHER = re.compile(r""" (?: (?P.)? (?P[<>=^]) @@ -155,7 +153,6 @@ def _round_to_figures(n, d, figures): # to interpret it. (?P0|[1-9][0-9]*)? (?P[,_])? - (?Pd?) """, re.DOTALL | re.VERBOSE).fullmatch @@ -434,9 +431,12 @@ def __str__(self): else: return '%s/%s' % (self._numerator, self._denominator) - def _format_int_style(self, match): - """Helper method for __format__; handles 'd' presentation type.""" + def _format_general(self, match): + """Helper method for __format__. + Handles fill, alignment, signs, and thousands separators in the + case of no presentation type. + """ # Validate and parse the format specifier. fill = match["fill"] or " " align = match["align"] or ">" @@ -565,8 +565,8 @@ def _format_float_style(self, match): def __format__(self, format_spec, /): """Format this fraction according to the given format specification.""" - if match := _INT_FORMAT_SPECIFICATION_MATCHER(format_spec): - return self._format_int_style(match) + if match := _GENERAL_FORMAT_SPECIFICATION_MATCHER(format_spec): + return self._format_general(match) if match := _FLOAT_FORMAT_SPECIFICATION_MATCHER(format_spec): # Refuse the temptation to guess if both alignment _and_ diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index cc0deb05430ec7..a7355fd920bc5c 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -848,9 +848,8 @@ def denominator(self): self.assertEqual(type(f.numerator), myint) self.assertEqual(type(f.denominator), myint) - def test_format_d_presentation_type(self): - # Triples (fraction, specification, expected_result). We test both - # with and without a trailing 'd' on the specification. + def test_format_no_presentation_type(self): + # Triples (fraction, specification, expected_result). testcases = [ # Explicit sign handling (F(2, 3), '+', '+2/3'), @@ -898,7 +897,6 @@ def test_format_d_presentation_type(self): for fraction, spec, expected in testcases: with self.subTest(fraction=fraction, spec=spec): self.assertEqual(format(fraction, spec), expected) - self.assertEqual(format(fraction, spec + 'd'), expected) def test_format_e_presentation_type(self): # Triples (fraction, specification, expected_result) From 2fc7d5696ea592f8342ce4bbaa7ab75eb8fcb747 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 3 Dec 2023 09:57:45 +0000 Subject: [PATCH 09/13] Fix single backtick --- Doc/library/fractions.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 3ea223e7a807d2..b9efe2363433bc 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -216,7 +216,8 @@ another rational number, or from a string. :ref:`format specification mini-language `. The "alternate form" flag ``'#'`` is supported: if present, it forces the output string to always include an explicit denominator, even when the value being - formatted is an exact integer. The zero-fill flag `'0'` is not supported. + formatted is an exact integer. The zero-fill flag ``'0'`` is not + supported. If the ``format_spec`` format specification string does end with one of the presentation types ``'e'``, ``'E'``, ``'f'``, ``'F'``, ``'g'``, From 0df75d8288418b57cb2daf8f77fa41389a7e5947 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 3 Dec 2023 09:59:27 +0000 Subject: [PATCH 10/13] Fix grammar - 'or' is better than 'and' here --- Doc/library/fractions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index b9efe2363433bc..d319a0ada9d910 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -211,7 +211,7 @@ another rational number, or from a string. If the ``format_spec`` format specification string does not end with one of the presentation types ``'e'``, ``'E'``, ``'f'``, ``'F'``, ``'g'``, - ``'G'`` and ``'%'`` then formatting follows the general rules for fill, + ``'G'`` or ``'%'`` then formatting follows the general rules for fill, alignment, sign handling, minimum width, and grouping as described in the :ref:`format specification mini-language `. The "alternate form" flag ``'#'`` is supported: if present, it forces the output string to @@ -221,7 +221,7 @@ another rational number, or from a string. If the ``format_spec`` format specification string does end with one of the presentation types ``'e'``, ``'E'``, ``'f'``, ``'F'``, ``'g'``, - ``'G'`` and ``'%'`` then formatting follows the rules outlined for the + ``'G'`` or ``'%'`` then formatting follows the rules outlined for the :class:`float` type in the :ref:`formatspec` section. Here are some examples:: From 9cdc4084cda711177f52d055f53a738a93469f93 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 3 Dec 2023 10:15:43 +0000 Subject: [PATCH 11/13] Tweak wording --- Doc/library/fractions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index d319a0ada9d910..7a6697b0786b23 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -219,7 +219,7 @@ another rational number, or from a string. formatted is an exact integer. The zero-fill flag ``'0'`` is not supported. - If the ``format_spec`` format specification string does end with one of + If the ``format_spec`` format specification string ends with one of the presentation types ``'e'``, ``'E'``, ``'f'``, ``'F'``, ``'g'``, ``'G'`` or ``'%'`` then formatting follows the rules outlined for the :class:`float` type in the :ref:`formatspec` section. From 30260f99b88e5c0fd9fd5d5494f3768e8e69c4bb Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 3 Dec 2023 10:20:09 +0000 Subject: [PATCH 12/13] Update invalid format tests --- Lib/test/test_fractions.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index a7355fd920bc5c..84779526ce0eb0 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -1256,12 +1256,10 @@ def test_invalid_formats(self): '.%', # Z instead of z for negative zero suppression 'Z.2f' - # D instead of d for integer-style formatting - '10D', - # z flag not supported for integer-style formatting - 'zd', - # zero padding not supported for integer-style formatting - '05d', + # z flag not supported for general formatting + 'z', + # zero padding not supported for general formatting + '05', ] for spec in invalid_specs: with self.subTest(spec=spec): From e736e8ea2eaebaf034055d988f6b8f5cac7b1cac Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 3 Dec 2023 10:41:50 +0000 Subject: [PATCH 13/13] Fix a long line in the .rst source --- Doc/library/fractions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 7a6697b0786b23..887c3844d20faa 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -214,8 +214,8 @@ another rational number, or from a string. ``'G'`` or ``'%'`` then formatting follows the general rules for fill, alignment, sign handling, minimum width, and grouping as described in the :ref:`format specification mini-language `. The "alternate - form" flag ``'#'`` is supported: if present, it forces the output string to - always include an explicit denominator, even when the value being + form" flag ``'#'`` is supported: if present, it forces the output string + to always include an explicit denominator, even when the value being formatted is an exact integer. The zero-fill flag ``'0'`` is not supported.