##// END OF EJS Templates
Skip: no pexpect on win32
Matthias Bussonnier -
Show More
@@ -1,389 +1,390 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 bdb
7 import bdb
8 import builtins
8 import builtins
9 import os
9 import os
10 import signal
10 import signal
11 import subprocess
11 import subprocess
12 import sys
12 import sys
13 import time
13 import time
14 import warnings
14 import warnings
15 from subprocess import PIPE, CalledProcessError, check_output
15 from subprocess import PIPE, CalledProcessError, check_output
16 from tempfile import NamedTemporaryFile
16 from tempfile import NamedTemporaryFile
17 from textwrap import dedent
17 from textwrap import dedent
18 from unittest.mock import patch
18 from unittest.mock import patch
19
19
20 import nose.tools as nt
20 import nose.tools as nt
21
21
22 from IPython.core import debugger
22 from IPython.core import debugger
23 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
23 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
24 from IPython.testing.decorators import skip_win32
24 from IPython.testing.decorators import skip_win32
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Helper classes, from CPython's Pdb test suite
27 # Helper classes, from CPython's Pdb test suite
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class _FakeInput(object):
30 class _FakeInput(object):
31 """
31 """
32 A fake input stream for pdb's interactive debugger. Whenever a
32 A fake input stream for pdb's interactive debugger. Whenever a
33 line is read, print it (to simulate the user typing it), and then
33 line is read, print it (to simulate the user typing it), and then
34 return it. The set of lines to return is specified in the
34 return it. The set of lines to return is specified in the
35 constructor; they should not have trailing newlines.
35 constructor; they should not have trailing newlines.
36 """
36 """
37 def __init__(self, lines):
37 def __init__(self, lines):
38 self.lines = iter(lines)
38 self.lines = iter(lines)
39
39
40 def readline(self):
40 def readline(self):
41 line = next(self.lines)
41 line = next(self.lines)
42 print(line)
42 print(line)
43 return line+'\n'
43 return line+'\n'
44
44
45 class PdbTestInput(object):
45 class PdbTestInput(object):
46 """Context manager that makes testing Pdb in doctests easier."""
46 """Context manager that makes testing Pdb in doctests easier."""
47
47
48 def __init__(self, input):
48 def __init__(self, input):
49 self.input = input
49 self.input = input
50
50
51 def __enter__(self):
51 def __enter__(self):
52 self.real_stdin = sys.stdin
52 self.real_stdin = sys.stdin
53 sys.stdin = _FakeInput(self.input)
53 sys.stdin = _FakeInput(self.input)
54
54
55 def __exit__(self, *exc):
55 def __exit__(self, *exc):
56 sys.stdin = self.real_stdin
56 sys.stdin = self.real_stdin
57
57
58 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
59 # Tests
59 # Tests
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61
61
62 def test_longer_repr():
62 def test_longer_repr():
63 from reprlib import repr as trepr
63 from reprlib import repr as trepr
64
64
65 a = '1234567890'* 7
65 a = '1234567890'* 7
66 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
66 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
67 a_trunc = "'123456789012...8901234567890'"
67 a_trunc = "'123456789012...8901234567890'"
68 nt.assert_equal(trepr(a), a_trunc)
68 nt.assert_equal(trepr(a), a_trunc)
69 # The creation of our tracer modifies the repr module's repr function
69 # The creation of our tracer modifies the repr module's repr function
70 # in-place, since that global is used directly by the stdlib's pdb module.
70 # in-place, since that global is used directly by the stdlib's pdb module.
71 with warnings.catch_warnings():
71 with warnings.catch_warnings():
72 warnings.simplefilter('ignore', DeprecationWarning)
72 warnings.simplefilter('ignore', DeprecationWarning)
73 debugger.Tracer()
73 debugger.Tracer()
74 nt.assert_equal(trepr(a), ar)
74 nt.assert_equal(trepr(a), ar)
75
75
76 def test_ipdb_magics():
76 def test_ipdb_magics():
77 '''Test calling some IPython magics from ipdb.
77 '''Test calling some IPython magics from ipdb.
78
78
79 First, set up some test functions and classes which we can inspect.
79 First, set up some test functions and classes which we can inspect.
80
80
81 >>> class ExampleClass(object):
81 >>> class ExampleClass(object):
82 ... """Docstring for ExampleClass."""
82 ... """Docstring for ExampleClass."""
83 ... def __init__(self):
83 ... def __init__(self):
84 ... """Docstring for ExampleClass.__init__"""
84 ... """Docstring for ExampleClass.__init__"""
85 ... pass
85 ... pass
86 ... def __str__(self):
86 ... def __str__(self):
87 ... return "ExampleClass()"
87 ... return "ExampleClass()"
88
88
89 >>> def example_function(x, y, z="hello"):
89 >>> def example_function(x, y, z="hello"):
90 ... """Docstring for example_function."""
90 ... """Docstring for example_function."""
91 ... pass
91 ... pass
92
92
93 >>> old_trace = sys.gettrace()
93 >>> old_trace = sys.gettrace()
94
94
95 Create a function which triggers ipdb.
95 Create a function which triggers ipdb.
96
96
97 >>> def trigger_ipdb():
97 >>> def trigger_ipdb():
98 ... a = ExampleClass()
98 ... a = ExampleClass()
99 ... debugger.Pdb().set_trace()
99 ... debugger.Pdb().set_trace()
100
100
101 >>> with PdbTestInput([
101 >>> with PdbTestInput([
102 ... 'pdef example_function',
102 ... 'pdef example_function',
103 ... 'pdoc ExampleClass',
103 ... 'pdoc ExampleClass',
104 ... 'up',
104 ... 'up',
105 ... 'down',
105 ... 'down',
106 ... 'list',
106 ... 'list',
107 ... 'pinfo a',
107 ... 'pinfo a',
108 ... 'll',
108 ... 'll',
109 ... 'continue',
109 ... 'continue',
110 ... ]):
110 ... ]):
111 ... trigger_ipdb()
111 ... trigger_ipdb()
112 --Return--
112 --Return--
113 None
113 None
114 > <doctest ...>(3)trigger_ipdb()
114 > <doctest ...>(3)trigger_ipdb()
115 1 def trigger_ipdb():
115 1 def trigger_ipdb():
116 2 a = ExampleClass()
116 2 a = ExampleClass()
117 ----> 3 debugger.Pdb().set_trace()
117 ----> 3 debugger.Pdb().set_trace()
118 <BLANKLINE>
118 <BLANKLINE>
119 ipdb> pdef example_function
119 ipdb> pdef example_function
120 example_function(x, y, z='hello')
120 example_function(x, y, z='hello')
121 ipdb> pdoc ExampleClass
121 ipdb> pdoc ExampleClass
122 Class docstring:
122 Class docstring:
123 Docstring for ExampleClass.
123 Docstring for ExampleClass.
124 Init docstring:
124 Init docstring:
125 Docstring for ExampleClass.__init__
125 Docstring for ExampleClass.__init__
126 ipdb> up
126 ipdb> up
127 > <doctest ...>(11)<module>()
127 > <doctest ...>(11)<module>()
128 7 'pinfo a',
128 7 'pinfo a',
129 8 'll',
129 8 'll',
130 9 'continue',
130 9 'continue',
131 10 ]):
131 10 ]):
132 ---> 11 trigger_ipdb()
132 ---> 11 trigger_ipdb()
133 <BLANKLINE>
133 <BLANKLINE>
134 ipdb> down
134 ipdb> down
135 None
135 None
136 > <doctest ...>(3)trigger_ipdb()
136 > <doctest ...>(3)trigger_ipdb()
137 1 def trigger_ipdb():
137 1 def trigger_ipdb():
138 2 a = ExampleClass()
138 2 a = ExampleClass()
139 ----> 3 debugger.Pdb().set_trace()
139 ----> 3 debugger.Pdb().set_trace()
140 <BLANKLINE>
140 <BLANKLINE>
141 ipdb> list
141 ipdb> list
142 1 def trigger_ipdb():
142 1 def trigger_ipdb():
143 2 a = ExampleClass()
143 2 a = ExampleClass()
144 ----> 3 debugger.Pdb().set_trace()
144 ----> 3 debugger.Pdb().set_trace()
145 <BLANKLINE>
145 <BLANKLINE>
146 ipdb> pinfo a
146 ipdb> pinfo a
147 Type: ExampleClass
147 Type: ExampleClass
148 String form: ExampleClass()
148 String form: ExampleClass()
149 Namespace: Local...
149 Namespace: Local...
150 Docstring: Docstring for ExampleClass.
150 Docstring: Docstring for ExampleClass.
151 Init docstring: Docstring for ExampleClass.__init__
151 Init docstring: Docstring for ExampleClass.__init__
152 ipdb> ll
152 ipdb> ll
153 1 def trigger_ipdb():
153 1 def trigger_ipdb():
154 2 a = ExampleClass()
154 2 a = ExampleClass()
155 ----> 3 debugger.Pdb().set_trace()
155 ----> 3 debugger.Pdb().set_trace()
156 <BLANKLINE>
156 <BLANKLINE>
157 ipdb> continue
157 ipdb> continue
158
158
159 Restore previous trace function, e.g. for coverage.py
159 Restore previous trace function, e.g. for coverage.py
160
160
161 >>> sys.settrace(old_trace)
161 >>> sys.settrace(old_trace)
162 '''
162 '''
163
163
164 def test_ipdb_magics2():
164 def test_ipdb_magics2():
165 '''Test ipdb with a very short function.
165 '''Test ipdb with a very short function.
166
166
167 >>> old_trace = sys.gettrace()
167 >>> old_trace = sys.gettrace()
168
168
169 >>> def bar():
169 >>> def bar():
170 ... pass
170 ... pass
171
171
172 Run ipdb.
172 Run ipdb.
173
173
174 >>> with PdbTestInput([
174 >>> with PdbTestInput([
175 ... 'continue',
175 ... 'continue',
176 ... ]):
176 ... ]):
177 ... debugger.Pdb().runcall(bar)
177 ... debugger.Pdb().runcall(bar)
178 > <doctest ...>(2)bar()
178 > <doctest ...>(2)bar()
179 1 def bar():
179 1 def bar():
180 ----> 2 pass
180 ----> 2 pass
181 <BLANKLINE>
181 <BLANKLINE>
182 ipdb> continue
182 ipdb> continue
183
183
184 Restore previous trace function, e.g. for coverage.py
184 Restore previous trace function, e.g. for coverage.py
185
185
186 >>> sys.settrace(old_trace)
186 >>> sys.settrace(old_trace)
187 '''
187 '''
188
188
189 def can_quit():
189 def can_quit():
190 '''Test that quit work in ipydb
190 '''Test that quit work in ipydb
191
191
192 >>> old_trace = sys.gettrace()
192 >>> old_trace = sys.gettrace()
193
193
194 >>> def bar():
194 >>> def bar():
195 ... pass
195 ... pass
196
196
197 >>> with PdbTestInput([
197 >>> with PdbTestInput([
198 ... 'quit',
198 ... 'quit',
199 ... ]):
199 ... ]):
200 ... debugger.Pdb().runcall(bar)
200 ... debugger.Pdb().runcall(bar)
201 > <doctest ...>(2)bar()
201 > <doctest ...>(2)bar()
202 1 def bar():
202 1 def bar():
203 ----> 2 pass
203 ----> 2 pass
204 <BLANKLINE>
204 <BLANKLINE>
205 ipdb> quit
205 ipdb> quit
206
206
207 Restore previous trace function, e.g. for coverage.py
207 Restore previous trace function, e.g. for coverage.py
208
208
209 >>> sys.settrace(old_trace)
209 >>> sys.settrace(old_trace)
210 '''
210 '''
211
211
212
212
213 def can_exit():
213 def can_exit():
214 '''Test that quit work in ipydb
214 '''Test that quit work in ipydb
215
215
216 >>> old_trace = sys.gettrace()
216 >>> old_trace = sys.gettrace()
217
217
218 >>> def bar():
218 >>> def bar():
219 ... pass
219 ... pass
220
220
221 >>> with PdbTestInput([
221 >>> with PdbTestInput([
222 ... 'exit',
222 ... 'exit',
223 ... ]):
223 ... ]):
224 ... debugger.Pdb().runcall(bar)
224 ... debugger.Pdb().runcall(bar)
225 > <doctest ...>(2)bar()
225 > <doctest ...>(2)bar()
226 1 def bar():
226 1 def bar():
227 ----> 2 pass
227 ----> 2 pass
228 <BLANKLINE>
228 <BLANKLINE>
229 ipdb> exit
229 ipdb> exit
230
230
231 Restore previous trace function, e.g. for coverage.py
231 Restore previous trace function, e.g. for coverage.py
232
232
233 >>> sys.settrace(old_trace)
233 >>> sys.settrace(old_trace)
234 '''
234 '''
235
235
236
236
237 def test_interruptible_core_debugger():
237 def test_interruptible_core_debugger():
238 """The debugger can be interrupted.
238 """The debugger can be interrupted.
239
239
240 The presumption is there is some mechanism that causes a KeyboardInterrupt
240 The presumption is there is some mechanism that causes a KeyboardInterrupt
241 (this is implemented in ipykernel). We want to ensure the
241 (this is implemented in ipykernel). We want to ensure the
242 KeyboardInterrupt cause debugging to cease.
242 KeyboardInterrupt cause debugging to cease.
243 """
243 """
244 def raising_input(msg="", called=[0]):
244 def raising_input(msg="", called=[0]):
245 called[0] += 1
245 called[0] += 1
246 if called[0] == 1:
246 if called[0] == 1:
247 raise KeyboardInterrupt()
247 raise KeyboardInterrupt()
248 else:
248 else:
249 raise AssertionError("input() should only be called once!")
249 raise AssertionError("input() should only be called once!")
250
250
251 with patch.object(builtins, "input", raising_input):
251 with patch.object(builtins, "input", raising_input):
252 debugger.InterruptiblePdb().set_trace()
252 debugger.InterruptiblePdb().set_trace()
253 # The way this test will fail is by set_trace() never exiting,
253 # The way this test will fail is by set_trace() never exiting,
254 # resulting in a timeout by the test runner. The alternative
254 # resulting in a timeout by the test runner. The alternative
255 # implementation would involve a subprocess, but that adds issues with
255 # implementation would involve a subprocess, but that adds issues with
256 # interrupting subprocesses that are rather complex, so it's simpler
256 # interrupting subprocesses that are rather complex, so it's simpler
257 # just to do it this way.
257 # just to do it this way.
258
258
259 @skip_win32
259 @skip_win32
260 def test_xmode_skip():
260 def test_xmode_skip():
261 """that xmode skip frames
261 """that xmode skip frames
262
262
263 Not as a doctest as pytest does not run doctests.
263 Not as a doctest as pytest does not run doctests.
264 """
264 """
265 import pexpect
265 import pexpect
266 env = os.environ.copy()
266 env = os.environ.copy()
267 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
267 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
268
268
269 child = pexpect.spawn(
269 child = pexpect.spawn(
270 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
270 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
271 )
271 )
272 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
272 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
273
273
274 child.expect("IPython")
274 child.expect("IPython")
275 child.expect("\n")
275 child.expect("\n")
276 child.expect_exact("In [1]")
276 child.expect_exact("In [1]")
277
277
278 block = dedent(
278 block = dedent(
279 """
279 """
280 def f():
280 def f():
281 __tracebackhide__ = True
281 __tracebackhide__ = True
282 g()
282 g()
283
283
284 def g():
284 def g():
285 raise ValueError
285 raise ValueError
286
286
287 f()
287 f()
288 """
288 """
289 )
289 )
290
290
291 for line in block.splitlines():
291 for line in block.splitlines():
292 child.sendline(line)
292 child.sendline(line)
293 child.expect_exact(line)
293 child.expect_exact(line)
294 child.expect_exact("skipping")
294 child.expect_exact("skipping")
295
295
296 block = dedent(
296 block = dedent(
297 """
297 """
298 def f():
298 def f():
299 __tracebackhide__ = True
299 __tracebackhide__ = True
300 g()
300 g()
301
301
302 def g():
302 def g():
303 from IPython.core.debugger import set_trace
303 from IPython.core.debugger import set_trace
304 set_trace()
304 set_trace()
305
305
306 f()
306 f()
307 """
307 """
308 )
308 )
309
309
310 for line in block.splitlines():
310 for line in block.splitlines():
311 child.sendline(line)
311 child.sendline(line)
312 child.expect_exact(line)
312 child.expect_exact(line)
313
313
314 child.expect("ipdb>")
314 child.expect("ipdb>")
315 child.sendline("w")
315 child.sendline("w")
316 child.expect("hidden")
316 child.expect("hidden")
317 child.expect("ipdb>")
317 child.expect("ipdb>")
318 child.sendline("skip_hidden false")
318 child.sendline("skip_hidden false")
319 child.sendline("w")
319 child.sendline("w")
320 child.expect("__traceba")
320 child.expect("__traceba")
321 child.expect("ipdb>")
321 child.expect("ipdb>")
322
322
323 child.close()
323 child.close()
324
324
325
325
326 @skip_win32
326 def test_where_erase_value():
327 def test_where_erase_value():
327 """Test that `where` does not access f_locals and erase values."""
328 """Test that `where` does not access f_locals and erase values."""
328 import pexpect
329 import pexpect
329
330
330 env = os.environ.copy()
331 env = os.environ.copy()
331 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
332 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
332
333
333 child = pexpect.spawn(
334 child = pexpect.spawn(
334 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
335 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
335 )
336 )
336 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
337 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
337
338
338 child.expect("IPython")
339 child.expect("IPython")
339 child.expect("\n")
340 child.expect("\n")
340 child.expect_exact("In [1]")
341 child.expect_exact("In [1]")
341
342
342 block = dedent(
343 block = dedent(
343 """
344 """
344 def simple_f():
345 def simple_f():
345 myvar = 1
346 myvar = 1
346 print(myvar)
347 print(myvar)
347 1/0
348 1/0
348 print(myvar)
349 print(myvar)
349 simple_f() """
350 simple_f() """
350 )
351 )
351
352
352 for line in block.splitlines():
353 for line in block.splitlines():
353 child.sendline(line)
354 child.sendline(line)
354 child.expect_exact(line)
355 child.expect_exact(line)
355 child.expect_exact("ZeroDivisionError")
356 child.expect_exact("ZeroDivisionError")
356 child.expect_exact("In [2]:")
357 child.expect_exact("In [2]:")
357
358
358 child.sendline("%debug")
359 child.sendline("%debug")
359
360
360 ##
361 ##
361 child.expect("ipdb>")
362 child.expect("ipdb>")
362
363
363 child.sendline("myvar")
364 child.sendline("myvar")
364 child.expect("1")
365 child.expect("1")
365
366
366 ##
367 ##
367 child.expect("ipdb>")
368 child.expect("ipdb>")
368
369
369 child.sendline("myvar = 2")
370 child.sendline("myvar = 2")
370
371
371 ##
372 ##
372 child.expect_exact("ipdb>")
373 child.expect_exact("ipdb>")
373
374
374 child.sendline("myvar")
375 child.sendline("myvar")
375
376
376 child.expect_exact("2")
377 child.expect_exact("2")
377
378
378 ##
379 ##
379 child.expect("ipdb>")
380 child.expect("ipdb>")
380 child.sendline("where")
381 child.sendline("where")
381
382
382 ##
383 ##
383 child.expect("ipdb>")
384 child.expect("ipdb>")
384 child.sendline("myvar")
385 child.sendline("myvar")
385
386
386 child.expect_exact("2")
387 child.expect_exact("2")
387 child.expect("ipdb>")
388 child.expect("ipdb>")
388
389
389 child.close()
390 child.close()
General Comments 0
You need to be logged in to leave comments. Login now