17db96d56Sopenharmony_ciimport dis 27db96d56Sopenharmony_ciimport math 37db96d56Sopenharmony_ciimport os 47db96d56Sopenharmony_ciimport unittest 57db96d56Sopenharmony_ciimport sys 67db96d56Sopenharmony_ciimport ast 77db96d56Sopenharmony_ciimport _ast 87db96d56Sopenharmony_ciimport tempfile 97db96d56Sopenharmony_ciimport types 107db96d56Sopenharmony_ciimport textwrap 117db96d56Sopenharmony_cifrom test import support 127db96d56Sopenharmony_cifrom test.support import script_helper, requires_debug_ranges 137db96d56Sopenharmony_cifrom test.support.os_helper import FakePath 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ciclass TestSpecifics(unittest.TestCase): 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ci def compile_single(self, source): 197db96d56Sopenharmony_ci compile(source, "<single>", "single") 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ci def assertInvalidSingle(self, source): 227db96d56Sopenharmony_ci self.assertRaises(SyntaxError, self.compile_single, source) 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci def test_no_ending_newline(self): 257db96d56Sopenharmony_ci compile("hi", "<test>", "exec") 267db96d56Sopenharmony_ci compile("hi\r", "<test>", "exec") 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_ci def test_empty(self): 297db96d56Sopenharmony_ci compile("", "<test>", "exec") 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci def test_other_newlines(self): 327db96d56Sopenharmony_ci compile("\r\n", "<test>", "exec") 337db96d56Sopenharmony_ci compile("\r", "<test>", "exec") 347db96d56Sopenharmony_ci compile("hi\r\nstuff\r\ndef f():\n pass\r", "<test>", "exec") 357db96d56Sopenharmony_ci compile("this_is\rreally_old_mac\rdef f():\n pass", "<test>", "exec") 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci def test_debug_assignment(self): 387db96d56Sopenharmony_ci # catch assignments to __debug__ 397db96d56Sopenharmony_ci self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single') 407db96d56Sopenharmony_ci import builtins 417db96d56Sopenharmony_ci prev = builtins.__debug__ 427db96d56Sopenharmony_ci setattr(builtins, '__debug__', 'sure') 437db96d56Sopenharmony_ci self.assertEqual(__debug__, prev) 447db96d56Sopenharmony_ci setattr(builtins, '__debug__', prev) 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci def test_argument_handling(self): 477db96d56Sopenharmony_ci # detect duplicate positional and keyword arguments 487db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, 'lambda a,a:0') 497db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0') 507db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0') 517db96d56Sopenharmony_ci self.assertRaises(SyntaxError, exec, 'def f(a, a): pass') 527db96d56Sopenharmony_ci self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass') 537db96d56Sopenharmony_ci self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1') 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci def test_syntax_error(self): 567db96d56Sopenharmony_ci self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec") 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci def test_none_keyword_arg(self): 597db96d56Sopenharmony_ci self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec") 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci def test_duplicate_global_local(self): 627db96d56Sopenharmony_ci self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1') 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ci def test_exec_with_general_mapping_for_locals(self): 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci class M: 677db96d56Sopenharmony_ci "Test mapping interface versus possible calls from eval()." 687db96d56Sopenharmony_ci def __getitem__(self, key): 697db96d56Sopenharmony_ci if key == 'a': 707db96d56Sopenharmony_ci return 12 717db96d56Sopenharmony_ci raise KeyError 727db96d56Sopenharmony_ci def __setitem__(self, key, value): 737db96d56Sopenharmony_ci self.results = (key, value) 747db96d56Sopenharmony_ci def keys(self): 757db96d56Sopenharmony_ci return list('xyz') 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci m = M() 787db96d56Sopenharmony_ci g = globals() 797db96d56Sopenharmony_ci exec('z = a', g, m) 807db96d56Sopenharmony_ci self.assertEqual(m.results, ('z', 12)) 817db96d56Sopenharmony_ci try: 827db96d56Sopenharmony_ci exec('z = b', g, m) 837db96d56Sopenharmony_ci except NameError: 847db96d56Sopenharmony_ci pass 857db96d56Sopenharmony_ci else: 867db96d56Sopenharmony_ci self.fail('Did not detect a KeyError') 877db96d56Sopenharmony_ci exec('z = dir()', g, m) 887db96d56Sopenharmony_ci self.assertEqual(m.results, ('z', list('xyz'))) 897db96d56Sopenharmony_ci exec('z = globals()', g, m) 907db96d56Sopenharmony_ci self.assertEqual(m.results, ('z', g)) 917db96d56Sopenharmony_ci exec('z = locals()', g, m) 927db96d56Sopenharmony_ci self.assertEqual(m.results, ('z', m)) 937db96d56Sopenharmony_ci self.assertRaises(TypeError, exec, 'z = b', m) 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci class A: 967db96d56Sopenharmony_ci "Non-mapping" 977db96d56Sopenharmony_ci pass 987db96d56Sopenharmony_ci m = A() 997db96d56Sopenharmony_ci self.assertRaises(TypeError, exec, 'z = a', g, m) 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci # Verify that dict subclasses work as well 1027db96d56Sopenharmony_ci class D(dict): 1037db96d56Sopenharmony_ci def __getitem__(self, key): 1047db96d56Sopenharmony_ci if key == 'a': 1057db96d56Sopenharmony_ci return 12 1067db96d56Sopenharmony_ci return dict.__getitem__(self, key) 1077db96d56Sopenharmony_ci d = D() 1087db96d56Sopenharmony_ci exec('z = a', g, d) 1097db96d56Sopenharmony_ci self.assertEqual(d['z'], 12) 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ci def test_extended_arg(self): 1127db96d56Sopenharmony_ci # default: 1000 * 2.5 = 2500 repetitions 1137db96d56Sopenharmony_ci repeat = int(sys.getrecursionlimit() * 2.5) 1147db96d56Sopenharmony_ci longexpr = 'x = x or ' + '-x' * repeat 1157db96d56Sopenharmony_ci g = {} 1167db96d56Sopenharmony_ci code = ''' 1177db96d56Sopenharmony_cidef f(x): 1187db96d56Sopenharmony_ci %s 1197db96d56Sopenharmony_ci %s 1207db96d56Sopenharmony_ci %s 1217db96d56Sopenharmony_ci %s 1227db96d56Sopenharmony_ci %s 1237db96d56Sopenharmony_ci %s 1247db96d56Sopenharmony_ci %s 1257db96d56Sopenharmony_ci %s 1267db96d56Sopenharmony_ci %s 1277db96d56Sopenharmony_ci %s 1287db96d56Sopenharmony_ci # the expressions above have no effect, x == argument 1297db96d56Sopenharmony_ci while x: 1307db96d56Sopenharmony_ci x -= 1 1317db96d56Sopenharmony_ci # EXTENDED_ARG/JUMP_ABSOLUTE here 1327db96d56Sopenharmony_ci return x 1337db96d56Sopenharmony_ci''' % ((longexpr,)*10) 1347db96d56Sopenharmony_ci exec(code, g) 1357db96d56Sopenharmony_ci self.assertEqual(g['f'](5), 0) 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci def test_argument_order(self): 1387db96d56Sopenharmony_ci self.assertRaises(SyntaxError, exec, 'def f(a=1, b): pass') 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci def test_float_literals(self): 1417db96d56Sopenharmony_ci # testing bad float literals 1427db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, "2e") 1437db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, "2.0e+") 1447db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, "1e-") 1457db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, "3-4e/21") 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci def test_indentation(self): 1487db96d56Sopenharmony_ci # testing compile() of indented block w/o trailing newline" 1497db96d56Sopenharmony_ci s = """ 1507db96d56Sopenharmony_ciif 1: 1517db96d56Sopenharmony_ci if 2: 1527db96d56Sopenharmony_ci pass""" 1537db96d56Sopenharmony_ci compile(s, "<string>", "exec") 1547db96d56Sopenharmony_ci 1557db96d56Sopenharmony_ci # This test is probably specific to CPython and may not generalize 1567db96d56Sopenharmony_ci # to other implementations. We are trying to ensure that when 1577db96d56Sopenharmony_ci # the first line of code starts after 256, correct line numbers 1587db96d56Sopenharmony_ci # in tracebacks are still produced. 1597db96d56Sopenharmony_ci def test_leading_newlines(self): 1607db96d56Sopenharmony_ci s256 = "".join(["\n"] * 256 + ["spam"]) 1617db96d56Sopenharmony_ci co = compile(s256, 'fn', 'exec') 1627db96d56Sopenharmony_ci self.assertEqual(co.co_firstlineno, 1) 1637db96d56Sopenharmony_ci lines = list(co.co_lines()) 1647db96d56Sopenharmony_ci self.assertEqual(lines[0][2], 0) 1657db96d56Sopenharmony_ci self.assertEqual(lines[1][2], 257) 1667db96d56Sopenharmony_ci 1677db96d56Sopenharmony_ci def test_literals_with_leading_zeroes(self): 1687db96d56Sopenharmony_ci for arg in ["077787", "0xj", "0x.", "0e", "090000000000000", 1697db96d56Sopenharmony_ci "080000000000000", "000000000000009", "000000000000008", 1707db96d56Sopenharmony_ci "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2", 1717db96d56Sopenharmony_ci "0b101j", "0o153j", "0b100e1", "0o777e1", "0777", 1727db96d56Sopenharmony_ci "000777", "000000000000007"]: 1737db96d56Sopenharmony_ci self.assertRaises(SyntaxError, eval, arg) 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_ci self.assertEqual(eval("0xff"), 255) 1767db96d56Sopenharmony_ci self.assertEqual(eval("0777."), 777) 1777db96d56Sopenharmony_ci self.assertEqual(eval("0777.0"), 777) 1787db96d56Sopenharmony_ci self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777) 1797db96d56Sopenharmony_ci self.assertEqual(eval("0777e1"), 7770) 1807db96d56Sopenharmony_ci self.assertEqual(eval("0e0"), 0) 1817db96d56Sopenharmony_ci self.assertEqual(eval("0000e-012"), 0) 1827db96d56Sopenharmony_ci self.assertEqual(eval("09.5"), 9.5) 1837db96d56Sopenharmony_ci self.assertEqual(eval("0777j"), 777j) 1847db96d56Sopenharmony_ci self.assertEqual(eval("000"), 0) 1857db96d56Sopenharmony_ci self.assertEqual(eval("00j"), 0j) 1867db96d56Sopenharmony_ci self.assertEqual(eval("00.0"), 0) 1877db96d56Sopenharmony_ci self.assertEqual(eval("0e3"), 0) 1887db96d56Sopenharmony_ci self.assertEqual(eval("090000000000000."), 90000000000000.) 1897db96d56Sopenharmony_ci self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.) 1907db96d56Sopenharmony_ci self.assertEqual(eval("090000000000000e0"), 90000000000000.) 1917db96d56Sopenharmony_ci self.assertEqual(eval("090000000000000e-0"), 90000000000000.) 1927db96d56Sopenharmony_ci self.assertEqual(eval("090000000000000j"), 90000000000000j) 1937db96d56Sopenharmony_ci self.assertEqual(eval("000000000000008."), 8.) 1947db96d56Sopenharmony_ci self.assertEqual(eval("000000000000009."), 9.) 1957db96d56Sopenharmony_ci self.assertEqual(eval("0b101010"), 42) 1967db96d56Sopenharmony_ci self.assertEqual(eval("-0b000000000010"), -2) 1977db96d56Sopenharmony_ci self.assertEqual(eval("0o777"), 511) 1987db96d56Sopenharmony_ci self.assertEqual(eval("-0o0000010"), -8) 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci def test_int_literals_too_long(self): 2017db96d56Sopenharmony_ci n = 3000 2027db96d56Sopenharmony_ci source = f"a = 1\nb = 2\nc = {'3'*n}\nd = 4" 2037db96d56Sopenharmony_ci with support.adjust_int_max_str_digits(n): 2047db96d56Sopenharmony_ci compile(source, "<long_int_pass>", "exec") # no errors. 2057db96d56Sopenharmony_ci with support.adjust_int_max_str_digits(n-1): 2067db96d56Sopenharmony_ci with self.assertRaises(SyntaxError) as err_ctx: 2077db96d56Sopenharmony_ci compile(source, "<long_int_fail>", "exec") 2087db96d56Sopenharmony_ci exc = err_ctx.exception 2097db96d56Sopenharmony_ci self.assertEqual(exc.lineno, 3) 2107db96d56Sopenharmony_ci self.assertIn('Exceeds the limit ', str(exc)) 2117db96d56Sopenharmony_ci self.assertIn(' Consider hexadecimal ', str(exc)) 2127db96d56Sopenharmony_ci 2137db96d56Sopenharmony_ci def test_unary_minus(self): 2147db96d56Sopenharmony_ci # Verify treatment of unary minus on negative numbers SF bug #660455 2157db96d56Sopenharmony_ci if sys.maxsize == 2147483647: 2167db96d56Sopenharmony_ci # 32-bit machine 2177db96d56Sopenharmony_ci all_one_bits = '0xffffffff' 2187db96d56Sopenharmony_ci self.assertEqual(eval(all_one_bits), 4294967295) 2197db96d56Sopenharmony_ci self.assertEqual(eval("-" + all_one_bits), -4294967295) 2207db96d56Sopenharmony_ci elif sys.maxsize == 9223372036854775807: 2217db96d56Sopenharmony_ci # 64-bit machine 2227db96d56Sopenharmony_ci all_one_bits = '0xffffffffffffffff' 2237db96d56Sopenharmony_ci self.assertEqual(eval(all_one_bits), 18446744073709551615) 2247db96d56Sopenharmony_ci self.assertEqual(eval("-" + all_one_bits), -18446744073709551615) 2257db96d56Sopenharmony_ci else: 2267db96d56Sopenharmony_ci self.fail("How many bits *does* this machine have???") 2277db96d56Sopenharmony_ci # Verify treatment of constant folding on -(sys.maxsize+1) 2287db96d56Sopenharmony_ci # i.e. -2147483648 on 32 bit platforms. Should return int. 2297db96d56Sopenharmony_ci self.assertIsInstance(eval("%s" % (-sys.maxsize - 1)), int) 2307db96d56Sopenharmony_ci self.assertIsInstance(eval("%s" % (-sys.maxsize - 2)), int) 2317db96d56Sopenharmony_ci 2327db96d56Sopenharmony_ci if sys.maxsize == 9223372036854775807: 2337db96d56Sopenharmony_ci def test_32_63_bit_values(self): 2347db96d56Sopenharmony_ci a = +4294967296 # 1 << 32 2357db96d56Sopenharmony_ci b = -4294967296 # 1 << 32 2367db96d56Sopenharmony_ci c = +281474976710656 # 1 << 48 2377db96d56Sopenharmony_ci d = -281474976710656 # 1 << 48 2387db96d56Sopenharmony_ci e = +4611686018427387904 # 1 << 62 2397db96d56Sopenharmony_ci f = -4611686018427387904 # 1 << 62 2407db96d56Sopenharmony_ci g = +9223372036854775807 # 1 << 63 - 1 2417db96d56Sopenharmony_ci h = -9223372036854775807 # 1 << 63 - 1 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_ci for variable in self.test_32_63_bit_values.__code__.co_consts: 2447db96d56Sopenharmony_ci if variable is not None: 2457db96d56Sopenharmony_ci self.assertIsInstance(variable, int) 2467db96d56Sopenharmony_ci 2477db96d56Sopenharmony_ci def test_sequence_unpacking_error(self): 2487db96d56Sopenharmony_ci # Verify sequence packing/unpacking with "or". SF bug #757818 2497db96d56Sopenharmony_ci i,j = (1, -1) or (-1, 1) 2507db96d56Sopenharmony_ci self.assertEqual(i, 1) 2517db96d56Sopenharmony_ci self.assertEqual(j, -1) 2527db96d56Sopenharmony_ci 2537db96d56Sopenharmony_ci def test_none_assignment(self): 2547db96d56Sopenharmony_ci stmts = [ 2557db96d56Sopenharmony_ci 'None = 0', 2567db96d56Sopenharmony_ci 'None += 0', 2577db96d56Sopenharmony_ci '__builtins__.None = 0', 2587db96d56Sopenharmony_ci 'def None(): pass', 2597db96d56Sopenharmony_ci 'class None: pass', 2607db96d56Sopenharmony_ci '(a, None) = 0, 0', 2617db96d56Sopenharmony_ci 'for None in range(10): pass', 2627db96d56Sopenharmony_ci 'def f(None): pass', 2637db96d56Sopenharmony_ci 'import None', 2647db96d56Sopenharmony_ci 'import x as None', 2657db96d56Sopenharmony_ci 'from x import None', 2667db96d56Sopenharmony_ci 'from x import y as None' 2677db96d56Sopenharmony_ci ] 2687db96d56Sopenharmony_ci for stmt in stmts: 2697db96d56Sopenharmony_ci stmt += "\n" 2707db96d56Sopenharmony_ci self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single') 2717db96d56Sopenharmony_ci self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec') 2727db96d56Sopenharmony_ci 2737db96d56Sopenharmony_ci def test_import(self): 2747db96d56Sopenharmony_ci succeed = [ 2757db96d56Sopenharmony_ci 'import sys', 2767db96d56Sopenharmony_ci 'import os, sys', 2777db96d56Sopenharmony_ci 'import os as bar', 2787db96d56Sopenharmony_ci 'import os.path as bar', 2797db96d56Sopenharmony_ci 'from __future__ import nested_scopes, generators', 2807db96d56Sopenharmony_ci 'from __future__ import (nested_scopes,\ngenerators)', 2817db96d56Sopenharmony_ci 'from __future__ import (nested_scopes,\ngenerators,)', 2827db96d56Sopenharmony_ci 'from sys import stdin, stderr, stdout', 2837db96d56Sopenharmony_ci 'from sys import (stdin, stderr,\nstdout)', 2847db96d56Sopenharmony_ci 'from sys import (stdin, stderr,\nstdout,)', 2857db96d56Sopenharmony_ci 'from sys import (stdin\n, stderr, stdout)', 2867db96d56Sopenharmony_ci 'from sys import (stdin\n, stderr, stdout,)', 2877db96d56Sopenharmony_ci 'from sys import stdin as si, stdout as so, stderr as se', 2887db96d56Sopenharmony_ci 'from sys import (stdin as si, stdout as so, stderr as se)', 2897db96d56Sopenharmony_ci 'from sys import (stdin as si, stdout as so, stderr as se,)', 2907db96d56Sopenharmony_ci ] 2917db96d56Sopenharmony_ci fail = [ 2927db96d56Sopenharmony_ci 'import (os, sys)', 2937db96d56Sopenharmony_ci 'import (os), (sys)', 2947db96d56Sopenharmony_ci 'import ((os), (sys))', 2957db96d56Sopenharmony_ci 'import (sys', 2967db96d56Sopenharmony_ci 'import sys)', 2977db96d56Sopenharmony_ci 'import (os,)', 2987db96d56Sopenharmony_ci 'import os As bar', 2997db96d56Sopenharmony_ci 'import os.path a bar', 3007db96d56Sopenharmony_ci 'from sys import stdin As stdout', 3017db96d56Sopenharmony_ci 'from sys import stdin a stdout', 3027db96d56Sopenharmony_ci 'from (sys) import stdin', 3037db96d56Sopenharmony_ci 'from __future__ import (nested_scopes', 3047db96d56Sopenharmony_ci 'from __future__ import nested_scopes)', 3057db96d56Sopenharmony_ci 'from __future__ import nested_scopes,\ngenerators', 3067db96d56Sopenharmony_ci 'from sys import (stdin', 3077db96d56Sopenharmony_ci 'from sys import stdin)', 3087db96d56Sopenharmony_ci 'from sys import stdin, stdout,\nstderr', 3097db96d56Sopenharmony_ci 'from sys import stdin si', 3107db96d56Sopenharmony_ci 'from sys import stdin,', 3117db96d56Sopenharmony_ci 'from sys import (*)', 3127db96d56Sopenharmony_ci 'from sys import (stdin,, stdout, stderr)', 3137db96d56Sopenharmony_ci 'from sys import (stdin, stdout),', 3147db96d56Sopenharmony_ci ] 3157db96d56Sopenharmony_ci for stmt in succeed: 3167db96d56Sopenharmony_ci compile(stmt, 'tmp', 'exec') 3177db96d56Sopenharmony_ci for stmt in fail: 3187db96d56Sopenharmony_ci self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec') 3197db96d56Sopenharmony_ci 3207db96d56Sopenharmony_ci def test_for_distinct_code_objects(self): 3217db96d56Sopenharmony_ci # SF bug 1048870 3227db96d56Sopenharmony_ci def f(): 3237db96d56Sopenharmony_ci f1 = lambda x=1: x 3247db96d56Sopenharmony_ci f2 = lambda x=2: x 3257db96d56Sopenharmony_ci return f1, f2 3267db96d56Sopenharmony_ci f1, f2 = f() 3277db96d56Sopenharmony_ci self.assertNotEqual(id(f1.__code__), id(f2.__code__)) 3287db96d56Sopenharmony_ci 3297db96d56Sopenharmony_ci def test_lambda_doc(self): 3307db96d56Sopenharmony_ci l = lambda: "foo" 3317db96d56Sopenharmony_ci self.assertIsNone(l.__doc__) 3327db96d56Sopenharmony_ci 3337db96d56Sopenharmony_ci def test_encoding(self): 3347db96d56Sopenharmony_ci code = b'# -*- coding: badencoding -*-\npass\n' 3357db96d56Sopenharmony_ci self.assertRaises(SyntaxError, compile, code, 'tmp', 'exec') 3367db96d56Sopenharmony_ci code = '# -*- coding: badencoding -*-\n"\xc2\xa4"\n' 3377db96d56Sopenharmony_ci compile(code, 'tmp', 'exec') 3387db96d56Sopenharmony_ci self.assertEqual(eval(code), '\xc2\xa4') 3397db96d56Sopenharmony_ci code = '"\xc2\xa4"\n' 3407db96d56Sopenharmony_ci self.assertEqual(eval(code), '\xc2\xa4') 3417db96d56Sopenharmony_ci code = b'"\xc2\xa4"\n' 3427db96d56Sopenharmony_ci self.assertEqual(eval(code), '\xa4') 3437db96d56Sopenharmony_ci code = b'# -*- coding: latin1 -*-\n"\xc2\xa4"\n' 3447db96d56Sopenharmony_ci self.assertEqual(eval(code), '\xc2\xa4') 3457db96d56Sopenharmony_ci code = b'# -*- coding: utf-8 -*-\n"\xc2\xa4"\n' 3467db96d56Sopenharmony_ci self.assertEqual(eval(code), '\xa4') 3477db96d56Sopenharmony_ci code = b'# -*- coding: iso8859-15 -*-\n"\xc2\xa4"\n' 3487db96d56Sopenharmony_ci self.assertEqual(eval(code), '\xc2\u20ac') 3497db96d56Sopenharmony_ci code = '"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n' 3507db96d56Sopenharmony_ci self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xc2\xa4') 3517db96d56Sopenharmony_ci code = b'"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n' 3527db96d56Sopenharmony_ci self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xa4') 3537db96d56Sopenharmony_ci 3547db96d56Sopenharmony_ci def test_subscripts(self): 3557db96d56Sopenharmony_ci # SF bug 1448804 3567db96d56Sopenharmony_ci # Class to make testing subscript results easy 3577db96d56Sopenharmony_ci class str_map(object): 3587db96d56Sopenharmony_ci def __init__(self): 3597db96d56Sopenharmony_ci self.data = {} 3607db96d56Sopenharmony_ci def __getitem__(self, key): 3617db96d56Sopenharmony_ci return self.data[str(key)] 3627db96d56Sopenharmony_ci def __setitem__(self, key, value): 3637db96d56Sopenharmony_ci self.data[str(key)] = value 3647db96d56Sopenharmony_ci def __delitem__(self, key): 3657db96d56Sopenharmony_ci del self.data[str(key)] 3667db96d56Sopenharmony_ci def __contains__(self, key): 3677db96d56Sopenharmony_ci return str(key) in self.data 3687db96d56Sopenharmony_ci d = str_map() 3697db96d56Sopenharmony_ci # Index 3707db96d56Sopenharmony_ci d[1] = 1 3717db96d56Sopenharmony_ci self.assertEqual(d[1], 1) 3727db96d56Sopenharmony_ci d[1] += 1 3737db96d56Sopenharmony_ci self.assertEqual(d[1], 2) 3747db96d56Sopenharmony_ci del d[1] 3757db96d56Sopenharmony_ci self.assertNotIn(1, d) 3767db96d56Sopenharmony_ci # Tuple of indices 3777db96d56Sopenharmony_ci d[1, 1] = 1 3787db96d56Sopenharmony_ci self.assertEqual(d[1, 1], 1) 3797db96d56Sopenharmony_ci d[1, 1] += 1 3807db96d56Sopenharmony_ci self.assertEqual(d[1, 1], 2) 3817db96d56Sopenharmony_ci del d[1, 1] 3827db96d56Sopenharmony_ci self.assertNotIn((1, 1), d) 3837db96d56Sopenharmony_ci # Simple slice 3847db96d56Sopenharmony_ci d[1:2] = 1 3857db96d56Sopenharmony_ci self.assertEqual(d[1:2], 1) 3867db96d56Sopenharmony_ci d[1:2] += 1 3877db96d56Sopenharmony_ci self.assertEqual(d[1:2], 2) 3887db96d56Sopenharmony_ci del d[1:2] 3897db96d56Sopenharmony_ci self.assertNotIn(slice(1, 2), d) 3907db96d56Sopenharmony_ci # Tuple of simple slices 3917db96d56Sopenharmony_ci d[1:2, 1:2] = 1 3927db96d56Sopenharmony_ci self.assertEqual(d[1:2, 1:2], 1) 3937db96d56Sopenharmony_ci d[1:2, 1:2] += 1 3947db96d56Sopenharmony_ci self.assertEqual(d[1:2, 1:2], 2) 3957db96d56Sopenharmony_ci del d[1:2, 1:2] 3967db96d56Sopenharmony_ci self.assertNotIn((slice(1, 2), slice(1, 2)), d) 3977db96d56Sopenharmony_ci # Extended slice 3987db96d56Sopenharmony_ci d[1:2:3] = 1 3997db96d56Sopenharmony_ci self.assertEqual(d[1:2:3], 1) 4007db96d56Sopenharmony_ci d[1:2:3] += 1 4017db96d56Sopenharmony_ci self.assertEqual(d[1:2:3], 2) 4027db96d56Sopenharmony_ci del d[1:2:3] 4037db96d56Sopenharmony_ci self.assertNotIn(slice(1, 2, 3), d) 4047db96d56Sopenharmony_ci # Tuple of extended slices 4057db96d56Sopenharmony_ci d[1:2:3, 1:2:3] = 1 4067db96d56Sopenharmony_ci self.assertEqual(d[1:2:3, 1:2:3], 1) 4077db96d56Sopenharmony_ci d[1:2:3, 1:2:3] += 1 4087db96d56Sopenharmony_ci self.assertEqual(d[1:2:3, 1:2:3], 2) 4097db96d56Sopenharmony_ci del d[1:2:3, 1:2:3] 4107db96d56Sopenharmony_ci self.assertNotIn((slice(1, 2, 3), slice(1, 2, 3)), d) 4117db96d56Sopenharmony_ci # Ellipsis 4127db96d56Sopenharmony_ci d[...] = 1 4137db96d56Sopenharmony_ci self.assertEqual(d[...], 1) 4147db96d56Sopenharmony_ci d[...] += 1 4157db96d56Sopenharmony_ci self.assertEqual(d[...], 2) 4167db96d56Sopenharmony_ci del d[...] 4177db96d56Sopenharmony_ci self.assertNotIn(Ellipsis, d) 4187db96d56Sopenharmony_ci # Tuple of Ellipses 4197db96d56Sopenharmony_ci d[..., ...] = 1 4207db96d56Sopenharmony_ci self.assertEqual(d[..., ...], 1) 4217db96d56Sopenharmony_ci d[..., ...] += 1 4227db96d56Sopenharmony_ci self.assertEqual(d[..., ...], 2) 4237db96d56Sopenharmony_ci del d[..., ...] 4247db96d56Sopenharmony_ci self.assertNotIn((Ellipsis, Ellipsis), d) 4257db96d56Sopenharmony_ci 4267db96d56Sopenharmony_ci def test_annotation_limit(self): 4277db96d56Sopenharmony_ci # more than 255 annotations, should compile ok 4287db96d56Sopenharmony_ci s = "def f(%s): pass" 4297db96d56Sopenharmony_ci s %= ', '.join('a%d:%d' % (i,i) for i in range(300)) 4307db96d56Sopenharmony_ci compile(s, '?', 'exec') 4317db96d56Sopenharmony_ci 4327db96d56Sopenharmony_ci def test_mangling(self): 4337db96d56Sopenharmony_ci class A: 4347db96d56Sopenharmony_ci def f(): 4357db96d56Sopenharmony_ci __mangled = 1 4367db96d56Sopenharmony_ci __not_mangled__ = 2 4377db96d56Sopenharmony_ci import __mangled_mod 4387db96d56Sopenharmony_ci import __package__.module 4397db96d56Sopenharmony_ci 4407db96d56Sopenharmony_ci self.assertIn("_A__mangled", A.f.__code__.co_varnames) 4417db96d56Sopenharmony_ci self.assertIn("__not_mangled__", A.f.__code__.co_varnames) 4427db96d56Sopenharmony_ci self.assertIn("_A__mangled_mod", A.f.__code__.co_varnames) 4437db96d56Sopenharmony_ci self.assertIn("__package__", A.f.__code__.co_varnames) 4447db96d56Sopenharmony_ci 4457db96d56Sopenharmony_ci def test_compile_ast(self): 4467db96d56Sopenharmony_ci fname = __file__ 4477db96d56Sopenharmony_ci if fname.lower().endswith('pyc'): 4487db96d56Sopenharmony_ci fname = fname[:-1] 4497db96d56Sopenharmony_ci with open(fname, encoding='utf-8') as f: 4507db96d56Sopenharmony_ci fcontents = f.read() 4517db96d56Sopenharmony_ci sample_code = [ 4527db96d56Sopenharmony_ci ['<assign>', 'x = 5'], 4537db96d56Sopenharmony_ci ['<ifblock>', """if True:\n pass\n"""], 4547db96d56Sopenharmony_ci ['<forblock>', """for n in [1, 2, 3]:\n print(n)\n"""], 4557db96d56Sopenharmony_ci ['<deffunc>', """def foo():\n pass\nfoo()\n"""], 4567db96d56Sopenharmony_ci [fname, fcontents], 4577db96d56Sopenharmony_ci ] 4587db96d56Sopenharmony_ci 4597db96d56Sopenharmony_ci for fname, code in sample_code: 4607db96d56Sopenharmony_ci co1 = compile(code, '%s1' % fname, 'exec') 4617db96d56Sopenharmony_ci ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST) 4627db96d56Sopenharmony_ci self.assertTrue(type(ast) == _ast.Module) 4637db96d56Sopenharmony_ci co2 = compile(ast, '%s3' % fname, 'exec') 4647db96d56Sopenharmony_ci self.assertEqual(co1, co2) 4657db96d56Sopenharmony_ci # the code object's filename comes from the second compilation step 4667db96d56Sopenharmony_ci self.assertEqual(co2.co_filename, '%s3' % fname) 4677db96d56Sopenharmony_ci 4687db96d56Sopenharmony_ci # raise exception when node type doesn't match with compile mode 4697db96d56Sopenharmony_ci co1 = compile('print(1)', '<string>', 'exec', _ast.PyCF_ONLY_AST) 4707db96d56Sopenharmony_ci self.assertRaises(TypeError, compile, co1, '<ast>', 'eval') 4717db96d56Sopenharmony_ci 4727db96d56Sopenharmony_ci # raise exception when node type is no start node 4737db96d56Sopenharmony_ci self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec') 4747db96d56Sopenharmony_ci 4757db96d56Sopenharmony_ci # raise exception when node has invalid children 4767db96d56Sopenharmony_ci ast = _ast.Module() 4777db96d56Sopenharmony_ci ast.body = [_ast.BoolOp()] 4787db96d56Sopenharmony_ci self.assertRaises(TypeError, compile, ast, '<ast>', 'exec') 4797db96d56Sopenharmony_ci 4807db96d56Sopenharmony_ci def test_dict_evaluation_order(self): 4817db96d56Sopenharmony_ci i = 0 4827db96d56Sopenharmony_ci 4837db96d56Sopenharmony_ci def f(): 4847db96d56Sopenharmony_ci nonlocal i 4857db96d56Sopenharmony_ci i += 1 4867db96d56Sopenharmony_ci return i 4877db96d56Sopenharmony_ci 4887db96d56Sopenharmony_ci d = {f(): f(), f(): f()} 4897db96d56Sopenharmony_ci self.assertEqual(d, {1: 2, 3: 4}) 4907db96d56Sopenharmony_ci 4917db96d56Sopenharmony_ci def test_compile_filename(self): 4927db96d56Sopenharmony_ci for filename in 'file.py', b'file.py': 4937db96d56Sopenharmony_ci code = compile('pass', filename, 'exec') 4947db96d56Sopenharmony_ci self.assertEqual(code.co_filename, 'file.py') 4957db96d56Sopenharmony_ci for filename in bytearray(b'file.py'), memoryview(b'file.py'): 4967db96d56Sopenharmony_ci with self.assertWarns(DeprecationWarning): 4977db96d56Sopenharmony_ci code = compile('pass', filename, 'exec') 4987db96d56Sopenharmony_ci self.assertEqual(code.co_filename, 'file.py') 4997db96d56Sopenharmony_ci self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec') 5007db96d56Sopenharmony_ci 5017db96d56Sopenharmony_ci @support.cpython_only 5027db96d56Sopenharmony_ci def test_same_filename_used(self): 5037db96d56Sopenharmony_ci s = """def f(): pass\ndef g(): pass""" 5047db96d56Sopenharmony_ci c = compile(s, "myfile", "exec") 5057db96d56Sopenharmony_ci for obj in c.co_consts: 5067db96d56Sopenharmony_ci if isinstance(obj, types.CodeType): 5077db96d56Sopenharmony_ci self.assertIs(obj.co_filename, c.co_filename) 5087db96d56Sopenharmony_ci 5097db96d56Sopenharmony_ci def test_single_statement(self): 5107db96d56Sopenharmony_ci self.compile_single("1 + 2") 5117db96d56Sopenharmony_ci self.compile_single("\n1 + 2") 5127db96d56Sopenharmony_ci self.compile_single("1 + 2\n") 5137db96d56Sopenharmony_ci self.compile_single("1 + 2\n\n") 5147db96d56Sopenharmony_ci self.compile_single("1 + 2\t\t\n") 5157db96d56Sopenharmony_ci self.compile_single("1 + 2\t\t\n ") 5167db96d56Sopenharmony_ci self.compile_single("1 + 2 # one plus two") 5177db96d56Sopenharmony_ci self.compile_single("1; 2") 5187db96d56Sopenharmony_ci self.compile_single("import sys; sys") 5197db96d56Sopenharmony_ci self.compile_single("def f():\n pass") 5207db96d56Sopenharmony_ci self.compile_single("while False:\n pass") 5217db96d56Sopenharmony_ci self.compile_single("if x:\n f(x)") 5227db96d56Sopenharmony_ci self.compile_single("if x:\n f(x)\nelse:\n g(x)") 5237db96d56Sopenharmony_ci self.compile_single("class T:\n pass") 5247db96d56Sopenharmony_ci self.compile_single("c = '''\na=1\nb=2\nc=3\n'''") 5257db96d56Sopenharmony_ci 5267db96d56Sopenharmony_ci def test_bad_single_statement(self): 5277db96d56Sopenharmony_ci self.assertInvalidSingle('1\n2') 5287db96d56Sopenharmony_ci self.assertInvalidSingle('def f(): pass') 5297db96d56Sopenharmony_ci self.assertInvalidSingle('a = 13\nb = 187') 5307db96d56Sopenharmony_ci self.assertInvalidSingle('del x\ndel y') 5317db96d56Sopenharmony_ci self.assertInvalidSingle('f()\ng()') 5327db96d56Sopenharmony_ci self.assertInvalidSingle('f()\n# blah\nblah()') 5337db96d56Sopenharmony_ci self.assertInvalidSingle('f()\nxy # blah\nblah()') 5347db96d56Sopenharmony_ci self.assertInvalidSingle('x = 5 # comment\nx = 6\n') 5357db96d56Sopenharmony_ci self.assertInvalidSingle("c = '''\nd=1\n'''\na = 1\n\nb = 2\n") 5367db96d56Sopenharmony_ci 5377db96d56Sopenharmony_ci def test_particularly_evil_undecodable(self): 5387db96d56Sopenharmony_ci # Issue 24022 5397db96d56Sopenharmony_ci src = b'0000\x00\n00000000000\n\x00\n\x9e\n' 5407db96d56Sopenharmony_ci with tempfile.TemporaryDirectory() as tmpd: 5417db96d56Sopenharmony_ci fn = os.path.join(tmpd, "bad.py") 5427db96d56Sopenharmony_ci with open(fn, "wb") as fp: 5437db96d56Sopenharmony_ci fp.write(src) 5447db96d56Sopenharmony_ci res = script_helper.run_python_until_end(fn)[0] 5457db96d56Sopenharmony_ci self.assertIn(b"source code cannot contain null bytes", res.err) 5467db96d56Sopenharmony_ci 5477db96d56Sopenharmony_ci def test_yet_more_evil_still_undecodable(self): 5487db96d56Sopenharmony_ci # Issue #25388 5497db96d56Sopenharmony_ci src = b"#\x00\n#\xfd\n" 5507db96d56Sopenharmony_ci with tempfile.TemporaryDirectory() as tmpd: 5517db96d56Sopenharmony_ci fn = os.path.join(tmpd, "bad.py") 5527db96d56Sopenharmony_ci with open(fn, "wb") as fp: 5537db96d56Sopenharmony_ci fp.write(src) 5547db96d56Sopenharmony_ci res = script_helper.run_python_until_end(fn)[0] 5557db96d56Sopenharmony_ci self.assertIn(b"source code cannot contain null bytes", res.err) 5567db96d56Sopenharmony_ci 5577db96d56Sopenharmony_ci @support.cpython_only 5587db96d56Sopenharmony_ci def test_compiler_recursion_limit(self): 5597db96d56Sopenharmony_ci # Expected limit is sys.getrecursionlimit() * the scaling factor 5607db96d56Sopenharmony_ci # in symtable.c (currently 3) 5617db96d56Sopenharmony_ci # We expect to fail *at* that limit, because we use up some of 5627db96d56Sopenharmony_ci # the stack depth limit in the test suite code 5637db96d56Sopenharmony_ci # So we check the expected limit and 75% of that 5647db96d56Sopenharmony_ci # XXX (ncoghlan): duplicating the scaling factor here is a little 5657db96d56Sopenharmony_ci # ugly. Perhaps it should be exposed somewhere... 5667db96d56Sopenharmony_ci fail_depth = sys.getrecursionlimit() * 3 5677db96d56Sopenharmony_ci crash_depth = sys.getrecursionlimit() * 300 5687db96d56Sopenharmony_ci success_depth = int(fail_depth * 0.75) 5697db96d56Sopenharmony_ci 5707db96d56Sopenharmony_ci def check_limit(prefix, repeated, mode="single"): 5717db96d56Sopenharmony_ci expect_ok = prefix + repeated * success_depth 5727db96d56Sopenharmony_ci compile(expect_ok, '<test>', mode) 5737db96d56Sopenharmony_ci for depth in (fail_depth, crash_depth): 5747db96d56Sopenharmony_ci broken = prefix + repeated * depth 5757db96d56Sopenharmony_ci details = "Compiling ({!r} + {!r} * {})".format( 5767db96d56Sopenharmony_ci prefix, repeated, depth) 5777db96d56Sopenharmony_ci with self.assertRaises(RecursionError, msg=details): 5787db96d56Sopenharmony_ci compile(broken, '<test>', mode) 5797db96d56Sopenharmony_ci 5807db96d56Sopenharmony_ci check_limit("a", "()") 5817db96d56Sopenharmony_ci check_limit("a", ".b") 5827db96d56Sopenharmony_ci check_limit("a", "[0]") 5837db96d56Sopenharmony_ci check_limit("a", "*a") 5847db96d56Sopenharmony_ci # XXX Crashes in the parser. 5857db96d56Sopenharmony_ci # check_limit("a", " if a else a") 5867db96d56Sopenharmony_ci # check_limit("if a: pass", "\nelif a: pass", mode="exec") 5877db96d56Sopenharmony_ci 5887db96d56Sopenharmony_ci def test_null_terminated(self): 5897db96d56Sopenharmony_ci # The source code is null-terminated internally, but bytes-like 5907db96d56Sopenharmony_ci # objects are accepted, which could be not terminated. 5917db96d56Sopenharmony_ci with self.assertRaisesRegex(SyntaxError, "cannot contain null"): 5927db96d56Sopenharmony_ci compile("123\x00", "<dummy>", "eval") 5937db96d56Sopenharmony_ci with self.assertRaisesRegex(SyntaxError, "cannot contain null"): 5947db96d56Sopenharmony_ci compile(memoryview(b"123\x00"), "<dummy>", "eval") 5957db96d56Sopenharmony_ci code = compile(memoryview(b"123\x00")[1:-1], "<dummy>", "eval") 5967db96d56Sopenharmony_ci self.assertEqual(eval(code), 23) 5977db96d56Sopenharmony_ci code = compile(memoryview(b"1234")[1:-1], "<dummy>", "eval") 5987db96d56Sopenharmony_ci self.assertEqual(eval(code), 23) 5997db96d56Sopenharmony_ci code = compile(memoryview(b"$23$")[1:-1], "<dummy>", "eval") 6007db96d56Sopenharmony_ci self.assertEqual(eval(code), 23) 6017db96d56Sopenharmony_ci 6027db96d56Sopenharmony_ci # Also test when eval() and exec() do the compilation step 6037db96d56Sopenharmony_ci self.assertEqual(eval(memoryview(b"1234")[1:-1]), 23) 6047db96d56Sopenharmony_ci namespace = dict() 6057db96d56Sopenharmony_ci exec(memoryview(b"ax = 123")[1:-1], namespace) 6067db96d56Sopenharmony_ci self.assertEqual(namespace['x'], 12) 6077db96d56Sopenharmony_ci 6087db96d56Sopenharmony_ci def check_constant(self, func, expected): 6097db96d56Sopenharmony_ci for const in func.__code__.co_consts: 6107db96d56Sopenharmony_ci if repr(const) == repr(expected): 6117db96d56Sopenharmony_ci break 6127db96d56Sopenharmony_ci else: 6137db96d56Sopenharmony_ci self.fail("unable to find constant %r in %r" 6147db96d56Sopenharmony_ci % (expected, func.__code__.co_consts)) 6157db96d56Sopenharmony_ci 6167db96d56Sopenharmony_ci # Merging equal constants is not a strict requirement for the Python 6177db96d56Sopenharmony_ci # semantics, it's a more an implementation detail. 6187db96d56Sopenharmony_ci @support.cpython_only 6197db96d56Sopenharmony_ci def test_merge_constants(self): 6207db96d56Sopenharmony_ci # Issue #25843: compile() must merge constants which are equal 6217db96d56Sopenharmony_ci # and have the same type. 6227db96d56Sopenharmony_ci 6237db96d56Sopenharmony_ci def check_same_constant(const): 6247db96d56Sopenharmony_ci ns = {} 6257db96d56Sopenharmony_ci code = "f1, f2 = lambda: %r, lambda: %r" % (const, const) 6267db96d56Sopenharmony_ci exec(code, ns) 6277db96d56Sopenharmony_ci f1 = ns['f1'] 6287db96d56Sopenharmony_ci f2 = ns['f2'] 6297db96d56Sopenharmony_ci self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts) 6307db96d56Sopenharmony_ci self.check_constant(f1, const) 6317db96d56Sopenharmony_ci self.assertEqual(repr(f1()), repr(const)) 6327db96d56Sopenharmony_ci 6337db96d56Sopenharmony_ci check_same_constant(None) 6347db96d56Sopenharmony_ci check_same_constant(0) 6357db96d56Sopenharmony_ci check_same_constant(0.0) 6367db96d56Sopenharmony_ci check_same_constant(b'abc') 6377db96d56Sopenharmony_ci check_same_constant('abc') 6387db96d56Sopenharmony_ci 6397db96d56Sopenharmony_ci # Note: "lambda: ..." emits "LOAD_CONST Ellipsis", 6407db96d56Sopenharmony_ci # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis" 6417db96d56Sopenharmony_ci f1, f2 = lambda: ..., lambda: ... 6427db96d56Sopenharmony_ci self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts) 6437db96d56Sopenharmony_ci self.check_constant(f1, Ellipsis) 6447db96d56Sopenharmony_ci self.assertEqual(repr(f1()), repr(Ellipsis)) 6457db96d56Sopenharmony_ci 6467db96d56Sopenharmony_ci # Merge constants in tuple or frozenset 6477db96d56Sopenharmony_ci f1, f2 = lambda: "not a name", lambda: ("not a name",) 6487db96d56Sopenharmony_ci f3 = lambda x: x in {("not a name",)} 6497db96d56Sopenharmony_ci self.assertIs(f1.__code__.co_consts[1], 6507db96d56Sopenharmony_ci f2.__code__.co_consts[1][0]) 6517db96d56Sopenharmony_ci self.assertIs(next(iter(f3.__code__.co_consts[1])), 6527db96d56Sopenharmony_ci f2.__code__.co_consts[1]) 6537db96d56Sopenharmony_ci 6547db96d56Sopenharmony_ci # {0} is converted to a constant frozenset({0}) by the peephole 6557db96d56Sopenharmony_ci # optimizer 6567db96d56Sopenharmony_ci f1, f2 = lambda x: x in {0}, lambda x: x in {0} 6577db96d56Sopenharmony_ci self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts) 6587db96d56Sopenharmony_ci self.check_constant(f1, frozenset({0})) 6597db96d56Sopenharmony_ci self.assertTrue(f1(0)) 6607db96d56Sopenharmony_ci 6617db96d56Sopenharmony_ci # Merging equal co_linetable is not a strict requirement 6627db96d56Sopenharmony_ci # for the Python semantics, it's a more an implementation detail. 6637db96d56Sopenharmony_ci @support.cpython_only 6647db96d56Sopenharmony_ci def test_merge_code_attrs(self): 6657db96d56Sopenharmony_ci # See https://bugs.python.org/issue42217 6667db96d56Sopenharmony_ci f1 = lambda x: x.y.z 6677db96d56Sopenharmony_ci f2 = lambda a: a.b.c 6687db96d56Sopenharmony_ci 6697db96d56Sopenharmony_ci self.assertIs(f1.__code__.co_linetable, f2.__code__.co_linetable) 6707db96d56Sopenharmony_ci 6717db96d56Sopenharmony_ci # Stripping unused constants is not a strict requirement for the 6727db96d56Sopenharmony_ci # Python semantics, it's a more an implementation detail. 6737db96d56Sopenharmony_ci @support.cpython_only 6747db96d56Sopenharmony_ci def test_strip_unused_consts(self): 6757db96d56Sopenharmony_ci # Python 3.10rc1 appended None to co_consts when None is not used 6767db96d56Sopenharmony_ci # at all. See bpo-45056. 6777db96d56Sopenharmony_ci def f1(): 6787db96d56Sopenharmony_ci "docstring" 6797db96d56Sopenharmony_ci return 42 6807db96d56Sopenharmony_ci self.assertEqual(f1.__code__.co_consts, ("docstring", 42)) 6817db96d56Sopenharmony_ci 6827db96d56Sopenharmony_ci # This is a regression test for a CPython specific peephole optimizer 6837db96d56Sopenharmony_ci # implementation bug present in a few releases. It's assertion verifies 6847db96d56Sopenharmony_ci # that peephole optimization was actually done though that isn't an 6857db96d56Sopenharmony_ci # indication of the bugs presence or not (crashing is). 6867db96d56Sopenharmony_ci @support.cpython_only 6877db96d56Sopenharmony_ci def test_peephole_opt_unreachable_code_array_access_in_bounds(self): 6887db96d56Sopenharmony_ci """Regression test for issue35193 when run under clang msan.""" 6897db96d56Sopenharmony_ci def unused_code_at_end(): 6907db96d56Sopenharmony_ci return 3 6917db96d56Sopenharmony_ci raise RuntimeError("unreachable") 6927db96d56Sopenharmony_ci # The above function definition will trigger the out of bounds 6937db96d56Sopenharmony_ci # bug in the peephole optimizer as it scans opcodes past the 6947db96d56Sopenharmony_ci # RETURN_VALUE opcode. This does not always crash an interpreter. 6957db96d56Sopenharmony_ci # When you build with the clang memory sanitizer it reliably aborts. 6967db96d56Sopenharmony_ci self.assertEqual( 6977db96d56Sopenharmony_ci 'RETURN_VALUE', 6987db96d56Sopenharmony_ci list(dis.get_instructions(unused_code_at_end))[-1].opname) 6997db96d56Sopenharmony_ci 7007db96d56Sopenharmony_ci def test_dont_merge_constants(self): 7017db96d56Sopenharmony_ci # Issue #25843: compile() must not merge constants which are equal 7027db96d56Sopenharmony_ci # but have a different type. 7037db96d56Sopenharmony_ci 7047db96d56Sopenharmony_ci def check_different_constants(const1, const2): 7057db96d56Sopenharmony_ci ns = {} 7067db96d56Sopenharmony_ci exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns) 7077db96d56Sopenharmony_ci f1 = ns['f1'] 7087db96d56Sopenharmony_ci f2 = ns['f2'] 7097db96d56Sopenharmony_ci self.assertIsNot(f1.__code__, f2.__code__) 7107db96d56Sopenharmony_ci self.assertNotEqual(f1.__code__, f2.__code__) 7117db96d56Sopenharmony_ci self.check_constant(f1, const1) 7127db96d56Sopenharmony_ci self.check_constant(f2, const2) 7137db96d56Sopenharmony_ci self.assertEqual(repr(f1()), repr(const1)) 7147db96d56Sopenharmony_ci self.assertEqual(repr(f2()), repr(const2)) 7157db96d56Sopenharmony_ci 7167db96d56Sopenharmony_ci check_different_constants(0, 0.0) 7177db96d56Sopenharmony_ci check_different_constants(+0.0, -0.0) 7187db96d56Sopenharmony_ci check_different_constants((0,), (0.0,)) 7197db96d56Sopenharmony_ci check_different_constants('a', b'a') 7207db96d56Sopenharmony_ci check_different_constants(('a',), (b'a',)) 7217db96d56Sopenharmony_ci 7227db96d56Sopenharmony_ci # check_different_constants() cannot be used because repr(-0j) is 7237db96d56Sopenharmony_ci # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign. 7247db96d56Sopenharmony_ci f1, f2 = lambda: +0.0j, lambda: -0.0j 7257db96d56Sopenharmony_ci self.assertIsNot(f1.__code__, f2.__code__) 7267db96d56Sopenharmony_ci self.check_constant(f1, +0.0j) 7277db96d56Sopenharmony_ci self.check_constant(f2, -0.0j) 7287db96d56Sopenharmony_ci self.assertEqual(repr(f1()), repr(+0.0j)) 7297db96d56Sopenharmony_ci self.assertEqual(repr(f2()), repr(-0.0j)) 7307db96d56Sopenharmony_ci 7317db96d56Sopenharmony_ci # {0} is converted to a constant frozenset({0}) by the peephole 7327db96d56Sopenharmony_ci # optimizer 7337db96d56Sopenharmony_ci f1, f2 = lambda x: x in {0}, lambda x: x in {0.0} 7347db96d56Sopenharmony_ci self.assertIsNot(f1.__code__, f2.__code__) 7357db96d56Sopenharmony_ci self.check_constant(f1, frozenset({0})) 7367db96d56Sopenharmony_ci self.check_constant(f2, frozenset({0.0})) 7377db96d56Sopenharmony_ci self.assertTrue(f1(0)) 7387db96d56Sopenharmony_ci self.assertTrue(f2(0.0)) 7397db96d56Sopenharmony_ci 7407db96d56Sopenharmony_ci def test_path_like_objects(self): 7417db96d56Sopenharmony_ci # An implicit test for PyUnicode_FSDecoder(). 7427db96d56Sopenharmony_ci compile("42", FakePath("test_compile_pathlike"), "single") 7437db96d56Sopenharmony_ci 7447db96d56Sopenharmony_ci def test_stack_overflow(self): 7457db96d56Sopenharmony_ci # bpo-31113: Stack overflow when compile a long sequence of 7467db96d56Sopenharmony_ci # complex statements. 7477db96d56Sopenharmony_ci compile("if a: b\n" * 200000, "<dummy>", "exec") 7487db96d56Sopenharmony_ci 7497db96d56Sopenharmony_ci # Multiple users rely on the fact that CPython does not generate 7507db96d56Sopenharmony_ci # bytecode for dead code blocks. See bpo-37500 for more context. 7517db96d56Sopenharmony_ci @support.cpython_only 7527db96d56Sopenharmony_ci def test_dead_blocks_do_not_generate_bytecode(self): 7537db96d56Sopenharmony_ci def unused_block_if(): 7547db96d56Sopenharmony_ci if 0: 7557db96d56Sopenharmony_ci return 42 7567db96d56Sopenharmony_ci 7577db96d56Sopenharmony_ci def unused_block_while(): 7587db96d56Sopenharmony_ci while 0: 7597db96d56Sopenharmony_ci return 42 7607db96d56Sopenharmony_ci 7617db96d56Sopenharmony_ci def unused_block_if_else(): 7627db96d56Sopenharmony_ci if 1: 7637db96d56Sopenharmony_ci return None 7647db96d56Sopenharmony_ci else: 7657db96d56Sopenharmony_ci return 42 7667db96d56Sopenharmony_ci 7677db96d56Sopenharmony_ci def unused_block_while_else(): 7687db96d56Sopenharmony_ci while 1: 7697db96d56Sopenharmony_ci return None 7707db96d56Sopenharmony_ci else: 7717db96d56Sopenharmony_ci return 42 7727db96d56Sopenharmony_ci 7737db96d56Sopenharmony_ci funcs = [unused_block_if, unused_block_while, 7747db96d56Sopenharmony_ci unused_block_if_else, unused_block_while_else] 7757db96d56Sopenharmony_ci 7767db96d56Sopenharmony_ci for func in funcs: 7777db96d56Sopenharmony_ci opcodes = list(dis.get_instructions(func)) 7787db96d56Sopenharmony_ci self.assertLessEqual(len(opcodes), 4) 7797db96d56Sopenharmony_ci self.assertEqual('LOAD_CONST', opcodes[-2].opname) 7807db96d56Sopenharmony_ci self.assertEqual(None, opcodes[-2].argval) 7817db96d56Sopenharmony_ci self.assertEqual('RETURN_VALUE', opcodes[-1].opname) 7827db96d56Sopenharmony_ci 7837db96d56Sopenharmony_ci def test_false_while_loop(self): 7847db96d56Sopenharmony_ci def break_in_while(): 7857db96d56Sopenharmony_ci while False: 7867db96d56Sopenharmony_ci break 7877db96d56Sopenharmony_ci 7887db96d56Sopenharmony_ci def continue_in_while(): 7897db96d56Sopenharmony_ci while False: 7907db96d56Sopenharmony_ci continue 7917db96d56Sopenharmony_ci 7927db96d56Sopenharmony_ci funcs = [break_in_while, continue_in_while] 7937db96d56Sopenharmony_ci 7947db96d56Sopenharmony_ci # Check that we did not raise but we also don't generate bytecode 7957db96d56Sopenharmony_ci for func in funcs: 7967db96d56Sopenharmony_ci opcodes = list(dis.get_instructions(func)) 7977db96d56Sopenharmony_ci self.assertEqual(3, len(opcodes)) 7987db96d56Sopenharmony_ci self.assertEqual('LOAD_CONST', opcodes[1].opname) 7997db96d56Sopenharmony_ci self.assertEqual(None, opcodes[1].argval) 8007db96d56Sopenharmony_ci self.assertEqual('RETURN_VALUE', opcodes[2].opname) 8017db96d56Sopenharmony_ci 8027db96d56Sopenharmony_ci def test_consts_in_conditionals(self): 8037db96d56Sopenharmony_ci def and_true(x): 8047db96d56Sopenharmony_ci return True and x 8057db96d56Sopenharmony_ci 8067db96d56Sopenharmony_ci def and_false(x): 8077db96d56Sopenharmony_ci return False and x 8087db96d56Sopenharmony_ci 8097db96d56Sopenharmony_ci def or_true(x): 8107db96d56Sopenharmony_ci return True or x 8117db96d56Sopenharmony_ci 8127db96d56Sopenharmony_ci def or_false(x): 8137db96d56Sopenharmony_ci return False or x 8147db96d56Sopenharmony_ci 8157db96d56Sopenharmony_ci funcs = [and_true, and_false, or_true, or_false] 8167db96d56Sopenharmony_ci 8177db96d56Sopenharmony_ci # Check that condition is removed. 8187db96d56Sopenharmony_ci for func in funcs: 8197db96d56Sopenharmony_ci with self.subTest(func=func): 8207db96d56Sopenharmony_ci opcodes = list(dis.get_instructions(func)) 8217db96d56Sopenharmony_ci self.assertLessEqual(len(opcodes), 3) 8227db96d56Sopenharmony_ci self.assertIn('LOAD_', opcodes[-2].opname) 8237db96d56Sopenharmony_ci self.assertEqual('RETURN_VALUE', opcodes[-1].opname) 8247db96d56Sopenharmony_ci 8257db96d56Sopenharmony_ci def test_imported_load_method(self): 8267db96d56Sopenharmony_ci sources = [ 8277db96d56Sopenharmony_ci """\ 8287db96d56Sopenharmony_ci import os 8297db96d56Sopenharmony_ci def foo(): 8307db96d56Sopenharmony_ci return os.uname() 8317db96d56Sopenharmony_ci """, 8327db96d56Sopenharmony_ci """\ 8337db96d56Sopenharmony_ci import os as operating_system 8347db96d56Sopenharmony_ci def foo(): 8357db96d56Sopenharmony_ci return operating_system.uname() 8367db96d56Sopenharmony_ci """, 8377db96d56Sopenharmony_ci """\ 8387db96d56Sopenharmony_ci from os import path 8397db96d56Sopenharmony_ci def foo(x): 8407db96d56Sopenharmony_ci return path.join(x) 8417db96d56Sopenharmony_ci """, 8427db96d56Sopenharmony_ci """\ 8437db96d56Sopenharmony_ci from os import path as os_path 8447db96d56Sopenharmony_ci def foo(x): 8457db96d56Sopenharmony_ci return os_path.join(x) 8467db96d56Sopenharmony_ci """ 8477db96d56Sopenharmony_ci ] 8487db96d56Sopenharmony_ci for source in sources: 8497db96d56Sopenharmony_ci namespace = {} 8507db96d56Sopenharmony_ci exec(textwrap.dedent(source), namespace) 8517db96d56Sopenharmony_ci func = namespace['foo'] 8527db96d56Sopenharmony_ci with self.subTest(func=func.__name__): 8537db96d56Sopenharmony_ci opcodes = list(dis.get_instructions(func)) 8547db96d56Sopenharmony_ci instructions = [opcode.opname for opcode in opcodes] 8557db96d56Sopenharmony_ci self.assertNotIn('LOAD_METHOD', instructions) 8567db96d56Sopenharmony_ci self.assertIn('LOAD_ATTR', instructions) 8577db96d56Sopenharmony_ci self.assertIn('PRECALL', instructions) 8587db96d56Sopenharmony_ci 8597db96d56Sopenharmony_ci def test_lineno_procedure_call(self): 8607db96d56Sopenharmony_ci def call(): 8617db96d56Sopenharmony_ci ( 8627db96d56Sopenharmony_ci print() 8637db96d56Sopenharmony_ci ) 8647db96d56Sopenharmony_ci line1 = call.__code__.co_firstlineno + 1 8657db96d56Sopenharmony_ci assert line1 not in [line for (_, _, line) in call.__code__.co_lines()] 8667db96d56Sopenharmony_ci 8677db96d56Sopenharmony_ci def test_lineno_after_implicit_return(self): 8687db96d56Sopenharmony_ci TRUE = True 8697db96d56Sopenharmony_ci # Don't use constant True or False, as compiler will remove test 8707db96d56Sopenharmony_ci def if1(x): 8717db96d56Sopenharmony_ci x() 8727db96d56Sopenharmony_ci if TRUE: 8737db96d56Sopenharmony_ci pass 8747db96d56Sopenharmony_ci def if2(x): 8757db96d56Sopenharmony_ci x() 8767db96d56Sopenharmony_ci if TRUE: 8777db96d56Sopenharmony_ci pass 8787db96d56Sopenharmony_ci else: 8797db96d56Sopenharmony_ci pass 8807db96d56Sopenharmony_ci def if3(x): 8817db96d56Sopenharmony_ci x() 8827db96d56Sopenharmony_ci if TRUE: 8837db96d56Sopenharmony_ci pass 8847db96d56Sopenharmony_ci else: 8857db96d56Sopenharmony_ci return None 8867db96d56Sopenharmony_ci def if4(x): 8877db96d56Sopenharmony_ci x() 8887db96d56Sopenharmony_ci if not TRUE: 8897db96d56Sopenharmony_ci pass 8907db96d56Sopenharmony_ci funcs = [ if1, if2, if3, if4] 8917db96d56Sopenharmony_ci lastlines = [ 3, 3, 3, 2] 8927db96d56Sopenharmony_ci frame = None 8937db96d56Sopenharmony_ci def save_caller_frame(): 8947db96d56Sopenharmony_ci nonlocal frame 8957db96d56Sopenharmony_ci frame = sys._getframe(1) 8967db96d56Sopenharmony_ci for func, lastline in zip(funcs, lastlines, strict=True): 8977db96d56Sopenharmony_ci with self.subTest(func=func): 8987db96d56Sopenharmony_ci func(save_caller_frame) 8997db96d56Sopenharmony_ci self.assertEqual(frame.f_lineno-frame.f_code.co_firstlineno, lastline) 9007db96d56Sopenharmony_ci 9017db96d56Sopenharmony_ci def test_lineno_after_no_code(self): 9027db96d56Sopenharmony_ci def no_code1(): 9037db96d56Sopenharmony_ci "doc string" 9047db96d56Sopenharmony_ci 9057db96d56Sopenharmony_ci def no_code2(): 9067db96d56Sopenharmony_ci a: int 9077db96d56Sopenharmony_ci 9087db96d56Sopenharmony_ci for func in (no_code1, no_code2): 9097db96d56Sopenharmony_ci with self.subTest(func=func): 9107db96d56Sopenharmony_ci code = func.__code__ 9117db96d56Sopenharmony_ci lines = list(code.co_lines()) 9127db96d56Sopenharmony_ci start, end, line = lines[0] 9137db96d56Sopenharmony_ci self.assertEqual(start, 0) 9147db96d56Sopenharmony_ci self.assertEqual(line, code.co_firstlineno) 9157db96d56Sopenharmony_ci 9167db96d56Sopenharmony_ci def get_code_lines(self, code): 9177db96d56Sopenharmony_ci last_line = -2 9187db96d56Sopenharmony_ci res = [] 9197db96d56Sopenharmony_ci for _, _, line in code.co_lines(): 9207db96d56Sopenharmony_ci if line is not None and line != last_line: 9217db96d56Sopenharmony_ci res.append(line - code.co_firstlineno) 9227db96d56Sopenharmony_ci last_line = line 9237db96d56Sopenharmony_ci return res 9247db96d56Sopenharmony_ci 9257db96d56Sopenharmony_ci def test_lineno_attribute(self): 9267db96d56Sopenharmony_ci def load_attr(): 9277db96d56Sopenharmony_ci return ( 9287db96d56Sopenharmony_ci o. 9297db96d56Sopenharmony_ci a 9307db96d56Sopenharmony_ci ) 9317db96d56Sopenharmony_ci load_attr_lines = [ 0, 2, 3, 1 ] 9327db96d56Sopenharmony_ci 9337db96d56Sopenharmony_ci def load_method(): 9347db96d56Sopenharmony_ci return ( 9357db96d56Sopenharmony_ci o. 9367db96d56Sopenharmony_ci m( 9377db96d56Sopenharmony_ci 0 9387db96d56Sopenharmony_ci ) 9397db96d56Sopenharmony_ci ) 9407db96d56Sopenharmony_ci load_method_lines = [ 0, 2, 3, 4, 3, 1 ] 9417db96d56Sopenharmony_ci 9427db96d56Sopenharmony_ci def store_attr(): 9437db96d56Sopenharmony_ci ( 9447db96d56Sopenharmony_ci o. 9457db96d56Sopenharmony_ci a 9467db96d56Sopenharmony_ci ) = ( 9477db96d56Sopenharmony_ci v 9487db96d56Sopenharmony_ci ) 9497db96d56Sopenharmony_ci store_attr_lines = [ 0, 5, 2, 3 ] 9507db96d56Sopenharmony_ci 9517db96d56Sopenharmony_ci def aug_store_attr(): 9527db96d56Sopenharmony_ci ( 9537db96d56Sopenharmony_ci o. 9547db96d56Sopenharmony_ci a 9557db96d56Sopenharmony_ci ) += ( 9567db96d56Sopenharmony_ci v 9577db96d56Sopenharmony_ci ) 9587db96d56Sopenharmony_ci aug_store_attr_lines = [ 0, 2, 3, 5, 1, 3 ] 9597db96d56Sopenharmony_ci 9607db96d56Sopenharmony_ci funcs = [ load_attr, load_method, store_attr, aug_store_attr] 9617db96d56Sopenharmony_ci func_lines = [ load_attr_lines, load_method_lines, 9627db96d56Sopenharmony_ci store_attr_lines, aug_store_attr_lines] 9637db96d56Sopenharmony_ci 9647db96d56Sopenharmony_ci for func, lines in zip(funcs, func_lines, strict=True): 9657db96d56Sopenharmony_ci with self.subTest(func=func): 9667db96d56Sopenharmony_ci code_lines = self.get_code_lines(func.__code__) 9677db96d56Sopenharmony_ci self.assertEqual(lines, code_lines) 9687db96d56Sopenharmony_ci 9697db96d56Sopenharmony_ci def test_line_number_genexp(self): 9707db96d56Sopenharmony_ci 9717db96d56Sopenharmony_ci def return_genexp(): 9727db96d56Sopenharmony_ci return (1 9737db96d56Sopenharmony_ci for 9747db96d56Sopenharmony_ci x 9757db96d56Sopenharmony_ci in 9767db96d56Sopenharmony_ci y) 9777db96d56Sopenharmony_ci genexp_lines = [0, 2, 0] 9787db96d56Sopenharmony_ci 9797db96d56Sopenharmony_ci genexp_code = return_genexp.__code__.co_consts[1] 9807db96d56Sopenharmony_ci code_lines = self.get_code_lines(genexp_code) 9817db96d56Sopenharmony_ci self.assertEqual(genexp_lines, code_lines) 9827db96d56Sopenharmony_ci 9837db96d56Sopenharmony_ci def test_line_number_implicit_return_after_async_for(self): 9847db96d56Sopenharmony_ci 9857db96d56Sopenharmony_ci async def test(aseq): 9867db96d56Sopenharmony_ci async for i in aseq: 9877db96d56Sopenharmony_ci body 9887db96d56Sopenharmony_ci 9897db96d56Sopenharmony_ci expected_lines = [0, 1, 2, 1] 9907db96d56Sopenharmony_ci code_lines = self.get_code_lines(test.__code__) 9917db96d56Sopenharmony_ci self.assertEqual(expected_lines, code_lines) 9927db96d56Sopenharmony_ci 9937db96d56Sopenharmony_ci def test_big_dict_literal(self): 9947db96d56Sopenharmony_ci # The compiler has a flushing point in "compiler_dict" that calls compiles 9957db96d56Sopenharmony_ci # a portion of the dictionary literal when the loop that iterates over the items 9967db96d56Sopenharmony_ci # reaches 0xFFFF elements but the code was not including the boundary element, 9977db96d56Sopenharmony_ci # dropping the key at position 0xFFFF. See bpo-41531 for more information 9987db96d56Sopenharmony_ci 9997db96d56Sopenharmony_ci dict_size = 0xFFFF + 1 10007db96d56Sopenharmony_ci the_dict = "{" + ",".join(f"{x}:{x}" for x in range(dict_size)) + "}" 10017db96d56Sopenharmony_ci self.assertEqual(len(eval(the_dict)), dict_size) 10027db96d56Sopenharmony_ci 10037db96d56Sopenharmony_ci def test_redundant_jump_in_if_else_break(self): 10047db96d56Sopenharmony_ci # Check if bytecode containing jumps that simply point to the next line 10057db96d56Sopenharmony_ci # is generated around if-else-break style structures. See bpo-42615. 10067db96d56Sopenharmony_ci 10077db96d56Sopenharmony_ci def if_else_break(): 10087db96d56Sopenharmony_ci val = 1 10097db96d56Sopenharmony_ci while True: 10107db96d56Sopenharmony_ci if val > 0: 10117db96d56Sopenharmony_ci val -= 1 10127db96d56Sopenharmony_ci else: 10137db96d56Sopenharmony_ci break 10147db96d56Sopenharmony_ci val = -1 10157db96d56Sopenharmony_ci 10167db96d56Sopenharmony_ci INSTR_SIZE = 2 10177db96d56Sopenharmony_ci HANDLED_JUMPS = ( 10187db96d56Sopenharmony_ci 'POP_JUMP_IF_FALSE', 10197db96d56Sopenharmony_ci 'POP_JUMP_IF_TRUE', 10207db96d56Sopenharmony_ci 'JUMP_ABSOLUTE', 10217db96d56Sopenharmony_ci 'JUMP_FORWARD', 10227db96d56Sopenharmony_ci ) 10237db96d56Sopenharmony_ci 10247db96d56Sopenharmony_ci for line, instr in enumerate( 10257db96d56Sopenharmony_ci dis.Bytecode(if_else_break, show_caches=True) 10267db96d56Sopenharmony_ci ): 10277db96d56Sopenharmony_ci if instr.opname == 'JUMP_FORWARD': 10287db96d56Sopenharmony_ci self.assertNotEqual(instr.arg, 0) 10297db96d56Sopenharmony_ci elif instr.opname in HANDLED_JUMPS: 10307db96d56Sopenharmony_ci self.assertNotEqual(instr.arg, (line + 1)*INSTR_SIZE) 10317db96d56Sopenharmony_ci 10327db96d56Sopenharmony_ci def test_no_wraparound_jump(self): 10337db96d56Sopenharmony_ci # See https://bugs.python.org/issue46724 10347db96d56Sopenharmony_ci 10357db96d56Sopenharmony_ci def while_not_chained(a, b, c): 10367db96d56Sopenharmony_ci while not (a < b < c): 10377db96d56Sopenharmony_ci pass 10387db96d56Sopenharmony_ci 10397db96d56Sopenharmony_ci for instr in dis.Bytecode(while_not_chained): 10407db96d56Sopenharmony_ci self.assertNotEqual(instr.opname, "EXTENDED_ARG") 10417db96d56Sopenharmony_ci 10427db96d56Sopenharmony_ci def test_compare_positions(self): 10437db96d56Sopenharmony_ci for opname, op in [ 10447db96d56Sopenharmony_ci ("COMPARE_OP", "<"), 10457db96d56Sopenharmony_ci ("COMPARE_OP", "<="), 10467db96d56Sopenharmony_ci ("COMPARE_OP", ">"), 10477db96d56Sopenharmony_ci ("COMPARE_OP", ">="), 10487db96d56Sopenharmony_ci ("CONTAINS_OP", "in"), 10497db96d56Sopenharmony_ci ("CONTAINS_OP", "not in"), 10507db96d56Sopenharmony_ci ("IS_OP", "is"), 10517db96d56Sopenharmony_ci ("IS_OP", "is not"), 10527db96d56Sopenharmony_ci ]: 10537db96d56Sopenharmony_ci expr = f'a {op} b {op} c' 10547db96d56Sopenharmony_ci expected_positions = 2 * [(2, 2, 0, len(expr))] 10557db96d56Sopenharmony_ci for source in [ 10567db96d56Sopenharmony_ci f"\\\n{expr}", f'if \\\n{expr}: x', f"x if \\\n{expr} else y" 10577db96d56Sopenharmony_ci ]: 10587db96d56Sopenharmony_ci code = compile(source, "<test>", "exec") 10597db96d56Sopenharmony_ci actual_positions = [ 10607db96d56Sopenharmony_ci instruction.positions 10617db96d56Sopenharmony_ci for instruction in dis.get_instructions(code) 10627db96d56Sopenharmony_ci if instruction.opname == opname 10637db96d56Sopenharmony_ci ] 10647db96d56Sopenharmony_ci with self.subTest(source): 10657db96d56Sopenharmony_ci self.assertEqual(actual_positions, expected_positions) 10667db96d56Sopenharmony_ci 10677db96d56Sopenharmony_ci def test_apply_static_swaps(self): 10687db96d56Sopenharmony_ci def f(x, y): 10697db96d56Sopenharmony_ci a, a = x, y 10707db96d56Sopenharmony_ci return a 10717db96d56Sopenharmony_ci self.assertEqual(f("x", "y"), "y") 10727db96d56Sopenharmony_ci 10737db96d56Sopenharmony_ci def test_apply_static_swaps_2(self): 10747db96d56Sopenharmony_ci def f(x, y, z): 10757db96d56Sopenharmony_ci a, b, a = x, y, z 10767db96d56Sopenharmony_ci return a 10777db96d56Sopenharmony_ci self.assertEqual(f("x", "y", "z"), "z") 10787db96d56Sopenharmony_ci 10797db96d56Sopenharmony_ci def test_apply_static_swaps_3(self): 10807db96d56Sopenharmony_ci def f(x, y, z): 10817db96d56Sopenharmony_ci a, a, b = x, y, z 10827db96d56Sopenharmony_ci return a 10837db96d56Sopenharmony_ci self.assertEqual(f("x", "y", "z"), "y") 10847db96d56Sopenharmony_ci 10857db96d56Sopenharmony_ci 10867db96d56Sopenharmony_ci@requires_debug_ranges() 10877db96d56Sopenharmony_ciclass TestSourcePositions(unittest.TestCase): 10887db96d56Sopenharmony_ci # Ensure that compiled code snippets have correct line and column numbers 10897db96d56Sopenharmony_ci # in `co_positions()`. 10907db96d56Sopenharmony_ci 10917db96d56Sopenharmony_ci def check_positions_against_ast(self, snippet): 10927db96d56Sopenharmony_ci # Basic check that makes sure each line and column is at least present 10937db96d56Sopenharmony_ci # in one of the AST nodes of the source code. 10947db96d56Sopenharmony_ci code = compile(snippet, 'test_compile.py', 'exec') 10957db96d56Sopenharmony_ci ast_tree = compile(snippet, 'test_compile.py', 'exec', _ast.PyCF_ONLY_AST) 10967db96d56Sopenharmony_ci self.assertTrue(type(ast_tree) == _ast.Module) 10977db96d56Sopenharmony_ci 10987db96d56Sopenharmony_ci # Use an AST visitor that notes all the offsets. 10997db96d56Sopenharmony_ci lines, end_lines, columns, end_columns = set(), set(), set(), set() 11007db96d56Sopenharmony_ci class SourceOffsetVisitor(ast.NodeVisitor): 11017db96d56Sopenharmony_ci def generic_visit(self, node): 11027db96d56Sopenharmony_ci super().generic_visit(node) 11037db96d56Sopenharmony_ci if not isinstance(node, ast.expr) and not isinstance(node, ast.stmt): 11047db96d56Sopenharmony_ci return 11057db96d56Sopenharmony_ci lines.add(node.lineno) 11067db96d56Sopenharmony_ci end_lines.add(node.end_lineno) 11077db96d56Sopenharmony_ci columns.add(node.col_offset) 11087db96d56Sopenharmony_ci end_columns.add(node.end_col_offset) 11097db96d56Sopenharmony_ci 11107db96d56Sopenharmony_ci SourceOffsetVisitor().visit(ast_tree) 11117db96d56Sopenharmony_ci 11127db96d56Sopenharmony_ci # Check against the positions in the code object. 11137db96d56Sopenharmony_ci for (line, end_line, col, end_col) in code.co_positions(): 11147db96d56Sopenharmony_ci if line == 0: 11157db96d56Sopenharmony_ci continue # This is an artificial module-start line 11167db96d56Sopenharmony_ci # If the offset is not None (indicating missing data), ensure that 11177db96d56Sopenharmony_ci # it was part of one of the AST nodes. 11187db96d56Sopenharmony_ci if line is not None: 11197db96d56Sopenharmony_ci self.assertIn(line, lines) 11207db96d56Sopenharmony_ci if end_line is not None: 11217db96d56Sopenharmony_ci self.assertIn(end_line, end_lines) 11227db96d56Sopenharmony_ci if col is not None: 11237db96d56Sopenharmony_ci self.assertIn(col, columns) 11247db96d56Sopenharmony_ci if end_col is not None: 11257db96d56Sopenharmony_ci self.assertIn(end_col, end_columns) 11267db96d56Sopenharmony_ci 11277db96d56Sopenharmony_ci return code, ast_tree 11287db96d56Sopenharmony_ci 11297db96d56Sopenharmony_ci def assertOpcodeSourcePositionIs(self, code, opcode, 11307db96d56Sopenharmony_ci line, end_line, column, end_column, occurrence=1): 11317db96d56Sopenharmony_ci 11327db96d56Sopenharmony_ci for instr, position in zip( 11337db96d56Sopenharmony_ci dis.Bytecode(code, show_caches=True), code.co_positions(), strict=True 11347db96d56Sopenharmony_ci ): 11357db96d56Sopenharmony_ci if instr.opname == opcode: 11367db96d56Sopenharmony_ci occurrence -= 1 11377db96d56Sopenharmony_ci if not occurrence: 11387db96d56Sopenharmony_ci self.assertEqual(position[0], line) 11397db96d56Sopenharmony_ci self.assertEqual(position[1], end_line) 11407db96d56Sopenharmony_ci self.assertEqual(position[2], column) 11417db96d56Sopenharmony_ci self.assertEqual(position[3], end_column) 11427db96d56Sopenharmony_ci return 11437db96d56Sopenharmony_ci 11447db96d56Sopenharmony_ci self.fail(f"Opcode {opcode} not found in code") 11457db96d56Sopenharmony_ci 11467db96d56Sopenharmony_ci def test_simple_assignment(self): 11477db96d56Sopenharmony_ci snippet = "x = 1" 11487db96d56Sopenharmony_ci self.check_positions_against_ast(snippet) 11497db96d56Sopenharmony_ci 11507db96d56Sopenharmony_ci def test_compiles_to_extended_op_arg(self): 11517db96d56Sopenharmony_ci # Make sure we still have valid positions when the code compiles to an 11527db96d56Sopenharmony_ci # EXTENDED_ARG by performing a loop which needs a JUMP_ABSOLUTE after 11537db96d56Sopenharmony_ci # a bunch of opcodes. 11547db96d56Sopenharmony_ci snippet = "x = x\n" * 10_000 11557db96d56Sopenharmony_ci snippet += ("while x != 0:\n" 11567db96d56Sopenharmony_ci " x -= 1\n" 11577db96d56Sopenharmony_ci "while x != 0:\n" 11587db96d56Sopenharmony_ci " x += 1\n" 11597db96d56Sopenharmony_ci ) 11607db96d56Sopenharmony_ci 11617db96d56Sopenharmony_ci compiled_code, _ = self.check_positions_against_ast(snippet) 11627db96d56Sopenharmony_ci 11637db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', 11647db96d56Sopenharmony_ci line=10_000 + 2, end_line=10_000 + 2, 11657db96d56Sopenharmony_ci column=2, end_column=8, occurrence=1) 11667db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', 11677db96d56Sopenharmony_ci line=10_000 + 4, end_line=10_000 + 4, 11687db96d56Sopenharmony_ci column=2, end_column=9, occurrence=2) 11697db96d56Sopenharmony_ci 11707db96d56Sopenharmony_ci def test_multiline_expression(self): 11717db96d56Sopenharmony_ci snippet = """\ 11727db96d56Sopenharmony_cif( 11737db96d56Sopenharmony_ci 1, 2, 3, 4 11747db96d56Sopenharmony_ci) 11757db96d56Sopenharmony_ci""" 11767db96d56Sopenharmony_ci compiled_code, _ = self.check_positions_against_ast(snippet) 11777db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'CALL', 11787db96d56Sopenharmony_ci line=1, end_line=3, column=0, end_column=1) 11797db96d56Sopenharmony_ci 11807db96d56Sopenharmony_ci def test_very_long_line_end_offset(self): 11817db96d56Sopenharmony_ci # Make sure we get the correct column offset for offsets 11827db96d56Sopenharmony_ci # too large to store in a byte. 11837db96d56Sopenharmony_ci long_string = "a" * 1000 11847db96d56Sopenharmony_ci snippet = f"g('{long_string}')" 11857db96d56Sopenharmony_ci 11867db96d56Sopenharmony_ci compiled_code, _ = self.check_positions_against_ast(snippet) 11877db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'CALL', 11887db96d56Sopenharmony_ci line=1, end_line=1, column=0, end_column=1005) 11897db96d56Sopenharmony_ci 11907db96d56Sopenharmony_ci def test_complex_single_line_expression(self): 11917db96d56Sopenharmony_ci snippet = "a - b @ (c * x['key'] + 23)" 11927db96d56Sopenharmony_ci 11937db96d56Sopenharmony_ci compiled_code, _ = self.check_positions_against_ast(snippet) 11947db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_SUBSCR', 11957db96d56Sopenharmony_ci line=1, end_line=1, column=13, end_column=21) 11967db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', 11977db96d56Sopenharmony_ci line=1, end_line=1, column=9, end_column=21, occurrence=1) 11987db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', 11997db96d56Sopenharmony_ci line=1, end_line=1, column=9, end_column=26, occurrence=2) 12007db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', 12017db96d56Sopenharmony_ci line=1, end_line=1, column=4, end_column=27, occurrence=3) 12027db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', 12037db96d56Sopenharmony_ci line=1, end_line=1, column=0, end_column=27, occurrence=4) 12047db96d56Sopenharmony_ci 12057db96d56Sopenharmony_ci def test_multiline_assert_rewritten_as_method_call(self): 12067db96d56Sopenharmony_ci # GH-94694: Don't crash if pytest rewrites a multiline assert as a 12077db96d56Sopenharmony_ci # method call with the same location information: 12087db96d56Sopenharmony_ci tree = ast.parse("assert (\n42\n)") 12097db96d56Sopenharmony_ci old_node = tree.body[0] 12107db96d56Sopenharmony_ci new_node = ast.Expr( 12117db96d56Sopenharmony_ci ast.Call( 12127db96d56Sopenharmony_ci ast.Attribute( 12137db96d56Sopenharmony_ci ast.Name("spam", ast.Load()), 12147db96d56Sopenharmony_ci "eggs", 12157db96d56Sopenharmony_ci ast.Load(), 12167db96d56Sopenharmony_ci ), 12177db96d56Sopenharmony_ci [], 12187db96d56Sopenharmony_ci [], 12197db96d56Sopenharmony_ci ) 12207db96d56Sopenharmony_ci ) 12217db96d56Sopenharmony_ci ast.copy_location(new_node, old_node) 12227db96d56Sopenharmony_ci ast.fix_missing_locations(new_node) 12237db96d56Sopenharmony_ci tree.body[0] = new_node 12247db96d56Sopenharmony_ci compile(tree, "<test>", "exec") 12257db96d56Sopenharmony_ci 12267db96d56Sopenharmony_ci def test_push_null_load_global_positions(self): 12277db96d56Sopenharmony_ci source_template = """ 12287db96d56Sopenharmony_ci import abc, dis 12297db96d56Sopenharmony_ci import ast as art 12307db96d56Sopenharmony_ci 12317db96d56Sopenharmony_ci abc = None 12327db96d56Sopenharmony_ci dix = dis 12337db96d56Sopenharmony_ci ast = art 12347db96d56Sopenharmony_ci 12357db96d56Sopenharmony_ci def f(): 12367db96d56Sopenharmony_ci {} 12377db96d56Sopenharmony_ci """ 12387db96d56Sopenharmony_ci for body in [ 12397db96d56Sopenharmony_ci " abc.a()", 12407db96d56Sopenharmony_ci " art.a()", 12417db96d56Sopenharmony_ci " ast.a()", 12427db96d56Sopenharmony_ci " dis.a()", 12437db96d56Sopenharmony_ci " dix.a()", 12447db96d56Sopenharmony_ci " abc[...]()", 12457db96d56Sopenharmony_ci " art()()", 12467db96d56Sopenharmony_ci " (ast or ...)()", 12477db96d56Sopenharmony_ci " [dis]()", 12487db96d56Sopenharmony_ci " (dix + ...)()", 12497db96d56Sopenharmony_ci ]: 12507db96d56Sopenharmony_ci with self.subTest(body): 12517db96d56Sopenharmony_ci namespace = {} 12527db96d56Sopenharmony_ci source = textwrap.dedent(source_template.format(body)) 12537db96d56Sopenharmony_ci exec(source, namespace) 12547db96d56Sopenharmony_ci code = namespace["f"].__code__ 12557db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 12567db96d56Sopenharmony_ci code, 12577db96d56Sopenharmony_ci "LOAD_GLOBAL", 12587db96d56Sopenharmony_ci line=10, 12597db96d56Sopenharmony_ci end_line=10, 12607db96d56Sopenharmony_ci column=4, 12617db96d56Sopenharmony_ci end_column=7, 12627db96d56Sopenharmony_ci ) 12637db96d56Sopenharmony_ci 12647db96d56Sopenharmony_ci def test_attribute_augassign(self): 12657db96d56Sopenharmony_ci source = "(\n lhs \n . \n rhs \n ) += 42" 12667db96d56Sopenharmony_ci code = compile(source, "<test>", "exec") 12677db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 12687db96d56Sopenharmony_ci code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8 12697db96d56Sopenharmony_ci ) 12707db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 12717db96d56Sopenharmony_ci code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8 12727db96d56Sopenharmony_ci ) 12737db96d56Sopenharmony_ci 12747db96d56Sopenharmony_ci def test_attribute_del(self): 12757db96d56Sopenharmony_ci source = "del (\n lhs \n . \n rhs \n )" 12767db96d56Sopenharmony_ci code = compile(source, "<test>", "exec") 12777db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 12787db96d56Sopenharmony_ci code, "DELETE_ATTR", line=4, end_line=4, column=5, end_column=8 12797db96d56Sopenharmony_ci ) 12807db96d56Sopenharmony_ci 12817db96d56Sopenharmony_ci def test_attribute_load(self): 12827db96d56Sopenharmony_ci source = "(\n lhs \n . \n rhs \n )" 12837db96d56Sopenharmony_ci code = compile(source, "<test>", "exec") 12847db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 12857db96d56Sopenharmony_ci code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8 12867db96d56Sopenharmony_ci ) 12877db96d56Sopenharmony_ci 12887db96d56Sopenharmony_ci def test_attribute_store(self): 12897db96d56Sopenharmony_ci source = "(\n lhs \n . \n rhs \n ) = 42" 12907db96d56Sopenharmony_ci code = compile(source, "<test>", "exec") 12917db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 12927db96d56Sopenharmony_ci code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8 12937db96d56Sopenharmony_ci ) 12947db96d56Sopenharmony_ci 12957db96d56Sopenharmony_ci def test_method_call(self): 12967db96d56Sopenharmony_ci source = "(\n lhs \n . \n rhs \n )()" 12977db96d56Sopenharmony_ci code = compile(source, "<test>", "exec") 12987db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 12997db96d56Sopenharmony_ci code, "LOAD_METHOD", line=4, end_line=4, column=5, end_column=8 13007db96d56Sopenharmony_ci ) 13017db96d56Sopenharmony_ci self.assertOpcodeSourcePositionIs( 13027db96d56Sopenharmony_ci code, "CALL", line=4, end_line=5, column=5, end_column=10 13037db96d56Sopenharmony_ci ) 13047db96d56Sopenharmony_ci 13057db96d56Sopenharmony_ci def test_weird_attribute_position_regressions(self): 13067db96d56Sopenharmony_ci def f(): 13077db96d56Sopenharmony_ci (bar. 13087db96d56Sopenharmony_ci baz) 13097db96d56Sopenharmony_ci (bar. 13107db96d56Sopenharmony_ci baz( 13117db96d56Sopenharmony_ci )) 13127db96d56Sopenharmony_ci files().setdefault( 13137db96d56Sopenharmony_ci 0 13147db96d56Sopenharmony_ci ).setdefault( 13157db96d56Sopenharmony_ci 0 13167db96d56Sopenharmony_ci ) 13177db96d56Sopenharmony_ci for line, end_line, column, end_column in f.__code__.co_positions(): 13187db96d56Sopenharmony_ci self.assertIsNotNone(line) 13197db96d56Sopenharmony_ci self.assertIsNotNone(end_line) 13207db96d56Sopenharmony_ci self.assertIsNotNone(column) 13217db96d56Sopenharmony_ci self.assertIsNotNone(end_column) 13227db96d56Sopenharmony_ci self.assertLessEqual((line, column), (end_line, end_column)) 13237db96d56Sopenharmony_ci 13247db96d56Sopenharmony_ci @support.cpython_only 13257db96d56Sopenharmony_ci def test_column_offset_deduplication(self): 13267db96d56Sopenharmony_ci # GH-95150: Code with different column offsets shouldn't be merged! 13277db96d56Sopenharmony_ci for source in [ 13287db96d56Sopenharmony_ci "lambda: a", 13297db96d56Sopenharmony_ci "(a for b in c)", 13307db96d56Sopenharmony_ci "[a for b in c]", 13317db96d56Sopenharmony_ci "{a for b in c}", 13327db96d56Sopenharmony_ci "{a: b for c in d}", 13337db96d56Sopenharmony_ci ]: 13347db96d56Sopenharmony_ci with self.subTest(source): 13357db96d56Sopenharmony_ci code = compile(f"{source}, {source}", "<test>", "eval") 13367db96d56Sopenharmony_ci self.assertEqual(len(code.co_consts), 2) 13377db96d56Sopenharmony_ci self.assertIsInstance(code.co_consts[0], types.CodeType) 13387db96d56Sopenharmony_ci self.assertIsInstance(code.co_consts[1], types.CodeType) 13397db96d56Sopenharmony_ci self.assertNotEqual(code.co_consts[0], code.co_consts[1]) 13407db96d56Sopenharmony_ci self.assertNotEqual( 13417db96d56Sopenharmony_ci list(code.co_consts[0].co_positions()), 13427db96d56Sopenharmony_ci list(code.co_consts[1].co_positions()), 13437db96d56Sopenharmony_ci ) 13447db96d56Sopenharmony_ci 13457db96d56Sopenharmony_ci 13467db96d56Sopenharmony_ciclass TestExpressionStackSize(unittest.TestCase): 13477db96d56Sopenharmony_ci # These tests check that the computed stack size for a code object 13487db96d56Sopenharmony_ci # stays within reasonable bounds (see issue #21523 for an example 13497db96d56Sopenharmony_ci # dysfunction). 13507db96d56Sopenharmony_ci N = 100 13517db96d56Sopenharmony_ci 13527db96d56Sopenharmony_ci def check_stack_size(self, code): 13537db96d56Sopenharmony_ci # To assert that the alleged stack size is not O(N), we 13547db96d56Sopenharmony_ci # check that it is smaller than log(N). 13557db96d56Sopenharmony_ci if isinstance(code, str): 13567db96d56Sopenharmony_ci code = compile(code, "<foo>", "single") 13577db96d56Sopenharmony_ci max_size = math.ceil(math.log(len(code.co_code))) 13587db96d56Sopenharmony_ci self.assertLessEqual(code.co_stacksize, max_size) 13597db96d56Sopenharmony_ci 13607db96d56Sopenharmony_ci def test_and(self): 13617db96d56Sopenharmony_ci self.check_stack_size("x and " * self.N + "x") 13627db96d56Sopenharmony_ci 13637db96d56Sopenharmony_ci def test_or(self): 13647db96d56Sopenharmony_ci self.check_stack_size("x or " * self.N + "x") 13657db96d56Sopenharmony_ci 13667db96d56Sopenharmony_ci def test_and_or(self): 13677db96d56Sopenharmony_ci self.check_stack_size("x and x or " * self.N + "x") 13687db96d56Sopenharmony_ci 13697db96d56Sopenharmony_ci def test_chained_comparison(self): 13707db96d56Sopenharmony_ci self.check_stack_size("x < " * self.N + "x") 13717db96d56Sopenharmony_ci 13727db96d56Sopenharmony_ci def test_if_else(self): 13737db96d56Sopenharmony_ci self.check_stack_size("x if x else " * self.N + "x") 13747db96d56Sopenharmony_ci 13757db96d56Sopenharmony_ci def test_binop(self): 13767db96d56Sopenharmony_ci self.check_stack_size("x + " * self.N + "x") 13777db96d56Sopenharmony_ci 13787db96d56Sopenharmony_ci def test_list(self): 13797db96d56Sopenharmony_ci self.check_stack_size("[" + "x, " * self.N + "x]") 13807db96d56Sopenharmony_ci 13817db96d56Sopenharmony_ci def test_tuple(self): 13827db96d56Sopenharmony_ci self.check_stack_size("(" + "x, " * self.N + "x)") 13837db96d56Sopenharmony_ci 13847db96d56Sopenharmony_ci def test_set(self): 13857db96d56Sopenharmony_ci self.check_stack_size("{" + "x, " * self.N + "x}") 13867db96d56Sopenharmony_ci 13877db96d56Sopenharmony_ci def test_dict(self): 13887db96d56Sopenharmony_ci self.check_stack_size("{" + "x:x, " * self.N + "x:x}") 13897db96d56Sopenharmony_ci 13907db96d56Sopenharmony_ci def test_func_args(self): 13917db96d56Sopenharmony_ci self.check_stack_size("f(" + "x, " * self.N + ")") 13927db96d56Sopenharmony_ci 13937db96d56Sopenharmony_ci def test_func_kwargs(self): 13947db96d56Sopenharmony_ci kwargs = (f'a{i}=x' for i in range(self.N)) 13957db96d56Sopenharmony_ci self.check_stack_size("f(" + ", ".join(kwargs) + ")") 13967db96d56Sopenharmony_ci 13977db96d56Sopenharmony_ci def test_meth_args(self): 13987db96d56Sopenharmony_ci self.check_stack_size("o.m(" + "x, " * self.N + ")") 13997db96d56Sopenharmony_ci 14007db96d56Sopenharmony_ci def test_meth_kwargs(self): 14017db96d56Sopenharmony_ci kwargs = (f'a{i}=x' for i in range(self.N)) 14027db96d56Sopenharmony_ci self.check_stack_size("o.m(" + ", ".join(kwargs) + ")") 14037db96d56Sopenharmony_ci 14047db96d56Sopenharmony_ci def test_func_and(self): 14057db96d56Sopenharmony_ci code = "def f(x):\n" 14067db96d56Sopenharmony_ci code += " x and x\n" * self.N 14077db96d56Sopenharmony_ci self.check_stack_size(code) 14087db96d56Sopenharmony_ci 14097db96d56Sopenharmony_ci def test_stack_3050(self): 14107db96d56Sopenharmony_ci M = 3050 14117db96d56Sopenharmony_ci code = "x," * M + "=t" 14127db96d56Sopenharmony_ci # This raised on 3.10.0 to 3.10.5 14137db96d56Sopenharmony_ci compile(code, "<foo>", "single") 14147db96d56Sopenharmony_ci 14157db96d56Sopenharmony_ci def test_stack_3050_2(self): 14167db96d56Sopenharmony_ci M = 3050 14177db96d56Sopenharmony_ci args = ", ".join(f"arg{i}:type{i}" for i in range(M)) 14187db96d56Sopenharmony_ci code = f"def f({args}):\n pass" 14197db96d56Sopenharmony_ci # This raised on 3.10.0 to 3.10.5 14207db96d56Sopenharmony_ci compile(code, "<foo>", "single") 14217db96d56Sopenharmony_ci 14227db96d56Sopenharmony_ci 14237db96d56Sopenharmony_ciclass TestStackSizeStability(unittest.TestCase): 14247db96d56Sopenharmony_ci # Check that repeating certain snippets doesn't increase the stack size 14257db96d56Sopenharmony_ci # beyond what a single snippet requires. 14267db96d56Sopenharmony_ci 14277db96d56Sopenharmony_ci def check_stack_size(self, snippet, async_=False): 14287db96d56Sopenharmony_ci def compile_snippet(i): 14297db96d56Sopenharmony_ci ns = {} 14307db96d56Sopenharmony_ci script = """def func():\n""" + i * snippet 14317db96d56Sopenharmony_ci if async_: 14327db96d56Sopenharmony_ci script = "async " + script 14337db96d56Sopenharmony_ci code = compile(script, "<script>", "exec") 14347db96d56Sopenharmony_ci exec(code, ns, ns) 14357db96d56Sopenharmony_ci return ns['func'].__code__ 14367db96d56Sopenharmony_ci 14377db96d56Sopenharmony_ci sizes = [compile_snippet(i).co_stacksize for i in range(2, 5)] 14387db96d56Sopenharmony_ci if len(set(sizes)) != 1: 14397db96d56Sopenharmony_ci import dis, io 14407db96d56Sopenharmony_ci out = io.StringIO() 14417db96d56Sopenharmony_ci dis.dis(compile_snippet(1), file=out) 14427db96d56Sopenharmony_ci self.fail("stack sizes diverge with # of consecutive snippets: " 14437db96d56Sopenharmony_ci "%s\n%s\n%s" % (sizes, snippet, out.getvalue())) 14447db96d56Sopenharmony_ci 14457db96d56Sopenharmony_ci def test_if(self): 14467db96d56Sopenharmony_ci snippet = """ 14477db96d56Sopenharmony_ci if x: 14487db96d56Sopenharmony_ci a 14497db96d56Sopenharmony_ci """ 14507db96d56Sopenharmony_ci self.check_stack_size(snippet) 14517db96d56Sopenharmony_ci 14527db96d56Sopenharmony_ci def test_if_else(self): 14537db96d56Sopenharmony_ci snippet = """ 14547db96d56Sopenharmony_ci if x: 14557db96d56Sopenharmony_ci a 14567db96d56Sopenharmony_ci elif y: 14577db96d56Sopenharmony_ci b 14587db96d56Sopenharmony_ci else: 14597db96d56Sopenharmony_ci c 14607db96d56Sopenharmony_ci """ 14617db96d56Sopenharmony_ci self.check_stack_size(snippet) 14627db96d56Sopenharmony_ci 14637db96d56Sopenharmony_ci def test_try_except_bare(self): 14647db96d56Sopenharmony_ci snippet = """ 14657db96d56Sopenharmony_ci try: 14667db96d56Sopenharmony_ci a 14677db96d56Sopenharmony_ci except: 14687db96d56Sopenharmony_ci b 14697db96d56Sopenharmony_ci """ 14707db96d56Sopenharmony_ci self.check_stack_size(snippet) 14717db96d56Sopenharmony_ci 14727db96d56Sopenharmony_ci def test_try_except_qualified(self): 14737db96d56Sopenharmony_ci snippet = """ 14747db96d56Sopenharmony_ci try: 14757db96d56Sopenharmony_ci a 14767db96d56Sopenharmony_ci except ImportError: 14777db96d56Sopenharmony_ci b 14787db96d56Sopenharmony_ci except: 14797db96d56Sopenharmony_ci c 14807db96d56Sopenharmony_ci else: 14817db96d56Sopenharmony_ci d 14827db96d56Sopenharmony_ci """ 14837db96d56Sopenharmony_ci self.check_stack_size(snippet) 14847db96d56Sopenharmony_ci 14857db96d56Sopenharmony_ci def test_try_except_as(self): 14867db96d56Sopenharmony_ci snippet = """ 14877db96d56Sopenharmony_ci try: 14887db96d56Sopenharmony_ci a 14897db96d56Sopenharmony_ci except ImportError as e: 14907db96d56Sopenharmony_ci b 14917db96d56Sopenharmony_ci except: 14927db96d56Sopenharmony_ci c 14937db96d56Sopenharmony_ci else: 14947db96d56Sopenharmony_ci d 14957db96d56Sopenharmony_ci """ 14967db96d56Sopenharmony_ci self.check_stack_size(snippet) 14977db96d56Sopenharmony_ci 14987db96d56Sopenharmony_ci def test_try_except_star_qualified(self): 14997db96d56Sopenharmony_ci snippet = """ 15007db96d56Sopenharmony_ci try: 15017db96d56Sopenharmony_ci a 15027db96d56Sopenharmony_ci except* ImportError: 15037db96d56Sopenharmony_ci b 15047db96d56Sopenharmony_ci else: 15057db96d56Sopenharmony_ci c 15067db96d56Sopenharmony_ci """ 15077db96d56Sopenharmony_ci self.check_stack_size(snippet) 15087db96d56Sopenharmony_ci 15097db96d56Sopenharmony_ci def test_try_except_star_as(self): 15107db96d56Sopenharmony_ci snippet = """ 15117db96d56Sopenharmony_ci try: 15127db96d56Sopenharmony_ci a 15137db96d56Sopenharmony_ci except* ImportError as e: 15147db96d56Sopenharmony_ci b 15157db96d56Sopenharmony_ci else: 15167db96d56Sopenharmony_ci c 15177db96d56Sopenharmony_ci """ 15187db96d56Sopenharmony_ci self.check_stack_size(snippet) 15197db96d56Sopenharmony_ci 15207db96d56Sopenharmony_ci def test_try_except_star_finally(self): 15217db96d56Sopenharmony_ci snippet = """ 15227db96d56Sopenharmony_ci try: 15237db96d56Sopenharmony_ci a 15247db96d56Sopenharmony_ci except* A: 15257db96d56Sopenharmony_ci b 15267db96d56Sopenharmony_ci finally: 15277db96d56Sopenharmony_ci c 15287db96d56Sopenharmony_ci """ 15297db96d56Sopenharmony_ci self.check_stack_size(snippet) 15307db96d56Sopenharmony_ci 15317db96d56Sopenharmony_ci def test_try_finally(self): 15327db96d56Sopenharmony_ci snippet = """ 15337db96d56Sopenharmony_ci try: 15347db96d56Sopenharmony_ci a 15357db96d56Sopenharmony_ci finally: 15367db96d56Sopenharmony_ci b 15377db96d56Sopenharmony_ci """ 15387db96d56Sopenharmony_ci self.check_stack_size(snippet) 15397db96d56Sopenharmony_ci 15407db96d56Sopenharmony_ci def test_with(self): 15417db96d56Sopenharmony_ci snippet = """ 15427db96d56Sopenharmony_ci with x as y: 15437db96d56Sopenharmony_ci a 15447db96d56Sopenharmony_ci """ 15457db96d56Sopenharmony_ci self.check_stack_size(snippet) 15467db96d56Sopenharmony_ci 15477db96d56Sopenharmony_ci def test_while_else(self): 15487db96d56Sopenharmony_ci snippet = """ 15497db96d56Sopenharmony_ci while x: 15507db96d56Sopenharmony_ci a 15517db96d56Sopenharmony_ci else: 15527db96d56Sopenharmony_ci b 15537db96d56Sopenharmony_ci """ 15547db96d56Sopenharmony_ci self.check_stack_size(snippet) 15557db96d56Sopenharmony_ci 15567db96d56Sopenharmony_ci def test_for(self): 15577db96d56Sopenharmony_ci snippet = """ 15587db96d56Sopenharmony_ci for x in y: 15597db96d56Sopenharmony_ci a 15607db96d56Sopenharmony_ci """ 15617db96d56Sopenharmony_ci self.check_stack_size(snippet) 15627db96d56Sopenharmony_ci 15637db96d56Sopenharmony_ci def test_for_else(self): 15647db96d56Sopenharmony_ci snippet = """ 15657db96d56Sopenharmony_ci for x in y: 15667db96d56Sopenharmony_ci a 15677db96d56Sopenharmony_ci else: 15687db96d56Sopenharmony_ci b 15697db96d56Sopenharmony_ci """ 15707db96d56Sopenharmony_ci self.check_stack_size(snippet) 15717db96d56Sopenharmony_ci 15727db96d56Sopenharmony_ci def test_for_break_continue(self): 15737db96d56Sopenharmony_ci snippet = """ 15747db96d56Sopenharmony_ci for x in y: 15757db96d56Sopenharmony_ci if z: 15767db96d56Sopenharmony_ci break 15777db96d56Sopenharmony_ci elif u: 15787db96d56Sopenharmony_ci continue 15797db96d56Sopenharmony_ci else: 15807db96d56Sopenharmony_ci a 15817db96d56Sopenharmony_ci else: 15827db96d56Sopenharmony_ci b 15837db96d56Sopenharmony_ci """ 15847db96d56Sopenharmony_ci self.check_stack_size(snippet) 15857db96d56Sopenharmony_ci 15867db96d56Sopenharmony_ci def test_for_break_continue_inside_try_finally_block(self): 15877db96d56Sopenharmony_ci snippet = """ 15887db96d56Sopenharmony_ci for x in y: 15897db96d56Sopenharmony_ci try: 15907db96d56Sopenharmony_ci if z: 15917db96d56Sopenharmony_ci break 15927db96d56Sopenharmony_ci elif u: 15937db96d56Sopenharmony_ci continue 15947db96d56Sopenharmony_ci else: 15957db96d56Sopenharmony_ci a 15967db96d56Sopenharmony_ci finally: 15977db96d56Sopenharmony_ci f 15987db96d56Sopenharmony_ci else: 15997db96d56Sopenharmony_ci b 16007db96d56Sopenharmony_ci """ 16017db96d56Sopenharmony_ci self.check_stack_size(snippet) 16027db96d56Sopenharmony_ci 16037db96d56Sopenharmony_ci def test_for_break_continue_inside_finally_block(self): 16047db96d56Sopenharmony_ci snippet = """ 16057db96d56Sopenharmony_ci for x in y: 16067db96d56Sopenharmony_ci try: 16077db96d56Sopenharmony_ci t 16087db96d56Sopenharmony_ci finally: 16097db96d56Sopenharmony_ci if z: 16107db96d56Sopenharmony_ci break 16117db96d56Sopenharmony_ci elif u: 16127db96d56Sopenharmony_ci continue 16137db96d56Sopenharmony_ci else: 16147db96d56Sopenharmony_ci a 16157db96d56Sopenharmony_ci else: 16167db96d56Sopenharmony_ci b 16177db96d56Sopenharmony_ci """ 16187db96d56Sopenharmony_ci self.check_stack_size(snippet) 16197db96d56Sopenharmony_ci 16207db96d56Sopenharmony_ci def test_for_break_continue_inside_except_block(self): 16217db96d56Sopenharmony_ci snippet = """ 16227db96d56Sopenharmony_ci for x in y: 16237db96d56Sopenharmony_ci try: 16247db96d56Sopenharmony_ci t 16257db96d56Sopenharmony_ci except: 16267db96d56Sopenharmony_ci if z: 16277db96d56Sopenharmony_ci break 16287db96d56Sopenharmony_ci elif u: 16297db96d56Sopenharmony_ci continue 16307db96d56Sopenharmony_ci else: 16317db96d56Sopenharmony_ci a 16327db96d56Sopenharmony_ci else: 16337db96d56Sopenharmony_ci b 16347db96d56Sopenharmony_ci """ 16357db96d56Sopenharmony_ci self.check_stack_size(snippet) 16367db96d56Sopenharmony_ci 16377db96d56Sopenharmony_ci def test_for_break_continue_inside_with_block(self): 16387db96d56Sopenharmony_ci snippet = """ 16397db96d56Sopenharmony_ci for x in y: 16407db96d56Sopenharmony_ci with c: 16417db96d56Sopenharmony_ci if z: 16427db96d56Sopenharmony_ci break 16437db96d56Sopenharmony_ci elif u: 16447db96d56Sopenharmony_ci continue 16457db96d56Sopenharmony_ci else: 16467db96d56Sopenharmony_ci a 16477db96d56Sopenharmony_ci else: 16487db96d56Sopenharmony_ci b 16497db96d56Sopenharmony_ci """ 16507db96d56Sopenharmony_ci self.check_stack_size(snippet) 16517db96d56Sopenharmony_ci 16527db96d56Sopenharmony_ci def test_return_inside_try_finally_block(self): 16537db96d56Sopenharmony_ci snippet = """ 16547db96d56Sopenharmony_ci try: 16557db96d56Sopenharmony_ci if z: 16567db96d56Sopenharmony_ci return 16577db96d56Sopenharmony_ci else: 16587db96d56Sopenharmony_ci a 16597db96d56Sopenharmony_ci finally: 16607db96d56Sopenharmony_ci f 16617db96d56Sopenharmony_ci """ 16627db96d56Sopenharmony_ci self.check_stack_size(snippet) 16637db96d56Sopenharmony_ci 16647db96d56Sopenharmony_ci def test_return_inside_finally_block(self): 16657db96d56Sopenharmony_ci snippet = """ 16667db96d56Sopenharmony_ci try: 16677db96d56Sopenharmony_ci t 16687db96d56Sopenharmony_ci finally: 16697db96d56Sopenharmony_ci if z: 16707db96d56Sopenharmony_ci return 16717db96d56Sopenharmony_ci else: 16727db96d56Sopenharmony_ci a 16737db96d56Sopenharmony_ci """ 16747db96d56Sopenharmony_ci self.check_stack_size(snippet) 16757db96d56Sopenharmony_ci 16767db96d56Sopenharmony_ci def test_return_inside_except_block(self): 16777db96d56Sopenharmony_ci snippet = """ 16787db96d56Sopenharmony_ci try: 16797db96d56Sopenharmony_ci t 16807db96d56Sopenharmony_ci except: 16817db96d56Sopenharmony_ci if z: 16827db96d56Sopenharmony_ci return 16837db96d56Sopenharmony_ci else: 16847db96d56Sopenharmony_ci a 16857db96d56Sopenharmony_ci """ 16867db96d56Sopenharmony_ci self.check_stack_size(snippet) 16877db96d56Sopenharmony_ci 16887db96d56Sopenharmony_ci def test_return_inside_with_block(self): 16897db96d56Sopenharmony_ci snippet = """ 16907db96d56Sopenharmony_ci with c: 16917db96d56Sopenharmony_ci if z: 16927db96d56Sopenharmony_ci return 16937db96d56Sopenharmony_ci else: 16947db96d56Sopenharmony_ci a 16957db96d56Sopenharmony_ci """ 16967db96d56Sopenharmony_ci self.check_stack_size(snippet) 16977db96d56Sopenharmony_ci 16987db96d56Sopenharmony_ci def test_async_with(self): 16997db96d56Sopenharmony_ci snippet = """ 17007db96d56Sopenharmony_ci async with x as y: 17017db96d56Sopenharmony_ci a 17027db96d56Sopenharmony_ci """ 17037db96d56Sopenharmony_ci self.check_stack_size(snippet, async_=True) 17047db96d56Sopenharmony_ci 17057db96d56Sopenharmony_ci def test_async_for(self): 17067db96d56Sopenharmony_ci snippet = """ 17077db96d56Sopenharmony_ci async for x in y: 17087db96d56Sopenharmony_ci a 17097db96d56Sopenharmony_ci """ 17107db96d56Sopenharmony_ci self.check_stack_size(snippet, async_=True) 17117db96d56Sopenharmony_ci 17127db96d56Sopenharmony_ci def test_async_for_else(self): 17137db96d56Sopenharmony_ci snippet = """ 17147db96d56Sopenharmony_ci async for x in y: 17157db96d56Sopenharmony_ci a 17167db96d56Sopenharmony_ci else: 17177db96d56Sopenharmony_ci b 17187db96d56Sopenharmony_ci """ 17197db96d56Sopenharmony_ci self.check_stack_size(snippet, async_=True) 17207db96d56Sopenharmony_ci 17217db96d56Sopenharmony_ci def test_for_break_continue_inside_async_with_block(self): 17227db96d56Sopenharmony_ci snippet = """ 17237db96d56Sopenharmony_ci for x in y: 17247db96d56Sopenharmony_ci async with c: 17257db96d56Sopenharmony_ci if z: 17267db96d56Sopenharmony_ci break 17277db96d56Sopenharmony_ci elif u: 17287db96d56Sopenharmony_ci continue 17297db96d56Sopenharmony_ci else: 17307db96d56Sopenharmony_ci a 17317db96d56Sopenharmony_ci else: 17327db96d56Sopenharmony_ci b 17337db96d56Sopenharmony_ci """ 17347db96d56Sopenharmony_ci self.check_stack_size(snippet, async_=True) 17357db96d56Sopenharmony_ci 17367db96d56Sopenharmony_ci def test_return_inside_async_with_block(self): 17377db96d56Sopenharmony_ci snippet = """ 17387db96d56Sopenharmony_ci async with c: 17397db96d56Sopenharmony_ci if z: 17407db96d56Sopenharmony_ci return 17417db96d56Sopenharmony_ci else: 17427db96d56Sopenharmony_ci a 17437db96d56Sopenharmony_ci """ 17447db96d56Sopenharmony_ci self.check_stack_size(snippet, async_=True) 17457db96d56Sopenharmony_ci 17467db96d56Sopenharmony_ci 17477db96d56Sopenharmony_ciif __name__ == "__main__": 17487db96d56Sopenharmony_ci unittest.main() 1749