-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
shell.py
134 lines (114 loc) · 4.2 KB
/
shell.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2009- Spyder Kernels Contributors
#
# Licensed under the terms of the MIT License
# (see spyder_kernels/__init__.py for details)
# -----------------------------------------------------------------------------
"""
Spyder shell for Jupyter kernels.
"""
# Standard library imports
import bdb
import sys
import traceback
# Third-party imports
from ipykernel.zmqshell import ZMQInteractiveShell
# Local imports
from spyder_kernels.utils.mpl import automatic_backend
class SpyderShell(ZMQInteractiveShell):
"""Spyder shell."""
def __init__(self, *args, **kwargs):
# Create _pdb_obj before __init__
self._pdb_obj = None
super(SpyderShell, self).__init__(*args, **kwargs)
def _showtraceback(self, etype, evalue, stb):
"""
Don't show a traceback when exiting our debugger after entering
it through a `breakpoint()` call.
This is because calling `!exit` after `breakpoint()` raises
BdbQuit, which throws a long and useless traceback.
"""
if etype is bdb.BdbQuit:
stb = ['']
super(SpyderShell, self)._showtraceback(etype, evalue, stb)
def enable_matplotlib(self, gui=None):
"""Enable matplotlib."""
if gui is None or gui.lower() == "auto":
gui = automatic_backend()
gui, backend = super(SpyderShell, self).enable_matplotlib(gui)
try:
self.kernel.frontend_call(blocking=False).update_matplotlib_gui(gui)
except Exception:
pass
return gui, backend
# --- For Pdb namespace integration
def get_local_scope(self, stack_depth):
"""Get local scope at given frame depth."""
frame = sys._getframe(stack_depth + 1)
if self._pdb_frame is frame:
# Avoid calling f_locals on _pdb_frame
return self._pdb_obj.curframe_locals
else:
return frame.f_locals
def get_global_scope(self, stack_depth):
"""Get global scope at given frame depth."""
frame = sys._getframe(stack_depth + 1)
return frame.f_globals
def is_debugging(self):
"""
Check if we are currently debugging.
"""
return bool(self._pdb_frame)
@property
def pdb_session(self):
"""Get current pdb session."""
return self._pdb_obj
@pdb_session.setter
def pdb_session(self, pdb_obj):
"""Register Pdb session to use it later"""
self._pdb_obj = pdb_obj
@property
def _pdb_frame(self):
"""Return current Pdb frame if there is any"""
if self.pdb_session is not None:
return self.pdb_session.curframe
@property
def _pdb_locals(self):
"""
Return current Pdb frame locals if available. Otherwise
return an empty dictionary
"""
if self._pdb_frame is not None:
return self._pdb_obj.curframe_locals
else:
return {}
@property
def user_ns(self):
"""Get the current namespace."""
if self._pdb_frame is not None:
return self._pdb_frame.f_globals
else:
return self.__user_ns
@user_ns.setter
def user_ns(self, namespace):
"""Set user_ns."""
self.__user_ns = namespace
def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
exception_only=False, running_compiled_code=False):
"""Display the exception that just occurred."""
super(SpyderShell, self).showtraceback(
exc_tuple, filename, tb_offset,
exception_only, running_compiled_code)
if not exception_only:
try:
etype, value, tb = self._get_exc_info(exc_tuple)
stack = traceback.extract_tb(tb.tb_next)
for f_summary, f in zip(
stack, traceback.walk_tb(tb.tb_next)):
f_summary.locals = self.kernel.get_namespace_view(
frame=f[0])
self.kernel.frontend_call(blocking=False).show_traceback(
etype, value, stack)
except Exception:
return