interface work
This commit is contained in:
@@ -1,15 +1,28 @@
|
||||
from __future__ import print_function
|
||||
|
||||
from ipykernel.ipkernel import IPythonKernel
|
||||
|
||||
import sys
|
||||
import signal
|
||||
import yap
|
||||
# import ipdb
|
||||
# ipdb,set_trace()
|
||||
import io
|
||||
import getpass
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from IPython.core import release
|
||||
from ipython_genutils.py3compat import builtin_mod, PY3, unicode_type, safe_unicode
|
||||
from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
|
||||
from traitlets import Instance, Type, Any, List
|
||||
|
||||
from ipykernel.comm import CommManager
|
||||
from ipykernel.kernelbase import Kernel as KernelBase
|
||||
from ipykernel.zmqshell import ZMQInteractiveShell
|
||||
from .interactiveshell import YAPInteractiveShell
|
||||
from IPython.core.interactiveshell import InteractiveShellABC, InteractiveShell
|
||||
from contextlib import redirect_stdout
|
||||
|
||||
|
||||
|
||||
kernel_json = {
|
||||
"argv": [sys.executable,
|
||||
"argv": [sys.executable,
|
||||
"-m", "yap_kernel",
|
||||
"-f", "{connection_file}"],
|
||||
"display_name": " YAP-6.3",
|
||||
@@ -22,11 +35,26 @@ def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
class YAPKernel(IPythonKernel):
|
||||
class YAPKernel(KernelBase):
|
||||
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
|
||||
allow_none=True)
|
||||
shell_class = Type(ZMQInteractiveShell )
|
||||
user_ns = Instance(dict, args=None, allow_none=True)
|
||||
def _user_ns_changed(self, name, old, new):
|
||||
if self.shell is not None:
|
||||
self.shell.user_ns = new
|
||||
self.shell.init_user_ns()
|
||||
|
||||
# A reference to the Python builtin 'raw_input' function.
|
||||
# (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
|
||||
_sys_raw_input = Any()
|
||||
_sys_eval_input = Any()
|
||||
|
||||
|
||||
implementation = 'YAP Kernel'
|
||||
implementation_version = '1.0'
|
||||
language = 'text'
|
||||
language_version = '0.1'
|
||||
language_version = '6.3'
|
||||
banner = "YAP-6.3"
|
||||
language_info = {
|
||||
'mimetype': 'text/prolog',
|
||||
@@ -41,63 +69,349 @@ class YAPKernel(IPythonKernel):
|
||||
'file_extension': '.yap',
|
||||
}
|
||||
|
||||
def init_yap(self, **kwargs):
|
||||
# Signal handlers are inherited by
|
||||
# forked processes,
|
||||
# and we can't easily
|
||||
# reset it from the subprocess. Since kernelapp
|
||||
# ignores SIGINT except in
|
||||
# message handlers, we need to temporarily
|
||||
# reset the SIGINT handler
|
||||
# here so that yap and its children are interruptible.
|
||||
sig = signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
try:
|
||||
self.engine = yap.YAPEngine()
|
||||
self.q = None
|
||||
self.engine.query("load_files(library(python), [])").command()
|
||||
self.engine.query("load_files(library(jupyter), [])").command()
|
||||
banner = "YAP6-3 Kernel"
|
||||
self.olines = banner
|
||||
finally:
|
||||
signal.signal(signal.SIGINT, sig)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Things related to history management
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# sp = super(YAPKernel, self)
|
||||
super(YAPKernel, self).__init__(**kwargs)
|
||||
self.init_yap(**kwargs)
|
||||
self.shell.run_cell = self.yap_run_cell
|
||||
# Initialize the InteractiveShell subclass
|
||||
self.shell = self.shell_class.instance(parent=self,
|
||||
profile_dir = self.profile_dir,
|
||||
user_ns = self.user_ns,
|
||||
kernel = self,
|
||||
)
|
||||
self.shell.displayhook.session = self.session
|
||||
self.shell.displayhook.pub_socket = self.iopub_socket
|
||||
self.shell.displayhook.topic = self._topic('execute_result')
|
||||
self.shell.display_pub.session = self.session
|
||||
self.shell.display_pub.pub_socket = self.iopub_socket
|
||||
|
||||
self.comm_manager = CommManager(parent=self, kernel=self)
|
||||
|
||||
# self.shell._last_traceback = None
|
||||
self.shell.configurables.append(self.comm_manager)
|
||||
comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
|
||||
for msg_type in comm_msg_types:
|
||||
self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
|
||||
self.yap_shell = YAPInteractiveShell( self )
|
||||
|
||||
|
||||
def get_usage(self):
|
||||
return "This is the YAP kernel."
|
||||
|
||||
def yap_run_cell(self, s, store_history=False, silent=False,
|
||||
shell_futures=True):
|
||||
help_links = List([
|
||||
{
|
||||
'text': "Python",
|
||||
'url': "http://docs.python.org/%i.%i" % sys.version_info[:2],
|
||||
},
|
||||
{
|
||||
'text': "YAP",
|
||||
'url': "http://YAP.org/documentation.html",
|
||||
},
|
||||
{
|
||||
'text': "NumPy",
|
||||
'url': "http://docs.scipy.org/doc/numpy/reference/",
|
||||
},
|
||||
{
|
||||
'text': "SciPy",
|
||||
'url': "http://docs.scipy.org/doc/scipy/reference/",
|
||||
},
|
||||
{
|
||||
'text': "Matplotlib",
|
||||
'url': "http://matplotlib.org/contents.html",
|
||||
},
|
||||
{
|
||||
'text': "SymPy",
|
||||
'url': "http://docs.sympy.org/latest/index.html",
|
||||
},
|
||||
{
|
||||
'text': "pandas",
|
||||
'url': "http://pandas.pydata.org/pandas-docs/stable/",
|
||||
},
|
||||
]).tag(config=True)
|
||||
|
||||
if not self.q:
|
||||
self.q = self.engine.query(s)
|
||||
if self.q.next():
|
||||
myvs = self.q.namedVarsCopy()
|
||||
if myvs:
|
||||
i = 0
|
||||
for peq in myvs:
|
||||
name = peq[0]
|
||||
bind = peq[1]
|
||||
if bind.isVar():
|
||||
var = yap.YAPAtom('$VAR')
|
||||
f = yap.YAPFunctor(var, 1)
|
||||
bind.unify(yap.YAPApplTerm(f, (name)))
|
||||
else:
|
||||
i = bind.numberVars(i, True)
|
||||
print(name.text() + " = " + bind.text())
|
||||
else:
|
||||
print("yes")
|
||||
if self.q.deterministic():
|
||||
self.closeq()
|
||||
return
|
||||
print("No (more) answers")
|
||||
self.closeq()
|
||||
return
|
||||
# Kernel info fields
|
||||
implementation = 'YAP'
|
||||
implementation_version = release.version
|
||||
language_info = {
|
||||
'name': 'python',
|
||||
'version': sys.version.split()[0],
|
||||
'mimetype': 'text/x-python',
|
||||
'codemirror_mode': {
|
||||
'name': 'prolog',
|
||||
'version': sys.version_info[0]
|
||||
},
|
||||
'pygments_lexer': 'prolog',
|
||||
'nbconvert_exporter': 'python',
|
||||
'file_extension': '.yap'
|
||||
}
|
||||
|
||||
def closeq(self):
|
||||
if self.q:
|
||||
self.q.close()
|
||||
self.q = None
|
||||
@property
|
||||
def banner(self):
|
||||
return self.shell.banner
|
||||
|
||||
def start(self):
|
||||
self.shell.exit_now = False
|
||||
super(YAPKernel, self).start()
|
||||
|
||||
def set_parent(self, ident, parent):
|
||||
"""Overridden from parent to tell the display hook and output streams
|
||||
about the parent message.
|
||||
"""
|
||||
super(YAPKernel, self).set_parent(ident, parent)
|
||||
self.shell.set_parent(parent)
|
||||
|
||||
def init_metadata(self, parent):
|
||||
"""Initialize metadata.
|
||||
|
||||
Run at the beginning of each execution request.
|
||||
"""
|
||||
md = super(YAPKernel, self).init_metadata(parent)
|
||||
# FIXME: remove deprecated ipyparallel-specific code
|
||||
# This is required for ipyparallel < 5.0
|
||||
md.update({
|
||||
'dependencies_met' : True,
|
||||
'engine' : self.ident,
|
||||
})
|
||||
return md
|
||||
|
||||
def finish_metadata(self, parent, metadata, reply_content):
|
||||
"""Finish populating metadata.
|
||||
|
||||
Run after completing an execution request.
|
||||
"""
|
||||
# FIXME: remove deprecated ipyparallel-specific code
|
||||
# This is required by ipyparallel < 5.0
|
||||
metadata['status'] = reply_content['status']
|
||||
if reply_content['status'] == 'error' and reply_content['ename'] == 'UnmetDependency':
|
||||
metadata['dependencies_met'] = False
|
||||
|
||||
return metadata
|
||||
|
||||
def _forward_input(self, allow_stdin=False):
|
||||
"""Forward raw_input and getpass to the current frontend.
|
||||
|
||||
via input_request
|
||||
"""
|
||||
self._allow_stdin = allow_stdin
|
||||
|
||||
if PY3:
|
||||
self._sys_raw_input = builtin_mod.input
|
||||
builtin_mod.input = self.raw_input
|
||||
else:
|
||||
self._sys_raw_input = builtin_mod.raw_input
|
||||
self._sys_eval_input = builtin_mod.input
|
||||
builtin_mod.raw_input = self.raw_input
|
||||
builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
|
||||
self._save_getpass = getpass.getpass
|
||||
getpass.getpass = self.getpass
|
||||
|
||||
def _restore_input(self):
|
||||
"""Restore raw_input, getpass"""
|
||||
if PY3:
|
||||
builtin_mod.input = self._sys_raw_input
|
||||
else:
|
||||
builtin_mod.raw_input = self._sys_raw_input
|
||||
builtin_mod.input = self._sys_eval_input
|
||||
|
||||
getpass.getpass = self._save_getpass
|
||||
|
||||
@property
|
||||
def execution_count(self):
|
||||
return self.shell.execution_count
|
||||
|
||||
@execution_count.setter
|
||||
def execution_count(self, value):
|
||||
# Ignore the incrememnting done by KernelBase, in favour of our shell's
|
||||
# execution counter.
|
||||
pass
|
||||
|
||||
def do_execute(self, code, silent, store_history=True,
|
||||
user_expressions=None, allow_stdin=False):
|
||||
shell = self.shell # we'll need this a lot here
|
||||
|
||||
self._forward_input(allow_stdin)
|
||||
|
||||
reply_content = {}
|
||||
try:
|
||||
res = shell.run_cell(code, store_history=store_history, silent=silent)
|
||||
finally:
|
||||
self._restore_input()
|
||||
|
||||
if res.error_before_exec is not None:
|
||||
err = res.error_before_exec
|
||||
else:
|
||||
err = res.error_in_exec
|
||||
|
||||
if res.success:
|
||||
reply_content[u'status'] = u'ok'
|
||||
elif isinstance(err, KeyboardInterrupt):
|
||||
reply_content[u'status'] = u'aborted'
|
||||
else:
|
||||
reply_content[u'status'] = u'error'
|
||||
|
||||
reply_content.update({
|
||||
# u'traceback': shell._last_traceback or [],
|
||||
u'ename': unicode_type(type(err).__name__),
|
||||
u'evalue': safe_unicode(err),
|
||||
})
|
||||
|
||||
# FIXME: deprecate piece for ipyparallel:
|
||||
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id,
|
||||
method='execute')
|
||||
reply_content['engine_info'] = e_info
|
||||
|
||||
|
||||
# Return the execution counter so clients can display prompts
|
||||
reply_content['execution_count'] = shell.execution_count - 1
|
||||
|
||||
if 'traceback' in reply_content:
|
||||
self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
|
||||
|
||||
|
||||
# At this point, we can tell whether the main code execution succeeded
|
||||
# or not. If it did, we proceed to evaluate user_expressions
|
||||
if reply_content['status'] == 'ok':
|
||||
reply_content[u'user_expressions'] = \
|
||||
shell.user_expressions(user_expressions or {})
|
||||
else:
|
||||
# If there was an error, don't even try to compute expressions
|
||||
reply_content[u'user_expressions'] = {}
|
||||
|
||||
# Payloads should be retrieved regardless of outcome, so we can both
|
||||
# recover partial output (that could have been generated early in a
|
||||
# block, before an error) and always clear the payload system.
|
||||
reply_content[u'payload'] = shell.payload_manager.read_payload()
|
||||
# Be aggressive about clearing the payload because we don't want
|
||||
# it to sit in memory until the next execute_request comes in.
|
||||
shell.payload_manager.clear_payload()
|
||||
|
||||
return reply_content
|
||||
|
||||
def do_complete(self, code, cursor_pos):
|
||||
# FIXME: YAP completers currently assume single line,
|
||||
# but completion messages give multi-line context
|
||||
# For now, extract line from cell, based on cursor_pos:
|
||||
if cursor_pos is None:
|
||||
cursor_pos = len(code)
|
||||
line, offset = line_at_cursor(code, cursor_pos)
|
||||
line_cursor = cursor_pos - offset
|
||||
|
||||
txt, matches = self.shell.complete('', line, line_cursor)
|
||||
return {'matches' : matches,
|
||||
'cursor_end' : cursor_pos,
|
||||
'cursor_start' : cursor_pos - len(txt),
|
||||
'metadata' : {},
|
||||
'status' : 'ok'}
|
||||
|
||||
def do_inspect(self, code, cursor_pos, detail_level=0):
|
||||
name = token_at_cursor(code, cursor_pos)
|
||||
info = self.shell.object_inspect(name)
|
||||
|
||||
reply_content = {'status' : 'ok'}
|
||||
reply_content['data'] = data = {}
|
||||
reply_content['metadata'] = {}
|
||||
reply_content['found'] = info['found']
|
||||
if info['found']:
|
||||
info_text = self.shell.object_inspect_text(
|
||||
name,
|
||||
detail_level=detail_level,
|
||||
)
|
||||
data['text/plain'] = info_text
|
||||
|
||||
return reply_content
|
||||
|
||||
def do_history(self, hist_access_type, output, raw, session=0, start=0,
|
||||
stop=None, n=None, pattern=None, unique=False):
|
||||
if hist_access_type == 'tail':
|
||||
hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
|
||||
include_latest=True)
|
||||
|
||||
elif hist_access_type == 'range':
|
||||
hist = self.shell.history_manager.get_range(session, start, stop,
|
||||
raw=raw, output=output)
|
||||
|
||||
elif hist_access_type == 'search':
|
||||
hist = self.shell.history_manager.search(
|
||||
pattern, raw=raw, output=output, n=n, unique=unique)
|
||||
else:
|
||||
hist = []
|
||||
|
||||
return {
|
||||
'status': 'ok',
|
||||
'history' : list(hist),
|
||||
}
|
||||
|
||||
def do_shutdown(self, restart):
|
||||
self.shell.exit_now = True
|
||||
return dict(status='ok', restart=restart)
|
||||
|
||||
def do_is_complete(self, code):
|
||||
status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
|
||||
r = {'status': status}
|
||||
if status == 'incomplete':
|
||||
r['indent'] = ' ' * indent_spaces
|
||||
return r
|
||||
|
||||
def do_apply(self, content, bufs, msg_id, reply_metadata):
|
||||
from .serialize import serialize_object, unpack_apply_message
|
||||
shell = self.shell
|
||||
try:
|
||||
working = shell.user_ns
|
||||
|
||||
prefix = "_"+str(msg_id).replace("-","")+"_"
|
||||
|
||||
f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
|
||||
|
||||
fname = getattr(f, '__name__', 'f')
|
||||
|
||||
fname = prefix+"f"
|
||||
argname = prefix+"args"
|
||||
kwargname = prefix+"kwargs"
|
||||
resultname = prefix+"result"
|
||||
|
||||
ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
|
||||
# print ns
|
||||
working.update(ns)
|
||||
code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
|
||||
try:
|
||||
exec(code, shell.user_global_ns, shell.user_ns)
|
||||
result = working.get(resultname)
|
||||
finally:
|
||||
for key in ns:
|
||||
working.pop(key)
|
||||
|
||||
result_buf = serialize_object(result,
|
||||
buffer_threshold=self.session.buffer_threshold,
|
||||
item_threshold=self.session.item_threshold,
|
||||
)
|
||||
|
||||
except BaseException as e:
|
||||
# invoke YAP traceback formatting
|
||||
shell.showtraceback()
|
||||
reply_content = {
|
||||
u'traceback': shell._last_traceback or [],
|
||||
u'ename': unicode_type(type(e).__name__),
|
||||
u'evalue': safe_unicode(e),
|
||||
}
|
||||
# FIXME: deprecate piece for ipyparallel:
|
||||
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
|
||||
reply_content['engine_info'] = e_info
|
||||
|
||||
self.send_response(self.iopub_socket, u'error', reply_content,
|
||||
ident=self._topic('error'))
|
||||
self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
|
||||
result_buf = []
|
||||
reply_content['status'] = 'error'
|
||||
else:
|
||||
reply_content = {'status' : 'ok'}
|
||||
|
||||
return reply_content, result_buf
|
||||
|
||||
def do_clear(self):
|
||||
self.shell.reset(False)
|
||||
return dict(status='ok')
|
||||
|
||||
Reference in New Issue
Block a user