##// END OF EJS Templates
Make clearer and simpler how to user prompt-toolkit PDB...
Matthias Bussonnier -
Show More
@@ -1,612 +1,623 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 16 http://www.python.org/2.2.3/license.html"""
17 17
18 18 #*****************************************************************************
19 19 #
20 20 # This file is licensed under the PSF license.
21 21 #
22 22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 24 #
25 25 #
26 26 #*****************************************************************************
27 27 from __future__ import print_function
28 28
29 29 import bdb
30 30 import functools
31 31 import inspect
32 32 import sys
33 33 import warnings
34 34
35 35 from IPython import get_ipython
36 36 from IPython.utils import PyColorize, ulinecache
37 37 from IPython.utils import coloransi, py3compat
38 38 from IPython.core.excolors import exception_colors
39 39 from IPython.testing.skipdoctest import skip_doctest
40 40
41 41
42 42 prompt = 'ipdb> '
43 43
44 44 #We have to check this directly from sys.argv, config struct not yet available
45 45 from pdb import Pdb as OldPdb
46 46
47 47 # Allow the set_trace code to operate outside of an ipython instance, even if
48 48 # it does so with some limitations. The rest of this support is implemented in
49 49 # the Tracer constructor.
50 50
51 51 def make_arrow(pad):
52 52 """generate the leading arrow in front of traceback or debugger"""
53 53 if pad >= 2:
54 54 return '-'*(pad-2) + '> '
55 55 elif pad == 1:
56 56 return '>'
57 57 return ''
58 58
59 59
60 60 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
61 61 """Exception hook which handles `BdbQuit` exceptions.
62 62
63 63 All other exceptions are processed using the `excepthook`
64 64 parameter.
65 65 """
66 66 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
67 67 DeprecationWarning)
68 68 if et==bdb.BdbQuit:
69 69 print('Exiting Debugger.')
70 70 elif excepthook is not None:
71 71 excepthook(et, ev, tb)
72 72 else:
73 73 # Backwards compatibility. Raise deprecation warning?
74 74 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
75 75
76 76
77 77 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
78 78 warnings.warn(
79 79 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
80 80 DeprecationWarning)
81 81 print('Exiting Debugger.')
82 82
83 83
84 84 class Tracer(object):
85 """Class for local debugging, similar to pdb.set_trace.
85 """
86 DEPRECATED
87
88 Class for local debugging, similar to pdb.set_trace.
86 89
87 90 Instances of this class, when called, behave like pdb.set_trace, but
88 91 providing IPython's enhanced capabilities.
89 92
90 93 This is implemented as a class which must be initialized in your own code
91 94 and not as a standalone function because we need to detect at runtime
92 95 whether IPython is already active or not. That detection is done in the
93 96 constructor, ensuring that this code plays nicely with a running IPython,
94 97 while functioning acceptably (though with limitations) if outside of it.
95 98 """
96 99
97 100 @skip_doctest
98 101 def __init__(self, colors=None):
99 """Create a local debugger instance.
102 """
103 DEPRECATED
104
105 Create a local debugger instance.
100 106
101 107 Parameters
102 108 ----------
103 109
104 110 colors : str, optional
105 111 The name of the color scheme to use, it must be one of IPython's
106 112 valid color schemes. If not given, the function will default to
107 113 the current IPython scheme when running inside IPython, and to
108 114 'NoColor' otherwise.
109 115
110 116 Examples
111 117 --------
112 118 ::
113 119
114 120 from IPython.core.debugger import Tracer; debug_here = Tracer()
115 121
116 122 Later in your code::
117 123
118 124 debug_here() # -> will open up the debugger at that point.
119 125
120 126 Once the debugger activates, you can use all of its regular commands to
121 127 step through code, set breakpoints, etc. See the pdb documentation
122 128 from the Python standard library for usage details.
123 129 """
124 130 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
125 131 "`IPython.core.debugger.Pdb.set_trace()`",
126 132 DeprecationWarning)
127 133
128 134 ip = get_ipython()
129 135 if ip is None:
130 136 # Outside of ipython, we set our own exception hook manually
131 137 sys.excepthook = functools.partial(BdbQuit_excepthook,
132 138 excepthook=sys.excepthook)
133 139 def_colors = 'NoColor'
134 140 else:
135 141 # In ipython, we use its custom exception handler mechanism
136 142 def_colors = ip.colors
137 143 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
138 144
139 145 if colors is None:
140 146 colors = def_colors
141 147
142 148 # The stdlib debugger internally uses a modified repr from the `repr`
143 149 # module, that limits the length of printed strings to a hardcoded
144 150 # limit of 30 characters. That much trimming is too aggressive, let's
145 151 # at least raise that limit to 80 chars, which should be enough for
146 152 # most interactive uses.
147 153 try:
148 154 try:
149 155 from reprlib import aRepr # Py 3
150 156 except ImportError:
151 157 from repr import aRepr # Py 2
152 158 aRepr.maxstring = 80
153 159 except:
154 160 # This is only a user-facing convenience, so any error we encounter
155 161 # here can be warned about but can be otherwise ignored. These
156 162 # printouts will tell us about problems if this API changes
157 163 import traceback
158 164 traceback.print_exc()
159 165
160 166 self.debugger = Pdb(colors)
161 167
162 168 def __call__(self):
163 169 """Starts an interactive debugger at the point where called.
164 170
165 171 This is similar to the pdb.set_trace() function from the std lib, but
166 172 using IPython's enhanced debugger."""
167 173
168 174 self.debugger.set_trace(sys._getframe().f_back)
169 175
170 176
171 177 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
172 178 """Make new_fn have old_fn's doc string. This is particularly useful
173 179 for the ``do_...`` commands that hook into the help system.
174 180 Adapted from from a comp.lang.python posting
175 181 by Duncan Booth."""
176 182 def wrapper(*args, **kw):
177 183 return new_fn(*args, **kw)
178 184 if old_fn.__doc__:
179 185 wrapper.__doc__ = old_fn.__doc__ + additional_text
180 186 return wrapper
181 187
182 188
183 189 def _file_lines(fname):
184 190 """Return the contents of a named file as a list of lines.
185 191
186 192 This function never raises an IOError exception: if the file can't be
187 193 read, it simply returns an empty list."""
188 194
189 195 try:
190 196 outfile = open(fname)
191 197 except IOError:
192 198 return []
193 199 else:
194 200 out = outfile.readlines()
195 201 outfile.close()
196 202 return out
197 203
198 204
199 205 class Pdb(OldPdb, object):
200 """Modified Pdb class, does not load readline."""
206 """Modified Pdb class, does not load readline.
207
208 for a standalone version that uses promtp_toolkit, see
209 `IPython.terminal.debugger.TerminalPdb` and
210 `IPython.terminal.debugger.set_trace()`
211 """
201 212
202 213 def __init__(self, color_scheme=None, completekey=None,
203 214 stdin=None, stdout=None, context=5):
204 215
205 216 # Parent constructor:
206 217 try:
207 218 self.context = int(context)
208 219 if self.context <= 0:
209 220 raise ValueError("Context must be a positive integer")
210 221 except (TypeError, ValueError):
211 222 raise ValueError("Context must be a positive integer")
212 223
213 224 OldPdb.__init__(self, completekey, stdin, stdout)
214 225
215 226 # IPython changes...
216 227 self.shell = get_ipython()
217 228
218 229 if self.shell is None:
219 230 # No IPython instance running, we must create one
220 231 from IPython.terminal.interactiveshell import \
221 232 TerminalInteractiveShell
222 233 self.shell = TerminalInteractiveShell.instance()
223 234
224 235 if color_scheme is not None:
225 236 warnings.warn(
226 237 "The `color_scheme` argument is deprecated since version 5.1",
227 238 DeprecationWarning)
228 239 else:
229 240 color_scheme = self.shell.colors
230 241
231 242 self.aliases = {}
232 243
233 244 # Create color table: we copy the default one from the traceback
234 245 # module and add a few attributes needed for debugging
235 246 self.color_scheme_table = exception_colors()
236 247
237 248 # shorthands
238 249 C = coloransi.TermColors
239 250 cst = self.color_scheme_table
240 251
241 252 cst['NoColor'].colors.prompt = C.NoColor
242 253 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
243 254 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
244 255
245 256 cst['Linux'].colors.prompt = C.Green
246 257 cst['Linux'].colors.breakpoint_enabled = C.LightRed
247 258 cst['Linux'].colors.breakpoint_disabled = C.Red
248 259
249 260 cst['LightBG'].colors.prompt = C.Blue
250 261 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
251 262 cst['LightBG'].colors.breakpoint_disabled = C.Red
252 263
253 264 cst['Neutral'].colors.prompt = C.Blue
254 265 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
255 266 cst['Neutral'].colors.breakpoint_disabled = C.Red
256 267
257 268 self.set_colors(color_scheme)
258 269
259 270 # Add a python parser so we can syntax highlight source while
260 271 # debugging.
261 272 self.parser = PyColorize.Parser()
262 273
263 274 # Set the prompt - the default prompt is '(Pdb)'
264 275 self.prompt = prompt
265 276
266 277 def set_colors(self, scheme):
267 278 """Shorthand access to the color table scheme selector method."""
268 279 self.color_scheme_table.set_active_scheme(scheme)
269 280
270 281 def trace_dispatch(self, frame, event, arg):
271 282 try:
272 283 return super(Pdb, self).trace_dispatch(frame, event, arg)
273 284 except bdb.BdbQuit:
274 285 pass
275 286
276 287 def interaction(self, frame, traceback):
277 288 try:
278 289 OldPdb.interaction(self, frame, traceback)
279 290 except KeyboardInterrupt:
280 291 sys.stdout.write('\n' + self.shell.get_exception_only())
281 292
282 293 def parseline(self, line):
283 294 if line.startswith("!!"):
284 295 # Force standard behavior.
285 296 return super(Pdb, self).parseline(line[2:])
286 297 # "Smart command mode" from pdb++: don't execute commands if a variable
287 298 # with the same name exists.
288 299 cmd, arg, newline = super(Pdb, self).parseline(line)
289 300 # Fix for #9611: Do not trigger smart command if the command is `exit`
290 301 # or `quit` and it would resolve to their *global* value (the
291 302 # `ExitAutocall` object). Just checking that it is not present in the
292 303 # locals dict is not enough as locals and globals match at the
293 304 # toplevel.
294 305 if ((cmd in self.curframe.f_locals or cmd in self.curframe.f_globals)
295 306 and not (cmd in ["exit", "quit"]
296 307 and (self.curframe.f_locals is self.curframe.f_globals
297 308 or cmd not in self.curframe.f_locals))):
298 309 return super(Pdb, self).parseline("!" + line)
299 310 return super(Pdb, self).parseline(line)
300 311
301 312 def new_do_up(self, arg):
302 313 OldPdb.do_up(self, arg)
303 314 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
304 315
305 316 def new_do_down(self, arg):
306 317 OldPdb.do_down(self, arg)
307 318
308 319 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
309 320
310 321 def new_do_frame(self, arg):
311 322 OldPdb.do_frame(self, arg)
312 323
313 324 def new_do_quit(self, arg):
314 325
315 326 if hasattr(self, 'old_all_completions'):
316 327 self.shell.Completer.all_completions=self.old_all_completions
317 328
318 329 return OldPdb.do_quit(self, arg)
319 330
320 331 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
321 332
322 333 def new_do_restart(self, arg):
323 334 """Restart command. In the context of ipython this is exactly the same
324 335 thing as 'quit'."""
325 336 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
326 337 return self.do_quit(arg)
327 338
328 339 def print_stack_trace(self, context=None):
329 340 if context is None:
330 341 context = self.context
331 342 try:
332 343 context=int(context)
333 344 if context <= 0:
334 345 raise ValueError("Context must be a positive integer")
335 346 except (TypeError, ValueError):
336 347 raise ValueError("Context must be a positive integer")
337 348 try:
338 349 for frame_lineno in self.stack:
339 350 self.print_stack_entry(frame_lineno, context=context)
340 351 except KeyboardInterrupt:
341 352 pass
342 353
343 354 def print_stack_entry(self,frame_lineno, prompt_prefix='\n-> ',
344 355 context=None):
345 356 if context is None:
346 357 context = self.context
347 358 try:
348 359 context=int(context)
349 360 if context <= 0:
350 361 raise ValueError("Context must be a positive integer")
351 362 except (TypeError, ValueError):
352 363 raise ValueError("Context must be a positive integer")
353 364 print(self.format_stack_entry(frame_lineno, '', context))
354 365
355 366 # vds: >>
356 367 frame, lineno = frame_lineno
357 368 filename = frame.f_code.co_filename
358 369 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
359 370 # vds: <<
360 371
361 372 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
362 373 if context is None:
363 374 context = self.context
364 375 try:
365 376 context=int(context)
366 377 if context <= 0:
367 378 print("Context must be a positive integer")
368 379 except (TypeError, ValueError):
369 380 print("Context must be a positive integer")
370 381 try:
371 382 import reprlib # Py 3
372 383 except ImportError:
373 384 import repr as reprlib # Py 2
374 385
375 386 ret = []
376 387
377 388 Colors = self.color_scheme_table.active_colors
378 389 ColorsNormal = Colors.Normal
379 390 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
380 391 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
381 392 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
382 393 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
383 394 ColorsNormal)
384 395
385 396 frame, lineno = frame_lineno
386 397
387 398 return_value = ''
388 399 if '__return__' in frame.f_locals:
389 400 rv = frame.f_locals['__return__']
390 401 #return_value += '->'
391 402 return_value += reprlib.repr(rv) + '\n'
392 403 ret.append(return_value)
393 404
394 405 #s = filename + '(' + `lineno` + ')'
395 406 filename = self.canonic(frame.f_code.co_filename)
396 407 link = tpl_link % py3compat.cast_unicode(filename)
397 408
398 409 if frame.f_code.co_name:
399 410 func = frame.f_code.co_name
400 411 else:
401 412 func = "<lambda>"
402 413
403 414 call = ''
404 415 if func != '?':
405 416 if '__args__' in frame.f_locals:
406 417 args = reprlib.repr(frame.f_locals['__args__'])
407 418 else:
408 419 args = '()'
409 420 call = tpl_call % (func, args)
410 421
411 422 # The level info should be generated in the same format pdb uses, to
412 423 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
413 424 if frame is self.curframe:
414 425 ret.append('> ')
415 426 else:
416 427 ret.append(' ')
417 428 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
418 429
419 430 start = lineno - 1 - context//2
420 431 lines = ulinecache.getlines(filename)
421 432 start = min(start, len(lines) - context)
422 433 start = max(start, 0)
423 434 lines = lines[start : start + context]
424 435
425 436 for i,line in enumerate(lines):
426 437 show_arrow = (start + 1 + i == lineno)
427 438 linetpl = (frame is self.curframe or show_arrow) \
428 439 and tpl_line_em \
429 440 or tpl_line
430 441 ret.append(self.__format_line(linetpl, filename,
431 442 start + 1 + i, line,
432 443 arrow = show_arrow) )
433 444 return ''.join(ret)
434 445
435 446 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
436 447 bp_mark = ""
437 448 bp_mark_color = ""
438 449
439 450 scheme = self.color_scheme_table.active_scheme_name
440 451 new_line, err = self.parser.format2(line, 'str', scheme)
441 452 if not err: line = new_line
442 453
443 454 bp = None
444 455 if lineno in self.get_file_breaks(filename):
445 456 bps = self.get_breaks(filename, lineno)
446 457 bp = bps[-1]
447 458
448 459 if bp:
449 460 Colors = self.color_scheme_table.active_colors
450 461 bp_mark = str(bp.number)
451 462 bp_mark_color = Colors.breakpoint_enabled
452 463 if not bp.enabled:
453 464 bp_mark_color = Colors.breakpoint_disabled
454 465
455 466 numbers_width = 7
456 467 if arrow:
457 468 # This is the line with the error
458 469 pad = numbers_width - len(str(lineno)) - len(bp_mark)
459 470 num = '%s%s' % (make_arrow(pad), str(lineno))
460 471 else:
461 472 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
462 473
463 474 return tpl_line % (bp_mark_color + bp_mark, num, line)
464 475
465 476
466 477 def print_list_lines(self, filename, first, last):
467 478 """The printing (as opposed to the parsing part of a 'list'
468 479 command."""
469 480 try:
470 481 Colors = self.color_scheme_table.active_colors
471 482 ColorsNormal = Colors.Normal
472 483 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
473 484 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
474 485 src = []
475 486 if filename == "<string>" and hasattr(self, "_exec_filename"):
476 487 filename = self._exec_filename
477 488
478 489 for lineno in range(first, last+1):
479 490 line = ulinecache.getline(filename, lineno)
480 491 if not line:
481 492 break
482 493
483 494 if lineno == self.curframe.f_lineno:
484 495 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
485 496 else:
486 497 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
487 498
488 499 src.append(line)
489 500 self.lineno = lineno
490 501
491 502 print(''.join(src))
492 503
493 504 except KeyboardInterrupt:
494 505 pass
495 506
496 507 def do_list(self, arg):
497 508 self.lastcmd = 'list'
498 509 last = None
499 510 if arg:
500 511 try:
501 512 x = eval(arg, {}, {})
502 513 if type(x) == type(()):
503 514 first, last = x
504 515 first = int(first)
505 516 last = int(last)
506 517 if last < first:
507 518 # Assume it's a count
508 519 last = first + last
509 520 else:
510 521 first = max(1, int(x) - 5)
511 522 except:
512 523 print('*** Error in argument:', repr(arg))
513 524 return
514 525 elif self.lineno is None:
515 526 first = max(1, self.curframe.f_lineno - 5)
516 527 else:
517 528 first = self.lineno + 1
518 529 if last is None:
519 530 last = first + 10
520 531 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
521 532
522 533 # vds: >>
523 534 lineno = first
524 535 filename = self.curframe.f_code.co_filename
525 536 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
526 537 # vds: <<
527 538
528 539 do_l = do_list
529 540
530 541 def getsourcelines(self, obj):
531 542 lines, lineno = inspect.findsource(obj)
532 543 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
533 544 # must be a module frame: do not try to cut a block out of it
534 545 return lines, 1
535 546 elif inspect.ismodule(obj):
536 547 return lines, 1
537 548 return inspect.getblock(lines[lineno:]), lineno+1
538 549
539 550 def do_longlist(self, arg):
540 551 self.lastcmd = 'longlist'
541 552 try:
542 553 lines, lineno = self.getsourcelines(self.curframe)
543 554 except OSError as err:
544 555 self.error(err)
545 556 return
546 557 last = lineno + len(lines)
547 558 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
548 559 do_ll = do_longlist
549 560
550 561 def do_pdef(self, arg):
551 562 """Print the call signature for any callable object.
552 563
553 564 The debugger interface to %pdef"""
554 565 namespaces = [('Locals', self.curframe.f_locals),
555 566 ('Globals', self.curframe.f_globals)]
556 567 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
557 568
558 569 def do_pdoc(self, arg):
559 570 """Print the docstring for an object.
560 571
561 572 The debugger interface to %pdoc."""
562 573 namespaces = [('Locals', self.curframe.f_locals),
563 574 ('Globals', self.curframe.f_globals)]
564 575 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
565 576
566 577 def do_pfile(self, arg):
567 578 """Print (or run through pager) the file where an object is defined.
568 579
569 580 The debugger interface to %pfile.
570 581 """
571 582 namespaces = [('Locals', self.curframe.f_locals),
572 583 ('Globals', self.curframe.f_globals)]
573 584 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
574 585
575 586 def do_pinfo(self, arg):
576 587 """Provide detailed information about an object.
577 588
578 589 The debugger interface to %pinfo, i.e., obj?."""
579 590 namespaces = [('Locals', self.curframe.f_locals),
580 591 ('Globals', self.curframe.f_globals)]
581 592 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
582 593
583 594 def do_pinfo2(self, arg):
584 595 """Provide extra detailed information about an object.
585 596
586 597 The debugger interface to %pinfo2, i.e., obj??."""
587 598 namespaces = [('Locals', self.curframe.f_locals),
588 599 ('Globals', self.curframe.f_globals)]
589 600 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
590 601
591 602 def do_psource(self, arg):
592 603 """Print (or run through pager) the source code for an object."""
593 604 namespaces = [('Locals', self.curframe.f_locals),
594 605 ('Globals', self.curframe.f_globals)]
595 606 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
596 607
597 608 if sys.version_info > (3, ):
598 609 def do_where(self, arg):
599 610 """w(here)
600 611 Print a stack trace, with the most recent frame at the bottom.
601 612 An arrow indicates the "current frame", which determines the
602 613 context of most commands. 'bt' is an alias for this command.
603 614
604 615 Take a number as argument as an (optional) number of context line to
605 616 print"""
606 617 if arg:
607 618 context = int(arg)
608 619 self.print_stack_trace(context)
609 620 else:
610 621 self.print_stack_trace()
611 622
612 623 do_w = do_where
@@ -1,73 +1,77 b''
1 1 from IPython.core.debugger import Pdb
2 2
3 3 from IPython.core.completer import IPCompleter
4 4 from .ptutils import IPythonPTCompleter
5 5
6 6 from prompt_toolkit.token import Token
7 7 from prompt_toolkit.shortcuts import create_prompt_application
8 8 from prompt_toolkit.interface import CommandLineInterface
9 9 from prompt_toolkit.enums import EditingMode
10 10
11 11 class TerminalPdb(Pdb):
12 12 def __init__(self, *args, **kwargs):
13 13 Pdb.__init__(self, *args, **kwargs)
14 14 self._ptcomp = None
15 15 self.pt_init()
16 16
17 17 def pt_init(self):
18 18 def get_prompt_tokens(cli):
19 19 return [(Token.Prompt, self.prompt)]
20 20
21 21 if self._ptcomp is None:
22 22 compl = IPCompleter(shell=self.shell,
23 23 namespace={},
24 24 global_namespace={},
25 25 use_readline=False,
26 26 parent=self.shell,
27 27 )
28 28 self._ptcomp = IPythonPTCompleter(compl)
29 29
30 30 self._pt_app = create_prompt_application(
31 31 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
32 32 history=self.shell.debugger_history,
33 33 completer= self._ptcomp,
34 34 enable_history_search=True,
35 35 mouse_support=self.shell.mouse_support,
36 36 get_prompt_tokens=get_prompt_tokens
37 37 )
38 38 self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
39 39
40 40 def cmdloop(self, intro=None):
41 41 """Repeatedly issue a prompt, accept input, parse an initial prefix
42 42 off the received input, and dispatch to action methods, passing them
43 43 the remainder of the line as argument.
44 44
45 45 override the same methods from cmd.Cmd to provide prompt toolkit replacement.
46 46 """
47 47 if not self.use_rawinput:
48 48 raise ValueError('Sorry ipdb does not support use_rawinput=False')
49 49
50 50 self.preloop()
51 51
52 52 try:
53 53 if intro is not None:
54 54 self.intro = intro
55 55 if self.intro:
56 56 self.stdout.write(str(self.intro)+"\n")
57 57 stop = None
58 58 while not stop:
59 59 if self.cmdqueue:
60 60 line = self.cmdqueue.pop(0)
61 61 else:
62 62 self._ptcomp.ipy_completer.namespace = self.curframe_locals
63 63 self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
64 64 try:
65 65 line = self.pt_cli.run(reset_current_buffer=True).text
66 66 except EOFError:
67 67 line = 'EOF'
68 68 line = self.precmd(line)
69 69 stop = self.onecmd(line)
70 70 stop = self.postcmd(stop, line)
71 71 self.postloop()
72 72 except Exception:
73 73 raise
74
75 def set_trace():
76 TerminalPdb().set_trace()
77
General Comments 0
You need to be logged in to leave comments. Login now