Index: Lib/fractions.py =================================================================== --- Lib/fractions.py (revision 71785) +++ Lib/fractions.py (working copy) @@ -28,13 +28,14 @@ (?P[-+]?) # an optional sign, then (?=\d|\.\d) # lookahead for digit or .digit (?P\d*) # numerator (possibly empty) - (?: # followed by an optional - /(?P\d+) # / and denominator + (?: # followed by + (?:/(?P\d+))? # an optional denominator | # or - \.(?P\d*) # decimal point and fractional part - )? + (?:\.(?P\d*))? # an optional fractional part + (?:E(?P[-+]?\d+))? # and optional exponent + ) \s*\Z # and optional whitespace to finish -""", re.VERBOSE) +""", re.VERBOSE | re.IGNORECASE) class Fraction(numbers.Rational): @@ -65,22 +66,28 @@ if not isinstance(numerator, int) and denominator == 1: if isinstance(numerator, str): # Handle construction from strings. - input = numerator - m = _RATIONAL_FORMAT.match(input) + m = _RATIONAL_FORMAT.match(numerator) if m is None: - raise ValueError('Invalid literal for Fraction: %r' % input) - numerator = m.group('num') - decimal = m.group('decimal') - if decimal: - # The literal is a decimal number. - numerator = int(numerator + decimal) - denominator = 10**len(decimal) + raise ValueError('Invalid literal for Fraction: %r' % + numerator) + numerator = int(m.group('num') or '0') + denom = m.group('denom') + if denom: + denominator = int(denom) else: - # The literal is an integer or fraction. - numerator = int(numerator) - # Default denominator to 1. - denominator = int(m.group('denom') or 1) - + denominator = 1 + decimal = m.group('decimal') + if decimal: + scale = 10**len(decimal) + numerator = numerator * scale + int(decimal) + denominator *= scale + exp = m.group('exp') + if exp: + exp = int(exp) + if exp >= 0: + numerator *= 10**exp + else: + denominator *= 10**-exp if m.group('sign') == '-': numerator = -numerator Index: Lib/test/test_fractions.py =================================================================== --- Lib/test/test_fractions.py (revision 71785) +++ Lib/test/test_fractions.py (working copy) @@ -78,7 +78,11 @@ self.assertEquals((-16, 5), _components(F(" -3.2 "))) self.assertEquals((-3, 1), _components(F(" -3. "))) self.assertEquals((3, 5), _components(F(" .6 "))) - + self.assertEquals((1, 3125), _components(F("32.e-5"))) + self.assertEquals((1000000, 1), _components(F("1e+06"))) + self.assertEquals((-12300, 1), _components(F("-1.23e4"))) + self.assertEquals((0, 1), _components(F(" .0e+0\t"))) + self.assertRaisesMessage( ZeroDivisionError, "Fraction(3, 0)", F, "3/0") @@ -101,10 +105,6 @@ ValueError, "Invalid literal for Fraction: '3a2'", F, "3a2") self.assertRaisesMessage( - # Only parse ordinary decimals, not scientific form. - ValueError, "Invalid literal for Fraction: '3.2e4'", - F, "3.2e4") - self.assertRaisesMessage( # Don't accept combinations of decimals and rationals. ValueError, "Invalid literal for Fraction: '3/7.2'", F, "3/7.2")