From 1a37c55789d9e3457b8e00231be490dc6d971ac4 2019-06-11 09:30:23 From: Matthias Bussonnier Date: 2019-06-11 09:30:23 Subject: [PATCH] Fix state leakage and speedup in test-suite This is mostly visible when running the test via pytest that collect-then-run vs nose that runs as it collects. While I was at it I've improved some tests to be faster by changing the maximum recursion limit. --- diff --git a/IPython/core/tests/test_run.py b/IPython/core/tests/test_run.py index 2afa5ba..db308f1 100644 --- a/IPython/core/tests/test_run.py +++ b/IPython/core/tests/test_run.py @@ -35,7 +35,6 @@ from IPython.utils.io import capture_output from IPython.utils.tempdir import TemporaryDirectory from IPython.core import debugger - def doctest_refbug(): """Very nasty problem with references held by multiple runs of a script. See: https://github.com/ipython/ipython/issues/141 @@ -537,6 +536,8 @@ def test_run_tb(): nt.assert_not_in("execfile", out) nt.assert_in("RuntimeError", out) nt.assert_equal(out.count("---->"), 3) + del ip.user_ns['bar'] + del ip.user_ns['foo'] @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows") def test_script_tb(): diff --git a/IPython/core/tests/test_ultratb.py b/IPython/core/tests/test_ultratb.py index 536a4db..787a7ec 100644 --- a/IPython/core/tests/test_ultratb.py +++ b/IPython/core/tests/test_ultratb.py @@ -10,7 +10,8 @@ import traceback import unittest from unittest import mock -from ..ultratb import ColorTB, VerboseTB, find_recursion +import IPython.core.ultratb as ultratb +from IPython.core.ultratb import ColorTB, VerboseTB, find_recursion from IPython.testing import tools as tt @@ -18,8 +19,6 @@ from IPython.testing.decorators import onlyif_unicode_paths from IPython.utils.syspathcontext import prepended_to_syspath from IPython.utils.tempdir import TemporaryDirectory -ip = get_ipython() - file_1 = """1 2 3 @@ -31,6 +30,30 @@ file_2 = """def f(): 1/0 """ + +def recursionlimit(frames): + """ + decorator to set the recursion limit temporarily + """ + + def inner(test_function): + def wrapper(*args, **kwargs): + _orig_rec_limit = ultratb._FRAME_RECURSION_LIMIT + ultratb._FRAME_RECURSION_LIMIT = frames - 50 + + rl = sys.getrecursionlimit() + sys.setrecursionlimit(frames) + try: + return test_function(*args, **kwargs) + finally: + sys.setrecursionlimit(rl) + ultratb._FRAME_RECURSION_LIMIT = _orig_rec_limit + + return wrapper + + return inner + + class ChangedPyFileTest(unittest.TestCase): def test_changing_py_file(self): """Traceback produced if the line where the error occurred is missing? @@ -200,6 +223,8 @@ bar() # Assert syntax error during runtime generate stacktrace with tt.AssertPrints(["foo()", "bar()"]): ip.run_cell(syntax_error_at_runtime) + del ip.user_ns['bar'] + del ip.user_ns['foo'] def test_changing_py_file(self): with TemporaryDirectory() as td: @@ -302,14 +327,17 @@ def r3o2(): with tt.AssertNotPrints("frames repeated"): ip.run_cell("non_recurs()") + @recursionlimit(65) def test_recursion_one_frame(self): with tt.AssertPrints("1 frames repeated"): ip.run_cell("r1()") + @recursionlimit(65) def test_recursion_three_frames(self): with tt.AssertPrints("3 frames repeated"): ip.run_cell("r3o2()") + @recursionlimit(65) def test_find_recursion(self): captured = [] def capture_exc(*args, **kwargs): diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 3060be1..03b02b4 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -137,6 +137,12 @@ INDENT_SIZE = 8 # to users of ultratb who are NOT running inside ipython. DEFAULT_SCHEME = 'NoColor' + +# Number of frame above which we are likely to have a recursion and will +# **attempt** to detect it. Made modifiable mostly to speedup test suite +# as detecting recursion is one of our slowest test +_FRAME_RECURSION_LIMIT = 500 + # --------------------------------------------------------------------------- # Code begins @@ -431,7 +437,7 @@ def is_recursion_error(etype, value, records): # a recursion error. return (etype is recursion_error_type) \ and "recursion" in str(value).lower() \ - and len(records) > 500 + and len(records) > _FRAME_RECURSION_LIMIT def find_recursion(etype, value, records): """Identify the repeating stack frames from a RecursionError traceback diff --git a/IPython/extensions/tests/test_storemagic.py b/IPython/extensions/tests/test_storemagic.py index 373a716..a7b41ba 100644 --- a/IPython/extensions/tests/test_storemagic.py +++ b/IPython/extensions/tests/test_storemagic.py @@ -3,10 +3,13 @@ import tempfile, os from traitlets.config.loader import Config import nose.tools as nt -ip = get_ipython() -ip.magic('load_ext storemagic') + +def setup_module(): + ip.magic('load_ext storemagic') def test_store_restore(): + assert 'bar' not in ip.user_ns, "Error: some other test leaked `bar` in user_ns" + assert 'foo' not in ip.user_ns, "Error: some other test leaked `foo` in user_ns" ip.user_ns['foo'] = 78 ip.magic('alias bar echo "hello"') tmpd = tempfile.mkdtemp()