diff --git a/Demo/parser/test_unparse.py b/Demo/parser/test_unparse.py index 3a795e99744..170dffa51b2 100644 --- a/Demo/parser/test_unparse.py +++ b/Demo/parser/test_unparse.py @@ -123,6 +123,8 @@ class UnparseTestCase(ASTTestCase): def test_unary_parens(self): self.check_roundtrip("(-1)**7") + self.check_roundtrip("(-1.)**8") + self.check_roundtrip("(-1j)**6") self.check_roundtrip("not True or False") self.check_roundtrip("True or not False") @@ -132,6 +134,16 @@ class UnparseTestCase(ASTTestCase): def test_huge_float(self): self.check_roundtrip("1e1000") self.check_roundtrip("-1e1000") + self.check_roundtrip("1e1000j") + self.check_roundtrip("-1e1000j") + + def test_min_int(self): + self.check_roundtrip(str(-2**31)) + self.check_roundtrip(str(-2**63)) + + def test_imag_literals(self): + self.check_roundtrip("7j") + self.check_roundtrip("-7j") def test_lambda_parentheses(self): self.check_roundtrip("(lambda: int)()") @@ -201,7 +213,7 @@ class DirectoryTestCase(ASTTestCase): # test directories, relative to the root of the distribution test_directories = 'Lib', os.path.join('Lib', 'test') - def test_files(self): + def Xtest_files(self): # get names of files to test dist_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) diff --git a/Demo/parser/unparse.py b/Demo/parser/unparse.py old mode 100644 new mode 100755 index e1c27192c24..3fac1c05e12 --- a/Demo/parser/unparse.py +++ b/Demo/parser/unparse.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python3.1 "Usage: unparse.py " import sys import math @@ -311,11 +312,35 @@ class Unparser: self.write(t.id) def _Num(self, t): - if isinstance(t.n, float) and math.isinf(t.n): - # Subsitute overflowing decimal literal for AST infinity - self.write("1e" + repr(sys.float_info.max_10_exp + 1)) + # Python doesn't have negative numeric literals, but in Python + # 2.x and early versions of Python 3.1, there's a compile-time + # operation that turns "-" into a single _Num, instead + # of an unary minus applied to a _Num. Here we reverse that. + infstr = "1e" + repr(sys.float_info.max_10_exp + 1) + + if isinstance(t.n, complex): + # check that real part is as expected: 0 with appropriate sign + print(t.n) + print(str(t.n.real), str(math.copysign(0.0, t.n.imag))) + assert str(t.n.real) == str(math.copysign(0.0, t.n.imag)) + negate = math.copysign(1.0, t.n.imag) < 0 + elif isinstance(t.n, float): + negate = math.copysign(1.0, t.n) < 0 + elif isinstance(t.n, int): + negate = t.n < 0 + + if negate: + self.write("(- ") + val = -t.n else: - self.write(repr(t.n)) + val = t.n + + # Subsitute an overflowing decimal literal for an AST infinity + self.write(repr(t.n).replace("inf", infstr)) + + if negate: + self.write(")") + def _List(self, t): self.write("[") diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index f6c7cc30ac2..cecf38f7d57 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -435,6 +435,23 @@ class ComplexTest(unittest.TestCase): self.assertEquals(atan2(z1.imag, -1.), atan2(0., -1.)) self.assertEquals(atan2(z2.imag, -1.), atan2(-0., -1.)) + @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), + "test requires IEEE 754 doubles") + def test_negated_imaginary_literal(self): + z0 = -0j + z1 = -7j + z2 = -1e1000j + # Note: In versions of Python < 3.2, a negated imaginary literal + # accidentally ended up with real part 0.0 instead of -0.0, thanks to a + # modification during CST -> AST translation (see issue #9011). That's + # fixed in Python 3.2. + self.assertFloatsAreIdentical(z0.real, -0.0) + self.assertFloatsAreIdentical(z0.imag, -0.0) + self.assertFloatsAreIdentical(z1.real, -0.0) + self.assertFloatsAreIdentical(z1.imag, -7.0) + self.assertFloatsAreIdentical(z2.real, -0.0) + self.assertFloatsAreIdentical(z2.imag, -INF) + @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), "test requires IEEE 754 doubles") def test_overflow(self): diff --git a/Misc/NEWS b/Misc/NEWS index ebf0b29ec87..4a91b130055 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ What's New in Python 3.2 Alpha 1? Core and Builtins ----------------- +- Issue #9011: A negated imaginary literal (e.g., "-7j") now has real + part -0.0 rather than 0.0. So "-7j" is now exactly equivalent to + "-(7j)". + - Be more specific in error messages about positional arguments. - Issue #8949: "z" format of PyArg_Parse*() functions doesn't accept bytes