##// END OF EJS Templates
Merge branch 'main' into create_app_session_for_debugger_prompt
Merge branch 'main' into create_app_session_for_debugger_prompt

File last commit:

r27764:aefe51c6
r28087:23d5d48f merge
Show More
test_debugger.py
575 lines | 14.2 KiB | text/x-python | PythonLexer
Fernando Perez
Add simple test for modified repr as per review.
r7087 """Tests for debugging machinery.
"""
Min RK
fix some deprecations...
r22742 # Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
Fernando Perez
Add simple test for modified repr as per review.
r7087
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839 import builtins
import os
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 import sys
Matthias Bussonnier
Skip problemtic test on PyPy
r27325 import platform
Matthias Bussonnier
Expand and Fix PDB skip....
r26824
Itamar Turner-Trauring
Test for debugger interruption.
r25569 from tempfile import NamedTemporaryFile
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839 from textwrap import dedent
Itamar Turner-Trauring
Switch to a much simpler test. Interrupting processes encountered some issues...
r25606 from unittest.mock import patch
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929
Fernando Perez
Add simple test for modified repr as per review.
r7087 from IPython.core import debugger
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
from IPython.testing.decorators import skip_win32
Matthias Bussonnier
Skip problemtic test on PyPy
r27325 import pytest
Fernando Perez
Add simple test for modified repr as per review.
r7087
#-----------------------------------------------------------------------------
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 # Helper classes, from CPython's Pdb test suite
#-----------------------------------------------------------------------------
class _FakeInput(object):
"""
A fake input stream for pdb's interactive debugger. Whenever a
line is read, print it (to simulate the user typing it), and then
return it. The set of lines to return is specified in the
constructor; they should not have trailing newlines.
"""
def __init__(self, lines):
self.lines = iter(lines)
def readline(self):
line = next(self.lines)
Thomas Kluyver
Convert print statements to print function calls...
r13348 print(line)
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 return line+'\n'
class PdbTestInput(object):
"""Context manager that makes testing Pdb in doctests easier."""
def __init__(self, input):
self.input = input
def __enter__(self):
self.real_stdin = sys.stdin
sys.stdin = _FakeInput(self.input)
def __exit__(self, *exc):
sys.stdin = self.real_stdin
#-----------------------------------------------------------------------------
Fernando Perez
Add simple test for modified repr as per review.
r7087 # Tests
#-----------------------------------------------------------------------------
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 def test_ipdb_magics():
'''Test calling some IPython magics from ipdb.
First, set up some test functions and classes which we can inspect.
>>> class ExampleClass(object):
... """Docstring for ExampleClass."""
... def __init__(self):
... """Docstring for ExampleClass.__init__"""
... pass
... def __str__(self):
... return "ExampleClass()"
>>> def example_function(x, y, z="hello"):
... """Docstring for example_function."""
... pass
Thomas Kluyver
Fix clashes between debugger tests and coverage.py...
r12286 >>> old_trace = sys.gettrace()
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 Create a function which triggers ipdb.
>>> def trigger_ipdb():
... a = ExampleClass()
... debugger.Pdb().set_trace()
>>> with PdbTestInput([
... 'pdef example_function',
... 'pdoc ExampleClass',
Matthias Bussonnier
Write tests for ipdb...
r21851 ... 'up',
... 'down',
... 'list',
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 ... 'pinfo a',
Matthias Bussonnier
Write tests for ipdb...
r21851 ... 'll',
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 ... 'continue',
... ]):
... trigger_ipdb()
--Return--
None
> <doctest ...>(3)trigger_ipdb()
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
ipdb> pdef example_function
example_function(x, y, z='hello')
ipdb> pdoc ExampleClass
MinRK
sentence case...
r15712 Class docstring:
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 Docstring for ExampleClass.
MinRK
sentence case...
r15712 Init docstring:
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 Docstring for ExampleClass.__init__
Matthias Bussonnier
Write tests for ipdb...
r21851 ipdb> up
> <doctest ...>(11)<module>()
Thomas Kluyver
Fix debugger doctest to match atual output
r21945 7 'pinfo a',
8 'll',
Matthias Bussonnier
Write tests for ipdb...
r21851 9 'continue',
10 ]):
---> 11 trigger_ipdb()
<BLANKLINE>
ipdb> down
None
> <doctest ...>(3)trigger_ipdb()
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
ipdb> list
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 ipdb> pinfo a
MinRK
Update signature presentation in pinfo classes...
r15711 Type: ExampleClass
MinRK
sentence case...
r15712 String form: ExampleClass()
MinRK
Update signature presentation in pinfo classes...
r15711 Namespace: Local...
Docstring: Docstring for ExampleClass.
MinRK
sentence case...
r15712 Init docstring: Docstring for ExampleClass.__init__
Matthias Bussonnier
Write tests for ipdb...
r21851 ipdb> ll
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 ipdb> continue
Thomas Kluyver
Fix clashes between debugger tests and coverage.py...
r12286
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
Bradley M. Froehle
Add basic tests for calling pdef/pdoc/pinfo from ipdb.
r7929 '''
Bradley M. Froehle
Add test for gh-2697
r8929
Thomas Kluyver
Remove unused imports from IPython.core
r11124 def test_ipdb_magics2():
Bradley M. Froehle
Add test for gh-2697
r8929 '''Test ipdb with a very short function.
Thomas Kluyver
Fix clashes between debugger tests and coverage.py...
r12286
>>> old_trace = sys.gettrace()
Bradley M. Froehle
Add test for gh-2697
r8929
>>> def bar():
... pass
Run ipdb.
>>> with PdbTestInput([
... 'continue',
... ]):
... debugger.Pdb().runcall(bar)
> <doctest ...>(2)bar()
1 def bar():
----> 2 pass
<BLANKLINE>
ipdb> continue
Thomas Kluyver
Fix clashes between debugger tests and coverage.py...
r12286
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
Bradley M. Froehle
Add test for gh-2697
r8929 '''
Matthias Bussonnier
Add test that quit and exit work in debugger....
r22569
def can_quit():
'''Test that quit work in ipydb
>>> old_trace = sys.gettrace()
>>> def bar():
... pass
>>> with PdbTestInput([
... 'quit',
... ]):
... debugger.Pdb().runcall(bar)
> <doctest ...>(2)bar()
1 def bar():
----> 2 pass
<BLANKLINE>
ipdb> quit
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''
def can_exit():
'''Test that quit work in ipydb
>>> old_trace = sys.gettrace()
>>> def bar():
... pass
>>> with PdbTestInput([
... 'exit',
... ]):
... debugger.Pdb().runcall(bar)
> <doctest ...>(2)bar()
1 def bar():
----> 2 pass
<BLANKLINE>
ipdb> exit
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''
Itamar Turner-Trauring
Test for debugger interruption.
r25569
def test_interruptible_core_debugger():
Itamar Turner-Trauring
Sketch of working interrupt mechanism for Windows. Will need to be implemented in ipykernel.
r25587 """The debugger can be interrupted.
Itamar Turner-Trauring
Switch to a much simpler test. Interrupting processes encountered some issues...
r25606
The presumption is there is some mechanism that causes a KeyboardInterrupt
(this is implemented in ipykernel). We want to ensure the
KeyboardInterrupt cause debugging to cease.
Itamar Turner-Trauring
Sketch of working interrupt mechanism for Windows. Will need to be implemented in ipykernel.
r25587 """
Itamar Turner-Trauring
A maybe better-working interruptible Pdb. Also make separate class so we don't...
r25649 def raising_input(msg="", called=[0]):
called[0] += 1
Nikita Kniazev
Rewrite bunch of `raise AssertionError` and `assert False` tests
r27087 assert called[0] == 1, "input() should only be called once!"
raise KeyboardInterrupt()
Itamar Turner-Trauring
Switch to a much simpler test. Interrupting processes encountered some issues...
r25606
Nikita Kniazev
TST: Restore original trace function
r26957 tracer_orig = sys.gettrace()
try:
with patch.object(builtins, "input", raising_input):
debugger.InterruptiblePdb().set_trace()
# The way this test will fail is by set_trace() never exiting,
# resulting in a timeout by the test runner. The alternative
# implementation would involve a subprocess, but that adds issues
# with interrupting subprocesses that are rather complex, so it's
# simpler just to do it this way.
finally:
# restore the original trace function
sys.settrace(tracer_orig)
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839
@skip_win32
def test_xmode_skip():
"""that xmode skip frames
Not as a doctest as pytest does not run doctests.
"""
import pexpect
env = os.environ.copy()
env["IPY_TEST_SIMPLE_PROMPT"] = "1"
child = pexpect.spawn(
sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
)
child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
child.expect("IPython")
child.expect("\n")
child.expect_exact("In [1]")
block = dedent(
"""
Matthias Bussonnier
add test
r26594 def f():
__tracebackhide__ = True
g()
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839
Matthias Bussonnier
add test
r26594 def g():
raise ValueError
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839
Matthias Bussonnier
add test
r26594 f()
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839 """
)
for line in block.splitlines():
child.sendline(line)
child.expect_exact(line)
child.expect_exact("skipping")
block = dedent(
"""
Matthias Bussonnier
add test
r26594 def f():
__tracebackhide__ = True
g()
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839
Matthias Bussonnier
add test
r26594 def g():
from IPython.core.debugger import set_trace
set_trace()
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839
Matthias Bussonnier
add test
r26594 f()
Matthias Bussonnier
Implement understanding on __tracebackhide__...
r25839 """
)
for line in block.splitlines():
child.sendline(line)
child.expect_exact(line)
child.expect("ipdb>")
child.sendline("w")
child.expect("hidden")
child.expect("ipdb>")
child.sendline("skip_hidden false")
child.sendline("w")
child.expect("__traceba")
child.expect("ipdb>")
child.close()
Matthias Bussonnier
add test
r26594
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 skip_decorators_blocks = (
"""
Matthias Bussonnier
Expand and Fix PDB skip....
r26824 def helpers_helper():
pass # should not stop here except breakpoint
""",
"""
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 def helper_1():
Matthias Bussonnier
Expand and Fix PDB skip....
r26824 helpers_helper() # should not stop here
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 """,
"""
def helper_2():
pass # should not stop here
""",
"""
Matthias Bussonnier
Expand and Fix PDB skip....
r26824 def pdb_skipped_decorator2(function):
def wrapped_fn(*args, **kwargs):
__debuggerskip__ = True
helper_2()
__debuggerskip__ = False
result = function(*args, **kwargs)
__debuggerskip__ = True
helper_2()
return result
return wrapped_fn
""",
"""
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 def pdb_skipped_decorator(function):
def wrapped_fn(*args, **kwargs):
__debuggerskip__ = True
helper_1()
__debuggerskip__ = False
result = function(*args, **kwargs)
__debuggerskip__ = True
helper_2()
return result
return wrapped_fn
""",
"""
@pdb_skipped_decorator
Matthias Bussonnier
Expand and Fix PDB skip....
r26824 @pdb_skipped_decorator2
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 def bar(x, y):
return x * y
""",
"""import IPython.terminal.debugger as ipdb""",
"""
def f():
ipdb.set_trace()
bar(3, 4)
""",
"""
f()
""",
)
def _decorator_skip_setup():
import pexpect
env = os.environ.copy()
env["IPY_TEST_SIMPLE_PROMPT"] = "1"
Matthias Bussonnier
no CPR
r27691 env["PROMPT_TOOLKIT_NO_CPR"] = "1"
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810
child = pexpect.spawn(
sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
)
Nikita Kniazev
Tweak tests for PyPy and add CI runner...
r27235 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810
child.expect("IPython")
child.expect("\n")
Nikita Kniazev
Tweak tests for PyPy and add CI runner...
r27235 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
Matthias Bussonnier
extend buffer len
r27690 child.str_last_chars = 500
Nikita Kniazev
Tweak tests for PyPy and add CI runner...
r27235
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
in_prompt_number = 1
for cblock in dedented_blocks:
child.expect_exact(f"In [{in_prompt_number}]:")
in_prompt_number += 1
for line in cblock.splitlines():
child.sendline(line)
child.expect_exact(line)
child.sendline("")
return child
Matthias Bussonnier
always skip
r27695 @pytest.mark.skip(reason="recently fail for unknown reason on CI")
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 @skip_win32
def test_decorator_skip():
"""test that decorator frames can be skipped."""
child = _decorator_skip_setup()
Matthias Bussonnier
debug
r27694 child.expect_exact("ipython-input-8")
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 child.expect_exact("3 bar(3, 4)")
child.expect("ipdb>")
child.expect("ipdb>")
child.sendline("step")
child.expect_exact("step")
Matthias Bussonnier
debug
r27694 child.expect_exact("--Call--")
child.expect_exact("ipython-input-6")
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810
child.expect_exact("1 @pdb_skipped_decorator")
child.sendline("s")
child.expect_exact("return x * y")
child.close()
Matthias Bussonnier
always skip
r27695 @pytest.mark.skip(reason="recently fail for unknown reason on CI")
Matthias Bussonnier
replace skip by skipif
r27357 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 @skip_win32
def test_decorator_skip_disabled():
"""test that decorator frame skipping can be disabled"""
child = _decorator_skip_setup()
child.expect_exact("3 bar(3, 4)")
for input_, expected in [
("skip_predicates debuggerskip False", ""),
("skip_predicates", "debuggerskip : False"),
("step", "---> 2 def wrapped_fn"),
("step", "----> 3 __debuggerskip__"),
("step", "----> 4 helper_1()"),
("step", "---> 1 def helper_1():"),
Matthias Bussonnier
Expand and Fix PDB skip....
r26824 ("next", "----> 2 helpers_helper()"),
Matthias Bussonnier
Allow decorator frames to be marked as skippable....
r26810 ("next", "--Return--"),
("next", "----> 5 __debuggerskip__ = False"),
]:
child.expect("ipdb>")
child.sendline(input_)
child.expect_exact(input_)
child.expect_exact(expected)
child.close()
Matthias Bussonnier
replace skip by skipif
r27357 @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
Matthias Bussonnier
Skip: no pexpect on win32
r26596 @skip_win32
Matthias Bussonnier
Expand and Fix PDB skip....
r26824 def test_decorator_skip_with_breakpoint():
"""test that decorator frame skipping can be disabled"""
import pexpect
env = os.environ.copy()
env["IPY_TEST_SIMPLE_PROMPT"] = "1"
Matthias Bussonnier
try to fix tests
r27692 env["PROMPT_TOOLKIT_NO_CPR"] = "1"
Matthias Bussonnier
Expand and Fix PDB skip....
r26824
child = pexpect.spawn(
sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
)
Nikita Kniazev
Tweak tests for PyPy and add CI runner...
r27235 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
Matthias Bussonnier
try to fix tests
r27692 child.str_last_chars = 500
Matthias Bussonnier
Expand and Fix PDB skip....
r26824
child.expect("IPython")
child.expect("\n")
Nikita Kniazev
Tweak tests for PyPy and add CI runner...
r27235 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
Matthias Bussonnier
Expand and Fix PDB skip....
r26824 ### we need a filename, so we need to exec the full block with a filename
with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
name = tf.name[:-3].split("/")[-1]
tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
tf.flush()
codeblock = f"from {name} import f"
dedented_blocks = [
codeblock,
"f()",
]
in_prompt_number = 1
for cblock in dedented_blocks:
child.expect_exact(f"In [{in_prompt_number}]:")
in_prompt_number += 1
for line in cblock.splitlines():
child.sendline(line)
child.expect_exact(line)
child.sendline("")
# as the filename does not exists, we'll rely on the filename prompt
child.expect_exact("47 bar(3, 4)")
for input_, expected in [
(f"b {name}.py:3", ""),
("step", "1---> 3 pass # should not stop here except"),
("step", "---> 38 @pdb_skipped_decorator"),
("continue", ""),
]:
child.expect("ipdb>")
child.sendline(input_)
child.expect_exact(input_)
child.expect_exact(expected)
child.close()
@skip_win32
Matthias Bussonnier
add test
r26594 def test_where_erase_value():
Matthias Bussonnier
Update IPython/core/tests/test_debugger.py...
r26595 """Test that `where` does not access f_locals and erase values."""
Matthias Bussonnier
add test
r26594 import pexpect
env = os.environ.copy()
env["IPY_TEST_SIMPLE_PROMPT"] = "1"
child = pexpect.spawn(
sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
)
child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
child.expect("IPython")
child.expect("\n")
child.expect_exact("In [1]")
block = dedent(
"""
def simple_f():
myvar = 1
print(myvar)
1/0
print(myvar)
simple_f() """
)
for line in block.splitlines():
child.sendline(line)
child.expect_exact(line)
child.expect_exact("ZeroDivisionError")
child.expect_exact("In [2]:")
child.sendline("%debug")
##
child.expect("ipdb>")
child.sendline("myvar")
child.expect("1")
##
child.expect("ipdb>")
child.sendline("myvar = 2")
##
child.expect_exact("ipdb>")
child.sendline("myvar")
child.expect_exact("2")
##
child.expect("ipdb>")
child.sendline("where")
##
child.expect("ipdb>")
child.sendline("myvar")
child.expect_exact("2")
child.expect("ipdb>")
child.close()