python (3.11.7)
1 import dis
2 import math
3 import os
4 import unittest
5 import sys
6 import ast
7 import _ast
8 import tempfile
9 import types
10 import textwrap
11 from test import support
12 from test.support import script_helper, requires_debug_ranges
13 from test.support.os_helper import FakePath
14
15
16 class ESC[4;38;5;81mTestSpecifics(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
17
18 def compile_single(self, source):
19 compile(source, "<single>", "single")
20
21 def assertInvalidSingle(self, source):
22 self.assertRaises(SyntaxError, self.compile_single, source)
23
24 def test_no_ending_newline(self):
25 compile("hi", "<test>", "exec")
26 compile("hi\r", "<test>", "exec")
27
28 def test_empty(self):
29 compile("", "<test>", "exec")
30
31 def test_other_newlines(self):
32 compile("\r\n", "<test>", "exec")
33 compile("\r", "<test>", "exec")
34 compile("hi\r\nstuff\r\ndef f():\n pass\r", "<test>", "exec")
35 compile("this_is\rreally_old_mac\rdef f():\n pass", "<test>", "exec")
36
37 def test_debug_assignment(self):
38 # catch assignments to __debug__
39 self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single')
40 import builtins
41 prev = builtins.__debug__
42 setattr(builtins, '__debug__', 'sure')
43 self.assertEqual(__debug__, prev)
44 setattr(builtins, '__debug__', prev)
45
46 def test_argument_handling(self):
47 # detect duplicate positional and keyword arguments
48 self.assertRaises(SyntaxError, eval, 'lambda a,a:0')
49 self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0')
50 self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0')
51 self.assertRaises(SyntaxError, exec, 'def f(a, a): pass')
52 self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass')
53 self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
54
55 def test_syntax_error(self):
56 self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec")
57
58 def test_none_keyword_arg(self):
59 self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec")
60
61 def test_duplicate_global_local(self):
62 self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
63
64 def test_exec_with_general_mapping_for_locals(self):
65
66 class ESC[4;38;5;81mM:
67 "Test mapping interface versus possible calls from eval()."
68 def __getitem__(self, key):
69 if key == 'a':
70 return 12
71 raise KeyError
72 def __setitem__(self, key, value):
73 self.results = (key, value)
74 def keys(self):
75 return list('xyz')
76
77 m = M()
78 g = globals()
79 exec('z = a', g, m)
80 self.assertEqual(m.results, ('z', 12))
81 try:
82 exec('z = b', g, m)
83 except NameError:
84 pass
85 else:
86 self.fail('Did not detect a KeyError')
87 exec('z = dir()', g, m)
88 self.assertEqual(m.results, ('z', list('xyz')))
89 exec('z = globals()', g, m)
90 self.assertEqual(m.results, ('z', g))
91 exec('z = locals()', g, m)
92 self.assertEqual(m.results, ('z', m))
93 self.assertRaises(TypeError, exec, 'z = b', m)
94
95 class ESC[4;38;5;81mA:
96 "Non-mapping"
97 pass
98 m = A()
99 self.assertRaises(TypeError, exec, 'z = a', g, m)
100
101 # Verify that dict subclasses work as well
102 class ESC[4;38;5;81mD(ESC[4;38;5;149mdict):
103 def __getitem__(self, key):
104 if key == 'a':
105 return 12
106 return dict.__getitem__(self, key)
107 d = D()
108 exec('z = a', g, d)
109 self.assertEqual(d['z'], 12)
110
111 def test_extended_arg(self):
112 # default: 1000 * 2.5 = 2500 repetitions
113 repeat = int(sys.getrecursionlimit() * 2.5)
114 longexpr = 'x = x or ' + '-x' * repeat
115 g = {}
116 code = '''
117 def f(x):
118 %s
119 %s
120 %s
121 %s
122 %s
123 %s
124 %s
125 %s
126 %s
127 %s
128 # the expressions above have no effect, x == argument
129 while x:
130 x -= 1
131 # EXTENDED_ARG/JUMP_ABSOLUTE here
132 return x
133 ''' % ((longexpr,)*10)
134 exec(code, g)
135 self.assertEqual(g['f'](5), 0)
136
137 def test_argument_order(self):
138 self.assertRaises(SyntaxError, exec, 'def f(a=1, b): pass')
139
140 def test_float_literals(self):
141 # testing bad float literals
142 self.assertRaises(SyntaxError, eval, "2e")
143 self.assertRaises(SyntaxError, eval, "2.0e+")
144 self.assertRaises(SyntaxError, eval, "1e-")
145 self.assertRaises(SyntaxError, eval, "3-4e/21")
146
147 def test_indentation(self):
148 # testing compile() of indented block w/o trailing newline"
149 s = """
150 if 1:
151 if 2:
152 pass"""
153 compile(s, "<string>", "exec")
154
155 # This test is probably specific to CPython and may not generalize
156 # to other implementations. We are trying to ensure that when
157 # the first line of code starts after 256, correct line numbers
158 # in tracebacks are still produced.
159 def test_leading_newlines(self):
160 s256 = "".join(["\n"] * 256 + ["spam"])
161 co = compile(s256, 'fn', 'exec')
162 self.assertEqual(co.co_firstlineno, 1)
163 lines = list(co.co_lines())
164 self.assertEqual(lines[0][2], 0)
165 self.assertEqual(lines[1][2], 257)
166
167 def test_literals_with_leading_zeroes(self):
168 for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",
169 "080000000000000", "000000000000009", "000000000000008",
170 "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2",
171 "0b101j", "0o153j", "0b100e1", "0o777e1", "0777",
172 "000777", "000000000000007"]:
173 self.assertRaises(SyntaxError, eval, arg)
174
175 self.assertEqual(eval("0xff"), 255)
176 self.assertEqual(eval("0777."), 777)
177 self.assertEqual(eval("0777.0"), 777)
178 self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777)
179 self.assertEqual(eval("0777e1"), 7770)
180 self.assertEqual(eval("0e0"), 0)
181 self.assertEqual(eval("0000e-012"), 0)
182 self.assertEqual(eval("09.5"), 9.5)
183 self.assertEqual(eval("0777j"), 777j)
184 self.assertEqual(eval("000"), 0)
185 self.assertEqual(eval("00j"), 0j)
186 self.assertEqual(eval("00.0"), 0)
187 self.assertEqual(eval("0e3"), 0)
188 self.assertEqual(eval("090000000000000."), 90000000000000.)
189 self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.)
190 self.assertEqual(eval("090000000000000e0"), 90000000000000.)
191 self.assertEqual(eval("090000000000000e-0"), 90000000000000.)
192 self.assertEqual(eval("090000000000000j"), 90000000000000j)
193 self.assertEqual(eval("000000000000008."), 8.)
194 self.assertEqual(eval("000000000000009."), 9.)
195 self.assertEqual(eval("0b101010"), 42)
196 self.assertEqual(eval("-0b000000000010"), -2)
197 self.assertEqual(eval("0o777"), 511)
198 self.assertEqual(eval("-0o0000010"), -8)
199
200 def test_int_literals_too_long(self):
201 n = 3000
202 source = f"a = 1\nb = 2\nc = {'3'*n}\nd = 4"
203 with support.adjust_int_max_str_digits(n):
204 compile(source, "<long_int_pass>", "exec") # no errors.
205 with support.adjust_int_max_str_digits(n-1):
206 with self.assertRaises(SyntaxError) as err_ctx:
207 compile(source, "<long_int_fail>", "exec")
208 exc = err_ctx.exception
209 self.assertEqual(exc.lineno, 3)
210 self.assertIn('Exceeds the limit ', str(exc))
211 self.assertIn(' Consider hexadecimal ', str(exc))
212
213 def test_unary_minus(self):
214 # Verify treatment of unary minus on negative numbers SF bug #660455
215 if sys.maxsize == 2147483647:
216 # 32-bit machine
217 all_one_bits = '0xffffffff'
218 self.assertEqual(eval(all_one_bits), 4294967295)
219 self.assertEqual(eval("-" + all_one_bits), -4294967295)
220 elif sys.maxsize == 9223372036854775807:
221 # 64-bit machine
222 all_one_bits = '0xffffffffffffffff'
223 self.assertEqual(eval(all_one_bits), 18446744073709551615)
224 self.assertEqual(eval("-" + all_one_bits), -18446744073709551615)
225 else:
226 self.fail("How many bits *does* this machine have???")
227 # Verify treatment of constant folding on -(sys.maxsize+1)
228 # i.e. -2147483648 on 32 bit platforms. Should return int.
229 self.assertIsInstance(eval("%s" % (-sys.maxsize - 1)), int)
230 self.assertIsInstance(eval("%s" % (-sys.maxsize - 2)), int)
231
232 if sys.maxsize == 9223372036854775807:
233 def test_32_63_bit_values(self):
234 a = +4294967296 # 1 << 32
235 b = -4294967296 # 1 << 32
236 c = +281474976710656 # 1 << 48
237 d = -281474976710656 # 1 << 48
238 e = +4611686018427387904 # 1 << 62
239 f = -4611686018427387904 # 1 << 62
240 g = +9223372036854775807 # 1 << 63 - 1
241 h = -9223372036854775807 # 1 << 63 - 1
242
243 for variable in self.test_32_63_bit_values.__code__.co_consts:
244 if variable is not None:
245 self.assertIsInstance(variable, int)
246
247 def test_sequence_unpacking_error(self):
248 # Verify sequence packing/unpacking with "or". SF bug #757818
249 i,j = (1, -1) or (-1, 1)
250 self.assertEqual(i, 1)
251 self.assertEqual(j, -1)
252
253 def test_none_assignment(self):
254 stmts = [
255 'None = 0',
256 'None += 0',
257 '__builtins__.None = 0',
258 'def None(): pass',
259 'class None: pass',
260 '(a, None) = 0, 0',
261 'for None in range(10): pass',
262 'def f(None): pass',
263 'import None',
264 'import x as None',
265 'from x import None',
266 'from x import y as None'
267 ]
268 for stmt in stmts:
269 stmt += "\n"
270 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single')
271 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
272
273 def test_import(self):
274 succeed = [
275 'import sys',
276 'import os, sys',
277 'import os as bar',
278 'import os.path as bar',
279 'from __future__ import nested_scopes, generators',
280 'from __future__ import (nested_scopes,\ngenerators)',
281 'from __future__ import (nested_scopes,\ngenerators,)',
282 'from sys import stdin, stderr, stdout',
283 'from sys import (stdin, stderr,\nstdout)',
284 'from sys import (stdin, stderr,\nstdout,)',
285 'from sys import (stdin\n, stderr, stdout)',
286 'from sys import (stdin\n, stderr, stdout,)',
287 'from sys import stdin as si, stdout as so, stderr as se',
288 'from sys import (stdin as si, stdout as so, stderr as se)',
289 'from sys import (stdin as si, stdout as so, stderr as se,)',
290 ]
291 fail = [
292 'import (os, sys)',
293 'import (os), (sys)',
294 'import ((os), (sys))',
295 'import (sys',
296 'import sys)',
297 'import (os,)',
298 'import os As bar',
299 'import os.path a bar',
300 'from sys import stdin As stdout',
301 'from sys import stdin a stdout',
302 'from (sys) import stdin',
303 'from __future__ import (nested_scopes',
304 'from __future__ import nested_scopes)',
305 'from __future__ import nested_scopes,\ngenerators',
306 'from sys import (stdin',
307 'from sys import stdin)',
308 'from sys import stdin, stdout,\nstderr',
309 'from sys import stdin si',
310 'from sys import stdin,',
311 'from sys import (*)',
312 'from sys import (stdin,, stdout, stderr)',
313 'from sys import (stdin, stdout),',
314 ]
315 for stmt in succeed:
316 compile(stmt, 'tmp', 'exec')
317 for stmt in fail:
318 self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
319
320 def test_for_distinct_code_objects(self):
321 # SF bug 1048870
322 def f():
323 f1 = lambda x=1: x
324 f2 = lambda x=2: x
325 return f1, f2
326 f1, f2 = f()
327 self.assertNotEqual(id(f1.__code__), id(f2.__code__))
328
329 def test_lambda_doc(self):
330 l = lambda: "foo"
331 self.assertIsNone(l.__doc__)
332
333 def test_encoding(self):
334 code = b'# -*- coding: badencoding -*-\npass\n'
335 self.assertRaises(SyntaxError, compile, code, 'tmp', 'exec')
336 code = '# -*- coding: badencoding -*-\n"\xc2\xa4"\n'
337 compile(code, 'tmp', 'exec')
338 self.assertEqual(eval(code), '\xc2\xa4')
339 code = '"\xc2\xa4"\n'
340 self.assertEqual(eval(code), '\xc2\xa4')
341 code = b'"\xc2\xa4"\n'
342 self.assertEqual(eval(code), '\xa4')
343 code = b'# -*- coding: latin1 -*-\n"\xc2\xa4"\n'
344 self.assertEqual(eval(code), '\xc2\xa4')
345 code = b'# -*- coding: utf-8 -*-\n"\xc2\xa4"\n'
346 self.assertEqual(eval(code), '\xa4')
347 code = b'# -*- coding: iso8859-15 -*-\n"\xc2\xa4"\n'
348 self.assertEqual(eval(code), '\xc2\u20ac')
349 code = '"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n'
350 self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xc2\xa4')
351 code = b'"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n'
352 self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xa4')
353
354 def test_subscripts(self):
355 # SF bug 1448804
356 # Class to make testing subscript results easy
357 class ESC[4;38;5;81mstr_map(ESC[4;38;5;149mobject):
358 def __init__(self):
359 self.data = {}
360 def __getitem__(self, key):
361 return self.data[str(key)]
362 def __setitem__(self, key, value):
363 self.data[str(key)] = value
364 def __delitem__(self, key):
365 del self.data[str(key)]
366 def __contains__(self, key):
367 return str(key) in self.data
368 d = str_map()
369 # Index
370 d[1] = 1
371 self.assertEqual(d[1], 1)
372 d[1] += 1
373 self.assertEqual(d[1], 2)
374 del d[1]
375 self.assertNotIn(1, d)
376 # Tuple of indices
377 d[1, 1] = 1
378 self.assertEqual(d[1, 1], 1)
379 d[1, 1] += 1
380 self.assertEqual(d[1, 1], 2)
381 del d[1, 1]
382 self.assertNotIn((1, 1), d)
383 # Simple slice
384 d[1:2] = 1
385 self.assertEqual(d[1:2], 1)
386 d[1:2] += 1
387 self.assertEqual(d[1:2], 2)
388 del d[1:2]
389 self.assertNotIn(slice(1, 2), d)
390 # Tuple of simple slices
391 d[1:2, 1:2] = 1
392 self.assertEqual(d[1:2, 1:2], 1)
393 d[1:2, 1:2] += 1
394 self.assertEqual(d[1:2, 1:2], 2)
395 del d[1:2, 1:2]
396 self.assertNotIn((slice(1, 2), slice(1, 2)), d)
397 # Extended slice
398 d[1:2:3] = 1
399 self.assertEqual(d[1:2:3], 1)
400 d[1:2:3] += 1
401 self.assertEqual(d[1:2:3], 2)
402 del d[1:2:3]
403 self.assertNotIn(slice(1, 2, 3), d)
404 # Tuple of extended slices
405 d[1:2:3, 1:2:3] = 1
406 self.assertEqual(d[1:2:3, 1:2:3], 1)
407 d[1:2:3, 1:2:3] += 1
408 self.assertEqual(d[1:2:3, 1:2:3], 2)
409 del d[1:2:3, 1:2:3]
410 self.assertNotIn((slice(1, 2, 3), slice(1, 2, 3)), d)
411 # Ellipsis
412 d[...] = 1
413 self.assertEqual(d[...], 1)
414 d[...] += 1
415 self.assertEqual(d[...], 2)
416 del d[...]
417 self.assertNotIn(Ellipsis, d)
418 # Tuple of Ellipses
419 d[..., ...] = 1
420 self.assertEqual(d[..., ...], 1)
421 d[..., ...] += 1
422 self.assertEqual(d[..., ...], 2)
423 del d[..., ...]
424 self.assertNotIn((Ellipsis, Ellipsis), d)
425
426 def test_annotation_limit(self):
427 # more than 255 annotations, should compile ok
428 s = "def f(%s): pass"
429 s %= ', '.join('a%d:%d' % (i,i) for i in range(300))
430 compile(s, '?', 'exec')
431
432 def test_mangling(self):
433 class ESC[4;38;5;81mA:
434 def f():
435 __mangled = 1
436 __not_mangled__ = 2
437 import __mangled_mod
438 import __package__.module
439
440 self.assertIn("_A__mangled", A.f.__code__.co_varnames)
441 self.assertIn("__not_mangled__", A.f.__code__.co_varnames)
442 self.assertIn("_A__mangled_mod", A.f.__code__.co_varnames)
443 self.assertIn("__package__", A.f.__code__.co_varnames)
444
445 def test_compile_invalid_namedexpr(self):
446 # gh-109351
447 m = ast.Module(
448 body=[
449 ast.Expr(
450 value=ast.ListComp(
451 elt=ast.NamedExpr(
452 target=ast.Constant(value=1),
453 value=ast.Constant(value=3),
454 ),
455 generators=[
456 ast.comprehension(
457 target=ast.Name(id="x", ctx=ast.Store()),
458 iter=ast.Name(id="y", ctx=ast.Load()),
459 ifs=[],
460 is_async=0,
461 )
462 ],
463 )
464 )
465 ],
466 type_ignores=[],
467 )
468
469 with self.assertRaisesRegex(TypeError, "NamedExpr target must be a Name"):
470 compile(ast.fix_missing_locations(m), "<file>", "exec")
471
472 def test_compile_ast(self):
473 fname = __file__
474 if fname.lower().endswith('pyc'):
475 fname = fname[:-1]
476 with open(fname, encoding='utf-8') as f:
477 fcontents = f.read()
478 sample_code = [
479 ['<assign>', 'x = 5'],
480 ['<ifblock>', """if True:\n pass\n"""],
481 ['<forblock>', """for n in [1, 2, 3]:\n print(n)\n"""],
482 ['<deffunc>', """def foo():\n pass\nfoo()\n"""],
483 [fname, fcontents],
484 ]
485
486 for fname, code in sample_code:
487 co1 = compile(code, '%s1' % fname, 'exec')
488 ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST)
489 self.assertTrue(type(ast) == _ast.Module)
490 co2 = compile(ast, '%s3' % fname, 'exec')
491 self.assertEqual(co1, co2)
492 # the code object's filename comes from the second compilation step
493 self.assertEqual(co2.co_filename, '%s3' % fname)
494
495 # raise exception when node type doesn't match with compile mode
496 co1 = compile('print(1)', '<string>', 'exec', _ast.PyCF_ONLY_AST)
497 self.assertRaises(TypeError, compile, co1, '<ast>', 'eval')
498
499 # raise exception when node type is no start node
500 self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec')
501
502 # raise exception when node has invalid children
503 ast = _ast.Module()
504 ast.body = [_ast.BoolOp()]
505 self.assertRaises(TypeError, compile, ast, '<ast>', 'exec')
506
507 def test_dict_evaluation_order(self):
508 i = 0
509
510 def f():
511 nonlocal i
512 i += 1
513 return i
514
515 d = {f(): f(), f(): f()}
516 self.assertEqual(d, {1: 2, 3: 4})
517
518 def test_compile_filename(self):
519 for filename in 'file.py', b'file.py':
520 code = compile('pass', filename, 'exec')
521 self.assertEqual(code.co_filename, 'file.py')
522 for filename in bytearray(b'file.py'), memoryview(b'file.py'):
523 with self.assertWarns(DeprecationWarning):
524 code = compile('pass', filename, 'exec')
525 self.assertEqual(code.co_filename, 'file.py')
526 self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec')
527
528 @support.cpython_only
529 def test_same_filename_used(self):
530 s = """def f(): pass\ndef g(): pass"""
531 c = compile(s, "myfile", "exec")
532 for obj in c.co_consts:
533 if isinstance(obj, types.CodeType):
534 self.assertIs(obj.co_filename, c.co_filename)
535
536 def test_single_statement(self):
537 self.compile_single("1 + 2")
538 self.compile_single("\n1 + 2")
539 self.compile_single("1 + 2\n")
540 self.compile_single("1 + 2\n\n")
541 self.compile_single("1 + 2\t\t\n")
542 self.compile_single("1 + 2\t\t\n ")
543 self.compile_single("1 + 2 # one plus two")
544 self.compile_single("1; 2")
545 self.compile_single("import sys; sys")
546 self.compile_single("def f():\n pass")
547 self.compile_single("while False:\n pass")
548 self.compile_single("if x:\n f(x)")
549 self.compile_single("if x:\n f(x)\nelse:\n g(x)")
550 self.compile_single("class T:\n pass")
551 self.compile_single("c = '''\na=1\nb=2\nc=3\n'''")
552
553 def test_bad_single_statement(self):
554 self.assertInvalidSingle('1\n2')
555 self.assertInvalidSingle('def f(): pass')
556 self.assertInvalidSingle('a = 13\nb = 187')
557 self.assertInvalidSingle('del x\ndel y')
558 self.assertInvalidSingle('f()\ng()')
559 self.assertInvalidSingle('f()\n# blah\nblah()')
560 self.assertInvalidSingle('f()\nxy # blah\nblah()')
561 self.assertInvalidSingle('x = 5 # comment\nx = 6\n')
562 self.assertInvalidSingle("c = '''\nd=1\n'''\na = 1\n\nb = 2\n")
563
564 def test_particularly_evil_undecodable(self):
565 # Issue 24022
566 src = b'0000\x00\n00000000000\n\x00\n\x9e\n'
567 with tempfile.TemporaryDirectory() as tmpd:
568 fn = os.path.join(tmpd, "bad.py")
569 with open(fn, "wb") as fp:
570 fp.write(src)
571 res = script_helper.run_python_until_end(fn)[0]
572 self.assertIn(b"source code cannot contain null bytes", res.err)
573
574 def test_yet_more_evil_still_undecodable(self):
575 # Issue #25388
576 src = b"#\x00\n#\xfd\n"
577 with tempfile.TemporaryDirectory() as tmpd:
578 fn = os.path.join(tmpd, "bad.py")
579 with open(fn, "wb") as fp:
580 fp.write(src)
581 res = script_helper.run_python_until_end(fn)[0]
582 self.assertIn(b"source code cannot contain null bytes", res.err)
583
584 @support.cpython_only
585 def test_compiler_recursion_limit(self):
586 # Expected limit is sys.getrecursionlimit() * the scaling factor
587 # in symtable.c (currently 3)
588 # We expect to fail *at* that limit, because we use up some of
589 # the stack depth limit in the test suite code
590 # So we check the expected limit and 75% of that
591 # XXX (ncoghlan): duplicating the scaling factor here is a little
592 # ugly. Perhaps it should be exposed somewhere...
593 fail_depth = sys.getrecursionlimit() * 3
594 crash_depth = sys.getrecursionlimit() * 300
595 success_depth = int(fail_depth * 0.75)
596
597 def check_limit(prefix, repeated, mode="single"):
598 expect_ok = prefix + repeated * success_depth
599 compile(expect_ok, '<test>', mode)
600 for depth in (fail_depth, crash_depth):
601 broken = prefix + repeated * depth
602 details = "Compiling ({!r} + {!r} * {})".format(
603 prefix, repeated, depth)
604 with self.assertRaises(RecursionError, msg=details):
605 compile(broken, '<test>', mode)
606
607 check_limit("a", "()")
608 check_limit("a", ".b")
609 check_limit("a", "[0]")
610 check_limit("a", "*a")
611 # XXX Crashes in the parser.
612 # check_limit("a", " if a else a")
613 # check_limit("if a: pass", "\nelif a: pass", mode="exec")
614
615 def test_null_terminated(self):
616 # The source code is null-terminated internally, but bytes-like
617 # objects are accepted, which could be not terminated.
618 with self.assertRaisesRegex(SyntaxError, "cannot contain null"):
619 compile("123\x00", "<dummy>", "eval")
620 with self.assertRaisesRegex(SyntaxError, "cannot contain null"):
621 compile(memoryview(b"123\x00"), "<dummy>", "eval")
622 code = compile(memoryview(b"123\x00")[1:-1], "<dummy>", "eval")
623 self.assertEqual(eval(code), 23)
624 code = compile(memoryview(b"1234")[1:-1], "<dummy>", "eval")
625 self.assertEqual(eval(code), 23)
626 code = compile(memoryview(b"$23$")[1:-1], "<dummy>", "eval")
627 self.assertEqual(eval(code), 23)
628
629 # Also test when eval() and exec() do the compilation step
630 self.assertEqual(eval(memoryview(b"1234")[1:-1]), 23)
631 namespace = dict()
632 exec(memoryview(b"ax = 123")[1:-1], namespace)
633 self.assertEqual(namespace['x'], 12)
634
635 def check_constant(self, func, expected):
636 for const in func.__code__.co_consts:
637 if repr(const) == repr(expected):
638 break
639 else:
640 self.fail("unable to find constant %r in %r"
641 % (expected, func.__code__.co_consts))
642
643 # Merging equal constants is not a strict requirement for the Python
644 # semantics, it's a more an implementation detail.
645 @support.cpython_only
646 def test_merge_constants(self):
647 # Issue #25843: compile() must merge constants which are equal
648 # and have the same type.
649
650 def check_same_constant(const):
651 ns = {}
652 code = "f1, f2 = lambda: %r, lambda: %r" % (const, const)
653 exec(code, ns)
654 f1 = ns['f1']
655 f2 = ns['f2']
656 self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts)
657 self.check_constant(f1, const)
658 self.assertEqual(repr(f1()), repr(const))
659
660 check_same_constant(None)
661 check_same_constant(0)
662 check_same_constant(0.0)
663 check_same_constant(b'abc')
664 check_same_constant('abc')
665
666 # Note: "lambda: ..." emits "LOAD_CONST Ellipsis",
667 # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis"
668 f1, f2 = lambda: ..., lambda: ...
669 self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts)
670 self.check_constant(f1, Ellipsis)
671 self.assertEqual(repr(f1()), repr(Ellipsis))
672
673 # Merge constants in tuple or frozenset
674 f1, f2 = lambda: "not a name", lambda: ("not a name",)
675 f3 = lambda x: x in {("not a name",)}
676 self.assertIs(f1.__code__.co_consts[1],
677 f2.__code__.co_consts[1][0])
678 self.assertIs(next(iter(f3.__code__.co_consts[1])),
679 f2.__code__.co_consts[1])
680
681 # {0} is converted to a constant frozenset({0}) by the peephole
682 # optimizer
683 f1, f2 = lambda x: x in {0}, lambda x: x in {0}
684 self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts)
685 self.check_constant(f1, frozenset({0}))
686 self.assertTrue(f1(0))
687
688 # Merging equal co_linetable is not a strict requirement
689 # for the Python semantics, it's a more an implementation detail.
690 @support.cpython_only
691 def test_merge_code_attrs(self):
692 # See https://bugs.python.org/issue42217
693 f1 = lambda x: x.y.z
694 f2 = lambda a: a.b.c
695
696 self.assertIs(f1.__code__.co_linetable, f2.__code__.co_linetable)
697
698 # Stripping unused constants is not a strict requirement for the
699 # Python semantics, it's a more an implementation detail.
700 @support.cpython_only
701 def test_strip_unused_consts(self):
702 # Python 3.10rc1 appended None to co_consts when None is not used
703 # at all. See bpo-45056.
704 def f1():
705 "docstring"
706 return 42
707 self.assertEqual(f1.__code__.co_consts, ("docstring", 42))
708
709 # This is a regression test for a CPython specific peephole optimizer
710 # implementation bug present in a few releases. It's assertion verifies
711 # that peephole optimization was actually done though that isn't an
712 # indication of the bugs presence or not (crashing is).
713 @support.cpython_only
714 def test_peephole_opt_unreachable_code_array_access_in_bounds(self):
715 """Regression test for issue35193 when run under clang msan."""
716 def unused_code_at_end():
717 return 3
718 raise RuntimeError("unreachable")
719 # The above function definition will trigger the out of bounds
720 # bug in the peephole optimizer as it scans opcodes past the
721 # RETURN_VALUE opcode. This does not always crash an interpreter.
722 # When you build with the clang memory sanitizer it reliably aborts.
723 self.assertEqual(
724 'RETURN_VALUE',
725 list(dis.get_instructions(unused_code_at_end))[-1].opname)
726
727 def test_dont_merge_constants(self):
728 # Issue #25843: compile() must not merge constants which are equal
729 # but have a different type.
730
731 def check_different_constants(const1, const2):
732 ns = {}
733 exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns)
734 f1 = ns['f1']
735 f2 = ns['f2']
736 self.assertIsNot(f1.__code__, f2.__code__)
737 self.assertNotEqual(f1.__code__, f2.__code__)
738 self.check_constant(f1, const1)
739 self.check_constant(f2, const2)
740 self.assertEqual(repr(f1()), repr(const1))
741 self.assertEqual(repr(f2()), repr(const2))
742
743 check_different_constants(0, 0.0)
744 check_different_constants(+0.0, -0.0)
745 check_different_constants((0,), (0.0,))
746 check_different_constants('a', b'a')
747 check_different_constants(('a',), (b'a',))
748
749 # check_different_constants() cannot be used because repr(-0j) is
750 # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign.
751 f1, f2 = lambda: +0.0j, lambda: -0.0j
752 self.assertIsNot(f1.__code__, f2.__code__)
753 self.check_constant(f1, +0.0j)
754 self.check_constant(f2, -0.0j)
755 self.assertEqual(repr(f1()), repr(+0.0j))
756 self.assertEqual(repr(f2()), repr(-0.0j))
757
758 # {0} is converted to a constant frozenset({0}) by the peephole
759 # optimizer
760 f1, f2 = lambda x: x in {0}, lambda x: x in {0.0}
761 self.assertIsNot(f1.__code__, f2.__code__)
762 self.check_constant(f1, frozenset({0}))
763 self.check_constant(f2, frozenset({0.0}))
764 self.assertTrue(f1(0))
765 self.assertTrue(f2(0.0))
766
767 def test_path_like_objects(self):
768 # An implicit test for PyUnicode_FSDecoder().
769 compile("42", FakePath("test_compile_pathlike"), "single")
770
771 @support.requires_resource('cpu')
772 def test_stack_overflow(self):
773 # bpo-31113: Stack overflow when compile a long sequence of
774 # complex statements.
775 compile("if a: b\n" * 200000, "<dummy>", "exec")
776
777 # Multiple users rely on the fact that CPython does not generate
778 # bytecode for dead code blocks. See bpo-37500 for more context.
779 @support.cpython_only
780 def test_dead_blocks_do_not_generate_bytecode(self):
781 def unused_block_if():
782 if 0:
783 return 42
784
785 def unused_block_while():
786 while 0:
787 return 42
788
789 def unused_block_if_else():
790 if 1:
791 return None
792 else:
793 return 42
794
795 def unused_block_while_else():
796 while 1:
797 return None
798 else:
799 return 42
800
801 funcs = [unused_block_if, unused_block_while,
802 unused_block_if_else, unused_block_while_else]
803
804 for func in funcs:
805 opcodes = list(dis.get_instructions(func))
806 self.assertLessEqual(len(opcodes), 4)
807 self.assertEqual('LOAD_CONST', opcodes[-2].opname)
808 self.assertEqual(None, opcodes[-2].argval)
809 self.assertEqual('RETURN_VALUE', opcodes[-1].opname)
810
811 def test_false_while_loop(self):
812 def break_in_while():
813 while False:
814 break
815
816 def continue_in_while():
817 while False:
818 continue
819
820 funcs = [break_in_while, continue_in_while]
821
822 # Check that we did not raise but we also don't generate bytecode
823 for func in funcs:
824 opcodes = list(dis.get_instructions(func))
825 self.assertEqual(3, len(opcodes))
826 self.assertEqual('LOAD_CONST', opcodes[1].opname)
827 self.assertEqual(None, opcodes[1].argval)
828 self.assertEqual('RETURN_VALUE', opcodes[2].opname)
829
830 def test_consts_in_conditionals(self):
831 def and_true(x):
832 return True and x
833
834 def and_false(x):
835 return False and x
836
837 def or_true(x):
838 return True or x
839
840 def or_false(x):
841 return False or x
842
843 funcs = [and_true, and_false, or_true, or_false]
844
845 # Check that condition is removed.
846 for func in funcs:
847 with self.subTest(func=func):
848 opcodes = list(dis.get_instructions(func))
849 self.assertLessEqual(len(opcodes), 3)
850 self.assertIn('LOAD_', opcodes[-2].opname)
851 self.assertEqual('RETURN_VALUE', opcodes[-1].opname)
852
853 def test_imported_load_method(self):
854 sources = [
855 """\
856 import os
857 def foo():
858 return os.uname()
859 """,
860 """\
861 import os as operating_system
862 def foo():
863 return operating_system.uname()
864 """,
865 """\
866 from os import path
867 def foo(x):
868 return path.join(x)
869 """,
870 """\
871 from os import path as os_path
872 def foo(x):
873 return os_path.join(x)
874 """
875 ]
876 for source in sources:
877 namespace = {}
878 exec(textwrap.dedent(source), namespace)
879 func = namespace['foo']
880 with self.subTest(func=func.__name__):
881 opcodes = list(dis.get_instructions(func))
882 instructions = [opcode.opname for opcode in opcodes]
883 self.assertNotIn('LOAD_METHOD', instructions)
884 self.assertIn('LOAD_ATTR', instructions)
885 self.assertIn('PRECALL', instructions)
886
887 def test_lineno_procedure_call(self):
888 def call():
889 (
890 print()
891 )
892 line1 = call.__code__.co_firstlineno + 1
893 assert line1 not in [line for (_, _, line) in call.__code__.co_lines()]
894
895 def test_lineno_after_implicit_return(self):
896 TRUE = True
897 # Don't use constant True or False, as compiler will remove test
898 def if1(x):
899 x()
900 if TRUE:
901 pass
902 def if2(x):
903 x()
904 if TRUE:
905 pass
906 else:
907 pass
908 def if3(x):
909 x()
910 if TRUE:
911 pass
912 else:
913 return None
914 def if4(x):
915 x()
916 if not TRUE:
917 pass
918 funcs = [ if1, if2, if3, if4]
919 lastlines = [ 3, 3, 3, 2]
920 frame = None
921 def save_caller_frame():
922 nonlocal frame
923 frame = sys._getframe(1)
924 for func, lastline in zip(funcs, lastlines, strict=True):
925 with self.subTest(func=func):
926 func(save_caller_frame)
927 self.assertEqual(frame.f_lineno-frame.f_code.co_firstlineno, lastline)
928
929 def test_lineno_after_no_code(self):
930 def no_code1():
931 "doc string"
932
933 def no_code2():
934 a: int
935
936 for func in (no_code1, no_code2):
937 with self.subTest(func=func):
938 code = func.__code__
939 lines = list(code.co_lines())
940 start, end, line = lines[0]
941 self.assertEqual(start, 0)
942 self.assertEqual(line, code.co_firstlineno)
943
944 def get_code_lines(self, code):
945 last_line = -2
946 res = []
947 for _, _, line in code.co_lines():
948 if line is not None and line != last_line:
949 res.append(line - code.co_firstlineno)
950 last_line = line
951 return res
952
953 def test_lineno_attribute(self):
954 def load_attr():
955 return (
956 o.
957 a
958 )
959 load_attr_lines = [ 0, 2, 3, 1 ]
960
961 def load_method():
962 return (
963 o.
964 m(
965 0
966 )
967 )
968 load_method_lines = [ 0, 2, 3, 4, 3, 1 ]
969
970 def store_attr():
971 (
972 o.
973 a
974 ) = (
975 v
976 )
977 store_attr_lines = [ 0, 5, 2, 3 ]
978
979 def aug_store_attr():
980 (
981 o.
982 a
983 ) += (
984 v
985 )
986 aug_store_attr_lines = [ 0, 2, 3, 5, 1, 3 ]
987
988 funcs = [ load_attr, load_method, store_attr, aug_store_attr]
989 func_lines = [ load_attr_lines, load_method_lines,
990 store_attr_lines, aug_store_attr_lines]
991
992 for func, lines in zip(funcs, func_lines, strict=True):
993 with self.subTest(func=func):
994 code_lines = self.get_code_lines(func.__code__)
995 self.assertEqual(lines, code_lines)
996
997 def test_line_number_genexp(self):
998
999 def return_genexp():
1000 return (1
1001 for
1002 x
1003 in
1004 y)
1005 genexp_lines = [0, 2, 0]
1006
1007 genexp_code = return_genexp.__code__.co_consts[1]
1008 code_lines = self.get_code_lines(genexp_code)
1009 self.assertEqual(genexp_lines, code_lines)
1010
1011 def test_line_number_implicit_return_after_async_for(self):
1012
1013 async def test(aseq):
1014 async for i in aseq:
1015 body
1016
1017 expected_lines = [0, 1, 2, 1]
1018 code_lines = self.get_code_lines(test.__code__)
1019 self.assertEqual(expected_lines, code_lines)
1020
1021 def test_big_dict_literal(self):
1022 # The compiler has a flushing point in "compiler_dict" that calls compiles
1023 # a portion of the dictionary literal when the loop that iterates over the items
1024 # reaches 0xFFFF elements but the code was not including the boundary element,
1025 # dropping the key at position 0xFFFF. See bpo-41531 for more information
1026
1027 dict_size = 0xFFFF + 1
1028 the_dict = "{" + ",".join(f"{x}:{x}" for x in range(dict_size)) + "}"
1029 self.assertEqual(len(eval(the_dict)), dict_size)
1030
1031 def test_redundant_jump_in_if_else_break(self):
1032 # Check if bytecode containing jumps that simply point to the next line
1033 # is generated around if-else-break style structures. See bpo-42615.
1034
1035 def if_else_break():
1036 val = 1
1037 while True:
1038 if val > 0:
1039 val -= 1
1040 else:
1041 break
1042 val = -1
1043
1044 INSTR_SIZE = 2
1045 HANDLED_JUMPS = (
1046 'POP_JUMP_IF_FALSE',
1047 'POP_JUMP_IF_TRUE',
1048 'JUMP_ABSOLUTE',
1049 'JUMP_FORWARD',
1050 )
1051
1052 for line, instr in enumerate(
1053 dis.Bytecode(if_else_break, show_caches=True)
1054 ):
1055 if instr.opname == 'JUMP_FORWARD':
1056 self.assertNotEqual(instr.arg, 0)
1057 elif instr.opname in HANDLED_JUMPS:
1058 self.assertNotEqual(instr.arg, (line + 1)*INSTR_SIZE)
1059
1060 def test_no_wraparound_jump(self):
1061 # See https://bugs.python.org/issue46724
1062
1063 def while_not_chained(a, b, c):
1064 while not (a < b < c):
1065 pass
1066
1067 for instr in dis.Bytecode(while_not_chained):
1068 self.assertNotEqual(instr.opname, "EXTENDED_ARG")
1069
1070 def test_compare_positions(self):
1071 for opname, op in [
1072 ("COMPARE_OP", "<"),
1073 ("COMPARE_OP", "<="),
1074 ("COMPARE_OP", ">"),
1075 ("COMPARE_OP", ">="),
1076 ("CONTAINS_OP", "in"),
1077 ("CONTAINS_OP", "not in"),
1078 ("IS_OP", "is"),
1079 ("IS_OP", "is not"),
1080 ]:
1081 expr = f'a {op} b {op} c'
1082 expected_positions = 2 * [(2, 2, 0, len(expr))]
1083 for source in [
1084 f"\\\n{expr}", f'if \\\n{expr}: x', f"x if \\\n{expr} else y"
1085 ]:
1086 code = compile(source, "<test>", "exec")
1087 actual_positions = [
1088 instruction.positions
1089 for instruction in dis.get_instructions(code)
1090 if instruction.opname == opname
1091 ]
1092 with self.subTest(source):
1093 self.assertEqual(actual_positions, expected_positions)
1094
1095 def test_apply_static_swaps(self):
1096 def f(x, y):
1097 a, a = x, y
1098 return a
1099 self.assertEqual(f("x", "y"), "y")
1100
1101 def test_apply_static_swaps_2(self):
1102 def f(x, y, z):
1103 a, b, a = x, y, z
1104 return a
1105 self.assertEqual(f("x", "y", "z"), "z")
1106
1107 def test_apply_static_swaps_3(self):
1108 def f(x, y, z):
1109 a, a, b = x, y, z
1110 return a
1111 self.assertEqual(f("x", "y", "z"), "y")
1112
1113
1114 @requires_debug_ranges()
1115 class ESC[4;38;5;81mTestSourcePositions(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
1116 # Ensure that compiled code snippets have correct line and column numbers
1117 # in `co_positions()`.
1118
1119 def check_positions_against_ast(self, snippet):
1120 # Basic check that makes sure each line and column is at least present
1121 # in one of the AST nodes of the source code.
1122 code = compile(snippet, 'test_compile.py', 'exec')
1123 ast_tree = compile(snippet, 'test_compile.py', 'exec', _ast.PyCF_ONLY_AST)
1124 self.assertTrue(type(ast_tree) == _ast.Module)
1125
1126 # Use an AST visitor that notes all the offsets.
1127 lines, end_lines, columns, end_columns = set(), set(), set(), set()
1128 class ESC[4;38;5;81mSourceOffsetVisitor(ESC[4;38;5;149mastESC[4;38;5;149m.ESC[4;38;5;149mNodeVisitor):
1129 def generic_visit(self, node):
1130 super().generic_visit(node)
1131 if not isinstance(node, ast.expr) and not isinstance(node, ast.stmt):
1132 return
1133 lines.add(node.lineno)
1134 end_lines.add(node.end_lineno)
1135 columns.add(node.col_offset)
1136 end_columns.add(node.end_col_offset)
1137
1138 SourceOffsetVisitor().visit(ast_tree)
1139
1140 # Check against the positions in the code object.
1141 for (line, end_line, col, end_col) in code.co_positions():
1142 if line == 0:
1143 continue # This is an artificial module-start line
1144 # If the offset is not None (indicating missing data), ensure that
1145 # it was part of one of the AST nodes.
1146 if line is not None:
1147 self.assertIn(line, lines)
1148 if end_line is not None:
1149 self.assertIn(end_line, end_lines)
1150 if col is not None:
1151 self.assertIn(col, columns)
1152 if end_col is not None:
1153 self.assertIn(end_col, end_columns)
1154
1155 return code, ast_tree
1156
1157 def assertOpcodeSourcePositionIs(self, code, opcode,
1158 line, end_line, column, end_column, occurrence=1):
1159
1160 for instr, position in zip(
1161 dis.Bytecode(code, show_caches=True), code.co_positions(), strict=True
1162 ):
1163 if instr.opname == opcode:
1164 occurrence -= 1
1165 if not occurrence:
1166 self.assertEqual(position[0], line)
1167 self.assertEqual(position[1], end_line)
1168 self.assertEqual(position[2], column)
1169 self.assertEqual(position[3], end_column)
1170 return
1171
1172 self.fail(f"Opcode {opcode} not found in code")
1173
1174 def test_simple_assignment(self):
1175 snippet = "x = 1"
1176 self.check_positions_against_ast(snippet)
1177
1178 def test_compiles_to_extended_op_arg(self):
1179 # Make sure we still have valid positions when the code compiles to an
1180 # EXTENDED_ARG by performing a loop which needs a JUMP_ABSOLUTE after
1181 # a bunch of opcodes.
1182 snippet = "x = x\n" * 10_000
1183 snippet += ("while x != 0:\n"
1184 " x -= 1\n"
1185 "while x != 0:\n"
1186 " x += 1\n"
1187 )
1188
1189 compiled_code, _ = self.check_positions_against_ast(snippet)
1190
1191 self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
1192 line=10_000 + 2, end_line=10_000 + 2,
1193 column=2, end_column=8, occurrence=1)
1194 self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
1195 line=10_000 + 4, end_line=10_000 + 4,
1196 column=2, end_column=9, occurrence=2)
1197
1198 def test_multiline_expression(self):
1199 snippet = """\
1200 f(
1201 1, 2, 3, 4
1202 )
1203 """
1204 compiled_code, _ = self.check_positions_against_ast(snippet)
1205 self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
1206 line=1, end_line=3, column=0, end_column=1)
1207
1208 def test_very_long_line_end_offset(self):
1209 # Make sure we get the correct column offset for offsets
1210 # too large to store in a byte.
1211 long_string = "a" * 1000
1212 snippet = f"g('{long_string}')"
1213
1214 compiled_code, _ = self.check_positions_against_ast(snippet)
1215 self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
1216 line=1, end_line=1, column=0, end_column=1005)
1217
1218 def test_complex_single_line_expression(self):
1219 snippet = "a - b @ (c * x['key'] + 23)"
1220
1221 compiled_code, _ = self.check_positions_against_ast(snippet)
1222 self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_SUBSCR',
1223 line=1, end_line=1, column=13, end_column=21)
1224 self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
1225 line=1, end_line=1, column=9, end_column=21, occurrence=1)
1226 self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
1227 line=1, end_line=1, column=9, end_column=26, occurrence=2)
1228 self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
1229 line=1, end_line=1, column=4, end_column=27, occurrence=3)
1230 self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
1231 line=1, end_line=1, column=0, end_column=27, occurrence=4)
1232
1233 def test_multiline_assert_rewritten_as_method_call(self):
1234 # GH-94694: Don't crash if pytest rewrites a multiline assert as a
1235 # method call with the same location information:
1236 tree = ast.parse("assert (\n42\n)")
1237 old_node = tree.body[0]
1238 new_node = ast.Expr(
1239 ast.Call(
1240 ast.Attribute(
1241 ast.Name("spam", ast.Load()),
1242 "eggs",
1243 ast.Load(),
1244 ),
1245 [],
1246 [],
1247 )
1248 )
1249 ast.copy_location(new_node, old_node)
1250 ast.fix_missing_locations(new_node)
1251 tree.body[0] = new_node
1252 compile(tree, "<test>", "exec")
1253
1254 def test_push_null_load_global_positions(self):
1255 source_template = """
1256 import abc, dis
1257 import ast as art
1258
1259 abc = None
1260 dix = dis
1261 ast = art
1262
1263 def f():
1264 {}
1265 """
1266 for body in [
1267 " abc.a()",
1268 " art.a()",
1269 " ast.a()",
1270 " dis.a()",
1271 " dix.a()",
1272 " abc[...]()",
1273 " art()()",
1274 " (ast or ...)()",
1275 " [dis]()",
1276 " (dix + ...)()",
1277 ]:
1278 with self.subTest(body):
1279 namespace = {}
1280 source = textwrap.dedent(source_template.format(body))
1281 exec(source, namespace)
1282 code = namespace["f"].__code__
1283 self.assertOpcodeSourcePositionIs(
1284 code,
1285 "LOAD_GLOBAL",
1286 line=10,
1287 end_line=10,
1288 column=4,
1289 end_column=7,
1290 )
1291
1292 def test_attribute_augassign(self):
1293 source = "(\n lhs \n . \n rhs \n ) += 42"
1294 code = compile(source, "<test>", "exec")
1295 self.assertOpcodeSourcePositionIs(
1296 code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
1297 )
1298 self.assertOpcodeSourcePositionIs(
1299 code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8
1300 )
1301
1302 def test_attribute_del(self):
1303 source = "del (\n lhs \n . \n rhs \n )"
1304 code = compile(source, "<test>", "exec")
1305 self.assertOpcodeSourcePositionIs(
1306 code, "DELETE_ATTR", line=4, end_line=4, column=5, end_column=8
1307 )
1308
1309 def test_attribute_load(self):
1310 source = "(\n lhs \n . \n rhs \n )"
1311 code = compile(source, "<test>", "exec")
1312 self.assertOpcodeSourcePositionIs(
1313 code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
1314 )
1315
1316 def test_attribute_store(self):
1317 source = "(\n lhs \n . \n rhs \n ) = 42"
1318 code = compile(source, "<test>", "exec")
1319 self.assertOpcodeSourcePositionIs(
1320 code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8
1321 )
1322
1323 def test_method_call(self):
1324 source = "(\n lhs \n . \n rhs \n )()"
1325 code = compile(source, "<test>", "exec")
1326 self.assertOpcodeSourcePositionIs(
1327 code, "LOAD_METHOD", line=4, end_line=4, column=5, end_column=8
1328 )
1329 self.assertOpcodeSourcePositionIs(
1330 code, "CALL", line=4, end_line=5, column=5, end_column=10
1331 )
1332
1333 def test_weird_attribute_position_regressions(self):
1334 def f():
1335 (bar.
1336 baz)
1337 (bar.
1338 baz(
1339 ))
1340 files().setdefault(
1341 0
1342 ).setdefault(
1343 0
1344 )
1345 for line, end_line, column, end_column in f.__code__.co_positions():
1346 self.assertIsNotNone(line)
1347 self.assertIsNotNone(end_line)
1348 self.assertIsNotNone(column)
1349 self.assertIsNotNone(end_column)
1350 self.assertLessEqual((line, column), (end_line, end_column))
1351
1352 @support.cpython_only
1353 def test_column_offset_deduplication(self):
1354 # GH-95150: Code with different column offsets shouldn't be merged!
1355 for source in [
1356 "lambda: a",
1357 "(a for b in c)",
1358 "[a for b in c]",
1359 "{a for b in c}",
1360 "{a: b for c in d}",
1361 ]:
1362 with self.subTest(source):
1363 code = compile(f"{source}, {source}", "<test>", "eval")
1364 self.assertEqual(len(code.co_consts), 2)
1365 self.assertIsInstance(code.co_consts[0], types.CodeType)
1366 self.assertIsInstance(code.co_consts[1], types.CodeType)
1367 self.assertNotEqual(code.co_consts[0], code.co_consts[1])
1368 self.assertNotEqual(
1369 list(code.co_consts[0].co_positions()),
1370 list(code.co_consts[1].co_positions()),
1371 )
1372
1373
1374 class ESC[4;38;5;81mTestExpressionStackSize(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
1375 # These tests check that the computed stack size for a code object
1376 # stays within reasonable bounds (see issue #21523 for an example
1377 # dysfunction).
1378 N = 100
1379
1380 def check_stack_size(self, code):
1381 # To assert that the alleged stack size is not O(N), we
1382 # check that it is smaller than log(N).
1383 if isinstance(code, str):
1384 code = compile(code, "<foo>", "single")
1385 max_size = math.ceil(math.log(len(code.co_code)))
1386 self.assertLessEqual(code.co_stacksize, max_size)
1387
1388 def test_and(self):
1389 self.check_stack_size("x and " * self.N + "x")
1390
1391 def test_or(self):
1392 self.check_stack_size("x or " * self.N + "x")
1393
1394 def test_and_or(self):
1395 self.check_stack_size("x and x or " * self.N + "x")
1396
1397 def test_chained_comparison(self):
1398 self.check_stack_size("x < " * self.N + "x")
1399
1400 def test_if_else(self):
1401 self.check_stack_size("x if x else " * self.N + "x")
1402
1403 def test_binop(self):
1404 self.check_stack_size("x + " * self.N + "x")
1405
1406 def test_list(self):
1407 self.check_stack_size("[" + "x, " * self.N + "x]")
1408
1409 def test_tuple(self):
1410 self.check_stack_size("(" + "x, " * self.N + "x)")
1411
1412 def test_set(self):
1413 self.check_stack_size("{" + "x, " * self.N + "x}")
1414
1415 def test_dict(self):
1416 self.check_stack_size("{" + "x:x, " * self.N + "x:x}")
1417
1418 def test_func_args(self):
1419 self.check_stack_size("f(" + "x, " * self.N + ")")
1420
1421 def test_func_kwargs(self):
1422 kwargs = (f'a{i}=x' for i in range(self.N))
1423 self.check_stack_size("f(" + ", ".join(kwargs) + ")")
1424
1425 def test_meth_args(self):
1426 self.check_stack_size("o.m(" + "x, " * self.N + ")")
1427
1428 def test_meth_kwargs(self):
1429 kwargs = (f'a{i}=x' for i in range(self.N))
1430 self.check_stack_size("o.m(" + ", ".join(kwargs) + ")")
1431
1432 def test_func_and(self):
1433 code = "def f(x):\n"
1434 code += " x and x\n" * self.N
1435 self.check_stack_size(code)
1436
1437 def test_stack_3050(self):
1438 M = 3050
1439 code = "x," * M + "=t"
1440 # This raised on 3.10.0 to 3.10.5
1441 compile(code, "<foo>", "single")
1442
1443 def test_stack_3050_2(self):
1444 M = 3050
1445 args = ", ".join(f"arg{i}:type{i}" for i in range(M))
1446 code = f"def f({args}):\n pass"
1447 # This raised on 3.10.0 to 3.10.5
1448 compile(code, "<foo>", "single")
1449
1450
1451 class ESC[4;38;5;81mTestStackSizeStability(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
1452 # Check that repeating certain snippets doesn't increase the stack size
1453 # beyond what a single snippet requires.
1454
1455 def check_stack_size(self, snippet, async_=False):
1456 def compile_snippet(i):
1457 ns = {}
1458 script = """def func():\n""" + i * snippet
1459 if async_:
1460 script = "async " + script
1461 code = compile(script, "<script>", "exec")
1462 exec(code, ns, ns)
1463 return ns['func'].__code__
1464
1465 sizes = [compile_snippet(i).co_stacksize for i in range(2, 5)]
1466 if len(set(sizes)) != 1:
1467 import dis, io
1468 out = io.StringIO()
1469 dis.dis(compile_snippet(1), file=out)
1470 self.fail("stack sizes diverge with # of consecutive snippets: "
1471 "%s\n%s\n%s" % (sizes, snippet, out.getvalue()))
1472
1473 def test_if(self):
1474 snippet = """
1475 if x:
1476 a
1477 """
1478 self.check_stack_size(snippet)
1479
1480 def test_if_else(self):
1481 snippet = """
1482 if x:
1483 a
1484 elif y:
1485 b
1486 else:
1487 c
1488 """
1489 self.check_stack_size(snippet)
1490
1491 def test_try_except_bare(self):
1492 snippet = """
1493 try:
1494 a
1495 except:
1496 b
1497 """
1498 self.check_stack_size(snippet)
1499
1500 def test_try_except_qualified(self):
1501 snippet = """
1502 try:
1503 a
1504 except ImportError:
1505 b
1506 except:
1507 c
1508 else:
1509 d
1510 """
1511 self.check_stack_size(snippet)
1512
1513 def test_try_except_as(self):
1514 snippet = """
1515 try:
1516 a
1517 except ImportError as e:
1518 b
1519 except:
1520 c
1521 else:
1522 d
1523 """
1524 self.check_stack_size(snippet)
1525
1526 def test_try_except_star_qualified(self):
1527 snippet = """
1528 try:
1529 a
1530 except* ImportError:
1531 b
1532 else:
1533 c
1534 """
1535 self.check_stack_size(snippet)
1536
1537 def test_try_except_star_as(self):
1538 snippet = """
1539 try:
1540 a
1541 except* ImportError as e:
1542 b
1543 else:
1544 c
1545 """
1546 self.check_stack_size(snippet)
1547
1548 def test_try_except_star_finally(self):
1549 snippet = """
1550 try:
1551 a
1552 except* A:
1553 b
1554 finally:
1555 c
1556 """
1557 self.check_stack_size(snippet)
1558
1559 def test_try_finally(self):
1560 snippet = """
1561 try:
1562 a
1563 finally:
1564 b
1565 """
1566 self.check_stack_size(snippet)
1567
1568 def test_with(self):
1569 snippet = """
1570 with x as y:
1571 a
1572 """
1573 self.check_stack_size(snippet)
1574
1575 def test_while_else(self):
1576 snippet = """
1577 while x:
1578 a
1579 else:
1580 b
1581 """
1582 self.check_stack_size(snippet)
1583
1584 def test_for(self):
1585 snippet = """
1586 for x in y:
1587 a
1588 """
1589 self.check_stack_size(snippet)
1590
1591 def test_for_else(self):
1592 snippet = """
1593 for x in y:
1594 a
1595 else:
1596 b
1597 """
1598 self.check_stack_size(snippet)
1599
1600 def test_for_break_continue(self):
1601 snippet = """
1602 for x in y:
1603 if z:
1604 break
1605 elif u:
1606 continue
1607 else:
1608 a
1609 else:
1610 b
1611 """
1612 self.check_stack_size(snippet)
1613
1614 def test_for_break_continue_inside_try_finally_block(self):
1615 snippet = """
1616 for x in y:
1617 try:
1618 if z:
1619 break
1620 elif u:
1621 continue
1622 else:
1623 a
1624 finally:
1625 f
1626 else:
1627 b
1628 """
1629 self.check_stack_size(snippet)
1630
1631 def test_for_break_continue_inside_finally_block(self):
1632 snippet = """
1633 for x in y:
1634 try:
1635 t
1636 finally:
1637 if z:
1638 break
1639 elif u:
1640 continue
1641 else:
1642 a
1643 else:
1644 b
1645 """
1646 self.check_stack_size(snippet)
1647
1648 def test_for_break_continue_inside_except_block(self):
1649 snippet = """
1650 for x in y:
1651 try:
1652 t
1653 except:
1654 if z:
1655 break
1656 elif u:
1657 continue
1658 else:
1659 a
1660 else:
1661 b
1662 """
1663 self.check_stack_size(snippet)
1664
1665 def test_for_break_continue_inside_with_block(self):
1666 snippet = """
1667 for x in y:
1668 with c:
1669 if z:
1670 break
1671 elif u:
1672 continue
1673 else:
1674 a
1675 else:
1676 b
1677 """
1678 self.check_stack_size(snippet)
1679
1680 def test_return_inside_try_finally_block(self):
1681 snippet = """
1682 try:
1683 if z:
1684 return
1685 else:
1686 a
1687 finally:
1688 f
1689 """
1690 self.check_stack_size(snippet)
1691
1692 def test_return_inside_finally_block(self):
1693 snippet = """
1694 try:
1695 t
1696 finally:
1697 if z:
1698 return
1699 else:
1700 a
1701 """
1702 self.check_stack_size(snippet)
1703
1704 def test_return_inside_except_block(self):
1705 snippet = """
1706 try:
1707 t
1708 except:
1709 if z:
1710 return
1711 else:
1712 a
1713 """
1714 self.check_stack_size(snippet)
1715
1716 def test_return_inside_with_block(self):
1717 snippet = """
1718 with c:
1719 if z:
1720 return
1721 else:
1722 a
1723 """
1724 self.check_stack_size(snippet)
1725
1726 def test_async_with(self):
1727 snippet = """
1728 async with x as y:
1729 a
1730 """
1731 self.check_stack_size(snippet, async_=True)
1732
1733 def test_async_for(self):
1734 snippet = """
1735 async for x in y:
1736 a
1737 """
1738 self.check_stack_size(snippet, async_=True)
1739
1740 def test_async_for_else(self):
1741 snippet = """
1742 async for x in y:
1743 a
1744 else:
1745 b
1746 """
1747 self.check_stack_size(snippet, async_=True)
1748
1749 def test_for_break_continue_inside_async_with_block(self):
1750 snippet = """
1751 for x in y:
1752 async with c:
1753 if z:
1754 break
1755 elif u:
1756 continue
1757 else:
1758 a
1759 else:
1760 b
1761 """
1762 self.check_stack_size(snippet, async_=True)
1763
1764 def test_return_inside_async_with_block(self):
1765 snippet = """
1766 async with c:
1767 if z:
1768 return
1769 else:
1770 a
1771 """
1772 self.check_stack_size(snippet, async_=True)
1773
1774
1775 if __name__ == "__main__":
1776 unittest.main()