asm
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2009- Spyder Kernels Contributors
|
||||
#
|
||||
# Licensed under the terms of the MIT License
|
||||
# (see spyder_kernels/__init__.py for details)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
Console kernel
|
||||
"""
|
||||
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2009- Spyder Kernels Contributors
|
||||
#
|
||||
# Licensed under the terms of the MIT License
|
||||
# (see spyder_kernels/__init__.py for details)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Remove the current working directory from sys.path for Python 3.7+
|
||||
# because since that version it's added by default to sys.path when
|
||||
# using 'python -m'.
|
||||
if sys.version_info[0] == 3 and sys.version_info[1] >= 7:
|
||||
cwd = os.getcwd()
|
||||
if cwd in sys.path:
|
||||
sys.path.remove(cwd)
|
||||
|
||||
from spyder_kernels.console import start
|
||||
try:
|
||||
start.main()
|
||||
except Exception:
|
||||
# We have to explicitely write to __stderr__ as stderr might already
|
||||
# have been replaced.
|
||||
import traceback
|
||||
traceback.print_exc(file=sys.__stderr__)
|
||||
sys.__stderr__.flush()
|
||||
raise
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,867 @@
|
||||
# -*- 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 kernel for Jupyter.
|
||||
"""
|
||||
|
||||
# Standard library imports
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
|
||||
# Third-party imports
|
||||
from ipykernel.ipkernel import IPythonKernel
|
||||
from ipykernel import eventloops
|
||||
from traitlets.config.loader import LazyConfigValue
|
||||
|
||||
# Local imports
|
||||
from spyder_kernels.py3compat import (
|
||||
TEXT_TYPES, to_text_string, PY3)
|
||||
from spyder_kernels.comms.frontendcomm import FrontendComm
|
||||
from spyder_kernels.utils.iofuncs import iofunctions
|
||||
from spyder_kernels.utils.mpl import (
|
||||
MPL_BACKENDS_FROM_SPYDER, MPL_BACKENDS_TO_SPYDER, INLINE_FIGURE_FORMATS)
|
||||
from spyder_kernels.utils.nsview import (
|
||||
get_remote_data, make_remote_view, get_size)
|
||||
from spyder_kernels.console.shell import SpyderShell
|
||||
|
||||
if PY3:
|
||||
import faulthandler
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Excluded variables from the Variable Explorer (i.e. they are not
|
||||
# shown at all there)
|
||||
EXCLUDED_NAMES = ['In', 'Out', 'exit', 'get_ipython', 'quit']
|
||||
|
||||
|
||||
class SpyderKernel(IPythonKernel):
|
||||
"""Spyder kernel for Jupyter."""
|
||||
|
||||
shell_class = SpyderShell
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SpyderKernel, self).__init__(*args, **kwargs)
|
||||
|
||||
self.comm_manager.get_comm = self._get_comm
|
||||
self.frontend_comm = FrontendComm(self)
|
||||
|
||||
# All functions that can be called through the comm
|
||||
handlers = {
|
||||
'set_breakpoints': self.set_spyder_breakpoints,
|
||||
'set_pdb_ignore_lib': self.set_pdb_ignore_lib,
|
||||
'set_pdb_execute_events': self.set_pdb_execute_events,
|
||||
'set_pdb_use_exclamation_mark': self.set_pdb_use_exclamation_mark,
|
||||
'get_value': self.get_value,
|
||||
'load_data': self.load_data,
|
||||
'save_namespace': self.save_namespace,
|
||||
'is_defined': self.is_defined,
|
||||
'get_doc': self.get_doc,
|
||||
'get_source': self.get_source,
|
||||
'set_value': self.set_value,
|
||||
'remove_value': self.remove_value,
|
||||
'copy_value': self.copy_value,
|
||||
'set_cwd': self.set_cwd,
|
||||
'get_cwd': self.get_cwd,
|
||||
'get_syspath': self.get_syspath,
|
||||
'get_env': self.get_env,
|
||||
'close_all_mpl_figures': self.close_all_mpl_figures,
|
||||
'show_mpl_backend_errors': self.show_mpl_backend_errors,
|
||||
'get_namespace_view': self.get_namespace_view,
|
||||
'set_namespace_view_settings': self.set_namespace_view_settings,
|
||||
'get_var_properties': self.get_var_properties,
|
||||
'set_sympy_forecolor': self.set_sympy_forecolor,
|
||||
'update_syspath': self.update_syspath,
|
||||
'is_special_kernel_valid': self.is_special_kernel_valid,
|
||||
'get_matplotlib_backend': self.get_matplotlib_backend,
|
||||
'get_mpl_interactive_backend': self.get_mpl_interactive_backend,
|
||||
'pdb_input_reply': self.pdb_input_reply,
|
||||
'_interrupt_eventloop': self._interrupt_eventloop,
|
||||
'enable_faulthandler': self.enable_faulthandler,
|
||||
}
|
||||
for call_id in handlers:
|
||||
self.frontend_comm.register_call_handler(
|
||||
call_id, handlers[call_id])
|
||||
|
||||
self.namespace_view_settings = {}
|
||||
self._mpl_backend_error = None
|
||||
self._running_namespace = None
|
||||
self.faulthandler_handle = None
|
||||
|
||||
# -- Public API -----------------------------------------------------------
|
||||
def do_shutdown(self, restart):
|
||||
"""Disable faulthandler if enabled before proceeding."""
|
||||
self.disable_faulthandler()
|
||||
super(SpyderKernel, self).do_shutdown(restart)
|
||||
|
||||
def frontend_call(self, blocking=False, broadcast=True,
|
||||
timeout=None, callback=None):
|
||||
"""Call the frontend."""
|
||||
# If not broadcast, send only to the calling comm
|
||||
if broadcast:
|
||||
comm_id = None
|
||||
else:
|
||||
comm_id = self.frontend_comm.calling_comm_id
|
||||
|
||||
return self.frontend_comm.remote_call(
|
||||
blocking=blocking,
|
||||
comm_id=comm_id,
|
||||
callback=callback,
|
||||
timeout=timeout)
|
||||
|
||||
def enable_faulthandler(self, fn):
|
||||
"""
|
||||
Open a file to save the faulthandling and identifiers for
|
||||
internal threads.
|
||||
"""
|
||||
if not PY3:
|
||||
# Not implemented
|
||||
return
|
||||
self.disable_faulthandler()
|
||||
f = open(fn, 'w')
|
||||
self.faulthandler_handle = f
|
||||
f.write("Main thread id:\n")
|
||||
f.write(hex(threading.main_thread().ident))
|
||||
f.write('\nSystem threads ids:\n')
|
||||
f.write(" ".join([hex(thread.ident) for thread in threading.enumerate()
|
||||
if thread is not threading.main_thread()]))
|
||||
f.write('\n')
|
||||
faulthandler.enable(f)
|
||||
|
||||
def disable_faulthandler(self):
|
||||
"""
|
||||
Cancel the faulthandling, close the file handle and remove the file.
|
||||
"""
|
||||
if not PY3:
|
||||
# Not implemented
|
||||
return
|
||||
if self.faulthandler_handle:
|
||||
faulthandler.disable()
|
||||
self.faulthandler_handle.close()
|
||||
self.faulthandler_handle = None
|
||||
|
||||
# --- For the Variable Explorer
|
||||
def set_namespace_view_settings(self, settings):
|
||||
"""Set namespace_view_settings."""
|
||||
self.namespace_view_settings = settings
|
||||
|
||||
def get_namespace_view(self):
|
||||
"""
|
||||
Return the namespace view
|
||||
|
||||
This is a dictionary with the following structure
|
||||
|
||||
{'a':
|
||||
{
|
||||
'type': 'str',
|
||||
'size': 1,
|
||||
'view': '1',
|
||||
'python_type': 'int',
|
||||
'numpy_type': 'Unknown'
|
||||
}
|
||||
}
|
||||
|
||||
Here:
|
||||
* 'a' is the variable name.
|
||||
* 'type' and 'size' are self-evident.
|
||||
* 'view' is its value or its repr computed with
|
||||
`value_to_display`.
|
||||
* 'python_type' is its Python type computed with
|
||||
`get_type_string`.
|
||||
* 'numpy_type' is its Numpy type (if any) computed with
|
||||
`get_numpy_type_string`.
|
||||
"""
|
||||
|
||||
settings = self.namespace_view_settings
|
||||
if settings:
|
||||
ns = self._get_current_namespace()
|
||||
view = make_remote_view(ns, settings, EXCLUDED_NAMES)
|
||||
return view
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_var_properties(self):
|
||||
"""
|
||||
Get some properties of the variables in the current
|
||||
namespace
|
||||
"""
|
||||
settings = self.namespace_view_settings
|
||||
if settings:
|
||||
ns = self._get_current_namespace()
|
||||
data = get_remote_data(ns, settings, mode='editable',
|
||||
more_excluded_names=EXCLUDED_NAMES)
|
||||
|
||||
properties = {}
|
||||
for name, value in list(data.items()):
|
||||
properties[name] = {
|
||||
'is_list': self._is_list(value),
|
||||
'is_dict': self._is_dict(value),
|
||||
'is_set': self._is_set(value),
|
||||
'len': self._get_len(value),
|
||||
'is_array': self._is_array(value),
|
||||
'is_image': self._is_image(value),
|
||||
'is_data_frame': self._is_data_frame(value),
|
||||
'is_series': self._is_series(value),
|
||||
'array_shape': self._get_array_shape(value),
|
||||
'array_ndim': self._get_array_ndim(value)
|
||||
}
|
||||
|
||||
return properties
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_value(self, name):
|
||||
"""Get the value of a variable"""
|
||||
ns = self._get_current_namespace()
|
||||
return ns[name]
|
||||
|
||||
def set_value(self, name, value):
|
||||
"""Set the value of a variable"""
|
||||
ns = self._get_reference_namespace(name)
|
||||
ns[name] = value
|
||||
self.log.debug(ns)
|
||||
|
||||
def remove_value(self, name):
|
||||
"""Remove a variable"""
|
||||
ns = self._get_reference_namespace(name)
|
||||
ns.pop(name)
|
||||
|
||||
def copy_value(self, orig_name, new_name):
|
||||
"""Copy a variable"""
|
||||
ns = self._get_reference_namespace(orig_name)
|
||||
ns[new_name] = ns[orig_name]
|
||||
|
||||
def load_data(self, filename, ext, overwrite=False):
|
||||
"""
|
||||
Load data from filename.
|
||||
|
||||
Use 'overwrite' to determine if conflicts between variable names need
|
||||
to be handle or not.
|
||||
|
||||
For example, if a loaded variable is call 'var'
|
||||
and there is already a variable 'var' in the namespace, having
|
||||
'overwrite=True' will cause 'var' to be updated.
|
||||
In the other hand, with 'overwrite=False', a new variable will be
|
||||
created with a sufix starting with 000 i.e 'var000' (default behavior).
|
||||
"""
|
||||
from spyder_kernels.utils.misc import fix_reference_name
|
||||
|
||||
glbs = self.shell.user_ns
|
||||
load_func = iofunctions.load_funcs[ext]
|
||||
data, error_message = load_func(filename)
|
||||
|
||||
if error_message:
|
||||
return error_message
|
||||
|
||||
if not overwrite:
|
||||
# We convert to list since we mutate this dictionary
|
||||
for key in list(data.keys()):
|
||||
new_key = fix_reference_name(key, blacklist=list(glbs.keys()))
|
||||
if new_key != key:
|
||||
data[new_key] = data.pop(key)
|
||||
|
||||
try:
|
||||
glbs.update(data)
|
||||
except Exception as error:
|
||||
return str(error)
|
||||
|
||||
return None
|
||||
|
||||
def save_namespace(self, filename):
|
||||
"""Save namespace into filename"""
|
||||
ns = self._get_current_namespace()
|
||||
settings = self.namespace_view_settings
|
||||
data = get_remote_data(ns, settings, mode='picklable',
|
||||
more_excluded_names=EXCLUDED_NAMES).copy()
|
||||
return iofunctions.save(data, filename)
|
||||
|
||||
# --- For Pdb
|
||||
def _do_complete(self, code, cursor_pos):
|
||||
"""Call parent class do_complete"""
|
||||
return super(SpyderKernel, self).do_complete(code, cursor_pos)
|
||||
|
||||
def do_complete(self, code, cursor_pos):
|
||||
"""
|
||||
Call PdB complete if we are debugging.
|
||||
|
||||
Public method of ipykernel overwritten for debugging.
|
||||
"""
|
||||
if self.shell.is_debugging():
|
||||
return self.shell.pdb_session.do_complete(code, cursor_pos)
|
||||
return self._do_complete(code, cursor_pos)
|
||||
|
||||
def set_spyder_breakpoints(self, breakpoints):
|
||||
"""
|
||||
Handle a message from the frontend
|
||||
"""
|
||||
if self.shell.pdb_session:
|
||||
self.shell.pdb_session.set_spyder_breakpoints(breakpoints)
|
||||
|
||||
def set_pdb_ignore_lib(self, state):
|
||||
"""
|
||||
Change the "Ignore libraries while stepping" debugger setting.
|
||||
"""
|
||||
if self.shell.pdb_session:
|
||||
self.shell.pdb_session.pdb_ignore_lib = state
|
||||
|
||||
def set_pdb_execute_events(self, state):
|
||||
"""
|
||||
Handle a message from the frontend
|
||||
"""
|
||||
if self.shell.pdb_session:
|
||||
self.shell.pdb_session.pdb_execute_events = state
|
||||
|
||||
def set_pdb_use_exclamation_mark(self, state):
|
||||
"""
|
||||
Set an option on the current debugging session to decide wether
|
||||
the Pdb commands needs to be prefixed by '!'
|
||||
"""
|
||||
if self.shell.pdb_session:
|
||||
self.shell.pdb_session.pdb_use_exclamation_mark = state
|
||||
|
||||
def pdb_input_reply(self, line, echo_stack_entry=True):
|
||||
"""Get a pdb command from the frontend."""
|
||||
debugger = self.shell.pdb_session
|
||||
if debugger:
|
||||
debugger._disable_next_stack_entry = not echo_stack_entry
|
||||
debugger._cmd_input_line = line
|
||||
if self.eventloop:
|
||||
# Interrupting the eventloop is only implemented when a message is
|
||||
# received on the shell channel, but this message is queued and
|
||||
# won't be processed because an `execute` message is being
|
||||
# processed. Therefore we process the message here (control chan.)
|
||||
# and request a dummy message to be sent on the shell channel to
|
||||
# stop the eventloop. This will call back `_interrupt_eventloop`.
|
||||
self.frontend_call().request_interrupt_eventloop()
|
||||
|
||||
def _interrupt_eventloop(self):
|
||||
"""Interrupts the eventloop."""
|
||||
# Receiving the request is enough to stop the eventloop.
|
||||
pass
|
||||
|
||||
# --- For the Help plugin
|
||||
def is_defined(self, obj, force_import=False):
|
||||
"""Return True if object is defined in current namespace"""
|
||||
from spyder_kernels.utils.dochelpers import isdefined
|
||||
|
||||
ns = self._get_current_namespace(with_magics=True)
|
||||
return isdefined(obj, force_import=force_import, namespace=ns)
|
||||
|
||||
def get_doc(self, objtxt):
|
||||
"""Get object documentation dictionary"""
|
||||
try:
|
||||
import matplotlib
|
||||
matplotlib.rcParams['docstring.hardcopy'] = True
|
||||
except:
|
||||
pass
|
||||
from spyder_kernels.utils.dochelpers import getdoc
|
||||
|
||||
obj, valid = self._eval(objtxt)
|
||||
if valid:
|
||||
return getdoc(obj)
|
||||
|
||||
def get_source(self, objtxt):
|
||||
"""Get object source"""
|
||||
from spyder_kernels.utils.dochelpers import getsource
|
||||
|
||||
obj, valid = self._eval(objtxt)
|
||||
if valid:
|
||||
return getsource(obj)
|
||||
|
||||
# -- For Matplolib
|
||||
def get_matplotlib_backend(self):
|
||||
"""Get current matplotlib backend."""
|
||||
try:
|
||||
import matplotlib
|
||||
return MPL_BACKENDS_TO_SPYDER[matplotlib.get_backend()]
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_mpl_interactive_backend(self):
|
||||
"""
|
||||
Get current Matplotlib interactive backend.
|
||||
|
||||
This is different from the current backend because, for instance, the
|
||||
user can set first the Qt5 backend, then the Inline one. In that case,
|
||||
the current backend is Inline, but the current interactive one is Qt5,
|
||||
and this backend can't be changed without a kernel restart.
|
||||
"""
|
||||
# Mapping from frameworks to backend names.
|
||||
mapping = {
|
||||
'qt': 'QtAgg',
|
||||
'tk': 'TkAgg',
|
||||
'macosx': 'MacOSX'
|
||||
}
|
||||
|
||||
# --- Get interactive framework
|
||||
framework = None
|
||||
|
||||
# Detect if there is a graphical framework running by checking the
|
||||
# eventloop function attached to the kernel.eventloop attribute (see
|
||||
# `ipykernel.eventloops.enable_gui` for context).
|
||||
from IPython.core.getipython import get_ipython
|
||||
loop_func = get_ipython().kernel.eventloop
|
||||
|
||||
if loop_func is not None:
|
||||
if loop_func == eventloops.loop_tk:
|
||||
framework = 'tk'
|
||||
elif loop_func == eventloops.loop_qt5:
|
||||
framework = 'qt'
|
||||
elif loop_func == eventloops.loop_cocoa:
|
||||
framework = 'macosx'
|
||||
else:
|
||||
# Spyder doesn't handle other backends
|
||||
framework = 'other'
|
||||
|
||||
# --- Return backend according to framework
|
||||
if framework is None:
|
||||
# Since no interactive backend has been set yet, this is
|
||||
# equivalent to having the inline one.
|
||||
return 0
|
||||
elif framework in mapping:
|
||||
return MPL_BACKENDS_TO_SPYDER[mapping[framework]]
|
||||
else:
|
||||
# This covers the case of other backends (e.g. Wx or Gtk)
|
||||
# which users can set interactively with the %matplotlib
|
||||
# magic but not through our Preferences.
|
||||
return -1
|
||||
|
||||
def set_matplotlib_backend(self, backend, pylab=False):
|
||||
"""Set matplotlib backend given a Spyder backend option."""
|
||||
mpl_backend = MPL_BACKENDS_FROM_SPYDER[to_text_string(backend)]
|
||||
self._set_mpl_backend(mpl_backend, pylab=pylab)
|
||||
|
||||
def set_mpl_inline_figure_format(self, figure_format):
|
||||
"""Set the inline figure format to use with matplotlib."""
|
||||
mpl_figure_format = INLINE_FIGURE_FORMATS[figure_format]
|
||||
self._set_config_option(
|
||||
'InlineBackend.figure_format', mpl_figure_format)
|
||||
|
||||
def set_mpl_inline_resolution(self, resolution):
|
||||
"""Set inline figure resolution."""
|
||||
self._set_mpl_inline_rc_config('figure.dpi', resolution)
|
||||
|
||||
def set_mpl_inline_figure_size(self, width, height):
|
||||
"""Set inline figure size."""
|
||||
value = (width, height)
|
||||
self._set_mpl_inline_rc_config('figure.figsize', value)
|
||||
|
||||
def set_mpl_inline_bbox_inches(self, bbox_inches):
|
||||
"""
|
||||
Set inline print figure bbox inches.
|
||||
|
||||
The change is done by updating the 'print_figure_kwargs' config dict.
|
||||
"""
|
||||
from IPython.core.getipython import get_ipython
|
||||
config = get_ipython().kernel.config
|
||||
inline_config = (
|
||||
config['InlineBackend'] if 'InlineBackend' in config else {})
|
||||
print_figure_kwargs = (
|
||||
inline_config['print_figure_kwargs']
|
||||
if 'print_figure_kwargs' in inline_config else {})
|
||||
bbox_inches_dict = {
|
||||
'bbox_inches': 'tight' if bbox_inches else None}
|
||||
print_figure_kwargs.update(bbox_inches_dict)
|
||||
|
||||
# This seems to be necessary for newer versions of Traitlets because
|
||||
# print_figure_kwargs doesn't return a dict.
|
||||
if isinstance(print_figure_kwargs, LazyConfigValue):
|
||||
figure_kwargs_dict = print_figure_kwargs.to_dict().get('update')
|
||||
if figure_kwargs_dict:
|
||||
print_figure_kwargs = figure_kwargs_dict
|
||||
|
||||
self._set_config_option(
|
||||
'InlineBackend.print_figure_kwargs', print_figure_kwargs)
|
||||
|
||||
# -- For completions
|
||||
def set_jedi_completer(self, use_jedi):
|
||||
"""Enable/Disable jedi as the completer for the kernel."""
|
||||
self._set_config_option('IPCompleter.use_jedi', use_jedi)
|
||||
|
||||
def set_greedy_completer(self, use_greedy):
|
||||
"""Enable/Disable greedy completer for the kernel."""
|
||||
self._set_config_option('IPCompleter.greedy', use_greedy)
|
||||
|
||||
def set_autocall(self, autocall):
|
||||
"""Enable/Disable autocall funtionality."""
|
||||
self._set_config_option('ZMQInteractiveShell.autocall', autocall)
|
||||
|
||||
# --- Additional methods
|
||||
def set_cwd(self, dirname):
|
||||
"""Set current working directory."""
|
||||
os.chdir(dirname)
|
||||
|
||||
def get_cwd(self):
|
||||
"""Get current working directory."""
|
||||
try:
|
||||
return os.getcwd()
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
def get_syspath(self):
|
||||
"""Return sys.path contents."""
|
||||
return sys.path[:]
|
||||
|
||||
def get_env(self):
|
||||
"""Get environment variables."""
|
||||
return os.environ.copy()
|
||||
|
||||
def close_all_mpl_figures(self):
|
||||
"""Close all Matplotlib figures."""
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
plt.close('all')
|
||||
except:
|
||||
pass
|
||||
|
||||
def is_special_kernel_valid(self):
|
||||
"""
|
||||
Check if optional dependencies are available for special consoles.
|
||||
"""
|
||||
try:
|
||||
if os.environ.get('SPY_AUTOLOAD_PYLAB_O') == 'True':
|
||||
import matplotlib
|
||||
elif os.environ.get('SPY_SYMPY_O') == 'True':
|
||||
import sympy
|
||||
elif os.environ.get('SPY_RUN_CYTHON') == 'True':
|
||||
import cython
|
||||
except Exception:
|
||||
# Use Exception instead of ImportError here because modules can
|
||||
# fail to be imported due to a lot of issues.
|
||||
if os.environ.get('SPY_AUTOLOAD_PYLAB_O') == 'True':
|
||||
return u'matplotlib'
|
||||
elif os.environ.get('SPY_SYMPY_O') == 'True':
|
||||
return u'sympy'
|
||||
elif os.environ.get('SPY_RUN_CYTHON') == 'True':
|
||||
return u'cython'
|
||||
return None
|
||||
|
||||
def update_syspath(self, path_dict, new_path_dict):
|
||||
"""
|
||||
Update the PYTHONPATH of the kernel.
|
||||
|
||||
`path_dict` and `new_path_dict` have the paths as keys and the state
|
||||
as values. The state is `True` for active and `False` for inactive.
|
||||
|
||||
`path_dict` corresponds to the previous state of the PYTHONPATH.
|
||||
`new_path_dict` corresponds to the new state of the PYTHONPATH.
|
||||
"""
|
||||
# Remove old paths
|
||||
for path in path_dict:
|
||||
while path in sys.path:
|
||||
sys.path.remove(path)
|
||||
|
||||
# Add new paths
|
||||
pypath = [path for path, active in new_path_dict.items() if active]
|
||||
if pypath:
|
||||
sys.path.extend(pypath)
|
||||
os.environ.update({'PYTHONPATH': os.pathsep.join(pypath)})
|
||||
else:
|
||||
os.environ.pop('PYTHONPATH', None)
|
||||
|
||||
# -- Private API ---------------------------------------------------
|
||||
# --- For the Variable Explorer
|
||||
def _get_current_namespace(self, with_magics=False):
|
||||
"""
|
||||
Return current namespace
|
||||
|
||||
This is globals() if not debugging, or a dictionary containing
|
||||
both locals() and globals() for current frame when debugging
|
||||
"""
|
||||
ns = {}
|
||||
if self.shell.is_debugging() and self.shell.pdb_session.curframe:
|
||||
# Stopped at a pdb prompt
|
||||
ns.update(self.shell.user_ns)
|
||||
ns.update(self.shell._pdb_locals)
|
||||
else:
|
||||
# Give access to the running namespace if there is one
|
||||
if self._running_namespace is None:
|
||||
ns.update(self.shell.user_ns)
|
||||
else:
|
||||
# This is true when a file is executing.
|
||||
running_globals, running_locals = self._running_namespace
|
||||
ns.update(running_globals)
|
||||
if running_locals is not None:
|
||||
ns.update(running_locals)
|
||||
|
||||
# Add magics to ns so we can show help about them on the Help
|
||||
# plugin
|
||||
if with_magics:
|
||||
line_magics = self.shell.magics_manager.magics['line']
|
||||
cell_magics = self.shell.magics_manager.magics['cell']
|
||||
ns.update(line_magics)
|
||||
ns.update(cell_magics)
|
||||
return ns
|
||||
|
||||
def _get_reference_namespace(self, name):
|
||||
"""
|
||||
Return namespace where reference name is defined
|
||||
|
||||
It returns the globals() if reference has not yet been defined
|
||||
"""
|
||||
lcls = self.shell._pdb_locals
|
||||
if name in lcls:
|
||||
return lcls
|
||||
return self.shell.user_ns
|
||||
|
||||
def _get_len(self, var):
|
||||
"""Return sequence length"""
|
||||
try:
|
||||
return get_size(var)
|
||||
except:
|
||||
return None
|
||||
|
||||
def _is_array(self, var):
|
||||
"""Return True if variable is a NumPy array"""
|
||||
try:
|
||||
import numpy
|
||||
return isinstance(var, numpy.ndarray)
|
||||
except:
|
||||
return False
|
||||
|
||||
def _is_image(self, var):
|
||||
"""Return True if variable is a PIL.Image image"""
|
||||
try:
|
||||
from PIL import Image
|
||||
return isinstance(var, Image.Image)
|
||||
except:
|
||||
return False
|
||||
|
||||
def _is_data_frame(self, var):
|
||||
"""Return True if variable is a DataFrame"""
|
||||
try:
|
||||
from pandas import DataFrame
|
||||
return isinstance(var, DataFrame)
|
||||
except:
|
||||
return False
|
||||
|
||||
def _is_series(self, var):
|
||||
"""Return True if variable is a Series"""
|
||||
try:
|
||||
from pandas import Series
|
||||
return isinstance(var, Series)
|
||||
except:
|
||||
return False
|
||||
|
||||
def _is_list(self, var):
|
||||
"""Return True if variable is a list or tuple."""
|
||||
# The try/except is necessary to fix spyder-ide/spyder#19516.
|
||||
try:
|
||||
return isinstance(var, (tuple, list))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _is_dict(self, var):
|
||||
"""Return True if variable is a dictionary."""
|
||||
# The try/except is necessary to fix spyder-ide/spyder#19516.
|
||||
try:
|
||||
return isinstance(var, dict)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _is_set(self, var):
|
||||
"""Return True if variable is a set."""
|
||||
# The try/except is necessary to fix spyder-ide/spyder#19516.
|
||||
try:
|
||||
return isinstance(var, set)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _get_array_shape(self, var):
|
||||
"""Return array's shape"""
|
||||
try:
|
||||
if self._is_array(var):
|
||||
return var.shape
|
||||
else:
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
|
||||
def _get_array_ndim(self, var):
|
||||
"""Return array's ndim"""
|
||||
try:
|
||||
if self._is_array(var):
|
||||
return var.ndim
|
||||
else:
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
|
||||
# --- For the Help plugin
|
||||
def _eval(self, text):
|
||||
"""
|
||||
Evaluate text and return (obj, valid)
|
||||
where *obj* is the object represented by *text*
|
||||
and *valid* is True if object evaluation did not raise any exception
|
||||
"""
|
||||
from spyder_kernels.py3compat import is_text_string
|
||||
|
||||
assert is_text_string(text)
|
||||
ns = self._get_current_namespace(with_magics=True)
|
||||
try:
|
||||
return eval(text, ns), True
|
||||
except:
|
||||
return None, False
|
||||
|
||||
# --- For Matplotlib
|
||||
def _set_mpl_backend(self, backend, pylab=False):
|
||||
"""
|
||||
Set a backend for Matplotlib.
|
||||
|
||||
backend: A parameter that can be passed to %matplotlib
|
||||
(e.g. 'inline' or 'tk').
|
||||
pylab: Is the pylab magic should be used in order to populate the
|
||||
namespace from numpy and matplotlib
|
||||
"""
|
||||
import traceback
|
||||
from IPython.core.getipython import get_ipython
|
||||
|
||||
# Don't proceed further if there's any error while importing Matplotlib
|
||||
try:
|
||||
import matplotlib
|
||||
except Exception:
|
||||
return
|
||||
|
||||
generic_error = (
|
||||
"\n" + "="*73 + "\n"
|
||||
"NOTE: The following error appeared when setting "
|
||||
"your Matplotlib backend!!\n" + "="*73 + "\n\n"
|
||||
"{0}"
|
||||
)
|
||||
|
||||
magic = 'pylab' if pylab else 'matplotlib'
|
||||
|
||||
error = None
|
||||
try:
|
||||
# This prevents Matplotlib to automatically set the backend, which
|
||||
# overrides our own mechanism.
|
||||
matplotlib.rcParams['backend'] = 'Agg'
|
||||
|
||||
# Set the backend
|
||||
get_ipython().run_line_magic(magic, backend)
|
||||
except RuntimeError as err:
|
||||
# This catches errors generated by ipykernel when
|
||||
# trying to set a backend. See issue 5541
|
||||
if "GUI eventloops" in str(err):
|
||||
previous_backend = matplotlib.get_backend()
|
||||
if not backend in previous_backend.lower():
|
||||
# Only inform about an error if the user selected backend
|
||||
# and the one set by Matplotlib are different. Else this
|
||||
# message is very confusing.
|
||||
error = (
|
||||
"\n"
|
||||
"NOTE: Spyder *can't* set your selected Matplotlib "
|
||||
"backend because there is a previous backend already "
|
||||
"in use.\n\n"
|
||||
"Your backend will be {0}".format(previous_backend)
|
||||
)
|
||||
# This covers other RuntimeError's
|
||||
else:
|
||||
error = generic_error.format(traceback.format_exc())
|
||||
except ImportError as err:
|
||||
additional_info = (
|
||||
"This is most likely caused by missing packages in the Python "
|
||||
"environment\n"
|
||||
"or installation whose interpreter is located at:\n\n"
|
||||
" {0}"
|
||||
).format(sys.executable)
|
||||
|
||||
error = generic_error.format(err) + '\n\n' + additional_info
|
||||
except Exception:
|
||||
error = generic_error.format(traceback.format_exc())
|
||||
|
||||
self._mpl_backend_error = error
|
||||
|
||||
def _set_config_option(self, option, value):
|
||||
"""
|
||||
Set config options using the %config magic.
|
||||
|
||||
As parameters:
|
||||
option: config option, for example 'InlineBackend.figure_format'.
|
||||
value: value of the option, for example 'SVG', 'Retina', etc.
|
||||
"""
|
||||
from IPython.core.getipython import get_ipython
|
||||
try:
|
||||
base_config = "{option} = "
|
||||
value_line = (
|
||||
"'{value}'" if isinstance(value, TEXT_TYPES) else "{value}")
|
||||
config_line = base_config + value_line
|
||||
get_ipython().run_line_magic(
|
||||
'config',
|
||||
config_line.format(option=option, value=value))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _set_mpl_inline_rc_config(self, option, value):
|
||||
"""
|
||||
Update any of the Matplolib rcParams given an option and value.
|
||||
"""
|
||||
try:
|
||||
from matplotlib import rcParams
|
||||
rcParams[option] = value
|
||||
except Exception:
|
||||
# Needed in case matplolib isn't installed
|
||||
pass
|
||||
|
||||
def show_mpl_backend_errors(self):
|
||||
"""Show Matplotlib backend errors after the prompt is ready."""
|
||||
if self._mpl_backend_error is not None:
|
||||
print(self._mpl_backend_error) # spyder: test-skip
|
||||
|
||||
def set_sympy_forecolor(self, background_color='dark'):
|
||||
"""Set SymPy forecolor depending on console background."""
|
||||
if os.environ.get('SPY_SYMPY_O') == 'True':
|
||||
try:
|
||||
from sympy import init_printing
|
||||
from IPython.core.getipython import get_ipython
|
||||
if background_color == 'dark':
|
||||
init_printing(forecolor='White', ip=get_ipython())
|
||||
elif background_color == 'light':
|
||||
init_printing(forecolor='Black', ip=get_ipython())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# --- Others
|
||||
def _load_autoreload_magic(self):
|
||||
"""Load %autoreload magic."""
|
||||
from IPython.core.getipython import get_ipython
|
||||
try:
|
||||
get_ipython().run_line_magic('reload_ext', 'autoreload')
|
||||
get_ipython().run_line_magic('autoreload', '2')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _load_wurlitzer(self):
|
||||
"""Load wurlitzer extension."""
|
||||
# Wurlitzer has no effect on Windows
|
||||
if not os.name == 'nt':
|
||||
from IPython.core.getipython import get_ipython
|
||||
# Enclose this in a try/except because if it fails the
|
||||
# console will be totally unusable.
|
||||
# Fixes spyder-ide/spyder#8668
|
||||
try:
|
||||
get_ipython().run_line_magic('reload_ext', 'wurlitzer')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _get_comm(self, comm_id):
|
||||
"""
|
||||
We need to redefine this method from ipykernel.comm_manager to
|
||||
avoid showing a warning when the comm corresponding to comm_id
|
||||
is not present.
|
||||
|
||||
Fixes spyder-ide/spyder#15498
|
||||
"""
|
||||
try:
|
||||
return self.comm_manager.comms[comm_id]
|
||||
except KeyError:
|
||||
pass
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2009- Spyder Kernels Contributors
|
||||
#
|
||||
# Licensed under the terms of the MIT License
|
||||
# (see spyder_kernels/__init__.py for details)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
Custom Spyder Outstream class.
|
||||
"""
|
||||
|
||||
from ipykernel.iostream import OutStream
|
||||
|
||||
|
||||
class TTYOutStream(OutStream):
|
||||
"""Subclass of OutStream that represents a TTY."""
|
||||
|
||||
def __init__(self, session, pub_thread, name, pipe=None, echo=None, *,
|
||||
watchfd=True):
|
||||
super().__init__(session, pub_thread, name, pipe,
|
||||
echo=echo, watchfd=watchfd, isatty=True)
|
||||
@@ -0,0 +1,115 @@
|
||||
# -*- 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()
|
||||
@@ -0,0 +1,335 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -----------------------------------------------------------------------------
|
||||
# Copyright (c) 2009- Spyder Kernels Contributors
|
||||
#
|
||||
# Licensed under the terms of the MIT License
|
||||
# (see spyder_kernels/__init__.py for details)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
File used to start kernels for the IPython Console
|
||||
"""
|
||||
|
||||
# Standard library imports
|
||||
import os
|
||||
import os.path as osp
|
||||
import sys
|
||||
import site
|
||||
|
||||
from traitlets import DottedObjectName
|
||||
import ipykernel
|
||||
|
||||
# Local imports
|
||||
from spyder_kernels.utils.misc import is_module_installed
|
||||
from spyder_kernels.utils.mpl import (
|
||||
MPL_BACKENDS_FROM_SPYDER, INLINE_FIGURE_FORMATS)
|
||||
|
||||
|
||||
PY2 = sys.version[0] == '2'
|
||||
IPYKERNEL_6 = ipykernel.__version__[0] >= '6'
|
||||
|
||||
|
||||
def import_spydercustomize():
|
||||
"""Import our customizations into the kernel."""
|
||||
here = osp.dirname(__file__)
|
||||
parent = osp.dirname(here)
|
||||
customize_dir = osp.join(parent, 'customize')
|
||||
|
||||
# Remove current directory from sys.path to prevent kernel
|
||||
# crashes when people name Python files or modules with
|
||||
# the same name as standard library modules.
|
||||
# See spyder-ide/spyder#8007
|
||||
while '' in sys.path:
|
||||
sys.path.remove('')
|
||||
|
||||
# Import our customizations
|
||||
site.addsitedir(customize_dir)
|
||||
import spydercustomize # noqa
|
||||
|
||||
# Remove our customize path from sys.path
|
||||
try:
|
||||
sys.path.remove(customize_dir)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
def sympy_config(mpl_backend):
|
||||
"""Sympy configuration"""
|
||||
if mpl_backend is not None:
|
||||
lines = """
|
||||
from sympy.interactive import init_session
|
||||
init_session()
|
||||
%matplotlib {0}
|
||||
""".format(mpl_backend)
|
||||
else:
|
||||
lines = """
|
||||
from sympy.interactive import init_session
|
||||
init_session()
|
||||
"""
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
def kernel_config():
|
||||
"""Create a config object with IPython kernel options."""
|
||||
from IPython.core.application import get_ipython_dir
|
||||
from traitlets.config.loader import Config, load_pyconfig_files
|
||||
|
||||
# ---- IPython config ----
|
||||
try:
|
||||
profile_path = osp.join(get_ipython_dir(), 'profile_default')
|
||||
cfg = load_pyconfig_files(['ipython_config.py',
|
||||
'ipython_kernel_config.py'],
|
||||
profile_path)
|
||||
except:
|
||||
cfg = Config()
|
||||
|
||||
# ---- Spyder config ----
|
||||
spy_cfg = Config()
|
||||
|
||||
# Enable/disable certain features for testing
|
||||
testing = os.environ.get('SPY_TESTING') == 'True'
|
||||
if testing:
|
||||
# Don't load nor save history in our IPython consoles.
|
||||
spy_cfg.HistoryAccessor.enabled = False
|
||||
|
||||
# Until we implement Issue 1052
|
||||
spy_cfg.InteractiveShell.xmode = 'Plain'
|
||||
|
||||
# Jedi completer. It's only available in Python 3
|
||||
jedi_o = os.environ.get('SPY_JEDI_O') == 'True'
|
||||
if not PY2:
|
||||
spy_cfg.IPCompleter.use_jedi = jedi_o
|
||||
|
||||
# Clear terminal arguments input.
|
||||
# This needs to be done before adding the exec_lines that come from
|
||||
# Spyder, to avoid deleting the sys module if users want to import
|
||||
# it through them.
|
||||
# See spyder-ide/spyder#15788
|
||||
clear_argv = "import sys; sys.argv = ['']; del sys"
|
||||
spy_cfg.IPKernelApp.exec_lines = [clear_argv]
|
||||
|
||||
# Set our runfile in builtins here to prevent other packages shadowing it.
|
||||
# This started to be a problem since IPykernel 6.3.0.
|
||||
if not PY2:
|
||||
spy_cfg.IPKernelApp.exec_lines.append(
|
||||
"import builtins; "
|
||||
"builtins.runfile = builtins.spyder_runfile; "
|
||||
"del builtins.spyder_runfile; del builtins"
|
||||
)
|
||||
|
||||
# Prevent other libraries to change the breakpoint builtin.
|
||||
# This started to be a problem since IPykernel 6.3.0.
|
||||
if sys.version_info[0:2] >= (3, 7):
|
||||
spy_cfg.IPKernelApp.exec_lines.append(
|
||||
"import sys; import pdb; "
|
||||
"sys.breakpointhook = pdb.set_trace; "
|
||||
"del sys; del pdb"
|
||||
)
|
||||
|
||||
# Run lines of code at startup
|
||||
run_lines_o = os.environ.get('SPY_RUN_LINES_O')
|
||||
if run_lines_o is not None:
|
||||
spy_cfg.IPKernelApp.exec_lines += (
|
||||
[x.strip() for x in run_lines_o.split(';')]
|
||||
)
|
||||
|
||||
# Load %autoreload magic
|
||||
spy_cfg.IPKernelApp.exec_lines.append(
|
||||
"get_ipython().kernel._load_autoreload_magic()")
|
||||
|
||||
# Load wurlitzer extension
|
||||
spy_cfg.IPKernelApp.exec_lines.append(
|
||||
"get_ipython().kernel._load_wurlitzer()")
|
||||
|
||||
# Default inline backend configuration
|
||||
# This is useful to have when people doesn't
|
||||
# use our config system to configure the
|
||||
# inline backend but want to use
|
||||
# '%matplotlib inline' at runtime
|
||||
spy_cfg.InlineBackend.rc = {
|
||||
'figure.figsize': (6.0, 4.0),
|
||||
# 72 dpi matches SVG/qtconsole.
|
||||
# This only affects PNG export, as SVG has no dpi setting.
|
||||
'figure.dpi': 72,
|
||||
# 12pt labels get cutoff on 6x4 logplots, so use 10pt.
|
||||
'font.size': 10,
|
||||
# 10pt still needs a little more room on the xlabel
|
||||
'figure.subplot.bottom': .125,
|
||||
# Play nicely with any background color.
|
||||
'figure.facecolor': 'white',
|
||||
'figure.edgecolor': 'white'
|
||||
}
|
||||
|
||||
# Pylab configuration
|
||||
mpl_backend = None
|
||||
if is_module_installed('matplotlib'):
|
||||
# Set Matplotlib backend with Spyder options
|
||||
pylab_o = os.environ.get('SPY_PYLAB_O')
|
||||
backend_o = os.environ.get('SPY_BACKEND_O')
|
||||
if pylab_o == 'True' and backend_o is not None:
|
||||
mpl_backend = MPL_BACKENDS_FROM_SPYDER[backend_o]
|
||||
# Inline backend configuration
|
||||
if mpl_backend == 'inline':
|
||||
# Figure format
|
||||
format_o = os.environ.get('SPY_FORMAT_O')
|
||||
formats = INLINE_FIGURE_FORMATS
|
||||
if format_o is not None:
|
||||
spy_cfg.InlineBackend.figure_format = formats[format_o]
|
||||
|
||||
# Resolution
|
||||
resolution_o = os.environ.get('SPY_RESOLUTION_O')
|
||||
if resolution_o is not None:
|
||||
spy_cfg.InlineBackend.rc['figure.dpi'] = float(
|
||||
resolution_o)
|
||||
|
||||
# Figure size
|
||||
width_o = float(os.environ.get('SPY_WIDTH_O'))
|
||||
height_o = float(os.environ.get('SPY_HEIGHT_O'))
|
||||
if width_o is not None and height_o is not None:
|
||||
spy_cfg.InlineBackend.rc['figure.figsize'] = (width_o,
|
||||
height_o)
|
||||
|
||||
# Print figure kwargs
|
||||
bbox_inches_o = os.environ.get('SPY_BBOX_INCHES_O')
|
||||
bbox_inches = 'tight' if bbox_inches_o == 'True' else None
|
||||
spy_cfg.InlineBackend.print_figure_kwargs.update(
|
||||
{'bbox_inches': bbox_inches})
|
||||
else:
|
||||
# Set Matplotlib backend to inline for external kernels.
|
||||
# Fixes issue 108
|
||||
mpl_backend = 'inline'
|
||||
|
||||
# Automatically load Pylab and Numpy, or only set Matplotlib
|
||||
# backend
|
||||
autoload_pylab_o = os.environ.get('SPY_AUTOLOAD_PYLAB_O') == 'True'
|
||||
command = "get_ipython().kernel._set_mpl_backend('{0}', {1})"
|
||||
spy_cfg.IPKernelApp.exec_lines.append(
|
||||
command.format(mpl_backend, autoload_pylab_o))
|
||||
|
||||
# Enable Cython magic
|
||||
run_cython = os.environ.get('SPY_RUN_CYTHON') == 'True'
|
||||
if run_cython and is_module_installed('Cython'):
|
||||
spy_cfg.IPKernelApp.exec_lines.append('%reload_ext Cython')
|
||||
|
||||
# Run a file at startup
|
||||
use_file_o = os.environ.get('SPY_USE_FILE_O')
|
||||
run_file_o = os.environ.get('SPY_RUN_FILE_O')
|
||||
if use_file_o == 'True' and run_file_o is not None:
|
||||
if osp.exists(run_file_o):
|
||||
spy_cfg.IPKernelApp.file_to_run = run_file_o
|
||||
|
||||
# Autocall
|
||||
autocall_o = os.environ.get('SPY_AUTOCALL_O')
|
||||
if autocall_o is not None:
|
||||
spy_cfg.ZMQInteractiveShell.autocall = int(autocall_o)
|
||||
|
||||
# To handle the banner by ourselves in IPython 3+
|
||||
spy_cfg.ZMQInteractiveShell.banner1 = ''
|
||||
|
||||
# Greedy completer
|
||||
greedy_o = os.environ.get('SPY_GREEDY_O') == 'True'
|
||||
spy_cfg.IPCompleter.greedy = greedy_o
|
||||
|
||||
# Sympy loading
|
||||
sympy_o = os.environ.get('SPY_SYMPY_O') == 'True'
|
||||
if sympy_o and is_module_installed('sympy'):
|
||||
lines = sympy_config(mpl_backend)
|
||||
spy_cfg.IPKernelApp.exec_lines.append(lines)
|
||||
|
||||
# Disable the new mechanism to capture and forward low-level output
|
||||
# in IPykernel 6. For that we have Wurlitzer.
|
||||
if not PY2:
|
||||
spy_cfg.IPKernelApp.capture_fd_output = False
|
||||
|
||||
# Merge IPython and Spyder configs. Spyder prefs will have prevalence
|
||||
# over IPython ones
|
||||
cfg._merge(spy_cfg)
|
||||
return cfg
|
||||
|
||||
|
||||
def varexp(line):
|
||||
"""
|
||||
Spyder's variable explorer magic
|
||||
|
||||
Used to generate plots, histograms and images of the variables displayed
|
||||
on it.
|
||||
"""
|
||||
ip = get_ipython() #analysis:ignore
|
||||
funcname, name = line.split()
|
||||
try:
|
||||
import guiqwt.pyplot as pyplot
|
||||
except:
|
||||
import matplotlib.pyplot as pyplot
|
||||
pyplot.figure();
|
||||
getattr(pyplot, funcname[2:])(ip.kernel._get_current_namespace()[name])
|
||||
pyplot.show()
|
||||
|
||||
|
||||
def main():
|
||||
# Remove this module's path from sys.path:
|
||||
try:
|
||||
sys.path.remove(osp.dirname(__file__))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
locals().pop('__file__')
|
||||
except KeyError:
|
||||
pass
|
||||
__doc__ = ''
|
||||
__name__ = '__main__'
|
||||
|
||||
# Import our customizations into the kernel
|
||||
import_spydercustomize()
|
||||
|
||||
# Remove current directory from sys.path to prevent kernel
|
||||
# crashes when people name Python files or modules with
|
||||
# the same name as standard library modules.
|
||||
# See spyder-ide/spyder#8007
|
||||
while '' in sys.path:
|
||||
sys.path.remove('')
|
||||
|
||||
# Main imports
|
||||
from ipykernel.kernelapp import IPKernelApp
|
||||
from spyder_kernels.console.kernel import SpyderKernel
|
||||
|
||||
class SpyderKernelApp(IPKernelApp):
|
||||
|
||||
if IPYKERNEL_6:
|
||||
outstream_class = DottedObjectName(
|
||||
'spyder_kernels.console.outstream.TTYOutStream')
|
||||
|
||||
def init_pdb(self):
|
||||
"""
|
||||
This method was added in IPykernel 5.3.1 and it replaces
|
||||
the debugger used by the kernel with a new class
|
||||
introduced in IPython 7.15 during kernel's initialization.
|
||||
Therefore, it doesn't allow us to use our debugger.
|
||||
"""
|
||||
pass
|
||||
|
||||
# Fire up the kernel instance.
|
||||
kernel = SpyderKernelApp.instance()
|
||||
kernel.kernel_class = SpyderKernel
|
||||
try:
|
||||
kernel.config = kernel_config()
|
||||
except:
|
||||
pass
|
||||
kernel.initialize()
|
||||
|
||||
# Set our own magics
|
||||
kernel.shell.register_magic_function(varexp)
|
||||
|
||||
# Set Pdb class to be used by %debug and %pdb.
|
||||
# This makes IPython consoles to use the class defined in our
|
||||
# sitecustomize instead of their default one.
|
||||
import pdb
|
||||
kernel.shell.InteractiveTB.debugger_cls = pdb.Pdb
|
||||
|
||||
# Start the (infinite) kernel event loop.
|
||||
kernel.start()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user