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