diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-04-22 18:15:25 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-04-22 18:15:25 (GMT) |
commit | 8100bd8431cae4b079ffc1f0c3e33ba019661994 (patch) | |
tree | 4e1d824f65678b76d2438e7a8edbc34689c4b4f3 | |
parent | ebafbb705cbc92e7917e2dea423c141ec2b276b4 (diff) | |
download | cpython-8100bd8431cae4b079ffc1f0c3e33ba019661994.zip cpython-8100bd8431cae4b079ffc1f0c3e33ba019661994.tar.gz cpython-8100bd8431cae4b079ffc1f0c3e33ba019661994.tar.bz2 |
Issue #5812: make Fraction('1e-6') valid. Backport of r71806.
-rw-r--r-- | Doc/library/fractions.rst | 17 | ||||
-rwxr-xr-x | Lib/fractions.py | 45 | ||||
-rw-r--r-- | Lib/test/test_fractions.py | 12 | ||||
-rw-r--r-- | Misc/NEWS | 4 |
4 files changed, 46 insertions, 32 deletions
diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index 36df11c..5e9758e 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -27,20 +27,17 @@ another rational number, or from a string. *other_fraction* is an instance of :class:`numbers.Rational` and returns an :class:`Fraction` instance with the same value. The last version of the constructor expects a string or unicode - instance in one of two possible forms. The first form is:: + instance. The usual form for this instance is:: [sign] numerator ['/' denominator] where the optional ``sign`` may be either '+' or '-' and ``numerator`` and ``denominator`` (if present) are strings of - decimal digits. The second permitted form is that of a number - containing a decimal point:: - - [sign] integer '.' [fraction] | [sign] '.' fraction - - where ``integer`` and ``fraction`` are strings of digits. In - either form the input string may also have leading and/or trailing - whitespace. Here are some examples:: + decimal digits. In addition, any string that represents a finite + value and is accepted by the :class:`float` constructor is also + accepted by the :class:`Fraction` constructor. In either form the + input string may also have leading and/or trailing whitespace. + Here are some examples:: >>> from fractions import Fraction >>> Fraction(16, -10) @@ -58,6 +55,8 @@ another rational number, or from a string. Fraction(1414213, 1000000) >>> Fraction('-.125') Fraction(-1, 8) + >>> Fraction('7e-6') + Fraction(7, 1000000) The :class:`Fraction` class inherits from the abstract base class diff --git a/Lib/fractions.py b/Lib/fractions.py index 446ad8e..7db6b5b 100755 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -30,13 +30,14 @@ _RATIONAL_FORMAT = re.compile(r""" (?P<sign>[-+]?) # an optional sign, then (?=\d|\.\d) # lookahead for digit or .digit (?P<num>\d*) # numerator (possibly empty) - (?: # followed by an optional - /(?P<denom>\d+) # / and denominator + (?: # followed by + (?:/(?P<denom>\d+))? # an optional denominator | # or - \.(?P<decimal>\d*) # decimal point and fractional part - )? + (?:\.(?P<decimal>\d*))? # an optional fractional part + (?:E(?P<exp>[-+]?\d+))? # and optional exponent + ) \s*\Z # and optional whitespace to finish -""", re.VERBOSE) +""", re.VERBOSE | re.IGNORECASE) class Fraction(Rational): @@ -67,22 +68,28 @@ class Fraction(Rational): if type(numerator) not in (int, long) and denominator == 1: if isinstance(numerator, basestring): # 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 diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 0509f92..a180912 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -80,6 +80,11 @@ class FractionTest(unittest.TestCase): self.assertEquals((-16, 5), _components(F(u" -3.2 "))) self.assertEquals((-3, 1), _components(F(u" -3. "))) self.assertEquals((3, 5), _components(F(u" .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.assertEquals((0, 1), _components(F("-0.000e0"))) self.assertRaisesMessage( @@ -89,6 +94,9 @@ class FractionTest(unittest.TestCase): ValueError, "Invalid literal for Fraction: '3/'", F, "3/") self.assertRaisesMessage( + ValueError, "Invalid literal for Fraction: '/2'", + F, "/2") + self.assertRaisesMessage( ValueError, "Invalid literal for Fraction: '3 /2'", F, "3 /2") self.assertRaisesMessage( @@ -104,10 +112,6 @@ class FractionTest(unittest.TestCase): 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 fractions. ValueError, "Invalid literal for Fraction: '3/7.2'", F, "3/7.2") @@ -241,6 +241,10 @@ Core and Builtins Library ------- +- Issue #5812: Fraction('1e6') is valid: more generally, any string + that's valid for float() is now valid for Fraction(), with the + exception of strings representing NaNs and infinities. + - Issue #5795: Fixed test_distutils failure on Debian ppc. - Issue #5768: Fixed bug in Unicode output logic and test case for same. |