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
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
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()
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1226
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user