1import math 2import os 3import unittest 4import sys 5import _ast 6import tempfile 7import types 8from test import support 9from test.support import script_helper 10 11class TestSpecifics(unittest.TestCase): 12 13 def compile_single(self, source): 14 compile(source, "<single>", "single") 15 16 def assertInvalidSingle(self, source): 17 self.assertRaises(SyntaxError, self.compile_single, source) 18 19 def test_no_ending_newline(self): 20 compile("hi", "<test>", "exec") 21 compile("hi\r", "<test>", "exec") 22 23 def test_empty(self): 24 compile("", "<test>", "exec") 25 26 def test_other_newlines(self): 27 compile("\r\n", "<test>", "exec") 28 compile("\r", "<test>", "exec") 29 compile("hi\r\nstuff\r\ndef f():\n pass\r", "<test>", "exec") 30 compile("this_is\rreally_old_mac\rdef f():\n pass", "<test>", "exec") 31 32 def test_debug_assignment(self): 33 # catch assignments to __debug__ 34 self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single') 35 import builtins 36 prev = builtins.__debug__ 37 setattr(builtins, '__debug__', 'sure') 38 setattr(builtins, '__debug__', prev) 39 40 def test_argument_handling(self): 41 # detect duplicate positional and keyword arguments 42 self.assertRaises(SyntaxError, eval, 'lambda a,a:0') 43 self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0') 44 self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0') 45 self.assertRaises(SyntaxError, exec, 'def f(a, a): pass') 46 self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass') 47 self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1') 48 49 def test_syntax_error(self): 50 self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec") 51 52 def test_none_keyword_arg(self): 53 self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec") 54 55 def test_duplicate_global_local(self): 56 self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1') 57 58 def test_exec_with_general_mapping_for_locals(self): 59 60 class M: 61 "Test mapping interface versus possible calls from eval()." 62 def __getitem__(self, key): 63 if key == 'a': 64 return 12 65 raise KeyError 66 def __setitem__(self, key, value): 67 self.results = (key, value) 68 def keys(self): 69 return list('xyz') 70 71 m = M() 72 g = globals() 73 exec('z = a', g, m) 74 self.assertEqual(m.results, ('z', 12)) 75 try: 76 exec('z = b', g, m) 77 except NameError: 78 pass 79 else: 80 self.fail('Did not detect a KeyError') 81 exec('z = dir()', g, m) 82 self.assertEqual(m.results, ('z', list('xyz'))) 83 exec('z = globals()', g, m) 84 self.assertEqual(m.results, ('z', g)) 85 exec('z = locals()', g, m) 86 self.assertEqual(m.results, ('z', m)) 87 self.assertRaises(TypeError, exec, 'z = b', m) 88 89 class A: 90 "Non-mapping" 91 pass 92 m = A() 93 self.assertRaises(TypeError, exec, 'z = a', g, m) 94 95 # Verify that dict subclasses work as well 96 class D(dict): 97 def __getitem__(self, key): 98 if key == 'a': 99 return 12 100 return dict.__getitem__(self, key) 101 d = D() 102 exec('z = a', g, d) 103 self.assertEqual(d['z'], 12) 104 105 def test_extended_arg(self): 106 longexpr = 'x = x or ' + '-x' * 2500 107 g = {} 108 code = ''' 109def f(x): 110 %s 111 %s 112 %s 113 %s 114 %s 115 %s 116 %s 117 %s 118 %s 119 %s 120 # the expressions above have no effect, x == argument 121 while x: 122 x -= 1 123 # EXTENDED_ARG/JUMP_ABSOLUTE here 124 return x 125''' % ((longexpr,)*10) 126 exec(code, g) 127 self.assertEqual(g['f'](5), 0) 128 129 def test_argument_order(self): 130 self.assertRaises(SyntaxError, exec, 'def f(a=1, b): pass') 131 132 def test_float_literals(self): 133 # testing bad float literals 134 self.assertRaises(SyntaxError, eval, "2e") 135 self.assertRaises(SyntaxError, eval, "2.0e+") 136 self.assertRaises(SyntaxError, eval, "1e-") 137 self.assertRaises(SyntaxError, eval, "3-4e/21") 138 139 def test_indentation(self): 140 # testing compile() of indented block w/o trailing newline" 141 s = """ 142if 1: 143 if 2: 144 pass""" 145 compile(s, "<string>", "exec") 146 147 # This test is probably specific to CPython and may not generalize 148 # to other implementations. We are trying to ensure that when 149 # the first line of code starts after 256, correct line numbers 150 # in tracebacks are still produced. 151 def test_leading_newlines(self): 152 s256 = "".join(["\n"] * 256 + ["spam"]) 153 co = compile(s256, 'fn', 'exec') 154 self.assertEqual(co.co_firstlineno, 257) 155 self.assertEqual(co.co_lnotab, bytes()) 156 157 def test_literals_with_leading_zeroes(self): 158 for arg in ["077787", "0xj", "0x.", "0e", "090000000000000", 159 "080000000000000", "000000000000009", "000000000000008", 160 "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2", 161 "0b101j2", "0o153j2", "0b100e1", "0o777e1", "0777", 162 "000777", "000000000000007"]: 163 self.assertRaises(SyntaxError, eval, arg) 164 165 self.assertEqual(eval("0xff"), 255) 166 self.assertEqual(eval("0777."), 777) 167 self.assertEqual(eval("0777.0"), 777) 168 self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777) 169 self.assertEqual(eval("0777e1"), 7770) 170 self.assertEqual(eval("0e0"), 0) 171 self.assertEqual(eval("0000e-012"), 0) 172 self.assertEqual(eval("09.5"), 9.5) 173 self.assertEqual(eval("0777j"), 777j) 174 self.assertEqual(eval("000"), 0) 175 self.assertEqual(eval("00j"), 0j) 176 self.assertEqual(eval("00.0"), 0) 177 self.assertEqual(eval("0e3"), 0) 178 self.assertEqual(eval("090000000000000."), 90000000000000.) 179 self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.) 180 self.assertEqual(eval("090000000000000e0"), 90000000000000.) 181 self.assertEqual(eval("090000000000000e-0"), 90000000000000.) 182 self.assertEqual(eval("090000000000000j"), 90000000000000j) 183 self.assertEqual(eval("000000000000008."), 8.) 184 self.assertEqual(eval("000000000000009."), 9.) 185 self.assertEqual(eval("0b101010"), 42) 186 self.assertEqual(eval("-0b000000000010"), -2) 187 self.assertEqual(eval("0o777"), 511) 188 self.assertEqual(eval("-0o0000010"), -8) 189 190 def test_unary_minus(self): 191 # Verify treatment of unary minus on negative numbers SF bug #660455 192 if sys.maxsize == 2147483647: 193 # 32-bit machine 194 all_one_bits = '0xffffffff' 195 self.assertEqual(eval(all_one_bits), 4294967295) 196 self.assertEqual(eval("-" + all_one_bits), -4294967295) 197 elif sys.maxsize == 9223372036854775807: 198 # 64-bit machine 199 all_one_bits = '0xffffffffffffffff' 200 self.assertEqual(eval(all_one_bits), 18446744073709551615) 201 self.assertEqual(eval("-" + all_one_bits), -18446744073709551615) 202 else: 203 self.fail("How many bits *does* this machine have???") 204 # Verify treatment of constant folding on -(sys.maxsize+1) 205 # i.e. -2147483648 on 32 bit platforms. Should return int. 206 self.assertIsInstance(eval("%s" % (-sys.maxsize - 1)), int) 207 self.assertIsInstance(eval("%s" % (-sys.maxsize - 2)), int) 208 209 if sys.maxsize == 9223372036854775807: 210 def test_32_63_bit_values(self): 211 a = +4294967296 # 1 << 32 212 b = -4294967296 # 1 << 32 213 c = +281474976710656 # 1 << 48 214 d = -281474976710656 # 1 << 48 215 e = +4611686018427387904 # 1 << 62 216 f = -4611686018427387904 # 1 << 62 217 g = +9223372036854775807 # 1 << 63 - 1 218 h = -9223372036854775807 # 1 << 63 - 1 219 220 for variable in self.test_32_63_bit_values.__code__.co_consts: 221 if variable is not None: 222 self.assertIsInstance(variable, int) 223 224 def test_sequence_unpacking_error(self): 225 # Verify sequence packing/unpacking with "or". SF bug #757818 226 i,j = (1, -1) or (-1, 1) 227 self.assertEqual(i, 1) 228 self.assertEqual(j, -1) 229 230 def test_none_assignment(self): 231 stmts = [ 232 'None = 0', 233 'None += 0', 234 '__builtins__.None = 0', 235 'def None(): pass', 236 'class None: pass', 237 '(a, None) = 0, 0', 238 'for None in range(10): pass', 239 'def f(None): pass', 240 'import None', 241 'import x as None', 242 'from x import None', 243 'from x import y as None' 244 ] 245 for stmt in stmts: 246 stmt += "\n" 247 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single') 248 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec') 249 250 def test_import(self): 251 succeed = [ 252 'import sys', 253 'import os, sys', 254 'import os as bar', 255 'import os.path as bar', 256 'from __future__ import nested_scopes, generators', 257 'from __future__ import (nested_scopes,\ngenerators)', 258 'from __future__ import (nested_scopes,\ngenerators,)', 259 'from sys import stdin, stderr, stdout', 260 'from sys import (stdin, stderr,\nstdout)', 261 'from sys import (stdin, stderr,\nstdout,)', 262 'from sys import (stdin\n, stderr, stdout)', 263 'from sys import (stdin\n, stderr, stdout,)', 264 'from sys import stdin as si, stdout as so, stderr as se', 265 'from sys import (stdin as si, stdout as so, stderr as se)', 266 'from sys import (stdin as si, stdout as so, stderr as se,)', 267 ] 268 fail = [ 269 'import (os, sys)', 270 'import (os), (sys)', 271 'import ((os), (sys))', 272 'import (sys', 273 'import sys)', 274 'import (os,)', 275 'import os As bar', 276 'import os.path a bar', 277 'from sys import stdin As stdout', 278 'from sys import stdin a stdout', 279 'from (sys) import stdin', 280 'from __future__ import (nested_scopes', 281 'from __future__ import nested_scopes)', 282 'from __future__ import nested_scopes,\ngenerators', 283 'from sys import (stdin', 284 'from sys import stdin)', 285 'from sys import stdin, stdout,\nstderr', 286 'from sys import stdin si', 287 'from sys import stdin,' 288 'from sys import (*)', 289 'from sys import (stdin,, stdout, stderr)', 290 'from sys import (stdin, stdout),', 291 ] 292 for stmt in succeed: 293 compile(stmt, 'tmp', 'exec') 294 for stmt in fail: 295 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec') 296 297 def test_for_distinct_code_objects(self): 298 # SF bug 1048870 299 def f(): 300 f1 = lambda x=1: x 301 f2 = lambda x=2: x 302 return f1, f2 303 f1, f2 = f() 304 self.assertNotEqual(id(f1.__code__), id(f2.__code__)) 305 306 def test_lambda_doc(self): 307 l = lambda: "foo" 308 self.assertIsNone(l.__doc__) 309 310 def test_encoding(self): 311 code = b'# -*- coding: badencoding -*-\npass\n' 312 self.assertRaises(SyntaxError, compile, code, 'tmp', 'exec') 313 code = '# -*- coding: badencoding -*-\n"\xc2\xa4"\n' 314 compile(code, 'tmp', 'exec') 315 self.assertEqual(eval(code), '\xc2\xa4') 316 code = '"\xc2\xa4"\n' 317 self.assertEqual(eval(code), '\xc2\xa4') 318 code = b'"\xc2\xa4"\n' 319 self.assertEqual(eval(code), '\xa4') 320 code = b'# -*- coding: latin1 -*-\n"\xc2\xa4"\n' 321 self.assertEqual(eval(code), '\xc2\xa4') 322 code = b'# -*- coding: utf-8 -*-\n"\xc2\xa4"\n' 323 self.assertEqual(eval(code), '\xa4') 324 code = b'# -*- coding: iso8859-15 -*-\n"\xc2\xa4"\n' 325 self.assertEqual(eval(code), '\xc2\u20ac') 326 code = '"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n' 327 self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xc2\xa4') 328 code = b'"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n' 329 self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xa4') 330 331 def test_subscripts(self): 332 # SF bug 1448804 333 # Class to make testing subscript results easy 334 class str_map(object): 335 def __init__(self): 336 self.data = {} 337 def __getitem__(self, key): 338 return self.data[str(key)] 339 def __setitem__(self, key, value): 340 self.data[str(key)] = value 341 def __delitem__(self, key): 342 del self.data[str(key)] 343 def __contains__(self, key): 344 return str(key) in self.data 345 d = str_map() 346 # Index 347 d[1] = 1 348 self.assertEqual(d[1], 1) 349 d[1] += 1 350 self.assertEqual(d[1], 2) 351 del d[1] 352 self.assertNotIn(1, d) 353 # Tuple of indices 354 d[1, 1] = 1 355 self.assertEqual(d[1, 1], 1) 356 d[1, 1] += 1 357 self.assertEqual(d[1, 1], 2) 358 del d[1, 1] 359 self.assertNotIn((1, 1), d) 360 # Simple slice 361 d[1:2] = 1 362 self.assertEqual(d[1:2], 1) 363 d[1:2] += 1 364 self.assertEqual(d[1:2], 2) 365 del d[1:2] 366 self.assertNotIn(slice(1, 2), d) 367 # Tuple of simple slices 368 d[1:2, 1:2] = 1 369 self.assertEqual(d[1:2, 1:2], 1) 370 d[1:2, 1:2] += 1 371 self.assertEqual(d[1:2, 1:2], 2) 372 del d[1:2, 1:2] 373 self.assertNotIn((slice(1, 2), slice(1, 2)), d) 374 # Extended slice 375 d[1:2:3] = 1 376 self.assertEqual(d[1:2:3], 1) 377 d[1:2:3] += 1 378 self.assertEqual(d[1:2:3], 2) 379 del d[1:2:3] 380 self.assertNotIn(slice(1, 2, 3), d) 381 # Tuple of extended slices 382 d[1:2:3, 1:2:3] = 1 383 self.assertEqual(d[1:2:3, 1:2:3], 1) 384 d[1:2:3, 1:2:3] += 1 385 self.assertEqual(d[1:2:3, 1:2:3], 2) 386 del d[1:2:3, 1:2:3] 387 self.assertNotIn((slice(1, 2, 3), slice(1, 2, 3)), d) 388 # Ellipsis 389 d[...] = 1 390 self.assertEqual(d[...], 1) 391 d[...] += 1 392 self.assertEqual(d[...], 2) 393 del d[...] 394 self.assertNotIn(Ellipsis, d) 395 # Tuple of Ellipses 396 d[..., ...] = 1 397 self.assertEqual(d[..., ...], 1) 398 d[..., ...] += 1 399 self.assertEqual(d[..., ...], 2) 400 del d[..., ...] 401 self.assertNotIn((Ellipsis, Ellipsis), d) 402 403 def test_annotation_limit(self): 404 # 16 bits are available for # of annotations, but only 8 bits are 405 # available for the parameter count, hence 255 406 # is the max. Ensure the result of too many annotations is a 407 # SyntaxError. 408 s = "def f(%s): pass" 409 s %= ', '.join('a%d:%d' % (i,i) for i in range(256)) 410 self.assertRaises(SyntaxError, compile, s, '?', 'exec') 411 # Test that the max # of annotations compiles. 412 s = "def f(%s): pass" 413 s %= ', '.join('a%d:%d' % (i,i) for i in range(255)) 414 compile(s, '?', 'exec') 415 416 def test_mangling(self): 417 class A: 418 def f(): 419 __mangled = 1 420 __not_mangled__ = 2 421 import __mangled_mod 422 import __package__.module 423 424 self.assertIn("_A__mangled", A.f.__code__.co_varnames) 425 self.assertIn("__not_mangled__", A.f.__code__.co_varnames) 426 self.assertIn("_A__mangled_mod", A.f.__code__.co_varnames) 427 self.assertIn("__package__", A.f.__code__.co_varnames) 428 429 def test_compile_ast(self): 430 fname = __file__ 431 if fname.lower().endswith('pyc'): 432 fname = fname[:-1] 433 with open(fname, 'r') as f: 434 fcontents = f.read() 435 sample_code = [ 436 ['<assign>', 'x = 5'], 437 ['<ifblock>', """if True:\n pass\n"""], 438 ['<forblock>', """for n in [1, 2, 3]:\n print(n)\n"""], 439 ['<deffunc>', """def foo():\n pass\nfoo()\n"""], 440 [fname, fcontents], 441 ] 442 443 for fname, code in sample_code: 444 co1 = compile(code, '%s1' % fname, 'exec') 445 ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST) 446 self.assertTrue(type(ast) == _ast.Module) 447 co2 = compile(ast, '%s3' % fname, 'exec') 448 self.assertEqual(co1, co2) 449 # the code object's filename comes from the second compilation step 450 self.assertEqual(co2.co_filename, '%s3' % fname) 451 452 # raise exception when node type doesn't match with compile mode 453 co1 = compile('print(1)', '<string>', 'exec', _ast.PyCF_ONLY_AST) 454 self.assertRaises(TypeError, compile, co1, '<ast>', 'eval') 455 456 # raise exception when node type is no start node 457 self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec') 458 459 # raise exception when node has invalid children 460 ast = _ast.Module() 461 ast.body = [_ast.BoolOp()] 462 self.assertRaises(TypeError, compile, ast, '<ast>', 'exec') 463 464 def test_dict_evaluation_order(self): 465 i = 0 466 467 def f(): 468 nonlocal i 469 i += 1 470 return i 471 472 d = {f(): f(), f(): f()} 473 self.assertEqual(d, {1: 2, 3: 4}) 474 475 def test_compile_filename(self): 476 for filename in 'file.py', b'file.py': 477 code = compile('pass', filename, 'exec') 478 self.assertEqual(code.co_filename, 'file.py') 479 for filename in bytearray(b'file.py'), memoryview(b'file.py'): 480 with self.assertWarns(DeprecationWarning): 481 code = compile('pass', filename, 'exec') 482 self.assertEqual(code.co_filename, 'file.py') 483 self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec') 484 485 @support.cpython_only 486 def test_same_filename_used(self): 487 s = """def f(): pass\ndef g(): pass""" 488 c = compile(s, "myfile", "exec") 489 for obj in c.co_consts: 490 if isinstance(obj, types.CodeType): 491 self.assertIs(obj.co_filename, c.co_filename) 492 493 def test_single_statement(self): 494 self.compile_single("1 + 2") 495 self.compile_single("\n1 + 2") 496 self.compile_single("1 + 2\n") 497 self.compile_single("1 + 2\n\n") 498 self.compile_single("1 + 2\t\t\n") 499 self.compile_single("1 + 2\t\t\n ") 500 self.compile_single("1 + 2 # one plus two") 501 self.compile_single("1; 2") 502 self.compile_single("import sys; sys") 503 self.compile_single("def f():\n pass") 504 self.compile_single("while False:\n pass") 505 self.compile_single("if x:\n f(x)") 506 self.compile_single("if x:\n f(x)\nelse:\n g(x)") 507 self.compile_single("class T:\n pass") 508 509 def test_bad_single_statement(self): 510 self.assertInvalidSingle('1\n2') 511 self.assertInvalidSingle('def f(): pass') 512 self.assertInvalidSingle('a = 13\nb = 187') 513 self.assertInvalidSingle('del x\ndel y') 514 self.assertInvalidSingle('f()\ng()') 515 self.assertInvalidSingle('f()\n# blah\nblah()') 516 self.assertInvalidSingle('f()\nxy # blah\nblah()') 517 self.assertInvalidSingle('x = 5 # comment\nx = 6\n') 518 519 def test_particularly_evil_undecodable(self): 520 # Issue 24022 521 src = b'0000\x00\n00000000000\n\x00\n\x9e\n' 522 with tempfile.TemporaryDirectory() as tmpd: 523 fn = os.path.join(tmpd, "bad.py") 524 with open(fn, "wb") as fp: 525 fp.write(src) 526 res = script_helper.run_python_until_end(fn)[0] 527 self.assertIn(b"Non-UTF-8", res.err) 528 529 def test_yet_more_evil_still_undecodable(self): 530 # Issue #25388 531 src = b"#\x00\n#\xfd\n" 532 with tempfile.TemporaryDirectory() as tmpd: 533 fn = os.path.join(tmpd, "bad.py") 534 with open(fn, "wb") as fp: 535 fp.write(src) 536 res = script_helper.run_python_until_end(fn)[0] 537 self.assertIn(b"Non-UTF-8", res.err) 538 539 @support.cpython_only 540 def test_compiler_recursion_limit(self): 541 # Expected limit is sys.getrecursionlimit() * the scaling factor 542 # in symtable.c (currently 3) 543 # We expect to fail *at* that limit, because we use up some of 544 # the stack depth limit in the test suite code 545 # So we check the expected limit and 75% of that 546 # XXX (ncoghlan): duplicating the scaling factor here is a little 547 # ugly. Perhaps it should be exposed somewhere... 548 fail_depth = sys.getrecursionlimit() * 3 549 success_depth = int(fail_depth * 0.75) 550 551 def check_limit(prefix, repeated): 552 expect_ok = prefix + repeated * success_depth 553 self.compile_single(expect_ok) 554 broken = prefix + repeated * fail_depth 555 details = "Compiling ({!r} + {!r} * {})".format( 556 prefix, repeated, fail_depth) 557 with self.assertRaises(RecursionError, msg=details): 558 self.compile_single(broken) 559 560 check_limit("a", "()") 561 check_limit("a", ".b") 562 check_limit("a", "[0]") 563 check_limit("a", "*a") 564 565 def test_null_terminated(self): 566 # The source code is null-terminated internally, but bytes-like 567 # objects are accepted, which could be not terminated. 568 with self.assertRaisesRegex(ValueError, "cannot contain null"): 569 compile("123\x00", "<dummy>", "eval") 570 with self.assertRaisesRegex(ValueError, "cannot contain null"): 571 compile(memoryview(b"123\x00"), "<dummy>", "eval") 572 code = compile(memoryview(b"123\x00")[1:-1], "<dummy>", "eval") 573 self.assertEqual(eval(code), 23) 574 code = compile(memoryview(b"1234")[1:-1], "<dummy>", "eval") 575 self.assertEqual(eval(code), 23) 576 code = compile(memoryview(b"$23$")[1:-1], "<dummy>", "eval") 577 self.assertEqual(eval(code), 23) 578 579 # Also test when eval() and exec() do the compilation step 580 self.assertEqual(eval(memoryview(b"1234")[1:-1]), 23) 581 namespace = dict() 582 exec(memoryview(b"ax = 123")[1:-1], namespace) 583 self.assertEqual(namespace['x'], 12) 584 585 def check_constant(self, func, expected): 586 for const in func.__code__.co_consts: 587 if repr(const) == repr(expected): 588 break 589 else: 590 self.fail("unable to find constant %r in %r" 591 % (expected, func.__code__.co_consts)) 592 593 # Merging equal constants is not a strict requirement for the Python 594 # semantics, it's a more an implementation detail. 595 @support.cpython_only 596 def test_merge_constants(self): 597 # Issue #25843: compile() must merge constants which are equal 598 # and have the same type. 599 600 def check_same_constant(const): 601 ns = {} 602 code = "f1, f2 = lambda: %r, lambda: %r" % (const, const) 603 exec(code, ns) 604 f1 = ns['f1'] 605 f2 = ns['f2'] 606 self.assertIs(f1.__code__, f2.__code__) 607 self.check_constant(f1, const) 608 self.assertEqual(repr(f1()), repr(const)) 609 610 check_same_constant(None) 611 check_same_constant(0) 612 check_same_constant(0.0) 613 check_same_constant(b'abc') 614 check_same_constant('abc') 615 616 # Note: "lambda: ..." emits "LOAD_CONST Ellipsis", 617 # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis" 618 f1, f2 = lambda: ..., lambda: ... 619 self.assertIs(f1.__code__, f2.__code__) 620 self.check_constant(f1, Ellipsis) 621 self.assertEqual(repr(f1()), repr(Ellipsis)) 622 623 # {0} is converted to a constant frozenset({0}) by the peephole 624 # optimizer 625 f1, f2 = lambda x: x in {0}, lambda x: x in {0} 626 self.assertIs(f1.__code__, f2.__code__) 627 self.check_constant(f1, frozenset({0})) 628 self.assertTrue(f1(0)) 629 630 def test_dont_merge_constants(self): 631 # Issue #25843: compile() must not merge constants which are equal 632 # but have a different type. 633 634 def check_different_constants(const1, const2): 635 ns = {} 636 exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns) 637 f1 = ns['f1'] 638 f2 = ns['f2'] 639 self.assertIsNot(f1.__code__, f2.__code__) 640 self.assertNotEqual(f1.__code__, f2.__code__) 641 self.check_constant(f1, const1) 642 self.check_constant(f2, const2) 643 self.assertEqual(repr(f1()), repr(const1)) 644 self.assertEqual(repr(f2()), repr(const2)) 645 646 check_different_constants(0, 0.0) 647 check_different_constants(+0.0, -0.0) 648 check_different_constants((0,), (0.0,)) 649 check_different_constants('a', b'a') 650 check_different_constants(('a',), (b'a',)) 651 652 # check_different_constants() cannot be used because repr(-0j) is 653 # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign. 654 f1, f2 = lambda: +0.0j, lambda: -0.0j 655 self.assertIsNot(f1.__code__, f2.__code__) 656 self.check_constant(f1, +0.0j) 657 self.check_constant(f2, -0.0j) 658 self.assertEqual(repr(f1()), repr(+0.0j)) 659 self.assertEqual(repr(f2()), repr(-0.0j)) 660 661 # {0} is converted to a constant frozenset({0}) by the peephole 662 # optimizer 663 f1, f2 = lambda x: x in {0}, lambda x: x in {0.0} 664 self.assertIsNot(f1.__code__, f2.__code__) 665 self.check_constant(f1, frozenset({0})) 666 self.check_constant(f2, frozenset({0.0})) 667 self.assertTrue(f1(0)) 668 self.assertTrue(f2(0.0)) 669 670 def test_path_like_objects(self): 671 # An implicit test for PyUnicode_FSDecoder(). 672 class PathLike: 673 def __init__(self, path): 674 self._path = path 675 def __fspath__(self): 676 return self._path 677 678 compile("42", PathLike("test_compile_pathlike"), "single") 679 680 681class TestStackSize(unittest.TestCase): 682 # These tests check that the computed stack size for a code object 683 # stays within reasonable bounds (see issue #21523 for an example 684 # dysfunction). 685 N = 100 686 687 def check_stack_size(self, code): 688 # To assert that the alleged stack size is not O(N), we 689 # check that it is smaller than log(N). 690 if isinstance(code, str): 691 code = compile(code, "<foo>", "single") 692 max_size = math.ceil(math.log(len(code.co_code))) 693 self.assertLessEqual(code.co_stacksize, max_size) 694 695 def test_and(self): 696 self.check_stack_size("x and " * self.N + "x") 697 698 def test_or(self): 699 self.check_stack_size("x or " * self.N + "x") 700 701 def test_and_or(self): 702 self.check_stack_size("x and x or " * self.N + "x") 703 704 def test_chained_comparison(self): 705 self.check_stack_size("x < " * self.N + "x") 706 707 def test_if_else(self): 708 self.check_stack_size("x if x else " * self.N + "x") 709 710 def test_binop(self): 711 self.check_stack_size("x + " * self.N + "x") 712 713 def test_func_and(self): 714 code = "def f(x):\n" 715 code += " x and x\n" * self.N 716 self.check_stack_size(code) 717 718 719if __name__ == "__main__": 720 unittest.main() 721