summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_compile.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_compile.py')
-rw-r--r--Lib/test/test_compile.py291
1 files changed, 290 insertions, 1 deletions
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index ae3043a..29aa362 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -672,7 +672,7 @@ if 1:
compile("42", PathLike("test_compile_pathlike"), "single")
-class TestStackSize(unittest.TestCase):
+class TestExpressionStackSize(unittest.TestCase):
# These tests check that the computed stack size for a code object
# stays within reasonable bounds (see issue #21523 for an example
# dysfunction).
@@ -710,5 +710,294 @@ class TestStackSize(unittest.TestCase):
self.check_stack_size(code)
+class TestStackSizeStability(unittest.TestCase):
+ # Check that repeating certain snippets doesn't increase the stack size
+ # beyond what a single snippet requires.
+
+ def check_stack_size(self, snippet, async_=False):
+ def compile_snippet(i):
+ ns = {}
+ script = """def func():\n""" + i * snippet
+ if async_:
+ script = "async " + script
+ code = compile(script, "<script>", "exec")
+ exec(code, ns, ns)
+ return ns['func'].__code__
+
+ sizes = [compile_snippet(i).co_stacksize for i in range(2, 5)]
+ if len(set(sizes)) != 1:
+ import dis, io
+ out = io.StringIO()
+ dis.dis(compile_snippet(1), file=out)
+ self.fail("stack sizes diverge with # of consecutive snippets: "
+ "%s\n%s\n%s" % (sizes, snippet, out.getvalue()))
+
+ def test_if(self):
+ snippet = """
+ if x:
+ a
+ """
+ self.check_stack_size(snippet)
+
+ def test_if_else(self):
+ snippet = """
+ if x:
+ a
+ elif y:
+ b
+ else:
+ c
+ """
+ self.check_stack_size(snippet)
+
+ def test_try_except_bare(self):
+ snippet = """
+ try:
+ a
+ except:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_try_except_qualified(self):
+ snippet = """
+ try:
+ a
+ except ImportError:
+ b
+ except:
+ c
+ else:
+ d
+ """
+ self.check_stack_size(snippet)
+
+ def test_try_except_as(self):
+ snippet = """
+ try:
+ a
+ except ImportError as e:
+ b
+ except:
+ c
+ else:
+ d
+ """
+ self.check_stack_size(snippet)
+
+ def test_try_finally(self):
+ snippet = """
+ try:
+ a
+ finally:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_with(self):
+ snippet = """
+ with x as y:
+ a
+ """
+ self.check_stack_size(snippet)
+
+ def test_while_else(self):
+ snippet = """
+ while x:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_for(self):
+ snippet = """
+ for x in y:
+ a
+ """
+ self.check_stack_size(snippet)
+
+ def test_for_else(self):
+ snippet = """
+ for x in y:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_for_break_continue(self):
+ snippet = """
+ for x in y:
+ if z:
+ break
+ elif u:
+ continue
+ else:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_for_break_continue_inside_try_finally_block(self):
+ snippet = """
+ for x in y:
+ try:
+ if z:
+ break
+ elif u:
+ continue
+ else:
+ a
+ finally:
+ f
+ else:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_for_break_inside_finally_block(self):
+ snippet = """
+ for x in y:
+ try:
+ t
+ finally:
+ if z:
+ break
+ else:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_for_break_continue_inside_except_block(self):
+ snippet = """
+ for x in y:
+ try:
+ t
+ except:
+ if z:
+ break
+ elif u:
+ continue
+ else:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_for_break_continue_inside_with_block(self):
+ snippet = """
+ for x in y:
+ with c:
+ if z:
+ break
+ elif u:
+ continue
+ else:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet)
+
+ def test_return_inside_try_finally_block(self):
+ snippet = """
+ try:
+ if z:
+ return
+ else:
+ a
+ finally:
+ f
+ """
+ self.check_stack_size(snippet)
+
+ def test_return_inside_finally_block(self):
+ snippet = """
+ try:
+ t
+ finally:
+ if z:
+ return
+ else:
+ a
+ """
+ self.check_stack_size(snippet)
+
+ def test_return_inside_except_block(self):
+ snippet = """
+ try:
+ t
+ except:
+ if z:
+ return
+ else:
+ a
+ """
+ self.check_stack_size(snippet)
+
+ def test_return_inside_with_block(self):
+ snippet = """
+ with c:
+ if z:
+ return
+ else:
+ a
+ """
+ self.check_stack_size(snippet)
+
+ def test_async_with(self):
+ snippet = """
+ async with x as y:
+ a
+ """
+ self.check_stack_size(snippet, async_=True)
+
+ def test_async_for(self):
+ snippet = """
+ async for x in y:
+ a
+ """
+ self.check_stack_size(snippet, async_=True)
+
+ def test_async_for_else(self):
+ snippet = """
+ async for x in y:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet, async_=True)
+
+ def test_for_break_continue_inside_async_with_block(self):
+ snippet = """
+ for x in y:
+ async with c:
+ if z:
+ break
+ elif u:
+ continue
+ else:
+ a
+ else:
+ b
+ """
+ self.check_stack_size(snippet, async_=True)
+
+ def test_return_inside_async_with_block(self):
+ snippet = """
+ async with c:
+ if z:
+ return
+ else:
+ a
+ """
+ self.check_stack_size(snippet, async_=True)
+
+
if __name__ == "__main__":
unittest.main()