1 import dis 2 import math 3 import os 4 import unittest 5 import sys 6 import _ast 7 import tempfile 8 import types 9 from test import support 10 from test.support import script_helper, FakePath 11 12 class 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 = ''' 111 def 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 = """ 144 if 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 # {0} is converted to a constant frozenset({0}) by the peephole 619 # optimizer 620 f1, f2 = lambda x: x in {0}, lambda x: x in {0} 621 self.assertIs(f1.__code__, f2.__code__) 622 self.check_constant(f1, frozenset({0})) 623 self.assertTrue(f1(0)) 624 625 # This is a regression test for a CPython specific peephole optimizer 626 # implementation bug present in a few releases. It's assertion verifies 627 # that peephole optimization was actually done though that isn't an 628 # indication of the bugs presence or not (crashing is). 629 @support.cpython_only 630 def test_peephole_opt_unreachable_code_array_access_in_bounds(self): 631 """Regression test for issue35193 when run under clang msan.""" 632 def unused_code_at_end(): 633 return 3 634 raise RuntimeError("unreachable") 635 # The above function definition will trigger the out of bounds 636 # bug in the peephole optimizer as it scans opcodes past the 637 # RETURN_VALUE opcode. This does not always crash an interpreter. 638 # When you build with the clang memory sanitizer it reliably aborts. 639 self.assertEqual( 640 'RETURN_VALUE', 641 list(dis.get_instructions(unused_code_at_end))[-1].opname) 642 643 def test_dont_merge_constants(self): 644 # Issue #25843: compile() must not merge constants which are equal 645 # but have a different type. 646 647 def check_different_constants(const1, const2): 648 ns = {} 649 exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns) 650 f1 = ns['f1'] 651 f2 = ns['f2'] 652 self.assertIsNot(f1.__code__, f2.__code__) 653 self.assertNotEqual(f1.__code__, f2.__code__) 654 self.check_constant(f1, const1) 655 self.check_constant(f2, const2) 656 self.assertEqual(repr(f1()), repr(const1)) 657 self.assertEqual(repr(f2()), repr(const2)) 658 659 check_different_constants(0, 0.0) 660 check_different_constants(+0.0, -0.0) 661 check_different_constants((0,), (0.0,)) 662 check_different_constants('a', b'a') 663 check_different_constants(('a',), (b'a',)) 664 665 # check_different_constants() cannot be used because repr(-0j) is 666 # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign. 667 f1, f2 = lambda: +0.0j, lambda: -0.0j 668 self.assertIsNot(f1.__code__, f2.__code__) 669 self.check_constant(f1, +0.0j) 670 self.check_constant(f2, -0.0j) 671 self.assertEqual(repr(f1()), repr(+0.0j)) 672 self.assertEqual(repr(f2()), repr(-0.0j)) 673 674 # {0} is converted to a constant frozenset({0}) by the peephole 675 # optimizer 676 f1, f2 = lambda x: x in {0}, lambda x: x in {0.0} 677 self.assertIsNot(f1.__code__, f2.__code__) 678 self.check_constant(f1, frozenset({0})) 679 self.check_constant(f2, frozenset({0.0})) 680 self.assertTrue(f1(0)) 681 self.assertTrue(f2(0.0)) 682 683 def test_path_like_objects(self): 684 # An implicit test for PyUnicode_FSDecoder(). 685 compile("42", FakePath("test_compile_pathlike"), "single") 686 687 def test_stack_overflow(self): 688 # bpo-31113: Stack overflow when compile a long sequence of 689 # complex statements. 690 compile("if a: b\n" * 200000, "<dummy>", "exec") 691 692 693 class TestExpressionStackSize(unittest.TestCase): 694 # These tests check that the computed stack size for a code object 695 # stays within reasonable bounds (see issue #21523 for an example 696 # dysfunction). 697 N = 100 698 699 def check_stack_size(self, code): 700 # To assert that the alleged stack size is not O(N), we 701 # check that it is smaller than log(N). 702 if isinstance(code, str): 703 code = compile(code, "<foo>", "single") 704 max_size = math.ceil(math.log(len(code.co_code))) 705 self.assertLessEqual(code.co_stacksize, max_size) 706 707 def test_and(self): 708 self.check_stack_size("x and " * self.N + "x") 709 710 def test_or(self): 711 self.check_stack_size("x or " * self.N + "x") 712 713 def test_and_or(self): 714 self.check_stack_size("x and x or " * self.N + "x") 715 716 def test_chained_comparison(self): 717 self.check_stack_size("x < " * self.N + "x") 718 719 def test_if_else(self): 720 self.check_stack_size("x if x else " * self.N + "x") 721 722 def test_binop(self): 723 self.check_stack_size("x + " * self.N + "x") 724 725 def test_func_and(self): 726 code = "def f(x):\n" 727 code += " x and x\n" * self.N 728 self.check_stack_size(code) 729 730 731 class TestStackSizeStability(unittest.TestCase): 732 # Check that repeating certain snippets doesn't increase the stack size 733 # beyond what a single snippet requires. 734 735 def check_stack_size(self, snippet, async_=False): 736 def compile_snippet(i): 737 ns = {} 738 script = """def func():\n""" + i * snippet 739 if async_: 740 script = "async " + script 741 code = compile(script, "<script>", "exec") 742 exec(code, ns, ns) 743 return ns['func'].__code__ 744 745 sizes = [compile_snippet(i).co_stacksize for i in range(2, 5)] 746 if len(set(sizes)) != 1: 747 import dis, io 748 out = io.StringIO() 749 dis.dis(compile_snippet(1), file=out) 750 self.fail("stack sizes diverge with # of consecutive snippets: " 751 "%s\n%s\n%s" % (sizes, snippet, out.getvalue())) 752 753 def test_if(self): 754 snippet = """ 755 if x: 756 a 757 """ 758 self.check_stack_size(snippet) 759 760 def test_if_else(self): 761 snippet = """ 762 if x: 763 a 764 elif y: 765 b 766 else: 767 c 768 """ 769 self.check_stack_size(snippet) 770 771 def test_try_except_bare(self): 772 snippet = """ 773 try: 774 a 775 except: 776 b 777 """ 778 self.check_stack_size(snippet) 779 780 def test_try_except_qualified(self): 781 snippet = """ 782 try: 783 a 784 except ImportError: 785 b 786 except: 787 c 788 else: 789 d 790 """ 791 self.check_stack_size(snippet) 792 793 def test_try_except_as(self): 794 snippet = """ 795 try: 796 a 797 except ImportError as e: 798 b 799 except: 800 c 801 else: 802 d 803 """ 804 self.check_stack_size(snippet) 805 806 def test_try_finally(self): 807 snippet = """ 808 try: 809 a 810 finally: 811 b 812 """ 813 self.check_stack_size(snippet) 814 815 def test_with(self): 816 snippet = """ 817 with x as y: 818 a 819 """ 820 self.check_stack_size(snippet) 821 822 def test_while_else(self): 823 snippet = """ 824 while x: 825 a 826 else: 827 b 828 """ 829 self.check_stack_size(snippet) 830 831 def test_for(self): 832 snippet = """ 833 for x in y: 834 a 835 """ 836 self.check_stack_size(snippet) 837 838 def test_for_else(self): 839 snippet = """ 840 for x in y: 841 a 842 else: 843 b 844 """ 845 self.check_stack_size(snippet) 846 847 def test_for_break_continue(self): 848 snippet = """ 849 for x in y: 850 if z: 851 break 852 elif u: 853 continue 854 else: 855 a 856 else: 857 b 858 """ 859 self.check_stack_size(snippet) 860 861 def test_for_break_continue_inside_try_finally_block(self): 862 snippet = """ 863 for x in y: 864 try: 865 if z: 866 break 867 elif u: 868 continue 869 else: 870 a 871 finally: 872 f 873 else: 874 b 875 """ 876 self.check_stack_size(snippet) 877 878 def test_for_break_inside_finally_block(self): 879 snippet = """ 880 for x in y: 881 try: 882 t 883 finally: 884 if z: 885 break 886 else: 887 a 888 else: 889 b 890 """ 891 self.check_stack_size(snippet) 892 893 def test_for_break_continue_inside_except_block(self): 894 snippet = """ 895 for x in y: 896 try: 897 t 898 except: 899 if z: 900 break 901 elif u: 902 continue 903 else: 904 a 905 else: 906 b 907 """ 908 self.check_stack_size(snippet) 909 910 def test_for_break_continue_inside_with_block(self): 911 snippet = """ 912 for x in y: 913 with c: 914 if z: 915 break 916 elif u: 917 continue 918 else: 919 a 920 else: 921 b 922 """ 923 self.check_stack_size(snippet) 924 925 def test_return_inside_try_finally_block(self): 926 snippet = """ 927 try: 928 if z: 929 return 930 else: 931 a 932 finally: 933 f 934 """ 935 self.check_stack_size(snippet) 936 937 def test_return_inside_finally_block(self): 938 snippet = """ 939 try: 940 t 941 finally: 942 if z: 943 return 944 else: 945 a 946 """ 947 self.check_stack_size(snippet) 948 949 def test_return_inside_except_block(self): 950 snippet = """ 951 try: 952 t 953 except: 954 if z: 955 return 956 else: 957 a 958 """ 959 self.check_stack_size(snippet) 960 961 def test_return_inside_with_block(self): 962 snippet = """ 963 with c: 964 if z: 965 return 966 else: 967 a 968 """ 969 self.check_stack_size(snippet) 970 971 def test_async_with(self): 972 snippet = """ 973 async with x as y: 974 a 975 """ 976 self.check_stack_size(snippet, async_=True) 977 978 def test_async_for(self): 979 snippet = """ 980 async for x in y: 981 a 982 """ 983 self.check_stack_size(snippet, async_=True) 984 985 def test_async_for_else(self): 986 snippet = """ 987 async for x in y: 988 a 989 else: 990 b 991 """ 992 self.check_stack_size(snippet, async_=True) 993 994 def test_for_break_continue_inside_async_with_block(self): 995 snippet = """ 996 for x in y: 997 async with c: 998 if z: 999 break 1000 elif u: 1001 continue 1002 else: 1003 a 1004 else: 1005 b 1006 """ 1007 self.check_stack_size(snippet, async_=True) 1008 1009 def test_return_inside_async_with_block(self): 1010 snippet = """ 1011 async with c: 1012 if z: 1013 return 1014 else: 1015 a 1016 """ 1017 self.check_stack_size(snippet, async_=True) 1018 1019 1020 if __name__ == "__main__": 1021 unittest.main() 1022