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