116 lines
3.3 KiB
Python
116 lines
3.3 KiB
Python
# -*- 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
|
|
|
|
# Third-party imports
|
|
from ipykernel.zmqshell import ZMQInteractiveShell
|
|
|
|
|
|
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)
|
|
|
|
# register post_execute
|
|
self.events.register('post_execute', self.do_post_execute)
|
|
|
|
# ---- Methods overriden by us.
|
|
def ask_exit(self):
|
|
"""Engage the exit actions."""
|
|
self.kernel.frontend_comm.close_thread()
|
|
return super(SpyderShell, self).ask_exit()
|
|
|
|
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)
|
|
|
|
# ---- 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 do_post_execute(self):
|
|
"""Flush __std*__ after execution."""
|
|
# Flush C standard streams.
|
|
sys.__stderr__.flush()
|
|
sys.__stdout__.flush()
|