Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 7 additions & 22 deletions IPython/core/tests/test_iplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ def doctest_tb_context():
ZeroDivisionError Traceback (most recent call last)
<BLANKLINE>
... in <module>
29 except IndexError:
30 mode = 'div'
31
---> 32 bar(mode)
<BLANKLINE>
... in bar(mode)
Expand All @@ -80,8 +80,6 @@ def doctest_tb_context():
6 x = 1
7 y = 0
----> 8 x/y
9
10 def sysexit(stat, mode):
<BLANKLINE>
ZeroDivisionError: ...
"""
Expand All @@ -97,17 +95,15 @@ def doctest_tb_verbose():
ZeroDivisionError Traceback (most recent call last)
<BLANKLINE>
... in <module>
29 except IndexError:
30 mode = 'div'
31
---> 32 bar(mode)
global bar = <function bar at ...>
global mode = 'div'
mode = 'div'
<BLANKLINE>
... in bar(mode='div')
14 "bar"
15 if mode=='div':
---> 16 div0()
global div0 = <function div0 at ...>
17 elif mode=='exit':
18 try:
<BLANKLINE>
Expand All @@ -117,8 +113,6 @@ def doctest_tb_verbose():
----> 8 x/y
x = 1
y = 0
9
10 def sysexit(stat, mode):
<BLANKLINE>
ZeroDivisionError: ...
"""
Expand Down Expand Up @@ -154,8 +148,8 @@ def doctest_tb_sysexit():
SystemExit Traceback (most recent call last)
<BLANKLINE>
...<module>
29 except IndexError:
30 mode = 'div'
31
---> 32 bar(mode)
<BLANKLINE>
...bar(mode)
Expand All @@ -166,11 +160,8 @@ def doctest_tb_sysexit():
24 raise ValueError('Unknown mode')
<BLANKLINE>
...sysexit(stat, mode)
9
10 def sysexit(stat, mode):
---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
12
13 def bar(mode):
<BLANKLINE>
SystemExit: (2, 'Mode = exit')

Expand All @@ -182,31 +173,25 @@ def doctest_tb_sysexit():
SystemExit Traceback (most recent call last)
<BLANKLINE>
... in <module>
29 except IndexError:
30 mode = 'div'
31
---> 32 bar(mode)
global bar = <function bar at ...>
global mode = 'exit'
mode = 'exit'
<BLANKLINE>
... in bar(mode='exit')
20 except:
21 stat = 1
---> 22 sysexit(stat, mode)
global sysexit = <function sysexit at ...>
stat = 2
mode = 'exit'
stat = 2
23 else:
24 raise ValueError('Unknown mode')
<BLANKLINE>
... in sysexit(stat=2, mode='exit')
9
10 def sysexit(stat, mode):
---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
global SystemExit = undefined
stat = 2
mode = 'exit'
12
13 def bar(mode):
<BLANKLINE>
SystemExit: (2, 'Mode = exit')
"""
Expand Down
78 changes: 10 additions & 68 deletions IPython/core/tests/test_ultratb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
"""
import io
import logging
import re
import sys
import os.path
from textwrap import dedent
import traceback
import unittest
from unittest import mock

import IPython.core.ultratb as ultratb
from IPython.core.ultratb import ColorTB, VerboseTB, find_recursion
from IPython.core.ultratb import ColorTB, VerboseTB


from IPython.testing import tools as tt
Expand All @@ -38,16 +37,12 @@ def recursionlimit(frames):

def inner(test_function):
def wrapper(*args, **kwargs):
_orig_rec_limit = ultratb._FRAME_RECURSION_LIMIT
ultratb._FRAME_RECURSION_LIMIT = 50

rl = sys.getrecursionlimit()
sys.setrecursionlimit(frames)
try:
return test_function(*args, **kwargs)
finally:
sys.setrecursionlimit(rl)
ultratb._FRAME_RECURSION_LIMIT = _orig_rec_limit
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe those were here to speedup the test suite by a lot (and/or failure on CI). Is that handled by stack_data ?

I'm happy if it needs to be removed for other reasons.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The speedup is provided by sys.setrecursionlimit. ultratb._FRAME_RECURSION_LIMIT was used for detecting recursion, although I don't know why it didn't use sys.getrecursionlimit.

stack_data doesn't detect recursion specifically, it detects any string of repeating frames, similar to the Python traceback.


return wrapper

Expand Down Expand Up @@ -350,45 +345,24 @@ def setUp(self):
ip.run_cell(self.DEFINITIONS)

def test_no_recursion(self):
with tt.AssertNotPrints("frames repeated"):
with tt.AssertNotPrints("skipping similar frames"):
ip.run_cell("non_recurs()")

@recursionlimit(150)
def test_recursion_one_frame(self):
with tt.AssertPrints("1 frames repeated"):
with tt.AssertPrints(re.compile(
r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2} times\)\]")
):
ip.run_cell("r1()")

@recursionlimit(150)
def test_recursion_three_frames(self):
with tt.AssertPrints("3 frames repeated"):
ip.run_cell("r3o2()")

@recursionlimit(150)
def test_find_recursion(self):
captured = []
def capture_exc(*args, **kwargs):
captured.append(sys.exc_info())
with mock.patch.object(ip, 'showtraceback', capture_exc):
with tt.AssertPrints("[... skipping similar frames: "), \
tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
ip.run_cell("r3o2()")

self.assertEqual(len(captured), 1)
etype, evalue, tb = captured[0]
self.assertIn("recursion", str(evalue))

records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
for r in records[:10]:
print(r[1:4])

# The outermost frames should be:
# 0: the 'cell' that was running when the exception came up
# 1: r3o2()
# 2: r3o1()
# 3: r3a()
# Then repeating r3b, r3c, r3a
last_unique, repeat_length = find_recursion(etype, evalue, records)
self.assertEqual(last_unique, 2)
self.assertEqual(repeat_length, 3)


#----------------------------------------------------------------------------

Expand Down Expand Up @@ -432,35 +406,3 @@ def eggs(f, g, z=globals()):
except:
handler(*sys.exc_info())
buff.write('')

from IPython.testing.decorators import skipif

class TokenizeFailureTest(unittest.TestCase):
"""Tests related to https://github.com/ipython/ipython/issues/6864."""

# that appear to test that we are handling an exception that can be thrown
# by the tokenizer due to a bug that seem to have been fixed in 3.8, though
# I'm unsure if other sequences can make it raise this error. Let's just
# skip in 3.8 for now
@skipif(sys.version_info > (3,8))
def testLogging(self):
message = "An unexpected error occurred while tokenizing input"
cell = 'raise ValueError("""a\nb""")'

stream = io.StringIO()
handler = logging.StreamHandler(stream)
logger = logging.getLogger()
loglevel = logger.level
logger.addHandler(handler)
self.addCleanup(lambda: logger.removeHandler(handler))
self.addCleanup(lambda: logger.setLevel(loglevel))

logger.setLevel(logging.INFO)
with tt.AssertNotPrints(message):
ip.run_cell(cell)
self.assertNotIn(message, stream.getvalue())

logger.setLevel(logging.DEBUG)
with tt.AssertNotPrints(message):
ip.run_cell(cell)
self.assertIn(message, stream.getvalue())
Loading