• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import dis
2import math
3import os
4import unittest
5import sys
6import _ast
7import tempfile
8import types
9from test import support
10from test.support import script_helper, FakePath
11
12class TestSpecifics(unittest.TestCase):
13
14    def compile_single(self, source):
15        compile(source, "<single>", "single")
16
17    def assertInvalidSingle(self, source):
18        self.assertRaises(SyntaxError, self.compile_single, source)
19
20    def test_no_ending_newline(self):
21        compile("hi", "<test>", "exec")
22        compile("hi\r", "<test>", "exec")
23
24    def test_empty(self):
25        compile("", "<test>", "exec")
26
27    def test_other_newlines(self):
28        compile("\r\n", "<test>", "exec")
29        compile("\r", "<test>", "exec")
30        compile("hi\r\nstuff\r\ndef f():\n    pass\r", "<test>", "exec")
31        compile("this_is\rreally_old_mac\rdef f():\n    pass", "<test>", "exec")
32
33    def test_debug_assignment(self):
34        # catch assignments to __debug__
35        self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single')
36        import builtins
37        prev = builtins.__debug__
38        setattr(builtins, '__debug__', 'sure')
39        self.assertEqual(__debug__, prev)
40        setattr(builtins, '__debug__', prev)
41
42    def test_argument_handling(self):
43        # detect duplicate positional and keyword arguments
44        self.assertRaises(SyntaxError, eval, 'lambda a,a:0')
45        self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0')
46        self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0')
47        self.assertRaises(SyntaxError, exec, 'def f(a, a): pass')
48        self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass')
49        self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
50
51    def test_syntax_error(self):
52        self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec")
53
54    def test_none_keyword_arg(self):
55        self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec")
56
57    def test_duplicate_global_local(self):
58        self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
59
60    def test_exec_with_general_mapping_for_locals(self):
61
62        class M:
63            "Test mapping interface versus possible calls from eval()."
64            def __getitem__(self, key):
65                if key == 'a':
66                    return 12
67                raise KeyError
68            def __setitem__(self, key, value):
69                self.results = (key, value)
70            def keys(self):
71                return list('xyz')
72
73        m = M()
74        g = globals()
75        exec('z = a', g, m)
76        self.assertEqual(m.results, ('z', 12))
77        try:
78            exec('z = b', g, m)
79        except NameError:
80            pass
81        else:
82            self.fail('Did not detect a KeyError')
83        exec('z = dir()', g, m)
84        self.assertEqual(m.results, ('z', list('xyz')))
85        exec('z = globals()', g, m)
86        self.assertEqual(m.results, ('z', g))
87        exec('z = locals()', g, m)
88        self.assertEqual(m.results, ('z', m))
89        self.assertRaises(TypeError, exec, 'z = b', m)
90
91        class A:
92            "Non-mapping"
93            pass
94        m = A()
95        self.assertRaises(TypeError, exec, 'z = a', g, m)
96
97        # Verify that dict subclasses work as well
98        class D(dict):
99            def __getitem__(self, key):
100                if key == 'a':
101                    return 12
102                return dict.__getitem__(self, key)
103        d = D()
104        exec('z = a', g, d)
105        self.assertEqual(d['z'], 12)
106
107    def test_extended_arg(self):
108        longexpr = 'x = x or ' + '-x' * 2500
109        g = {}
110        code = '''
111def f(x):
112    %s
113    %s
114    %s
115    %s
116    %s
117    %s
118    %s
119    %s
120    %s
121    %s
122    # the expressions above have no effect, x == argument
123    while x:
124        x -= 1
125        # EXTENDED_ARG/JUMP_ABSOLUTE here
126    return x
127''' % ((longexpr,)*10)
128        exec(code, g)
129        self.assertEqual(g['f'](5), 0)
130
131    def test_argument_order(self):
132        self.assertRaises(SyntaxError, exec, 'def f(a=1, b): pass')
133
134    def test_float_literals(self):
135        # testing bad float literals
136        self.assertRaises(SyntaxError, eval, "2e")
137        self.assertRaises(SyntaxError, eval, "2.0e+")
138        self.assertRaises(SyntaxError, eval, "1e-")
139        self.assertRaises(SyntaxError, eval, "3-4e/21")
140
141    def test_indentation(self):
142        # testing compile() of indented block w/o trailing newline"
143        s = """
144if 1:
145    if 2:
146        pass"""
147        compile(s, "<string>", "exec")
148
149    # This test is probably specific to CPython and may not generalize
150    # to other implementations.  We are trying to ensure that when
151    # the first line of code starts after 256, correct line numbers
152    # in tracebacks are still produced.
153    def test_leading_newlines(self):
154        s256 = "".join(["\n"] * 256 + ["spam"])
155        co = compile(s256, 'fn', 'exec')
156        self.assertEqual(co.co_firstlineno, 257)
157        self.assertEqual(co.co_lnotab, bytes())
158
159    def test_literals_with_leading_zeroes(self):
160        for arg in ["077787", "0xj", "0x.", "0e",  "090000000000000",
161                    "080000000000000", "000000000000009", "000000000000008",
162                    "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2",
163                    "0b101j2", "0o153j2", "0b100e1", "0o777e1", "0777",
164                    "000777", "000000000000007"]:
165            self.assertRaises(SyntaxError, eval, arg)
166
167        self.assertEqual(eval("0xff"), 255)
168        self.assertEqual(eval("0777."), 777)
169        self.assertEqual(eval("0777.0"), 777)
170        self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777)
171        self.assertEqual(eval("0777e1"), 7770)
172        self.assertEqual(eval("0e0"), 0)
173        self.assertEqual(eval("0000e-012"), 0)
174        self.assertEqual(eval("09.5"), 9.5)
175        self.assertEqual(eval("0777j"), 777j)
176        self.assertEqual(eval("000"), 0)
177        self.assertEqual(eval("00j"), 0j)
178        self.assertEqual(eval("00.0"), 0)
179        self.assertEqual(eval("0e3"), 0)
180        self.assertEqual(eval("090000000000000."), 90000000000000.)
181        self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.)
182        self.assertEqual(eval("090000000000000e0"), 90000000000000.)
183        self.assertEqual(eval("090000000000000e-0"), 90000000000000.)
184        self.assertEqual(eval("090000000000000j"), 90000000000000j)
185        self.assertEqual(eval("000000000000008."), 8.)
186        self.assertEqual(eval("000000000000009."), 9.)
187        self.assertEqual(eval("0b101010"), 42)
188        self.assertEqual(eval("-0b000000000010"), -2)
189        self.assertEqual(eval("0o777"), 511)
190        self.assertEqual(eval("-0o0000010"), -8)
191
192    def test_int_literals_too_long(self):
193        n = 3000
194        source = f"a = 1\nb = 2\nc = {'3'*n}\nd = 4"
195        with support.adjust_int_max_str_digits(n):
196            compile(source, "<long_int_pass>", "exec")  # no errors.
197        with support.adjust_int_max_str_digits(n-1):
198            with self.assertRaises(SyntaxError) as err_ctx:
199                compile(source, "<long_int_fail>", "exec")
200            exc = err_ctx.exception
201            self.assertEqual(exc.lineno, 3)
202            self.assertIn('Exceeds the limit ', str(exc))
203            self.assertIn(' Consider hexadecimal ', str(exc))
204
205    def test_unary_minus(self):
206        # Verify treatment of unary minus on negative numbers SF bug #660455
207        if sys.maxsize == 2147483647:
208            # 32-bit machine
209            all_one_bits = '0xffffffff'
210            self.assertEqual(eval(all_one_bits), 4294967295)
211            self.assertEqual(eval("-" + all_one_bits), -4294967295)
212        elif sys.maxsize == 9223372036854775807:
213            # 64-bit machine
214            all_one_bits = '0xffffffffffffffff'
215            self.assertEqual(eval(all_one_bits), 18446744073709551615)
216            self.assertEqual(eval("-" + all_one_bits), -18446744073709551615)
217        else:
218            self.fail("How many bits *does* this machine have???")
219        # Verify treatment of constant folding on -(sys.maxsize+1)
220        # i.e. -2147483648 on 32 bit platforms.  Should return int.
221        self.assertIsInstance(eval("%s" % (-sys.maxsize - 1)), int)
222        self.assertIsInstance(eval("%s" % (-sys.maxsize - 2)), int)
223
224    if sys.maxsize == 9223372036854775807:
225        def test_32_63_bit_values(self):
226            a = +4294967296  # 1 << 32
227            b = -4294967296  # 1 << 32
228            c = +281474976710656  # 1 << 48
229            d = -281474976710656  # 1 << 48
230            e = +4611686018427387904  # 1 << 62
231            f = -4611686018427387904  # 1 << 62
232            g = +9223372036854775807  # 1 << 63 - 1
233            h = -9223372036854775807  # 1 << 63 - 1
234
235            for variable in self.test_32_63_bit_values.__code__.co_consts:
236                if variable is not None:
237                    self.assertIsInstance(variable, int)
238
239    def test_sequence_unpacking_error(self):
240        # Verify sequence packing/unpacking with "or".  SF bug #757818
241        i,j = (1, -1) or (-1, 1)
242        self.assertEqual(i, 1)
243        self.assertEqual(j, -1)
244
245    def test_none_assignment(self):
246        stmts = [
247            'None = 0',
248            'None += 0',
249            '__builtins__.None = 0',
250            'def None(): pass',
251            'class None: pass',
252            '(a, None) = 0, 0',
253            'for None in range(10): pass',
254            'def f(None): pass',
255            'import None',
256            'import x as None',
257            'from x import None',
258            'from x import y as None'
259        ]
260        for stmt in stmts:
261            stmt += "\n"
262            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single')
263            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
264
265    def test_import(self):
266        succeed = [
267            'import sys',
268            'import os, sys',
269            'import os as bar',
270            'import os.path as bar',
271            'from __future__ import nested_scopes, generators',
272            'from __future__ import (nested_scopes,\ngenerators)',
273            'from __future__ import (nested_scopes,\ngenerators,)',
274            'from sys import stdin, stderr, stdout',
275            'from sys import (stdin, stderr,\nstdout)',
276            'from sys import (stdin, stderr,\nstdout,)',
277            'from sys import (stdin\n, stderr, stdout)',
278            'from sys import (stdin\n, stderr, stdout,)',
279            'from sys import stdin as si, stdout as so, stderr as se',
280            'from sys import (stdin as si, stdout as so, stderr as se)',
281            'from sys import (stdin as si, stdout as so, stderr as se,)',
282            ]
283        fail = [
284            'import (os, sys)',
285            'import (os), (sys)',
286            'import ((os), (sys))',
287            'import (sys',
288            'import sys)',
289            'import (os,)',
290            'import os As bar',
291            'import os.path a bar',
292            'from sys import stdin As stdout',
293            'from sys import stdin a stdout',
294            'from (sys) import stdin',
295            'from __future__ import (nested_scopes',
296            'from __future__ import nested_scopes)',
297            'from __future__ import nested_scopes,\ngenerators',
298            'from sys import (stdin',
299            'from sys import stdin)',
300            'from sys import stdin, stdout,\nstderr',
301            'from sys import stdin si',
302            'from sys import stdin,',
303            'from sys import (*)',
304            'from sys import (stdin,, stdout, stderr)',
305            'from sys import (stdin, stdout),',
306            ]
307        for stmt in succeed:
308            compile(stmt, 'tmp', 'exec')
309        for stmt in fail:
310            self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
311
312    def test_for_distinct_code_objects(self):
313        # SF bug 1048870
314        def f():
315            f1 = lambda x=1: x
316            f2 = lambda x=2: x
317            return f1, f2
318        f1, f2 = f()
319        self.assertNotEqual(id(f1.__code__), id(f2.__code__))
320
321    def test_lambda_doc(self):
322        l = lambda: "foo"
323        self.assertIsNone(l.__doc__)
324
325    def test_encoding(self):
326        code = b'# -*- coding: badencoding -*-\npass\n'
327        self.assertRaises(SyntaxError, compile, code, 'tmp', 'exec')
328        code = '# -*- coding: badencoding -*-\n"\xc2\xa4"\n'
329        compile(code, 'tmp', 'exec')
330        self.assertEqual(eval(code), '\xc2\xa4')
331        code = '"\xc2\xa4"\n'
332        self.assertEqual(eval(code), '\xc2\xa4')
333        code = b'"\xc2\xa4"\n'
334        self.assertEqual(eval(code), '\xa4')
335        code = b'# -*- coding: latin1 -*-\n"\xc2\xa4"\n'
336        self.assertEqual(eval(code), '\xc2\xa4')
337        code = b'# -*- coding: utf-8 -*-\n"\xc2\xa4"\n'
338        self.assertEqual(eval(code), '\xa4')
339        code = b'# -*- coding: iso8859-15 -*-\n"\xc2\xa4"\n'
340        self.assertEqual(eval(code), '\xc2\u20ac')
341        code = '"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n'
342        self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xc2\xa4')
343        code = b'"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n'
344        self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xa4')
345
346    def test_subscripts(self):
347        # SF bug 1448804
348        # Class to make testing subscript results easy
349        class str_map(object):
350            def __init__(self):
351                self.data = {}
352            def __getitem__(self, key):
353                return self.data[str(key)]
354            def __setitem__(self, key, value):
355                self.data[str(key)] = value
356            def __delitem__(self, key):
357                del self.data[str(key)]
358            def __contains__(self, key):
359                return str(key) in self.data
360        d = str_map()
361        # Index
362        d[1] = 1
363        self.assertEqual(d[1], 1)
364        d[1] += 1
365        self.assertEqual(d[1], 2)
366        del d[1]
367        self.assertNotIn(1, d)
368        # Tuple of indices
369        d[1, 1] = 1
370        self.assertEqual(d[1, 1], 1)
371        d[1, 1] += 1
372        self.assertEqual(d[1, 1], 2)
373        del d[1, 1]
374        self.assertNotIn((1, 1), d)
375        # Simple slice
376        d[1:2] = 1
377        self.assertEqual(d[1:2], 1)
378        d[1:2] += 1
379        self.assertEqual(d[1:2], 2)
380        del d[1:2]
381        self.assertNotIn(slice(1, 2), d)
382        # Tuple of simple slices
383        d[1:2, 1:2] = 1
384        self.assertEqual(d[1:2, 1:2], 1)
385        d[1:2, 1:2] += 1
386        self.assertEqual(d[1:2, 1:2], 2)
387        del d[1:2, 1:2]
388        self.assertNotIn((slice(1, 2), slice(1, 2)), d)
389        # Extended slice
390        d[1:2:3] = 1
391        self.assertEqual(d[1:2:3], 1)
392        d[1:2:3] += 1
393        self.assertEqual(d[1:2:3], 2)
394        del d[1:2:3]
395        self.assertNotIn(slice(1, 2, 3), d)
396        # Tuple of extended slices
397        d[1:2:3, 1:2:3] = 1
398        self.assertEqual(d[1:2:3, 1:2:3], 1)
399        d[1:2:3, 1:2:3] += 1
400        self.assertEqual(d[1:2:3, 1:2:3], 2)
401        del d[1:2:3, 1:2:3]
402        self.assertNotIn((slice(1, 2, 3), slice(1, 2, 3)), d)
403        # Ellipsis
404        d[...] = 1
405        self.assertEqual(d[...], 1)
406        d[...] += 1
407        self.assertEqual(d[...], 2)
408        del d[...]
409        self.assertNotIn(Ellipsis, d)
410        # Tuple of Ellipses
411        d[..., ...] = 1
412        self.assertEqual(d[..., ...], 1)
413        d[..., ...] += 1
414        self.assertEqual(d[..., ...], 2)
415        del d[..., ...]
416        self.assertNotIn((Ellipsis, Ellipsis), d)
417
418    def test_annotation_limit(self):
419        # more than 255 annotations, should compile ok
420        s = "def f(%s): pass"
421        s %= ', '.join('a%d:%d' % (i,i) for i in range(300))
422        compile(s, '?', 'exec')
423
424    def test_mangling(self):
425        class A:
426            def f():
427                __mangled = 1
428                __not_mangled__ = 2
429                import __mangled_mod
430                import __package__.module
431
432        self.assertIn("_A__mangled", A.f.__code__.co_varnames)
433        self.assertIn("__not_mangled__", A.f.__code__.co_varnames)
434        self.assertIn("_A__mangled_mod", A.f.__code__.co_varnames)
435        self.assertIn("__package__", A.f.__code__.co_varnames)
436
437    def test_compile_ast(self):
438        fname = __file__
439        if fname.lower().endswith('pyc'):
440            fname = fname[:-1]
441        with open(fname, 'r') as f:
442            fcontents = f.read()
443        sample_code = [
444            ['<assign>', 'x = 5'],
445            ['<ifblock>', """if True:\n    pass\n"""],
446            ['<forblock>', """for n in [1, 2, 3]:\n    print(n)\n"""],
447            ['<deffunc>', """def foo():\n    pass\nfoo()\n"""],
448            [fname, fcontents],
449        ]
450
451        for fname, code in sample_code:
452            co1 = compile(code, '%s1' % fname, 'exec')
453            ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST)
454            self.assertTrue(type(ast) == _ast.Module)
455            co2 = compile(ast, '%s3' % fname, 'exec')
456            self.assertEqual(co1, co2)
457            # the code object's filename comes from the second compilation step
458            self.assertEqual(co2.co_filename, '%s3' % fname)
459
460        # raise exception when node type doesn't match with compile mode
461        co1 = compile('print(1)', '<string>', 'exec', _ast.PyCF_ONLY_AST)
462        self.assertRaises(TypeError, compile, co1, '<ast>', 'eval')
463
464        # raise exception when node type is no start node
465        self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec')
466
467        # raise exception when node has invalid children
468        ast = _ast.Module()
469        ast.body = [_ast.BoolOp()]
470        self.assertRaises(TypeError, compile, ast, '<ast>', 'exec')
471
472    def test_dict_evaluation_order(self):
473        i = 0
474
475        def f():
476            nonlocal i
477            i += 1
478            return i
479
480        d = {f(): f(), f(): f()}
481        self.assertEqual(d, {1: 2, 3: 4})
482
483    def test_compile_filename(self):
484        for filename in 'file.py', b'file.py':
485            code = compile('pass', filename, 'exec')
486            self.assertEqual(code.co_filename, 'file.py')
487        for filename in bytearray(b'file.py'), memoryview(b'file.py'):
488            with self.assertWarns(DeprecationWarning):
489                code = compile('pass', filename, 'exec')
490            self.assertEqual(code.co_filename, 'file.py')
491        self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec')
492
493    @support.cpython_only
494    def test_same_filename_used(self):
495        s = """def f(): pass\ndef g(): pass"""
496        c = compile(s, "myfile", "exec")
497        for obj in c.co_consts:
498            if isinstance(obj, types.CodeType):
499                self.assertIs(obj.co_filename, c.co_filename)
500
501    def test_single_statement(self):
502        self.compile_single("1 + 2")
503        self.compile_single("\n1 + 2")
504        self.compile_single("1 + 2\n")
505        self.compile_single("1 + 2\n\n")
506        self.compile_single("1 + 2\t\t\n")
507        self.compile_single("1 + 2\t\t\n        ")
508        self.compile_single("1 + 2 # one plus two")
509        self.compile_single("1; 2")
510        self.compile_single("import sys; sys")
511        self.compile_single("def f():\n   pass")
512        self.compile_single("while False:\n   pass")
513        self.compile_single("if x:\n   f(x)")
514        self.compile_single("if x:\n   f(x)\nelse:\n   g(x)")
515        self.compile_single("class T:\n   pass")
516
517    def test_bad_single_statement(self):
518        self.assertInvalidSingle('1\n2')
519        self.assertInvalidSingle('def f(): pass')
520        self.assertInvalidSingle('a = 13\nb = 187')
521        self.assertInvalidSingle('del x\ndel y')
522        self.assertInvalidSingle('f()\ng()')
523        self.assertInvalidSingle('f()\n# blah\nblah()')
524        self.assertInvalidSingle('f()\nxy # blah\nblah()')
525        self.assertInvalidSingle('x = 5 # comment\nx = 6\n')
526
527    def test_particularly_evil_undecodable(self):
528        # Issue 24022
529        src = b'0000\x00\n00000000000\n\x00\n\x9e\n'
530        with tempfile.TemporaryDirectory() as tmpd:
531            fn = os.path.join(tmpd, "bad.py")
532            with open(fn, "wb") as fp:
533                fp.write(src)
534            res = script_helper.run_python_until_end(fn)[0]
535        self.assertIn(b"Non-UTF-8", res.err)
536
537    def test_yet_more_evil_still_undecodable(self):
538        # Issue #25388
539        src = b"#\x00\n#\xfd\n"
540        with tempfile.TemporaryDirectory() as tmpd:
541            fn = os.path.join(tmpd, "bad.py")
542            with open(fn, "wb") as fp:
543                fp.write(src)
544            res = script_helper.run_python_until_end(fn)[0]
545        self.assertIn(b"Non-UTF-8", res.err)
546
547    @support.cpython_only
548    def test_compiler_recursion_limit(self):
549        # Expected limit is sys.getrecursionlimit() * the scaling factor
550        # in symtable.c (currently 3)
551        # We expect to fail *at* that limit, because we use up some of
552        # the stack depth limit in the test suite code
553        # So we check the expected limit and 75% of that
554        # XXX (ncoghlan): duplicating the scaling factor here is a little
555        # ugly. Perhaps it should be exposed somewhere...
556        fail_depth = sys.getrecursionlimit() * 3
557        success_depth = int(fail_depth * 0.75)
558
559        def check_limit(prefix, repeated):
560            expect_ok = prefix + repeated * success_depth
561            self.compile_single(expect_ok)
562            broken = prefix + repeated * fail_depth
563            details = "Compiling ({!r} + {!r} * {})".format(
564                         prefix, repeated, fail_depth)
565            with self.assertRaises(RecursionError, msg=details):
566                self.compile_single(broken)
567
568        check_limit("a", "()")
569        check_limit("a", ".b")
570        check_limit("a", "[0]")
571        check_limit("a", "*a")
572
573    def test_null_terminated(self):
574        # The source code is null-terminated internally, but bytes-like
575        # objects are accepted, which could be not terminated.
576        with self.assertRaisesRegex(ValueError, "cannot contain null"):
577            compile("123\x00", "<dummy>", "eval")
578        with self.assertRaisesRegex(ValueError, "cannot contain null"):
579            compile(memoryview(b"123\x00"), "<dummy>", "eval")
580        code = compile(memoryview(b"123\x00")[1:-1], "<dummy>", "eval")
581        self.assertEqual(eval(code), 23)
582        code = compile(memoryview(b"1234")[1:-1], "<dummy>", "eval")
583        self.assertEqual(eval(code), 23)
584        code = compile(memoryview(b"$23$")[1:-1], "<dummy>", "eval")
585        self.assertEqual(eval(code), 23)
586
587        # Also test when eval() and exec() do the compilation step
588        self.assertEqual(eval(memoryview(b"1234")[1:-1]), 23)
589        namespace = dict()
590        exec(memoryview(b"ax = 123")[1:-1], namespace)
591        self.assertEqual(namespace['x'], 12)
592
593    def check_constant(self, func, expected):
594        for const in func.__code__.co_consts:
595            if repr(const) == repr(expected):
596                break
597        else:
598            self.fail("unable to find constant %r in %r"
599                      % (expected, func.__code__.co_consts))
600
601    # Merging equal constants is not a strict requirement for the Python
602    # semantics, it's a more an implementation detail.
603    @support.cpython_only
604    def test_merge_constants(self):
605        # Issue #25843: compile() must merge constants which are equal
606        # and have the same type.
607
608        def check_same_constant(const):
609            ns = {}
610            code = "f1, f2 = lambda: %r, lambda: %r" % (const, const)
611            exec(code, ns)
612            f1 = ns['f1']
613            f2 = ns['f2']
614            self.assertIs(f1.__code__, f2.__code__)
615            self.check_constant(f1, const)
616            self.assertEqual(repr(f1()), repr(const))
617
618        check_same_constant(None)
619        check_same_constant(0)
620        check_same_constant(0.0)
621        check_same_constant(b'abc')
622        check_same_constant('abc')
623
624        # Note: "lambda: ..." emits "LOAD_CONST Ellipsis",
625        # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis"
626        f1, f2 = lambda: ..., lambda: ...
627        self.assertIs(f1.__code__, f2.__code__)
628        self.check_constant(f1, Ellipsis)
629        self.assertEqual(repr(f1()), repr(Ellipsis))
630
631        # Merge constants in tuple or frozenset
632        f1, f2 = lambda: "not a name", lambda: ("not a name",)
633        f3 = lambda x: x in {("not a name",)}
634        self.assertIs(f1.__code__.co_consts[1],
635                      f2.__code__.co_consts[1][0])
636        self.assertIs(next(iter(f3.__code__.co_consts[1])),
637                      f2.__code__.co_consts[1])
638
639        # {0} is converted to a constant frozenset({0}) by the peephole
640        # optimizer
641        f1, f2 = lambda x: x in {0}, lambda x: x in {0}
642        self.assertIs(f1.__code__, f2.__code__)
643        self.check_constant(f1, frozenset({0}))
644        self.assertTrue(f1(0))
645
646    # This is a regression test for a CPython specific peephole optimizer
647    # implementation bug present in a few releases.  It's assertion verifies
648    # that peephole optimization was actually done though that isn't an
649    # indication of the bugs presence or not (crashing is).
650    @support.cpython_only
651    def test_peephole_opt_unreachable_code_array_access_in_bounds(self):
652        """Regression test for issue35193 when run under clang msan."""
653        def unused_code_at_end():
654            return 3
655            raise RuntimeError("unreachable")
656        # The above function definition will trigger the out of bounds
657        # bug in the peephole optimizer as it scans opcodes past the
658        # RETURN_VALUE opcode.  This does not always crash an interpreter.
659        # When you build with the clang memory sanitizer it reliably aborts.
660        self.assertEqual(
661            'RETURN_VALUE',
662            list(dis.get_instructions(unused_code_at_end))[-1].opname)
663
664    def test_dont_merge_constants(self):
665        # Issue #25843: compile() must not merge constants which are equal
666        # but have a different type.
667
668        def check_different_constants(const1, const2):
669            ns = {}
670            exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns)
671            f1 = ns['f1']
672            f2 = ns['f2']
673            self.assertIsNot(f1.__code__, f2.__code__)
674            self.assertNotEqual(f1.__code__, f2.__code__)
675            self.check_constant(f1, const1)
676            self.check_constant(f2, const2)
677            self.assertEqual(repr(f1()), repr(const1))
678            self.assertEqual(repr(f2()), repr(const2))
679
680        check_different_constants(0, 0.0)
681        check_different_constants(+0.0, -0.0)
682        check_different_constants((0,), (0.0,))
683        check_different_constants('a', b'a')
684        check_different_constants(('a',), (b'a',))
685
686        # check_different_constants() cannot be used because repr(-0j) is
687        # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign.
688        f1, f2 = lambda: +0.0j, lambda: -0.0j
689        self.assertIsNot(f1.__code__, f2.__code__)
690        self.check_constant(f1, +0.0j)
691        self.check_constant(f2, -0.0j)
692        self.assertEqual(repr(f1()), repr(+0.0j))
693        self.assertEqual(repr(f2()), repr(-0.0j))
694
695        # {0} is converted to a constant frozenset({0}) by the peephole
696        # optimizer
697        f1, f2 = lambda x: x in {0}, lambda x: x in {0.0}
698        self.assertIsNot(f1.__code__, f2.__code__)
699        self.check_constant(f1, frozenset({0}))
700        self.check_constant(f2, frozenset({0.0}))
701        self.assertTrue(f1(0))
702        self.assertTrue(f2(0.0))
703
704    def test_path_like_objects(self):
705        # An implicit test for PyUnicode_FSDecoder().
706        compile("42", FakePath("test_compile_pathlike"), "single")
707
708    def test_stack_overflow(self):
709        # bpo-31113: Stack overflow when compile a long sequence of
710        # complex statements.
711        compile("if a: b\n" * 200000, "<dummy>", "exec")
712
713    # Multiple users rely on the fact that CPython does not generate
714    # bytecode for dead code blocks. See bpo-37500 for more context.
715    @support.cpython_only
716    def test_dead_blocks_do_not_generate_bytecode(self):
717        def unused_block_if():
718            if 0:
719                return 42
720
721        def unused_block_while():
722            while 0:
723                return 42
724
725        def unused_block_if_else():
726            if 1:
727                return None
728            else:
729                return 42
730
731        def unused_block_while_else():
732            while 1:
733                return None
734            else:
735                return 42
736
737        funcs = [unused_block_if, unused_block_while,
738                 unused_block_if_else, unused_block_while_else]
739
740        for func in funcs:
741            opcodes = list(dis.get_instructions(func))
742            self.assertEqual(2, len(opcodes))
743            self.assertEqual('LOAD_CONST', opcodes[0].opname)
744            self.assertEqual(None, opcodes[0].argval)
745            self.assertEqual('RETURN_VALUE', opcodes[1].opname)
746
747    def test_false_while_loop(self):
748        def break_in_while():
749            while False:
750                break
751
752        def continue_in_while():
753            while False:
754                continue
755
756        funcs = [break_in_while, continue_in_while]
757
758        # Check that we did not raise but we also don't generate bytecode
759        for func in funcs:
760            opcodes = list(dis.get_instructions(func))
761            self.assertEqual(2, len(opcodes))
762            self.assertEqual('LOAD_CONST', opcodes[0].opname)
763            self.assertEqual(None, opcodes[0].argval)
764            self.assertEqual('RETURN_VALUE', opcodes[1].opname)
765
766class TestExpressionStackSize(unittest.TestCase):
767    # These tests check that the computed stack size for a code object
768    # stays within reasonable bounds (see issue #21523 for an example
769    # dysfunction).
770    N = 100
771
772    def check_stack_size(self, code):
773        # To assert that the alleged stack size is not O(N), we
774        # check that it is smaller than log(N).
775        if isinstance(code, str):
776            code = compile(code, "<foo>", "single")
777        max_size = math.ceil(math.log(len(code.co_code)))
778        self.assertLessEqual(code.co_stacksize, max_size)
779
780    def test_and(self):
781        self.check_stack_size("x and " * self.N + "x")
782
783    def test_or(self):
784        self.check_stack_size("x or " * self.N + "x")
785
786    def test_and_or(self):
787        self.check_stack_size("x and x or " * self.N + "x")
788
789    def test_chained_comparison(self):
790        self.check_stack_size("x < " * self.N + "x")
791
792    def test_if_else(self):
793        self.check_stack_size("x if x else " * self.N + "x")
794
795    def test_binop(self):
796        self.check_stack_size("x + " * self.N + "x")
797
798    def test_func_and(self):
799        code = "def f(x):\n"
800        code += "   x and x\n" * self.N
801        self.check_stack_size(code)
802
803
804class TestStackSizeStability(unittest.TestCase):
805    # Check that repeating certain snippets doesn't increase the stack size
806    # beyond what a single snippet requires.
807
808    def check_stack_size(self, snippet, async_=False):
809        def compile_snippet(i):
810            ns = {}
811            script = """def func():\n""" + i * snippet
812            if async_:
813                script = "async " + script
814            code = compile(script, "<script>", "exec")
815            exec(code, ns, ns)
816            return ns['func'].__code__
817
818        sizes = [compile_snippet(i).co_stacksize for i in range(2, 5)]
819        if len(set(sizes)) != 1:
820            import dis, io
821            out = io.StringIO()
822            dis.dis(compile_snippet(1), file=out)
823            self.fail("stack sizes diverge with # of consecutive snippets: "
824                      "%s\n%s\n%s" % (sizes, snippet, out.getvalue()))
825
826    def test_if(self):
827        snippet = """
828            if x:
829                a
830            """
831        self.check_stack_size(snippet)
832
833    def test_if_else(self):
834        snippet = """
835            if x:
836                a
837            elif y:
838                b
839            else:
840                c
841            """
842        self.check_stack_size(snippet)
843
844    def test_try_except_bare(self):
845        snippet = """
846            try:
847                a
848            except:
849                b
850            """
851        self.check_stack_size(snippet)
852
853    def test_try_except_qualified(self):
854        snippet = """
855            try:
856                a
857            except ImportError:
858                b
859            except:
860                c
861            else:
862                d
863            """
864        self.check_stack_size(snippet)
865
866    def test_try_except_as(self):
867        snippet = """
868            try:
869                a
870            except ImportError as e:
871                b
872            except:
873                c
874            else:
875                d
876            """
877        self.check_stack_size(snippet)
878
879    def test_try_finally(self):
880        snippet = """
881                try:
882                    a
883                finally:
884                    b
885            """
886        self.check_stack_size(snippet)
887
888    def test_with(self):
889        snippet = """
890            with x as y:
891                a
892            """
893        self.check_stack_size(snippet)
894
895    def test_while_else(self):
896        snippet = """
897            while x:
898                a
899            else:
900                b
901            """
902        self.check_stack_size(snippet)
903
904    def test_for(self):
905        snippet = """
906            for x in y:
907                a
908            """
909        self.check_stack_size(snippet)
910
911    def test_for_else(self):
912        snippet = """
913            for x in y:
914                a
915            else:
916                b
917            """
918        self.check_stack_size(snippet)
919
920    def test_for_break_continue(self):
921        snippet = """
922            for x in y:
923                if z:
924                    break
925                elif u:
926                    continue
927                else:
928                    a
929            else:
930                b
931            """
932        self.check_stack_size(snippet)
933
934    def test_for_break_continue_inside_try_finally_block(self):
935        snippet = """
936            for x in y:
937                try:
938                    if z:
939                        break
940                    elif u:
941                        continue
942                    else:
943                        a
944                finally:
945                    f
946            else:
947                b
948            """
949        self.check_stack_size(snippet)
950
951    def test_for_break_continue_inside_finally_block(self):
952        snippet = """
953            for x in y:
954                try:
955                    t
956                finally:
957                    if z:
958                        break
959                    elif u:
960                        continue
961                    else:
962                        a
963            else:
964                b
965            """
966        self.check_stack_size(snippet)
967
968    def test_for_break_continue_inside_except_block(self):
969        snippet = """
970            for x in y:
971                try:
972                    t
973                except:
974                    if z:
975                        break
976                    elif u:
977                        continue
978                    else:
979                        a
980            else:
981                b
982            """
983        self.check_stack_size(snippet)
984
985    def test_for_break_continue_inside_with_block(self):
986        snippet = """
987            for x in y:
988                with c:
989                    if z:
990                        break
991                    elif u:
992                        continue
993                    else:
994                        a
995            else:
996                b
997            """
998        self.check_stack_size(snippet)
999
1000    def test_return_inside_try_finally_block(self):
1001        snippet = """
1002            try:
1003                if z:
1004                    return
1005                else:
1006                    a
1007            finally:
1008                f
1009            """
1010        self.check_stack_size(snippet)
1011
1012    def test_return_inside_finally_block(self):
1013        snippet = """
1014            try:
1015                t
1016            finally:
1017                if z:
1018                    return
1019                else:
1020                    a
1021            """
1022        self.check_stack_size(snippet)
1023
1024    def test_return_inside_except_block(self):
1025        snippet = """
1026            try:
1027                t
1028            except:
1029                if z:
1030                    return
1031                else:
1032                    a
1033            """
1034        self.check_stack_size(snippet)
1035
1036    def test_return_inside_with_block(self):
1037        snippet = """
1038            with c:
1039                if z:
1040                    return
1041                else:
1042                    a
1043            """
1044        self.check_stack_size(snippet)
1045
1046    def test_async_with(self):
1047        snippet = """
1048            async with x as y:
1049                a
1050            """
1051        self.check_stack_size(snippet, async_=True)
1052
1053    def test_async_for(self):
1054        snippet = """
1055            async for x in y:
1056                a
1057            """
1058        self.check_stack_size(snippet, async_=True)
1059
1060    def test_async_for_else(self):
1061        snippet = """
1062            async for x in y:
1063                a
1064            else:
1065                b
1066            """
1067        self.check_stack_size(snippet, async_=True)
1068
1069    def test_for_break_continue_inside_async_with_block(self):
1070        snippet = """
1071            for x in y:
1072                async with c:
1073                    if z:
1074                        break
1075                    elif u:
1076                        continue
1077                    else:
1078                        a
1079            else:
1080                b
1081            """
1082        self.check_stack_size(snippet, async_=True)
1083
1084    def test_return_inside_async_with_block(self):
1085        snippet = """
1086            async with c:
1087                if z:
1088                    return
1089                else:
1090                    a
1091            """
1092        self.check_stack_size(snippet, async_=True)
1093
1094
1095if __name__ == "__main__":
1096    unittest.main()
1097