1import math
2import unittest
3import sys
4import _ast
5from test import test_support
6from test import script_helper
7import os
8import tempfile
9import textwrap
10
11class TestSpecifics(unittest.TestCase):
12
13    def test_no_ending_newline(self):
14        compile("hi", "<test>", "exec")
15        compile("hi\r", "<test>", "exec")
16
17    def test_empty(self):
18        compile("", "<test>", "exec")
19
20    def test_other_newlines(self):
21        compile("\r\n", "<test>", "exec")
22        compile("\r", "<test>", "exec")
23        compile("hi\r\nstuff\r\ndef f():\n    pass\r", "<test>", "exec")
24        compile("this_is\rreally_old_mac\rdef f():\n    pass", "<test>", "exec")
25
26    def test_debug_assignment(self):
27        # catch assignments to __debug__
28        self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single')
29        import __builtin__
30        prev = __builtin__.__debug__
31        setattr(__builtin__, '__debug__', 'sure')
32        setattr(__builtin__, '__debug__', prev)
33
34    def test_argument_handling(self):
35        # detect duplicate positional and keyword arguments
36        self.assertRaises(SyntaxError, eval, 'lambda a,a:0')
37        self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0')
38        self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0')
39        try:
40            exec 'def f(a, a): pass'
41            self.fail("duplicate arguments")
42        except SyntaxError:
43            pass
44        try:
45            exec 'def f(a = 0, a = 1): pass'
46            self.fail("duplicate keyword arguments")
47        except SyntaxError:
48            pass
49        try:
50            exec 'def f(a): global a; a = 1'
51            self.fail("variable is global and local")
52        except SyntaxError:
53            pass
54
55    def test_syntax_error(self):
56        self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec")
57
58    def test_none_keyword_arg(self):
59        self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec")
60
61    def test_duplicate_global_local(self):
62        try:
63            exec 'def f(a): global a; a = 1'
64            self.fail("variable is global and local")
65        except SyntaxError:
66            pass
67
68    def test_exec_functional_style(self):
69        # Exec'ing a tuple of length 2 works.
70        g = {'b': 2}
71        exec("a = b + 1", g)
72        self.assertEqual(g['a'], 3)
73
74        # As does exec'ing a tuple of length 3.
75        l = {'b': 3}
76        g = {'b': 5, 'c': 7}
77        exec("a = b + c", g, l)
78        self.assertNotIn('a', g)
79        self.assertEqual(l['a'], 10)
80
81        # Tuples not of length 2 or 3 are invalid.
82        with self.assertRaises(TypeError):
83            exec("a = b + 1",)
84
85        with self.assertRaises(TypeError):
86            exec("a = b + 1", {}, {}, {})
87
88        # Can't mix and match the two calling forms.
89        g = {'a': 3, 'b': 4}
90        l = {}
91        with self.assertRaises(TypeError):
92            exec("a = b + 1", g) in g
93        with self.assertRaises(TypeError):
94            exec("a = b + 1", g, l) in g, l
95
96    def test_nested_qualified_exec(self):
97        # Can use qualified exec in nested functions.
98        code = ["""
99def g():
100    def f():
101        if True:
102            exec "" in {}, {}
103        """, """
104def g():
105    def f():
106        if True:
107            exec("", {}, {})
108        """, """
109def g():
110    def f():
111        if True:
112            exec("", {})
113        """]
114        for c in code:
115            compile(c, "<code>", "exec")
116
117    def test_exec_with_general_mapping_for_locals(self):
118
119        class M:
120            "Test mapping interface versus possible calls from eval()."
121            def __getitem__(self, key):
122                if key == 'a':
123                    return 12
124                raise KeyError
125            def __setitem__(self, key, value):
126                self.results = (key, value)
127            def keys(self):
128                return list('xyz')
129
130        m = M()
131        g = globals()
132        exec 'z = a' in g, m
133        self.assertEqual(m.results, ('z', 12))
134        try:
135            exec 'z = b' in g, m
136        except NameError:
137            pass
138        else:
139            self.fail('Did not detect a KeyError')
140        exec 'z = dir()' in g, m
141        self.assertEqual(m.results, ('z', list('xyz')))
142        exec 'z = globals()' in g, m
143        self.assertEqual(m.results, ('z', g))
144        exec 'z = locals()' in g, m
145        self.assertEqual(m.results, ('z', m))
146        try:
147            exec 'z = b' in m
148        except TypeError:
149            pass
150        else:
151            self.fail('Did not validate globals as a real dict')
152
153        class A:
154            "Non-mapping"
155            pass
156        m = A()
157        try:
158            exec 'z = a' in g, m
159        except TypeError:
160            pass
161        else:
162            self.fail('Did not validate locals as a mapping')
163
164        # Verify that dict subclasses work as well
165        class D(dict):
166            def __getitem__(self, key):
167                if key == 'a':
168                    return 12
169                return dict.__getitem__(self, key)
170        d = D()
171        exec 'z = a' in g, d
172        self.assertEqual(d['z'], 12)
173
174    def test_extended_arg(self):
175        longexpr = 'x = x or ' + '-x' * 2500
176        code = '''
177def f(x):
178    %s
179    %s
180    %s
181    %s
182    %s
183    %s
184    %s
185    %s
186    %s
187    %s
188    # the expressions above have no effect, x == argument
189    while x:
190        x -= 1
191        # EXTENDED_ARG/JUMP_ABSOLUTE here
192    return x
193''' % ((longexpr,)*10)
194        exec code
195        self.assertEqual(f(5), 0)
196
197    def test_complex_args(self):
198
199        with test_support.check_py3k_warnings(
200                ("tuple parameter unpacking has been removed", SyntaxWarning)):
201            exec textwrap.dedent('''
202        def comp_args((a, b)):
203            return a,b
204        self.assertEqual(comp_args((1, 2)), (1, 2))
205
206        def comp_args((a, b)=(3, 4)):
207            return a, b
208        self.assertEqual(comp_args((1, 2)), (1, 2))
209        self.assertEqual(comp_args(), (3, 4))
210
211        def comp_args(a, (b, c)):
212            return a, b, c
213        self.assertEqual(comp_args(1, (2, 3)), (1, 2, 3))
214
215        def comp_args(a=2, (b, c)=(3, 4)):
216            return a, b, c
217        self.assertEqual(comp_args(1, (2, 3)), (1, 2, 3))
218        self.assertEqual(comp_args(), (2, 3, 4))
219        ''')
220
221    def test_argument_order(self):
222        try:
223            exec 'def f(a=1, (b, c)): pass'
224            self.fail("non-default args after default")
225        except SyntaxError:
226            pass
227
228    def test_float_literals(self):
229        # testing bad float literals
230        self.assertRaises(SyntaxError, eval, "2e")
231        self.assertRaises(SyntaxError, eval, "2.0e+")
232        self.assertRaises(SyntaxError, eval, "1e-")
233        self.assertRaises(SyntaxError, eval, "3-4e/21")
234
235    def test_indentation(self):
236        # testing compile() of indented block w/o trailing newline"
237        s = """
238if 1:
239    if 2:
240        pass"""
241        compile(s, "<string>", "exec")
242
243    # This test is probably specific to CPython and may not generalize
244    # to other implementations.  We are trying to ensure that when
245    # the first line of code starts after 256, correct line numbers
246    # in tracebacks are still produced.
247    def test_leading_newlines(self):
248        s256 = "".join(["\n"] * 256 + ["spam"])
249        co = compile(s256, 'fn', 'exec')
250        self.assertEqual(co.co_firstlineno, 257)
251        self.assertEqual(co.co_lnotab, '')
252
253    def test_literals_with_leading_zeroes(self):
254        for arg in ["077787", "0xj", "0x.", "0e",  "090000000000000",
255                    "080000000000000", "000000000000009", "000000000000008",
256                    "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2",
257                    "0b101j2", "0o153j2", "0b100e1", "0o777e1", "0o8", "0o78"]:
258            self.assertRaises(SyntaxError, eval, arg)
259
260        self.assertEqual(eval("0777"), 511)
261        self.assertEqual(eval("0777L"), 511)
262        self.assertEqual(eval("000777"), 511)
263        self.assertEqual(eval("0xff"), 255)
264        self.assertEqual(eval("0xffL"), 255)
265        self.assertEqual(eval("0XfF"), 255)
266        self.assertEqual(eval("0777."), 777)
267        self.assertEqual(eval("0777.0"), 777)
268        self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777)
269        self.assertEqual(eval("0777e1"), 7770)
270        self.assertEqual(eval("0e0"), 0)
271        self.assertEqual(eval("0000E-012"), 0)
272        self.assertEqual(eval("09.5"), 9.5)
273        self.assertEqual(eval("0777j"), 777j)
274        self.assertEqual(eval("00j"), 0j)
275        self.assertEqual(eval("00.0"), 0)
276        self.assertEqual(eval("0e3"), 0)
277        self.assertEqual(eval("090000000000000."), 90000000000000.)
278        self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.)
279        self.assertEqual(eval("090000000000000e0"), 90000000000000.)
280        self.assertEqual(eval("090000000000000e-0"), 90000000000000.)
281        self.assertEqual(eval("090000000000000j"), 90000000000000j)
282        self.assertEqual(eval("000000000000007"), 7)
283        self.assertEqual(eval("000000000000008."), 8.)
284        self.assertEqual(eval("000000000000009."), 9.)
285        self.assertEqual(eval("0b101010"), 42)
286        self.assertEqual(eval("-0b000000000010"), -2)
287        self.assertEqual(eval("0o777"), 511)
288        self.assertEqual(eval("-0o0000010"), -8)
289        self.assertEqual(eval("020000000000.0"), 20000000000.0)
290        self.assertEqual(eval("037777777777e0"), 37777777777.0)
291        self.assertEqual(eval("01000000000000000000000.0"),
292                         1000000000000000000000.0)
293
294    def test_unary_minus(self):
295        # Verify treatment of unary minus on negative numbers SF bug #660455
296        if sys.maxint == 2147483647:
297            # 32-bit machine
298            all_one_bits = '0xffffffff'
299            self.assertEqual(eval(all_one_bits), 4294967295L)
300            self.assertEqual(eval("-" + all_one_bits), -4294967295L)
301        elif sys.maxint == 9223372036854775807:
302            # 64-bit machine
303            all_one_bits = '0xffffffffffffffff'
304            self.assertEqual(eval(all_one_bits), 18446744073709551615L)
305            self.assertEqual(eval("-" + all_one_bits), -18446744073709551615L)
306        else:
307            self.fail("How many bits *does* this machine have???")
308        # Verify treatment of constant folding on -(sys.maxint+1)
309        # i.e. -2147483648 on 32 bit platforms.  Should return int, not long.
310        self.assertIsInstance(eval("%s" % (-sys.maxint - 1)), int)
311        self.assertIsInstance(eval("%s" % (-sys.maxint - 2)), long)
312
313    if sys.maxint == 9223372036854775807:
314        def test_32_63_bit_values(self):
315            a = +4294967296  # 1 << 32
316            b = -4294967296  # 1 << 32
317            c = +281474976710656  # 1 << 48
318            d = -281474976710656  # 1 << 48
319            e = +4611686018427387904  # 1 << 62
320            f = -4611686018427387904  # 1 << 62
321            g = +9223372036854775807  # 1 << 63 - 1
322            h = -9223372036854775807  # 1 << 63 - 1
323
324            for variable in self.test_32_63_bit_values.func_code.co_consts:
325                if variable is not None:
326                    self.assertIsInstance(variable, int)
327
328    def test_sequence_unpacking_error(self):
329        # Verify sequence packing/unpacking with "or".  SF bug #757818
330        i,j = (1, -1) or (-1, 1)
331        self.assertEqual(i, 1)
332        self.assertEqual(j, -1)
333
334    def test_none_assignment(self):
335        stmts = [
336            'None = 0',
337            'None += 0',
338            '__builtins__.None = 0',
339            'def None(): pass',
340            'class None: pass',
341            '(a, None) = 0, 0',
342            'for None in range(10): pass',
343            'def f(None): pass',
344            'import None',
345            'import x as None',
346            'from x import None',
347            'from x import y as None'
348        ]
349        for stmt in stmts:
350            stmt += "\n"
351            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single')
352            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
353        # This is ok.
354        compile("from None import x", "tmp", "exec")
355        compile("from x import None as y", "tmp", "exec")
356        compile("import None as x", "tmp", "exec")
357
358    def test_import(self):
359        succeed = [
360            'import sys',
361            'import os, sys',
362            'import os as bar',
363            'import os.path as bar',
364            'from __future__ import nested_scopes, generators',
365            'from __future__ import (nested_scopes,\ngenerators)',
366            'from __future__ import (nested_scopes,\ngenerators,)',
367            'from sys import stdin, stderr, stdout',
368            'from sys import (stdin, stderr,\nstdout)',
369            'from sys import (stdin, stderr,\nstdout,)',
370            'from sys import (stdin\n, stderr, stdout)',
371            'from sys import (stdin\n, stderr, stdout,)',
372            'from sys import stdin as si, stdout as so, stderr as se',
373            'from sys import (stdin as si, stdout as so, stderr as se)',
374            'from sys import (stdin as si, stdout as so, stderr as se,)',
375            ]
376        fail = [
377            'import (os, sys)',
378            'import (os), (sys)',
379            'import ((os), (sys))',
380            'import (sys',
381            'import sys)',
382            'import (os,)',
383            'import os As bar',
384            'import os.path a bar',
385            'from sys import stdin As stdout',
386            'from sys import stdin a stdout',
387            'from (sys) import stdin',
388            'from __future__ import (nested_scopes',
389            'from __future__ import nested_scopes)',
390            'from __future__ import nested_scopes,\ngenerators',
391            'from sys import (stdin',
392            'from sys import stdin)',
393            'from sys import stdin, stdout,\nstderr',
394            'from sys import stdin si',
395            'from sys import stdin,'
396            'from sys import (*)',
397            'from sys import (stdin,, stdout, stderr)',
398            'from sys import (stdin, stdout),',
399            ]
400        for stmt in succeed:
401            compile(stmt, 'tmp', 'exec')
402        for stmt in fail:
403            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
404
405    def test_for_distinct_code_objects(self):
406        # SF bug 1048870
407        def f():
408            f1 = lambda x=1: x
409            f2 = lambda x=2: x
410            return f1, f2
411        f1, f2 = f()
412        self.assertNotEqual(id(f1.func_code), id(f2.func_code))
413
414    def test_lambda_doc(self):
415        l = lambda: "foo"
416        self.assertIsNone(l.__doc__)
417
418    @test_support.requires_unicode
419    def test_encoding(self):
420        code = b'# -*- coding: badencoding -*-\npass\n'
421        self.assertRaises(SyntaxError, compile, code, 'tmp', 'exec')
422        code = u"# -*- coding: utf-8 -*-\npass\n"
423        self.assertRaises(SyntaxError, compile, code, "tmp", "exec")
424        code = 'u"\xc2\xa4"\n'
425        self.assertEqual(eval(code), u'\xc2\xa4')
426        code = u'u"\xc2\xa4"\n'
427        self.assertEqual(eval(code), u'\xc2\xa4')
428        code = '# -*- coding: latin1 -*-\nu"\xc2\xa4"\n'
429        self.assertEqual(eval(code), u'\xc2\xa4')
430        code = '# -*- coding: utf-8 -*-\nu"\xc2\xa4"\n'
431        self.assertEqual(eval(code), u'\xa4')
432        code = '# -*- coding: iso8859-15 -*-\nu"\xc2\xa4"\n'
433        self.assertEqual(eval(code), test_support.u(r'\xc2\u20ac'))
434        code = 'u"""\\\n# -*- coding: utf-8 -*-\n\xc2\xa4"""\n'
435        self.assertEqual(eval(code), u'# -*- coding: utf-8 -*-\n\xc2\xa4')
436
437    def test_subscripts(self):
438        # SF bug 1448804
439        # Class to make testing subscript results easy
440        class str_map(object):
441            def __init__(self):
442                self.data = {}
443            def __getitem__(self, key):
444                return self.data[str(key)]
445            def __setitem__(self, key, value):
446                self.data[str(key)] = value
447            def __delitem__(self, key):
448                del self.data[str(key)]
449            def __contains__(self, key):
450                return str(key) in self.data
451        d = str_map()
452        # Index
453        d[1] = 1
454        self.assertEqual(d[1], 1)
455        d[1] += 1
456        self.assertEqual(d[1], 2)
457        del d[1]
458        self.assertNotIn(1, d)
459        # Tuple of indices
460        d[1, 1] = 1
461        self.assertEqual(d[1, 1], 1)
462        d[1, 1] += 1
463        self.assertEqual(d[1, 1], 2)
464        del d[1, 1]
465        self.assertNotIn((1, 1), d)
466        # Simple slice
467        d[1:2] = 1
468        self.assertEqual(d[1:2], 1)
469        d[1:2] += 1
470        self.assertEqual(d[1:2], 2)
471        del d[1:2]
472        self.assertNotIn(slice(1, 2), d)
473        # Tuple of simple slices
474        d[1:2, 1:2] = 1
475        self.assertEqual(d[1:2, 1:2], 1)
476        d[1:2, 1:2] += 1
477        self.assertEqual(d[1:2, 1:2], 2)
478        del d[1:2, 1:2]
479        self.assertNotIn((slice(1, 2), slice(1, 2)), d)
480        # Extended slice
481        d[1:2:3] = 1
482        self.assertEqual(d[1:2:3], 1)
483        d[1:2:3] += 1
484        self.assertEqual(d[1:2:3], 2)
485        del d[1:2:3]
486        self.assertNotIn(slice(1, 2, 3), d)
487        # Tuple of extended slices
488        d[1:2:3, 1:2:3] = 1
489        self.assertEqual(d[1:2:3, 1:2:3], 1)
490        d[1:2:3, 1:2:3] += 1
491        self.assertEqual(d[1:2:3, 1:2:3], 2)
492        del d[1:2:3, 1:2:3]
493        self.assertNotIn((slice(1, 2, 3), slice(1, 2, 3)), d)
494        # Ellipsis
495        d[...] = 1
496        self.assertEqual(d[...], 1)
497        d[...] += 1
498        self.assertEqual(d[...], 2)
499        del d[...]
500        self.assertNotIn(Ellipsis, d)
501        # Tuple of Ellipses
502        d[..., ...] = 1
503        self.assertEqual(d[..., ...], 1)
504        d[..., ...] += 1
505        self.assertEqual(d[..., ...], 2)
506        del d[..., ...]
507        self.assertNotIn((Ellipsis, Ellipsis), d)
508
509    def test_mangling(self):
510        class A:
511            def f():
512                __mangled = 1
513                __not_mangled__ = 2
514                import __mangled_mod
515                import __package__.module
516
517        self.assertIn("_A__mangled", A.f.func_code.co_varnames)
518        self.assertIn("__not_mangled__", A.f.func_code.co_varnames)
519        self.assertIn("_A__mangled_mod", A.f.func_code.co_varnames)
520        self.assertIn("__package__", A.f.func_code.co_varnames)
521
522    def test_compile_ast(self):
523        fname = __file__
524        if fname.lower().endswith(('pyc', 'pyo')):
525            fname = fname[:-1]
526        with open(fname, 'r') as f:
527            fcontents = f.read()
528        sample_code = [
529            ['<assign>', 'x = 5'],
530            ['<print1>', 'print 1'],
531            ['<printv>', 'print v'],
532            ['<printTrue>', 'print True'],
533            ['<printList>', 'print []'],
534            ['<ifblock>', """if True:\n    pass\n"""],
535            ['<forblock>', """for n in [1, 2, 3]:\n    print n\n"""],
536            ['<deffunc>', """def foo():\n    pass\nfoo()\n"""],
537            [fname, fcontents],
538        ]
539
540        for fname, code in sample_code:
541            co1 = compile(code, '%s1' % fname, 'exec')
542            ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST)
543            self.assertTrue(type(ast) == _ast.Module)
544            co2 = compile(ast, '%s3' % fname, 'exec')
545            self.assertEqual(co1, co2)
546            # the code object's filename comes from the second compilation step
547            self.assertEqual(co2.co_filename, '%s3' % fname)
548
549        # raise exception when node type doesn't match with compile mode
550        co1 = compile('print 1', '<string>', 'exec', _ast.PyCF_ONLY_AST)
551        self.assertRaises(TypeError, compile, co1, '<ast>', 'eval')
552
553        # raise exception when node type is no start node
554        self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec')
555
556        # raise exception when node has invalid children
557        ast = _ast.Module()
558        ast.body = [_ast.BoolOp()]
559        self.assertRaises(TypeError, compile, ast, '<ast>', 'exec')
560
561    def test_yet_more_evil_still_undecodable(self):
562        # Issue #25388
563        src = b"#\x00\n#\xfd\n"
564        tmpd = tempfile.mkdtemp()
565        try:
566            fn = os.path.join(tmpd, "bad.py")
567            with open(fn, "wb") as fp:
568                fp.write(src)
569            rc, out, err = script_helper.assert_python_failure(fn)
570        finally:
571            test_support.rmtree(tmpd)
572        self.assertIn(b"Non-ASCII", err)
573
574    def test_null_terminated(self):
575        # The source code is null-terminated internally, but bytes-like
576        # objects are accepted, which could be not terminated.
577        with self.assertRaisesRegexp(TypeError, "without null bytes"):
578            compile(u"123\x00", "<dummy>", "eval")
579        with test_support.check_py3k_warnings():
580            with self.assertRaisesRegexp(TypeError, "without null bytes"):
581                compile(buffer("123\x00"), "<dummy>", "eval")
582            code = compile(buffer("123\x00", 1, 2), "<dummy>", "eval")
583            self.assertEqual(eval(code), 23)
584            code = compile(buffer("1234", 1, 2), "<dummy>", "eval")
585            self.assertEqual(eval(code), 23)
586            code = compile(buffer("$23$", 1, 2), "<dummy>", "eval")
587            self.assertEqual(eval(code), 23)
588
589class TestStackSize(unittest.TestCase):
590    # These tests check that the computed stack size for a code object
591    # stays within reasonable bounds (see issue #21523 for an example
592    # dysfunction).
593    N = 100
594
595    def check_stack_size(self, code):
596        # To assert that the alleged stack size is not O(N), we
597        # check that it is smaller than log(N).
598        if isinstance(code, str):
599            code = compile(code, "<foo>", "single")
600        max_size = math.ceil(math.log(len(code.co_code)))
601        self.assertLessEqual(code.co_stacksize, max_size)
602
603    def test_and(self):
604        self.check_stack_size("x and " * self.N + "x")
605
606    def test_or(self):
607        self.check_stack_size("x or " * self.N + "x")
608
609    def test_and_or(self):
610        self.check_stack_size("x and x or " * self.N + "x")
611
612    def test_chained_comparison(self):
613        self.check_stack_size("x < " * self.N + "x")
614
615    def test_if_else(self):
616        self.check_stack_size("x if x else " * self.N + "x")
617
618    def test_binop(self):
619        self.check_stack_size("x + " * self.N + "x")
620
621    def test_func_and(self):
622        code = "def f(x):\n"
623        code += "   x and x\n" * self.N
624        self.check_stack_size(code)
625
626    def check_constant(self, func, expected):
627        for const in func.__code__.co_consts:
628            if repr(const) == repr(expected):
629                break
630        else:
631            self.fail("unable to find constant %r in %r"
632                      % (expected, func.__code__.co_consts))
633
634    # Merging equal constants is not a strict requirement for the Python
635    # semantics, it's a more an implementation detail.
636    @test_support.cpython_only
637    def test_merge_constants(self):
638        # Issue #25843: compile() must merge constants which are equal
639        # and have the same type.
640
641        def check_same_constant(const):
642            ns = {}
643            code = "f1, f2 = lambda: %r, lambda: %r" % (const, const)
644            exec(code, ns)
645            f1 = ns['f1']
646            f2 = ns['f2']
647            self.assertIs(f1.__code__, f2.__code__)
648            self.check_constant(f1, const)
649            self.assertEqual(repr(f1()), repr(const))
650
651        check_same_constant(None)
652        check_same_constant(0)
653        check_same_constant(0.0)
654        check_same_constant(b'abc')
655        check_same_constant('abc')
656
657    def test_dont_merge_constants(self):
658        # Issue #25843: compile() must not merge constants which are equal
659        # but have a different type.
660
661        def check_different_constants(const1, const2):
662            ns = {}
663            exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns)
664            f1 = ns['f1']
665            f2 = ns['f2']
666            self.assertIsNot(f1.__code__, f2.__code__)
667            self.check_constant(f1, const1)
668            self.check_constant(f2, const2)
669            self.assertEqual(repr(f1()), repr(const1))
670            self.assertEqual(repr(f2()), repr(const2))
671
672        check_different_constants(0, 0.0)
673        check_different_constants(+0.0, -0.0)
674        check_different_constants((0,), (0.0,))
675
676        # check_different_constants() cannot be used because repr(-0j) is
677        # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign.
678        f1, f2 = lambda: +0.0j, lambda: -0.0j
679        self.assertIsNot(f1.__code__, f2.__code__)
680        self.check_constant(f1, +0.0j)
681        self.check_constant(f2, -0.0j)
682        self.assertEqual(repr(f1()), repr(+0.0j))
683        self.assertEqual(repr(f2()), repr(-0.0j))
684
685
686def test_main():
687    test_support.run_unittest(__name__)
688
689if __name__ == "__main__":
690    unittest.main()
691