##// END OF EJS Templates
fix uncaught `BdbQuit` exceptions on ipdb `exit`...
telamonian -
r27657:fc235985
parent child
Show More
@@ -1,32 +1,40
1 MANIFEST
1 MANIFEST
2 build
2 build
3 dist
3 dist
4 _build
4 _build
5 docs/man/*.gz
5 docs/man/*.gz
6 docs/source/api/generated
6 docs/source/api/generated
7 docs/source/config/options
7 docs/source/config/options
8 docs/source/config/shortcuts/*.csv
8 docs/source/config/shortcuts/*.csv
9 docs/source/savefig
9 docs/source/savefig
10 docs/source/interactive/magics-generated.txt
10 docs/source/interactive/magics-generated.txt
11 docs/gh-pages
11 docs/gh-pages
12 jupyter_notebook/notebook/static/mathjax
12 jupyter_notebook/notebook/static/mathjax
13 jupyter_notebook/static/style/*.map
13 jupyter_notebook/static/style/*.map
14 *.py[co]
14 *.py[co]
15 __pycache__
15 __pycache__
16 *.egg-info
16 *.egg-info
17 *~
17 *~
18 *.bak
18 *.bak
19 .ipynb_checkpoints
19 .ipynb_checkpoints
20 .tox
20 .tox
21 .DS_Store
21 .DS_Store
22 \#*#
22 \#*#
23 .#*
23 .#*
24 .cache
24 .cache
25 .coverage
25 .coverage
26 *.swp
26 *.swp
27 .vscode
27 .vscode
28 .pytest_cache
28 .pytest_cache
29 .python-version
29 .python-version
30 venv*/
30 venv*/
31 .idea/
32 .mypy_cache/
31 .mypy_cache/
32
33 # jetbrains ide stuff
34 *.iml
35 .idea/
36
37 # vscode ide stuff
38 *.code-workspace
39 .history
40 .vscode
@@ -1,1000 +1,999
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5
5
6 This is an extension to PDB which adds a number of new features.
6 This is an extension to PDB which adds a number of new features.
7 Note that there is also the `IPython.terminal.debugger` class which provides UI
7 Note that there is also the `IPython.terminal.debugger` class which provides UI
8 improvements.
8 improvements.
9
9
10 We also strongly recommend to use this via the `ipdb` package, which provides
10 We also strongly recommend to use this via the `ipdb` package, which provides
11 extra configuration options.
11 extra configuration options.
12
12
13 Among other things, this subclass of PDB:
13 Among other things, this subclass of PDB:
14 - supports many IPython magics like pdef/psource
14 - supports many IPython magics like pdef/psource
15 - hide frames in tracebacks based on `__tracebackhide__`
15 - hide frames in tracebacks based on `__tracebackhide__`
16 - allows to skip frames based on `__debuggerskip__`
16 - allows to skip frames based on `__debuggerskip__`
17
17
18 The skipping and hiding frames are configurable via the `skip_predicates`
18 The skipping and hiding frames are configurable via the `skip_predicates`
19 command.
19 command.
20
20
21 By default, frames from readonly files will be hidden, frames containing
21 By default, frames from readonly files will be hidden, frames containing
22 ``__tracebackhide__=True`` will be hidden.
22 ``__tracebackhide__=True`` will be hidden.
23
23
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
24 Frames containing ``__debuggerskip__`` will be stepped over, frames who's parent
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
25 frames value of ``__debuggerskip__`` is ``True`` will be skipped.
26
26
27 >>> def helpers_helper():
27 >>> def helpers_helper():
28 ... pass
28 ... pass
29 ...
29 ...
30 ... def helper_1():
30 ... def helper_1():
31 ... print("don't step in me")
31 ... print("don't step in me")
32 ... helpers_helpers() # will be stepped over unless breakpoint set.
32 ... helpers_helpers() # will be stepped over unless breakpoint set.
33 ...
33 ...
34 ...
34 ...
35 ... def helper_2():
35 ... def helper_2():
36 ... print("in me neither")
36 ... print("in me neither")
37 ...
37 ...
38
38
39 One can define a decorator that wraps a function between the two helpers:
39 One can define a decorator that wraps a function between the two helpers:
40
40
41 >>> def pdb_skipped_decorator(function):
41 >>> def pdb_skipped_decorator(function):
42 ...
42 ...
43 ...
43 ...
44 ... def wrapped_fn(*args, **kwargs):
44 ... def wrapped_fn(*args, **kwargs):
45 ... __debuggerskip__ = True
45 ... __debuggerskip__ = True
46 ... helper_1()
46 ... helper_1()
47 ... __debuggerskip__ = False
47 ... __debuggerskip__ = False
48 ... result = function(*args, **kwargs)
48 ... result = function(*args, **kwargs)
49 ... __debuggerskip__ = True
49 ... __debuggerskip__ = True
50 ... helper_2()
50 ... helper_2()
51 ... # setting __debuggerskip__ to False again is not necessary
51 ... # setting __debuggerskip__ to False again is not necessary
52 ... return result
52 ... return result
53 ...
53 ...
54 ... return wrapped_fn
54 ... return wrapped_fn
55
55
56 When decorating a function, ipdb will directly step into ``bar()`` by
56 When decorating a function, ipdb will directly step into ``bar()`` by
57 default:
57 default:
58
58
59 >>> @foo_decorator
59 >>> @foo_decorator
60 ... def bar(x, y):
60 ... def bar(x, y):
61 ... return x * y
61 ... return x * y
62
62
63
63
64 You can toggle the behavior with
64 You can toggle the behavior with
65
65
66 ipdb> skip_predicates debuggerskip false
66 ipdb> skip_predicates debuggerskip false
67
67
68 or configure it in your ``.pdbrc``
68 or configure it in your ``.pdbrc``
69
69
70
70
71
71
72 License
72 License
73 -------
73 -------
74
74
75 Modified from the standard pdb.Pdb class to avoid including readline, so that
75 Modified from the standard pdb.Pdb class to avoid including readline, so that
76 the command line completion of other programs which include this isn't
76 the command line completion of other programs which include this isn't
77 damaged.
77 damaged.
78
78
79 In the future, this class will be expanded with improvements over the standard
79 In the future, this class will be expanded with improvements over the standard
80 pdb.
80 pdb.
81
81
82 The original code in this file is mainly lifted out of cmd.py in Python 2.2,
82 The original code in this file is mainly lifted out of cmd.py in Python 2.2,
83 with minor changes. Licensing should therefore be under the standard Python
83 with minor changes. Licensing should therefore be under the standard Python
84 terms. For details on the PSF (Python Software Foundation) standard license,
84 terms. For details on the PSF (Python Software Foundation) standard license,
85 see:
85 see:
86
86
87 https://docs.python.org/2/license.html
87 https://docs.python.org/2/license.html
88
88
89
89
90 All the changes since then are under the same license as IPython.
90 All the changes since then are under the same license as IPython.
91
91
92 """
92 """
93
93
94 #*****************************************************************************
94 #*****************************************************************************
95 #
95 #
96 # This file is licensed under the PSF license.
96 # This file is licensed under the PSF license.
97 #
97 #
98 # Copyright (C) 2001 Python Software Foundation, www.python.org
98 # Copyright (C) 2001 Python Software Foundation, www.python.org
99 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
99 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
100 #
100 #
101 #
101 #
102 #*****************************************************************************
102 #*****************************************************************************
103
103
104 import bdb
105 import inspect
104 import inspect
106 import linecache
105 import linecache
107 import sys
106 import sys
108 import warnings
107 import warnings
109 import re
108 import re
110 import os
109 import os
111
110
112 from IPython import get_ipython
111 from IPython import get_ipython
113 from IPython.utils import PyColorize
112 from IPython.utils import PyColorize
114 from IPython.utils import coloransi, py3compat
113 from IPython.utils import coloransi, py3compat
115 from IPython.core.excolors import exception_colors
114 from IPython.core.excolors import exception_colors
116
115
117 # skip module docstests
116 # skip module docstests
118 __skip_doctest__ = True
117 __skip_doctest__ = True
119
118
120 prompt = 'ipdb> '
119 prompt = 'ipdb> '
121
120
122 # We have to check this directly from sys.argv, config struct not yet available
121 # We have to check this directly from sys.argv, config struct not yet available
123 from pdb import Pdb as OldPdb
122 from pdb import Pdb as OldPdb
124
123
125 # Allow the set_trace code to operate outside of an ipython instance, even if
124 # Allow the set_trace code to operate outside of an ipython instance, even if
126 # it does so with some limitations. The rest of this support is implemented in
125 # it does so with some limitations. The rest of this support is implemented in
127 # the Tracer constructor.
126 # the Tracer constructor.
128
127
129 DEBUGGERSKIP = "__debuggerskip__"
128 DEBUGGERSKIP = "__debuggerskip__"
130
129
131
130
132 def make_arrow(pad):
131 def make_arrow(pad):
133 """generate the leading arrow in front of traceback or debugger"""
132 """generate the leading arrow in front of traceback or debugger"""
134 if pad >= 2:
133 if pad >= 2:
135 return '-'*(pad-2) + '> '
134 return '-'*(pad-2) + '> '
136 elif pad == 1:
135 elif pad == 1:
137 return '>'
136 return '>'
138 return ''
137 return ''
139
138
140
139
141 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
140 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
142 """Exception hook which handles `BdbQuit` exceptions.
141 """Exception hook which handles `BdbQuit` exceptions.
143
142
144 All other exceptions are processed using the `excepthook`
143 All other exceptions are processed using the `excepthook`
145 parameter.
144 parameter.
146 """
145 """
147 raise ValueError(
146 raise ValueError(
148 "`BdbQuit_excepthook` is deprecated since version 5.1",
147 "`BdbQuit_excepthook` is deprecated since version 5.1",
149 )
148 )
150
149
151
150
152 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
151 def BdbQuit_IPython_excepthook(self, et, ev, tb, tb_offset=None):
153 raise ValueError(
152 raise ValueError(
154 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
153 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
155 DeprecationWarning, stacklevel=2)
154 DeprecationWarning, stacklevel=2)
156
155
157
156
158 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
157 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
159
158
160
159
161 def strip_indentation(multiline_string):
160 def strip_indentation(multiline_string):
162 return RGX_EXTRA_INDENT.sub('', multiline_string)
161 return RGX_EXTRA_INDENT.sub('', multiline_string)
163
162
164
163
165 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
164 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
166 """Make new_fn have old_fn's doc string. This is particularly useful
165 """Make new_fn have old_fn's doc string. This is particularly useful
167 for the ``do_...`` commands that hook into the help system.
166 for the ``do_...`` commands that hook into the help system.
168 Adapted from from a comp.lang.python posting
167 Adapted from from a comp.lang.python posting
169 by Duncan Booth."""
168 by Duncan Booth."""
170 def wrapper(*args, **kw):
169 def wrapper(*args, **kw):
171 return new_fn(*args, **kw)
170 return new_fn(*args, **kw)
172 if old_fn.__doc__:
171 if old_fn.__doc__:
173 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
172 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
174 return wrapper
173 return wrapper
175
174
176
175
177 class Pdb(OldPdb):
176 class Pdb(OldPdb):
178 """Modified Pdb class, does not load readline.
177 """Modified Pdb class, does not load readline.
179
178
180 for a standalone version that uses prompt_toolkit, see
179 for a standalone version that uses prompt_toolkit, see
181 `IPython.terminal.debugger.TerminalPdb` and
180 `IPython.terminal.debugger.TerminalPdb` and
182 `IPython.terminal.debugger.set_trace()`
181 `IPython.terminal.debugger.set_trace()`
183
182
184
183
185 This debugger can hide and skip frames that are tagged according to some predicates.
184 This debugger can hide and skip frames that are tagged according to some predicates.
186 See the `skip_predicates` commands.
185 See the `skip_predicates` commands.
187
186
188 """
187 """
189
188
190 default_predicates = {
189 default_predicates = {
191 "tbhide": True,
190 "tbhide": True,
192 "readonly": False,
191 "readonly": False,
193 "ipython_internal": True,
192 "ipython_internal": True,
194 "debuggerskip": True,
193 "debuggerskip": True,
195 }
194 }
196
195
197 def __init__(self, completekey=None, stdin=None, stdout=None, context=5, **kwargs):
196 def __init__(self, completekey=None, stdin=None, stdout=None, context=5, **kwargs):
198 """Create a new IPython debugger.
197 """Create a new IPython debugger.
199
198
200 Parameters
199 Parameters
201 ----------
200 ----------
202 completekey : default None
201 completekey : default None
203 Passed to pdb.Pdb.
202 Passed to pdb.Pdb.
204 stdin : default None
203 stdin : default None
205 Passed to pdb.Pdb.
204 Passed to pdb.Pdb.
206 stdout : default None
205 stdout : default None
207 Passed to pdb.Pdb.
206 Passed to pdb.Pdb.
208 context : int
207 context : int
209 Number of lines of source code context to show when
208 Number of lines of source code context to show when
210 displaying stacktrace information.
209 displaying stacktrace information.
211 **kwargs
210 **kwargs
212 Passed to pdb.Pdb.
211 Passed to pdb.Pdb.
213
212
214 Notes
213 Notes
215 -----
214 -----
216 The possibilities are python version dependent, see the python
215 The possibilities are python version dependent, see the python
217 docs for more info.
216 docs for more info.
218 """
217 """
219
218
220 # Parent constructor:
219 # Parent constructor:
221 try:
220 try:
222 self.context = int(context)
221 self.context = int(context)
223 if self.context <= 0:
222 if self.context <= 0:
224 raise ValueError("Context must be a positive integer")
223 raise ValueError("Context must be a positive integer")
225 except (TypeError, ValueError) as e:
224 except (TypeError, ValueError) as e:
226 raise ValueError("Context must be a positive integer") from e
225 raise ValueError("Context must be a positive integer") from e
227
226
228 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
227 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
229 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
228 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
230
229
231 # IPython changes...
230 # IPython changes...
232 self.shell = get_ipython()
231 self.shell = get_ipython()
233
232
234 if self.shell is None:
233 if self.shell is None:
235 save_main = sys.modules['__main__']
234 save_main = sys.modules['__main__']
236 # No IPython instance running, we must create one
235 # No IPython instance running, we must create one
237 from IPython.terminal.interactiveshell import \
236 from IPython.terminal.interactiveshell import \
238 TerminalInteractiveShell
237 TerminalInteractiveShell
239 self.shell = TerminalInteractiveShell.instance()
238 self.shell = TerminalInteractiveShell.instance()
240 # needed by any code which calls __import__("__main__") after
239 # needed by any code which calls __import__("__main__") after
241 # the debugger was entered. See also #9941.
240 # the debugger was entered. See also #9941.
242 sys.modules["__main__"] = save_main
241 sys.modules["__main__"] = save_main
243
242
244
243
245 color_scheme = self.shell.colors
244 color_scheme = self.shell.colors
246
245
247 self.aliases = {}
246 self.aliases = {}
248
247
249 # Create color table: we copy the default one from the traceback
248 # Create color table: we copy the default one from the traceback
250 # module and add a few attributes needed for debugging
249 # module and add a few attributes needed for debugging
251 self.color_scheme_table = exception_colors()
250 self.color_scheme_table = exception_colors()
252
251
253 # shorthands
252 # shorthands
254 C = coloransi.TermColors
253 C = coloransi.TermColors
255 cst = self.color_scheme_table
254 cst = self.color_scheme_table
256
255
257 cst['NoColor'].colors.prompt = C.NoColor
256 cst['NoColor'].colors.prompt = C.NoColor
258 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
257 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
259 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
258 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
260
259
261 cst['Linux'].colors.prompt = C.Green
260 cst['Linux'].colors.prompt = C.Green
262 cst['Linux'].colors.breakpoint_enabled = C.LightRed
261 cst['Linux'].colors.breakpoint_enabled = C.LightRed
263 cst['Linux'].colors.breakpoint_disabled = C.Red
262 cst['Linux'].colors.breakpoint_disabled = C.Red
264
263
265 cst['LightBG'].colors.prompt = C.Blue
264 cst['LightBG'].colors.prompt = C.Blue
266 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
265 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
267 cst['LightBG'].colors.breakpoint_disabled = C.Red
266 cst['LightBG'].colors.breakpoint_disabled = C.Red
268
267
269 cst['Neutral'].colors.prompt = C.Blue
268 cst['Neutral'].colors.prompt = C.Blue
270 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
269 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
271 cst['Neutral'].colors.breakpoint_disabled = C.Red
270 cst['Neutral'].colors.breakpoint_disabled = C.Red
272
271
273 # Add a python parser so we can syntax highlight source while
272 # Add a python parser so we can syntax highlight source while
274 # debugging.
273 # debugging.
275 self.parser = PyColorize.Parser(style=color_scheme)
274 self.parser = PyColorize.Parser(style=color_scheme)
276 self.set_colors(color_scheme)
275 self.set_colors(color_scheme)
277
276
278 # Set the prompt - the default prompt is '(Pdb)'
277 # Set the prompt - the default prompt is '(Pdb)'
279 self.prompt = prompt
278 self.prompt = prompt
280 self.skip_hidden = True
279 self.skip_hidden = True
281 self.report_skipped = True
280 self.report_skipped = True
282
281
283 # list of predicates we use to skip frames
282 # list of predicates we use to skip frames
284 self._predicates = self.default_predicates
283 self._predicates = self.default_predicates
285
284
286 #
285 #
287 def set_colors(self, scheme):
286 def set_colors(self, scheme):
288 """Shorthand access to the color table scheme selector method."""
287 """Shorthand access to the color table scheme selector method."""
289 self.color_scheme_table.set_active_scheme(scheme)
288 self.color_scheme_table.set_active_scheme(scheme)
290 self.parser.style = scheme
289 self.parser.style = scheme
291
290
292 def set_trace(self, frame=None):
291 def set_trace(self, frame=None):
293 if frame is None:
292 if frame is None:
294 frame = sys._getframe().f_back
293 frame = sys._getframe().f_back
295 self.initial_frame = frame
294 self.initial_frame = frame
296 return super().set_trace(frame)
295 return super().set_trace(frame)
297
296
298 def _hidden_predicate(self, frame):
297 def _hidden_predicate(self, frame):
299 """
298 """
300 Given a frame return whether it it should be hidden or not by IPython.
299 Given a frame return whether it it should be hidden or not by IPython.
301 """
300 """
302
301
303 if self._predicates["readonly"]:
302 if self._predicates["readonly"]:
304 fname = frame.f_code.co_filename
303 fname = frame.f_code.co_filename
305 # we need to check for file existence and interactively define
304 # we need to check for file existence and interactively define
306 # function would otherwise appear as RO.
305 # function would otherwise appear as RO.
307 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
306 if os.path.isfile(fname) and not os.access(fname, os.W_OK):
308 return True
307 return True
309
308
310 if self._predicates["tbhide"]:
309 if self._predicates["tbhide"]:
311 if frame in (self.curframe, getattr(self, "initial_frame", None)):
310 if frame in (self.curframe, getattr(self, "initial_frame", None)):
312 return False
311 return False
313 frame_locals = self._get_frame_locals(frame)
312 frame_locals = self._get_frame_locals(frame)
314 if "__tracebackhide__" not in frame_locals:
313 if "__tracebackhide__" not in frame_locals:
315 return False
314 return False
316 return frame_locals["__tracebackhide__"]
315 return frame_locals["__tracebackhide__"]
317 return False
316 return False
318
317
319 def hidden_frames(self, stack):
318 def hidden_frames(self, stack):
320 """
319 """
321 Given an index in the stack return whether it should be skipped.
320 Given an index in the stack return whether it should be skipped.
322
321
323 This is used in up/down and where to skip frames.
322 This is used in up/down and where to skip frames.
324 """
323 """
325 # The f_locals dictionary is updated from the actual frame
324 # The f_locals dictionary is updated from the actual frame
326 # locals whenever the .f_locals accessor is called, so we
325 # locals whenever the .f_locals accessor is called, so we
327 # avoid calling it here to preserve self.curframe_locals.
326 # avoid calling it here to preserve self.curframe_locals.
328 # Furthermore, there is no good reason to hide the current frame.
327 # Furthermore, there is no good reason to hide the current frame.
329 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
328 ip_hide = [self._hidden_predicate(s[0]) for s in stack]
330 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
329 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
331 if ip_start and self._predicates["ipython_internal"]:
330 if ip_start and self._predicates["ipython_internal"]:
332 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
331 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
333 return ip_hide
332 return ip_hide
334
333
335 def interaction(self, frame, traceback):
334 def interaction(self, frame, traceback):
336 try:
335 try:
337 OldPdb.interaction(self, frame, traceback)
336 OldPdb.interaction(self, frame, traceback)
338 except KeyboardInterrupt:
337 except KeyboardInterrupt:
339 self.stdout.write("\n" + self.shell.get_exception_only())
338 self.stdout.write("\n" + self.shell.get_exception_only())
340
339
341 def precmd(self, line):
340 def precmd(self, line):
342 """Perform useful escapes on the command before it is executed."""
341 """Perform useful escapes on the command before it is executed."""
343
342
344 if line.endswith("??"):
343 if line.endswith("??"):
345 line = "pinfo2 " + line[:-2]
344 line = "pinfo2 " + line[:-2]
346 elif line.endswith("?"):
345 elif line.endswith("?"):
347 line = "pinfo " + line[:-1]
346 line = "pinfo " + line[:-1]
348
347
349 line = super().precmd(line)
348 line = super().precmd(line)
350
349
351 return line
350 return line
352
351
353 def new_do_frame(self, arg):
352 def new_do_frame(self, arg):
354 OldPdb.do_frame(self, arg)
353 OldPdb.do_frame(self, arg)
355
354
356 def new_do_quit(self, arg):
355 def new_do_quit(self, arg):
357
356
358 if hasattr(self, 'old_all_completions'):
357 if hasattr(self, 'old_all_completions'):
359 self.shell.Completer.all_completions = self.old_all_completions
358 self.shell.Completer.all_completions = self.old_all_completions
360
359
361 return OldPdb.do_quit(self, arg)
360 return OldPdb.do_quit(self, arg)
362
361
363 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
362 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
364
363
365 def new_do_restart(self, arg):
364 def new_do_restart(self, arg):
366 """Restart command. In the context of ipython this is exactly the same
365 """Restart command. In the context of ipython this is exactly the same
367 thing as 'quit'."""
366 thing as 'quit'."""
368 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
367 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
369 return self.do_quit(arg)
368 return self.do_quit(arg)
370
369
371 def print_stack_trace(self, context=None):
370 def print_stack_trace(self, context=None):
372 Colors = self.color_scheme_table.active_colors
371 Colors = self.color_scheme_table.active_colors
373 ColorsNormal = Colors.Normal
372 ColorsNormal = Colors.Normal
374 if context is None:
373 if context is None:
375 context = self.context
374 context = self.context
376 try:
375 try:
377 context = int(context)
376 context = int(context)
378 if context <= 0:
377 if context <= 0:
379 raise ValueError("Context must be a positive integer")
378 raise ValueError("Context must be a positive integer")
380 except (TypeError, ValueError) as e:
379 except (TypeError, ValueError) as e:
381 raise ValueError("Context must be a positive integer") from e
380 raise ValueError("Context must be a positive integer") from e
382 try:
381 try:
383 skipped = 0
382 skipped = 0
384 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
383 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
385 if hidden and self.skip_hidden:
384 if hidden and self.skip_hidden:
386 skipped += 1
385 skipped += 1
387 continue
386 continue
388 if skipped:
387 if skipped:
389 print(
388 print(
390 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
389 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
391 )
390 )
392 skipped = 0
391 skipped = 0
393 self.print_stack_entry(frame_lineno, context=context)
392 self.print_stack_entry(frame_lineno, context=context)
394 if skipped:
393 if skipped:
395 print(
394 print(
396 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
395 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
397 )
396 )
398 except KeyboardInterrupt:
397 except KeyboardInterrupt:
399 pass
398 pass
400
399
401 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
400 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
402 context=None):
401 context=None):
403 if context is None:
402 if context is None:
404 context = self.context
403 context = self.context
405 try:
404 try:
406 context = int(context)
405 context = int(context)
407 if context <= 0:
406 if context <= 0:
408 raise ValueError("Context must be a positive integer")
407 raise ValueError("Context must be a positive integer")
409 except (TypeError, ValueError) as e:
408 except (TypeError, ValueError) as e:
410 raise ValueError("Context must be a positive integer") from e
409 raise ValueError("Context must be a positive integer") from e
411 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
410 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
412
411
413 # vds: >>
412 # vds: >>
414 frame, lineno = frame_lineno
413 frame, lineno = frame_lineno
415 filename = frame.f_code.co_filename
414 filename = frame.f_code.co_filename
416 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
415 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
417 # vds: <<
416 # vds: <<
418
417
419 def _get_frame_locals(self, frame):
418 def _get_frame_locals(self, frame):
420 """ "
419 """ "
421 Accessing f_local of current frame reset the namespace, so we want to avoid
420 Accessing f_local of current frame reset the namespace, so we want to avoid
422 that or the following can happen
421 that or the following can happen
423
422
424 ipdb> foo
423 ipdb> foo
425 "old"
424 "old"
426 ipdb> foo = "new"
425 ipdb> foo = "new"
427 ipdb> foo
426 ipdb> foo
428 "new"
427 "new"
429 ipdb> where
428 ipdb> where
430 ipdb> foo
429 ipdb> foo
431 "old"
430 "old"
432
431
433 So if frame is self.current_frame we instead return self.curframe_locals
432 So if frame is self.current_frame we instead return self.curframe_locals
434
433
435 """
434 """
436 if frame is self.curframe:
435 if frame is self.curframe:
437 return self.curframe_locals
436 return self.curframe_locals
438 else:
437 else:
439 return frame.f_locals
438 return frame.f_locals
440
439
441 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
440 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
442 if context is None:
441 if context is None:
443 context = self.context
442 context = self.context
444 try:
443 try:
445 context = int(context)
444 context = int(context)
446 if context <= 0:
445 if context <= 0:
447 print("Context must be a positive integer", file=self.stdout)
446 print("Context must be a positive integer", file=self.stdout)
448 except (TypeError, ValueError):
447 except (TypeError, ValueError):
449 print("Context must be a positive integer", file=self.stdout)
448 print("Context must be a positive integer", file=self.stdout)
450
449
451 import reprlib
450 import reprlib
452
451
453 ret = []
452 ret = []
454
453
455 Colors = self.color_scheme_table.active_colors
454 Colors = self.color_scheme_table.active_colors
456 ColorsNormal = Colors.Normal
455 ColorsNormal = Colors.Normal
457 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
456 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
458 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
457 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
459 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
458 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
460 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
459 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
461
460
462 frame, lineno = frame_lineno
461 frame, lineno = frame_lineno
463
462
464 return_value = ''
463 return_value = ''
465 loc_frame = self._get_frame_locals(frame)
464 loc_frame = self._get_frame_locals(frame)
466 if "__return__" in loc_frame:
465 if "__return__" in loc_frame:
467 rv = loc_frame["__return__"]
466 rv = loc_frame["__return__"]
468 # return_value += '->'
467 # return_value += '->'
469 return_value += reprlib.repr(rv) + "\n"
468 return_value += reprlib.repr(rv) + "\n"
470 ret.append(return_value)
469 ret.append(return_value)
471
470
472 #s = filename + '(' + `lineno` + ')'
471 #s = filename + '(' + `lineno` + ')'
473 filename = self.canonic(frame.f_code.co_filename)
472 filename = self.canonic(frame.f_code.co_filename)
474 link = tpl_link % py3compat.cast_unicode(filename)
473 link = tpl_link % py3compat.cast_unicode(filename)
475
474
476 if frame.f_code.co_name:
475 if frame.f_code.co_name:
477 func = frame.f_code.co_name
476 func = frame.f_code.co_name
478 else:
477 else:
479 func = "<lambda>"
478 func = "<lambda>"
480
479
481 call = ""
480 call = ""
482 if func != "?":
481 if func != "?":
483 if "__args__" in loc_frame:
482 if "__args__" in loc_frame:
484 args = reprlib.repr(loc_frame["__args__"])
483 args = reprlib.repr(loc_frame["__args__"])
485 else:
484 else:
486 args = '()'
485 args = '()'
487 call = tpl_call % (func, args)
486 call = tpl_call % (func, args)
488
487
489 # The level info should be generated in the same format pdb uses, to
488 # The level info should be generated in the same format pdb uses, to
490 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
489 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
491 if frame is self.curframe:
490 if frame is self.curframe:
492 ret.append('> ')
491 ret.append('> ')
493 else:
492 else:
494 ret.append(" ")
493 ret.append(" ")
495 ret.append("%s(%s)%s\n" % (link, lineno, call))
494 ret.append("%s(%s)%s\n" % (link, lineno, call))
496
495
497 start = lineno - 1 - context//2
496 start = lineno - 1 - context//2
498 lines = linecache.getlines(filename)
497 lines = linecache.getlines(filename)
499 start = min(start, len(lines) - context)
498 start = min(start, len(lines) - context)
500 start = max(start, 0)
499 start = max(start, 0)
501 lines = lines[start : start + context]
500 lines = lines[start : start + context]
502
501
503 for i, line in enumerate(lines):
502 for i, line in enumerate(lines):
504 show_arrow = start + 1 + i == lineno
503 show_arrow = start + 1 + i == lineno
505 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
504 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
506 ret.append(
505 ret.append(
507 self.__format_line(
506 self.__format_line(
508 linetpl, filename, start + 1 + i, line, arrow=show_arrow
507 linetpl, filename, start + 1 + i, line, arrow=show_arrow
509 )
508 )
510 )
509 )
511 return "".join(ret)
510 return "".join(ret)
512
511
513 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
512 def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
514 bp_mark = ""
513 bp_mark = ""
515 bp_mark_color = ""
514 bp_mark_color = ""
516
515
517 new_line, err = self.parser.format2(line, 'str')
516 new_line, err = self.parser.format2(line, 'str')
518 if not err:
517 if not err:
519 line = new_line
518 line = new_line
520
519
521 bp = None
520 bp = None
522 if lineno in self.get_file_breaks(filename):
521 if lineno in self.get_file_breaks(filename):
523 bps = self.get_breaks(filename, lineno)
522 bps = self.get_breaks(filename, lineno)
524 bp = bps[-1]
523 bp = bps[-1]
525
524
526 if bp:
525 if bp:
527 Colors = self.color_scheme_table.active_colors
526 Colors = self.color_scheme_table.active_colors
528 bp_mark = str(bp.number)
527 bp_mark = str(bp.number)
529 bp_mark_color = Colors.breakpoint_enabled
528 bp_mark_color = Colors.breakpoint_enabled
530 if not bp.enabled:
529 if not bp.enabled:
531 bp_mark_color = Colors.breakpoint_disabled
530 bp_mark_color = Colors.breakpoint_disabled
532
531
533 numbers_width = 7
532 numbers_width = 7
534 if arrow:
533 if arrow:
535 # This is the line with the error
534 # This is the line with the error
536 pad = numbers_width - len(str(lineno)) - len(bp_mark)
535 pad = numbers_width - len(str(lineno)) - len(bp_mark)
537 num = '%s%s' % (make_arrow(pad), str(lineno))
536 num = '%s%s' % (make_arrow(pad), str(lineno))
538 else:
537 else:
539 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
538 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
540
539
541 return tpl_line % (bp_mark_color + bp_mark, num, line)
540 return tpl_line % (bp_mark_color + bp_mark, num, line)
542
541
543 def print_list_lines(self, filename, first, last):
542 def print_list_lines(self, filename, first, last):
544 """The printing (as opposed to the parsing part of a 'list'
543 """The printing (as opposed to the parsing part of a 'list'
545 command."""
544 command."""
546 try:
545 try:
547 Colors = self.color_scheme_table.active_colors
546 Colors = self.color_scheme_table.active_colors
548 ColorsNormal = Colors.Normal
547 ColorsNormal = Colors.Normal
549 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
548 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
550 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
549 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
551 src = []
550 src = []
552 if filename == "<string>" and hasattr(self, "_exec_filename"):
551 if filename == "<string>" and hasattr(self, "_exec_filename"):
553 filename = self._exec_filename
552 filename = self._exec_filename
554
553
555 for lineno in range(first, last+1):
554 for lineno in range(first, last+1):
556 line = linecache.getline(filename, lineno)
555 line = linecache.getline(filename, lineno)
557 if not line:
556 if not line:
558 break
557 break
559
558
560 if lineno == self.curframe.f_lineno:
559 if lineno == self.curframe.f_lineno:
561 line = self.__format_line(
560 line = self.__format_line(
562 tpl_line_em, filename, lineno, line, arrow=True
561 tpl_line_em, filename, lineno, line, arrow=True
563 )
562 )
564 else:
563 else:
565 line = self.__format_line(
564 line = self.__format_line(
566 tpl_line, filename, lineno, line, arrow=False
565 tpl_line, filename, lineno, line, arrow=False
567 )
566 )
568
567
569 src.append(line)
568 src.append(line)
570 self.lineno = lineno
569 self.lineno = lineno
571
570
572 print(''.join(src), file=self.stdout)
571 print(''.join(src), file=self.stdout)
573
572
574 except KeyboardInterrupt:
573 except KeyboardInterrupt:
575 pass
574 pass
576