]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-87790: support thousands separators for formatting fractional part of Fraction...
authorSergey B Kirpichev <skirpichev@gmail.com>
Mon, 7 Jul 2025 08:16:31 +0000 (11:16 +0300)
committerGitHub <noreply@github.com>
Mon, 7 Jul 2025 08:16:31 +0000 (11:16 +0300)
Lib/fractions.py
Lib/test/test_fractions.py
Misc/NEWS.d/next/Library/2025-04-07-10-20-16.gh-issue-87790.X2SjJe.rst [new file with mode: 0644]

index a8c670685228d32e7cc0e10cd1c0ee1e85f00a43..c1b12e7a1c091c698b7398986ca1f3c95eb69204 100644 (file)
@@ -170,7 +170,11 @@ _FLOAT_FORMAT_SPECIFICATION_MATCHER = re.compile(r"""
     (?P<zeropad>0(?=[0-9]))?
     (?P<minimumwidth>[0-9]+)?
     (?P<thousands_sep>[,_])?
-    (?:\.(?P<precision>[0-9]+))?
+    (?:\.
+        (?=[,_0-9])  # lookahead for digit or separator
+        (?P<precision>[0-9]+)?
+        (?P<frac_separators>[,_])?
+    )?
     (?P<presentation_type>[eEfFgG%])
 """, re.DOTALL | re.VERBOSE).fullmatch
 
@@ -499,6 +503,7 @@ class Fraction(numbers.Rational):
         minimumwidth = int(match["minimumwidth"] or "0")
         thousands_sep = match["thousands_sep"]
         precision = int(match["precision"] or "6")
+        frac_sep = match["frac_separators"] or ""
         presentation_type = match["presentation_type"]
         trim_zeros = presentation_type in "gG" and not alternate_form
         trim_point = not alternate_form
@@ -555,6 +560,9 @@ class Fraction(numbers.Rational):
         if trim_zeros:
             frac_part = frac_part.rstrip("0")
         separator = "" if trim_point and not frac_part else "."
+        if frac_sep:
+            frac_part = frac_sep.join(frac_part[pos:pos + 3]
+                                      for pos in range(0, len(frac_part), 3))
         trailing = separator + frac_part + suffix
 
         # Do zero padding if required.
index 1875a2f529c9575b59ba97713315482b0fe405c1..cf42b86358dbcad80bcca7193841e812b4791b2f 100644 (file)
@@ -1322,6 +1322,8 @@ class FractionTest(unittest.TestCase):
             # Thousands separators
             (F('1234567.123456'), ',.5e', '1.23457e+06'),
             (F('123.123456'), '012_.2e', '0_001.23e+02'),
+            # Thousands separators for fractional part (or for integral too)
+            (F('1234567.123456'), '.5_e', '1.234_57e+06'),
             # z flag is legal, but never makes a difference to the output
             (F(-1, 7**100), 'z.6e', '-3.091690e-85'),
         ]
@@ -1447,6 +1449,12 @@ class FractionTest(unittest.TestCase):
             (F('1234567'), ',.2f', '1,234,567.00'),
             (F('12345678'), ',.2f', '12,345,678.00'),
             (F('12345678'), ',f', '12,345,678.000000'),
+            # Thousands separators for fractional part (or for integral too)
+            (F('123456.789123123'), '._f', '123456.789_123'),
+            (F('123456.789123123'), '.7_f', '123456.789_123_1'),
+            (F('123456.789123123'), '.9_f', '123456.789_123_123'),
+            (F('123456.789123123'), '.,f', '123456.789,123'),
+            (F('123456.789123123'), '_.,f', '123_456.789,123'),
             # Underscore as thousands separator
             (F(2, 3), '_.2f', '0.67'),
             (F(2, 3), '_.7f', '0.6666667'),
@@ -1620,6 +1628,11 @@ class FractionTest(unittest.TestCase):
             '.f',
             '.g',
             '.%',
+            # Thousands separators before precision
+            '._6e',
+            '._6f',
+            '._6g',
+            '._6%',
             # Z instead of z for negative zero suppression
             'Z.2f'
             # z flag not supported for general formatting
diff --git a/Misc/NEWS.d/next/Library/2025-04-07-10-20-16.gh-issue-87790.X2SjJe.rst b/Misc/NEWS.d/next/Library/2025-04-07-10-20-16.gh-issue-87790.X2SjJe.rst
new file mode 100644 (file)
index 0000000..be2a30d
--- /dev/null
@@ -0,0 +1,2 @@
+Support underscore and comma as thousands separators in the fractional part
+for :class:`~fractions.Fraction`'s formatting.  Patch by Sergey B Kirpichev.