Skip to content

Commit 5392ea2

Browse files
committed
Support thousands separators for formatting fractional part of Fraction.
See python/cpython#132204
1 parent c30e36b commit 5392ea2

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

src/quicktions.pyx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,11 @@ cdef object _FLOAT_FORMAT_SPECIFICATION_MATCHER = re.compile(r"""
650650
(?P<zeropad>0(?=[0-9]))?
651651
(?P<minimumwidth>[0-9]+)?
652652
(?P<thousands_sep>[,_])?
653-
(?:\.(?P<precision>[0-9]+))?
653+
(?:\.
654+
(?=[,_0-9]) # lookahead for digit or separator
655+
(?P<precision>[0-9]+)?
656+
(?P<frac_separators>[,_])?
657+
)?
654658
(?P<presentation_type>[eEfFgG%])
655659
$
656660
""", re.DOTALL | re.VERBOSE).match
@@ -989,6 +993,7 @@ cdef class Fraction:
989993
cdef Py_ssize_t minimumwidth = int(match["minimumwidth"] or "0")
990994
thousands_sep = match["thousands_sep"]
991995
cdef Py_ssize_t precision = int(match["precision"] or "6")
996+
cdef str frac_sep = match["frac_separators"] or ""
992997
cdef Py_UCS4 presentation_type = ord(match["presentation_type"])
993998
cdef bint trim_zeros = presentation_type in u"gG" and not alternate_form
994999
cdef bint trim_point = not alternate_form
@@ -1049,6 +1054,10 @@ cdef class Fraction:
10491054
if trim_zeros:
10501055
frac_part = frac_part.rstrip("0")
10511056
separator = "" if trim_point and not frac_part else "."
1057+
if frac_sep:
1058+
frac_part = frac_sep.join([
1059+
frac_part[pos:pos + 3] for pos in range(0, len(frac_part), 3)
1060+
])
10521061
trailing = separator + frac_part + suffix
10531062

10541063
# Do zero padding if required.

src/test_fractions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,6 +1530,8 @@ def test_format_e_presentation_type(self):
15301530
# Thousands separators
15311531
(F('1234567.123456'), ',.5e', '1.23457e+06'),
15321532
(F('123.123456'), '012_.2e', '0_001.23e+02'),
1533+
# Thousands separators for fractional part (or for integral too)
1534+
(F('1234567.123456'), '.5_e', '1.234_57e+06'),
15331535
# z flag is legal, but never makes a difference to the output
15341536
(F(-1, 7**100), 'z.6e', '-3.091690e-85'),
15351537
]
@@ -1655,6 +1657,12 @@ def test_format_f_presentation_type(self):
16551657
(F('1234567'), ',.2f', '1,234,567.00'),
16561658
(F('12345678'), ',.2f', '12,345,678.00'),
16571659
(F('12345678'), ',f', '12,345,678.000000'),
1660+
# Thousands separators for fractional part (or for integral too)
1661+
(F('123456.789123123'), '._f', '123456.789_123'),
1662+
(F('123456.789123123'), '.7_f', '123456.789_123_1'),
1663+
(F('123456.789123123'), '.9_f', '123456.789_123_123'),
1664+
(F('123456.789123123'), '.,f', '123456.789,123'),
1665+
(F('123456.789123123'), '_.,f', '123_456.789,123'),
16581666
# Underscore as thousands separator
16591667
(F(2, 3), '_.2f', '0.67'),
16601668
(F(2, 3), '_.7f', '0.6666667'),
@@ -1828,6 +1836,11 @@ def test_invalid_formats(self):
18281836
'.f',
18291837
'.g',
18301838
'.%',
1839+
# Thousands separators before precision
1840+
'._6e',
1841+
'._6f',
1842+
'._6g',
1843+
'._6%',
18311844
# Z instead of z for negative zero suppression
18321845
'Z.2f'
18331846
# z flag not supported for general formatting

0 commit comments

Comments
 (0)