##// END OF EJS Templates
Windows doesn't let you read files open for writing, I think.
Itamar Turner-Trauring -
Show More
@@ -1,274 +1,274 b''
1 """Tests for debugging machinery.
1 """Tests for debugging machinery.
2 """
2 """
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import sys
7 import sys
8 import warnings
8 import warnings
9 from tempfile import NamedTemporaryFile
9 from tempfile import NamedTemporaryFile
10 from subprocess import check_output
10 from subprocess import check_output
11
11
12 import nose.tools as nt
12 import nose.tools as nt
13
13
14 from IPython.core import debugger
14 from IPython.core import debugger
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Helper classes, from CPython's Pdb test suite
17 # Helper classes, from CPython's Pdb test suite
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 class _FakeInput(object):
20 class _FakeInput(object):
21 """
21 """
22 A fake input stream for pdb's interactive debugger. Whenever a
22 A fake input stream for pdb's interactive debugger. Whenever a
23 line is read, print it (to simulate the user typing it), and then
23 line is read, print it (to simulate the user typing it), and then
24 return it. The set of lines to return is specified in the
24 return it. The set of lines to return is specified in the
25 constructor; they should not have trailing newlines.
25 constructor; they should not have trailing newlines.
26 """
26 """
27 def __init__(self, lines):
27 def __init__(self, lines):
28 self.lines = iter(lines)
28 self.lines = iter(lines)
29
29
30 def readline(self):
30 def readline(self):
31 line = next(self.lines)
31 line = next(self.lines)
32 print(line)
32 print(line)
33 return line+'\n'
33 return line+'\n'
34
34
35 class PdbTestInput(object):
35 class PdbTestInput(object):
36 """Context manager that makes testing Pdb in doctests easier."""
36 """Context manager that makes testing Pdb in doctests easier."""
37
37
38 def __init__(self, input):
38 def __init__(self, input):
39 self.input = input
39 self.input = input
40
40
41 def __enter__(self):
41 def __enter__(self):
42 self.real_stdin = sys.stdin
42 self.real_stdin = sys.stdin
43 sys.stdin = _FakeInput(self.input)
43 sys.stdin = _FakeInput(self.input)
44
44
45 def __exit__(self, *exc):
45 def __exit__(self, *exc):
46 sys.stdin = self.real_stdin
46 sys.stdin = self.real_stdin
47
47
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 # Tests
49 # Tests
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51
51
52 def test_longer_repr():
52 def test_longer_repr():
53 from reprlib import repr as trepr
53 from reprlib import repr as trepr
54
54
55 a = '1234567890'* 7
55 a = '1234567890'* 7
56 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
56 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
57 a_trunc = "'123456789012...8901234567890'"
57 a_trunc = "'123456789012...8901234567890'"
58 nt.assert_equal(trepr(a), a_trunc)
58 nt.assert_equal(trepr(a), a_trunc)
59 # The creation of our tracer modifies the repr module's repr function
59 # The creation of our tracer modifies the repr module's repr function
60 # in-place, since that global is used directly by the stdlib's pdb module.
60 # in-place, since that global is used directly by the stdlib's pdb module.
61 with warnings.catch_warnings():
61 with warnings.catch_warnings():
62 warnings.simplefilter('ignore', DeprecationWarning)
62 warnings.simplefilter('ignore', DeprecationWarning)
63 debugger.Tracer()
63 debugger.Tracer()
64 nt.assert_equal(trepr(a), ar)
64 nt.assert_equal(trepr(a), ar)
65
65
66 def test_ipdb_magics():
66 def test_ipdb_magics():
67 '''Test calling some IPython magics from ipdb.
67 '''Test calling some IPython magics from ipdb.
68
68
69 First, set up some test functions and classes which we can inspect.
69 First, set up some test functions and classes which we can inspect.
70
70
71 >>> class ExampleClass(object):
71 >>> class ExampleClass(object):
72 ... """Docstring for ExampleClass."""
72 ... """Docstring for ExampleClass."""
73 ... def __init__(self):
73 ... def __init__(self):
74 ... """Docstring for ExampleClass.__init__"""
74 ... """Docstring for ExampleClass.__init__"""
75 ... pass
75 ... pass
76 ... def __str__(self):
76 ... def __str__(self):
77 ... return "ExampleClass()"
77 ... return "ExampleClass()"
78
78
79 >>> def example_function(x, y, z="hello"):
79 >>> def example_function(x, y, z="hello"):
80 ... """Docstring for example_function."""
80 ... """Docstring for example_function."""
81 ... pass
81 ... pass
82
82
83 >>> old_trace = sys.gettrace()
83 >>> old_trace = sys.gettrace()
84
84
85 Create a function which triggers ipdb.
85 Create a function which triggers ipdb.
86
86
87 >>> def trigger_ipdb():
87 >>> def trigger_ipdb():
88 ... a = ExampleClass()
88 ... a = ExampleClass()
89 ... debugger.Pdb().set_trace()
89 ... debugger.Pdb().set_trace()
90
90
91 >>> with PdbTestInput([
91 >>> with PdbTestInput([
92 ... 'pdef example_function',
92 ... 'pdef example_function',
93 ... 'pdoc ExampleClass',
93 ... 'pdoc ExampleClass',
94 ... 'up',
94 ... 'up',
95 ... 'down',
95 ... 'down',
96 ... 'list',
96 ... 'list',
97 ... 'pinfo a',
97 ... 'pinfo a',
98 ... 'll',
98 ... 'll',
99 ... 'continue',
99 ... 'continue',
100 ... ]):
100 ... ]):
101 ... trigger_ipdb()
101 ... trigger_ipdb()
102 --Return--
102 --Return--
103 None
103 None
104 > <doctest ...>(3)trigger_ipdb()
104 > <doctest ...>(3)trigger_ipdb()
105 1 def trigger_ipdb():
105 1 def trigger_ipdb():
106 2 a = ExampleClass()
106 2 a = ExampleClass()
107 ----> 3 debugger.Pdb().set_trace()
107 ----> 3 debugger.Pdb().set_trace()
108 <BLANKLINE>
108 <BLANKLINE>
109 ipdb> pdef example_function
109 ipdb> pdef example_function
110 example_function(x, y, z='hello')
110 example_function(x, y, z='hello')
111 ipdb> pdoc ExampleClass
111 ipdb> pdoc ExampleClass
112 Class docstring:
112 Class docstring:
113 Docstring for ExampleClass.
113 Docstring for ExampleClass.
114 Init docstring:
114 Init docstring:
115 Docstring for ExampleClass.__init__
115 Docstring for ExampleClass.__init__
116 ipdb> up
116 ipdb> up
117 > <doctest ...>(11)<module>()
117 > <doctest ...>(11)<module>()
118 7 'pinfo a',
118 7 'pinfo a',
119 8 'll',
119 8 'll',
120 9 'continue',
120 9 'continue',
121 10 ]):
121 10 ]):
122 ---> 11 trigger_ipdb()
122 ---> 11 trigger_ipdb()
123 <BLANKLINE>
123 <BLANKLINE>
124 ipdb> down
124 ipdb> down
125 None
125 None
126 > <doctest ...>(3)trigger_ipdb()
126 > <doctest ...>(3)trigger_ipdb()
127 1 def trigger_ipdb():
127 1 def trigger_ipdb():
128 2 a = ExampleClass()
128 2 a = ExampleClass()
129 ----> 3 debugger.Pdb().set_trace()
129 ----> 3 debugger.Pdb().set_trace()
130 <BLANKLINE>
130 <BLANKLINE>
131 ipdb> list
131 ipdb> list
132 1 def trigger_ipdb():
132 1 def trigger_ipdb():
133 2 a = ExampleClass()
133 2 a = ExampleClass()
134 ----> 3 debugger.Pdb().set_trace()
134 ----> 3 debugger.Pdb().set_trace()
135 <BLANKLINE>
135 <BLANKLINE>
136 ipdb> pinfo a
136 ipdb> pinfo a
137 Type: ExampleClass
137 Type: ExampleClass
138 String form: ExampleClass()
138 String form: ExampleClass()
139 Namespace: Local...
139 Namespace: Local...
140 Docstring: Docstring for ExampleClass.
140 Docstring: Docstring for ExampleClass.
141 Init docstring: Docstring for ExampleClass.__init__
141 Init docstring: Docstring for ExampleClass.__init__
142 ipdb> ll
142 ipdb> ll
143 1 def trigger_ipdb():
143 1 def trigger_ipdb():
144 2 a = ExampleClass()
144 2 a = ExampleClass()
145 ----> 3 debugger.Pdb().set_trace()
145 ----> 3 debugger.Pdb().set_trace()
146 <BLANKLINE>
146 <BLANKLINE>
147 ipdb> continue
147 ipdb> continue
148
148
149 Restore previous trace function, e.g. for coverage.py
149 Restore previous trace function, e.g. for coverage.py
150
150
151 >>> sys.settrace(old_trace)
151 >>> sys.settrace(old_trace)
152 '''
152 '''
153
153
154 def test_ipdb_magics2():
154 def test_ipdb_magics2():
155 '''Test ipdb with a very short function.
155 '''Test ipdb with a very short function.
156
156
157 >>> old_trace = sys.gettrace()
157 >>> old_trace = sys.gettrace()
158
158
159 >>> def bar():
159 >>> def bar():
160 ... pass
160 ... pass
161
161
162 Run ipdb.
162 Run ipdb.
163
163
164 >>> with PdbTestInput([
164 >>> with PdbTestInput([
165 ... 'continue',
165 ... 'continue',
166 ... ]):
166 ... ]):
167 ... debugger.Pdb().runcall(bar)
167 ... debugger.Pdb().runcall(bar)
168 > <doctest ...>(2)bar()
168 > <doctest ...>(2)bar()
169 1 def bar():
169 1 def bar():
170 ----> 2 pass
170 ----> 2 pass
171 <BLANKLINE>
171 <BLANKLINE>
172 ipdb> continue
172 ipdb> continue
173
173
174 Restore previous trace function, e.g. for coverage.py
174 Restore previous trace function, e.g. for coverage.py
175
175
176 >>> sys.settrace(old_trace)
176 >>> sys.settrace(old_trace)
177 '''
177 '''
178
178
179 def can_quit():
179 def can_quit():
180 '''Test that quit work in ipydb
180 '''Test that quit work in ipydb
181
181
182 >>> old_trace = sys.gettrace()
182 >>> old_trace = sys.gettrace()
183
183
184 >>> def bar():
184 >>> def bar():
185 ... pass
185 ... pass
186
186
187 >>> with PdbTestInput([
187 >>> with PdbTestInput([
188 ... 'quit',
188 ... 'quit',
189 ... ]):
189 ... ]):
190 ... debugger.Pdb().runcall(bar)
190 ... debugger.Pdb().runcall(bar)
191 > <doctest ...>(2)bar()
191 > <doctest ...>(2)bar()
192 1 def bar():
192 1 def bar():
193 ----> 2 pass
193 ----> 2 pass
194 <BLANKLINE>
194 <BLANKLINE>
195 ipdb> quit
195 ipdb> quit
196
196
197 Restore previous trace function, e.g. for coverage.py
197 Restore previous trace function, e.g. for coverage.py
198
198
199 >>> sys.settrace(old_trace)
199 >>> sys.settrace(old_trace)
200 '''
200 '''
201
201
202
202
203 def can_exit():
203 def can_exit():
204 '''Test that quit work in ipydb
204 '''Test that quit work in ipydb
205
205
206 >>> old_trace = sys.gettrace()
206 >>> old_trace = sys.gettrace()
207
207
208 >>> def bar():
208 >>> def bar():
209 ... pass
209 ... pass
210
210
211 >>> with PdbTestInput([
211 >>> with PdbTestInput([
212 ... 'exit',
212 ... 'exit',
213 ... ]):
213 ... ]):
214 ... debugger.Pdb().runcall(bar)
214 ... debugger.Pdb().runcall(bar)
215 > <doctest ...>(2)bar()
215 > <doctest ...>(2)bar()
216 1 def bar():
216 1 def bar():
217 ----> 2 pass
217 ----> 2 pass
218 <BLANKLINE>
218 <BLANKLINE>
219 ipdb> exit
219 ipdb> exit
220
220
221 Restore previous trace function, e.g. for coverage.py
221 Restore previous trace function, e.g. for coverage.py
222
222
223 >>> sys.settrace(old_trace)
223 >>> sys.settrace(old_trace)
224 '''
224 '''
225
225
226
226
227 interruptible_debugger = """\
227 interruptible_debugger = """\
228 import threading
228 import threading
229 import time
229 import time
230 from os import _exit
230 from os import _exit
231 from bdb import BdbQuit
231 from bdb import BdbQuit
232
232
233 from IPython.core.debugger import set_trace
233 from IPython.core.debugger import set_trace
234
234
235 def interrupt():
235 def interrupt():
236 time.sleep(0.1)
236 time.sleep(0.1)
237 import os, signal
237 import os, signal
238 os.kill(os.getpid(), signal.SIGINT)
238 os.kill(os.getpid(), signal.SIGINT)
239 threading.Thread(target=interrupt).start()
239 threading.Thread(target=interrupt).start()
240
240
241 # Timeout if the interrupt doesn't happen:
241 # Timeout if the interrupt doesn't happen:
242 def interrupt():
242 def interrupt():
243 try:
243 try:
244 time.sleep(2)
244 time.sleep(2)
245 except KeyboardInterrupt:
245 except KeyboardInterrupt:
246 return
246 return
247 _exit(7)
247 _exit(7)
248 threading.Thread(target=interrupt, daemon=True).start()
248 threading.Thread(target=interrupt, daemon=True).start()
249
249
250 def main():
250 def main():
251 set_trace()
251 set_trace()
252
252
253 if __name__ == '__main__':
253 if __name__ == '__main__':
254 try:
254 try:
255 #print("Starting debugger...")
255 #print("Starting debugger...")
256 main()
256 main()
257 print("Debugger exited without error.")
257 print("Debugger exited without error.")
258 except (KeyboardInterrupt, BdbQuit):
258 except (KeyboardInterrupt, BdbQuit):
259 print("Caught KeyboardInterrupt or BdbQuit, PASSED")
259 print("Caught KeyboardInterrupt or BdbQuit, PASSED")
260 except Exception as e:
260 except Exception as e:
261 print("Got wrong exception...")
261 print("Got wrong exception...")
262 raise e
262 raise e
263 """
263 """
264
264
265
265
266 def test_interruptible_core_debugger():
266 def test_interruptible_core_debugger():
267 """The debugger can be interrupted."""
267 """The debugger can be interrupted."""
268 with NamedTemporaryFile("w") as f:
268 with NamedTemporaryFile("w", delete=False) as f:
269 f.write(interruptible_debugger)
269 f.write(interruptible_debugger)
270 f.flush()
270 f.flush()
271 result = check_output([sys.executable, f.name],
271 result = check_output([sys.executable, f.name],
272 encoding=sys.getdefaultencoding())
272 encoding=sys.getdefaultencoding())
273 # Wait for it to start:
273 # Wait for it to start:
274 assert "PASSED" in result
274 assert "PASSED" in result
General Comments 0
You need to be logged in to leave comments. Login now