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