From f4cef9c83e01369a4d33dd775c53ba6dff9a63b7 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 28 Feb 2025 08:42:42 +0300 Subject: [PATCH] Correct handling of zeropad and fill_char options --- mpmath/libmp/libmpf.py | 14 ++++++-------- mpmath/tests/test_format.py | 13 +++++++------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/mpmath/libmp/libmpf.py b/mpmath/libmp/libmpf.py index c4b0807e..459e5714 100644 --- a/mpmath/libmp/libmpf.py +++ b/mpmath/libmp/libmpf.py @@ -1397,8 +1397,8 @@ _FLOAT_FORMAT_SPECIFICATION_MATCHER = re.compile(r""" (?P[-+ ]?) (?Pz)? (?P\#)? - (?P0)? - (?P0|[1-9][0-9]*)? + (?P0(?=0*[1-9]))? + (?P[0-9]+)? (?P[,_])? (?:\.(?P[0-9]+))? (?P[UDYZN])? @@ -1470,13 +1470,11 @@ def read_format_spec(format_spec): if rounding_char is not None: format_dict['rounding'] = _GMPY_ROUND_CHAR_DICT[rounding_char] - if match['zeropad'] and match['fill_char']: - raise ValueError('Cannot specify both 0-padding and a fill ' - 'character') - if match['zeropad']: - format_dict['align'] = '=' - format_dict['fill_char'] = '0' + if not match['align']: + format_dict['align'] = '=' + if not match['fill_char']: + format_dict['fill_char'] = '0' if format_dict['precision'] < 0 and format_dict['type'].lower() not in ['', 'a', 'b']: format_dict['precision'] = 6 diff --git a/mpmath/tests/test_format.py b/mpmath/tests/test_format.py index 8b73aa9b..3aeb69d9 100644 --- a/mpmath/tests/test_format.py +++ b/mpmath/tests/test_format.py @@ -54,7 +54,9 @@ def fmt_str(draw, types='fFeE', for_complex=False): skip_thousand_separators = True # Width - res += draw(st.sampled_from(['']*7 + list(map(str, range(1, 40))))) + res += draw(st.sampled_from(['']*7 + list(map(str, range(1, 40))) + + ([] if for_complex else ['0' + str(_) + for _ in range(40)]))) # grouping character (thousand_separators) gchar = draw(st.sampled_from([''] + list(',_'))) @@ -470,6 +472,7 @@ def test_mpf_fmt_cpython(): allow_subnormal=True)) @example(fmt='.0g', x=9.995074823339339e-05) # issue 880 @example(fmt='.016f', x=0.1) # issue 915 +@example(fmt='0030f', x=0.3) def test_mpf_floats_bulk(fmt, x): ''' These are additional random tests that check that mp.mpf and fp.mpf yield @@ -479,6 +482,9 @@ def test_mpf_floats_bulk(fmt, x): if not x and math.copysign(1, x) == -1: return # skip negative zero spec = read_format_spec(fmt) + if (spec['width'] > 0 and spec['fill_char'] == '0' + and spec['thousands_separators']): + return # issue 917 if not spec['type'] and spec['precision'] < 0 and math.isfinite(x): # The mpmath could choose a different decimal # representative (wrt CPython) for same binary @@ -799,11 +805,6 @@ def test_errors(): with pytest.raises(ValueError, match="Invalid format specifier '12.3 E '"): f"{mp.mpf('4'):12.3 E }" - with pytest.raises(ValueError, match="Cannot specify both 0-padding " - "and a fill character"): - f"{mp.mpf('4'):q<03f}" - - @settings(max_examples=10000) @given(st.floats(allow_nan=True, allow_infinity=True,