##// END OF EJS Templates
Make event triggering robust to (un)registration....
Make event triggering robust to (un)registration. Event callbacks can register or unregister new callbacks for the same event while executing, and the previous triggering implementation allowed for event callbacks to be inadvertently skipped. The fix is to make a copy of the list of callbacks before executing any of them. With this change, the resulting semantics are simple: any callbacks registered before triggering are executed, and any new callbacks registered are only visible at the next triggering of the event. Note that this could potentially break existing callers who expected newly-appended callbacks were immediately executed. Fixes #9447. Originally based on a patch by @marksandler2.

File last commit:

r21945:cbc04795
r22317:68860ee5
Show More
test_debugger.py
186 lines | 5.1 KiB | text/x-python | PythonLexer
"""Tests for debugging machinery.
"""
from __future__ import print_function
#-----------------------------------------------------------------------------
# Copyright (c) 2012, The IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import sys
# third-party
import nose.tools as nt
# Our own
from IPython.core import debugger
#-----------------------------------------------------------------------------
# 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)
print(line)
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
#-----------------------------------------------------------------------------
# Tests
#-----------------------------------------------------------------------------
def test_longer_repr():
try:
from reprlib import repr as trepr # Py 3
except ImportError:
from repr import repr as trepr # Py 2
a = '1234567890'* 7
ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
a_trunc = "'123456789012...8901234567890'"
nt.assert_equal(trepr(a), a_trunc)
# The creation of our tracer modifies the repr module's repr function
# in-place, since that global is used directly by the stdlib's pdb module.
t = debugger.Tracer()
nt.assert_equal(trepr(a), ar)
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
>>> old_trace = sys.gettrace()
Create a function which triggers ipdb.
>>> def trigger_ipdb():
... a = ExampleClass()
... debugger.Pdb().set_trace()
>>> with PdbTestInput([
... 'pdef example_function',
... 'pdoc ExampleClass',
... 'up',
... 'down',
... 'list',
... 'pinfo a',
... 'll',
... '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
Class docstring:
Docstring for ExampleClass.
Init docstring:
Docstring for ExampleClass.__init__
ipdb> up
> <doctest ...>(11)<module>()
7 'pinfo a',
8 'll',
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>
ipdb> pinfo a
Type: ExampleClass
String form: ExampleClass()
Namespace: Local...
Docstring: Docstring for ExampleClass.
Init docstring: Docstring for ExampleClass.__init__
ipdb> ll
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
ipdb> continue
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''
def test_ipdb_magics2():
'''Test ipdb with a very short function.
>>> old_trace = sys.gettrace()
>>> def bar():
... pass
Run ipdb.
>>> with PdbTestInput([
... 'continue',
... ]):
... debugger.Pdb().runcall(bar)
> <doctest ...>(2)bar()
1 def bar():
----> 2 pass
<BLANKLINE>
ipdb> continue
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''