[3.11] gh-114014: Update fractions.Fraction()'s rational parsing regex (GH-114015) (#114025)

Fix a bug in the regex used for parsing a string input to the `fractions.Fraction` constructor. That bug led to an inconsistent exception message being given for some inputs.

---------

Co-authored-by: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
Mark Dickinson 2024-01-13 18:22:31 +00:00 committed by GitHub
parent 25af45d9a4
commit 41edd37160
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 10 deletions

View File

@ -21,17 +21,17 @@ _PyHASH_MODULUS = sys.hash_info.modulus
_PyHASH_INF = sys.hash_info.inf
_RATIONAL_FORMAT = re.compile(r"""
\A\s* # optional whitespace at the start,
(?P<sign>[-+]?) # an optional sign, then
(?=\d|\.\d) # lookahead for digit or .digit
(?P<num>\d*|\d+(_\d+)*) # numerator (possibly empty)
(?: # followed by
(?:/(?P<denom>\d+(_\d+)*))? # an optional denominator
| # or
(?:\.(?P<decimal>d*|\d+(_\d+)*))? # an optional fractional part
(?:E(?P<exp>[-+]?\d+(_\d+)*))? # and optional exponent
\A\s* # optional whitespace at the start,
(?P<sign>[-+]?) # an optional sign, then
(?=\d|\.\d) # lookahead for digit or .digit
(?P<num>\d*|\d+(_\d+)*) # numerator (possibly empty)
(?: # followed by
(?:/(?P<denom>\d+(_\d+)*))? # an optional denominator
| # or
(?:\.(?P<decimal>\d*|\d+(_\d+)*))? # an optional fractional part
(?:E(?P<exp>[-+]?\d+(_\d+)*))? # and optional exponent
)
\s*\Z # and optional whitespace to finish
\s*\Z # and optional whitespace to finish
""", re.VERBOSE | re.IGNORECASE)

View File

@ -259,6 +259,30 @@ class FractionTest(unittest.TestCase):
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '1.1e+1__1'",
F, "1.1e+1__1")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '123.dd'",
F, "123.dd")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '123.5_dd'",
F, "123.5_dd")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: 'dd.5'",
F, "dd.5")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '7_dd'",
F, "7_dd")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '1/dd'",
F, "1/dd")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '1/123_dd'",
F, "1/123_dd")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '789edd'",
F, "789edd")
self.assertRaisesMessage(
ValueError, "Invalid literal for Fraction: '789e2_dd'",
F, "789e2_dd")
# Test catastrophic backtracking.
val = "9"*50 + "_"
self.assertRaisesMessage(

View File

@ -0,0 +1 @@
Fixed a bug in :class:`fractions.Fraction` where an invalid string using ``d`` in the decimals part creates a different error compared to other invalid letters/characters. Patch by Jeremiah Gabriel Pascual.