diff --git a/dyalog_kernel/kernel.py b/dyalog_kernel/kernel.py index 9395703..234fbae 100644 --- a/dyalog_kernel/kernel.py +++ b/dyalog_kernel/kernel.py @@ -9,8 +9,8 @@ from collections import deque - -from ipykernel.kernelbase import Kernel +from metakernel import MetaKernel +from IPython.display import HTML, Image from dyalog_kernel import __version__ if sys.platform.lower().startswith('win'): @@ -49,7 +49,7 @@ def writeln(s): sys.stdout = tmp_stdout -class DyalogKernel(Kernel): +class DyalogKernel(MetaKernel): implementation = 'Dyalog' implementation_version = __version__ @@ -72,60 +72,20 @@ class DyalogKernel(Kernel): dyalog_subprocess = None def out_error(self, s): - _content = { - 'output_type': 'stream', - 'name': 'stderr', # stdin or stderr - 'text': s - } - self.send_response(self.iopub_socket, 'stream', _content) + self.Error(s) def out_png(self, s): - _content = { - 'output_type': 'display_data', - 'data': { - #'text/plain' : ['multiline text data'], - 'image/png': s, - #'application/json':{ - # JSON data is included as-is - # 'json':'data', - #}, - }, - 'metadata': { - 'image/svg': { - 'width': 120, - 'height': 80, - }, - }, - } - self.send_response(self.iopub_socket, 'display_data', _content) + #width and height values are fixed to maintain consistency with original implementation + self.Display(Image(data=s, width=120, height=80)) def out_html(self, s): - _content = { - # 'output_type': 'display_data', - 'data': {'text/html': s}, - 'execution_count': self.execution_count, - 'metadata': '' - # 'transient': '' - } - self.send_response(self.iopub_socket, 'execute_result', _content) + self.Display(HTML(s)) def out_result(self, s): # injecting css: white-space:pre. Means no wrapping, RIDE SetPW will take care about line wrapping - html_start = '
'
html_end = ''
-
- _content = {
- # 'output_type': 'display_data',
- # 'data': {'text/plain': s},
- 'data': {'text/html': html_start + html.escape(s, False) + html_end},
- 'execution_count': self.execution_count,
- 'metadata': {},
-
- # 'transient': ''
- }
-
- self.send_response(self.iopub_socket, 'execute_result', _content)
+ self.Display(HTML(html_start + html.escape(s, False) + html_end))
def out_stream(self, s):
_content = {
@@ -195,7 +155,7 @@ def __init__(self, **kwargs):
#from ipykernel import get_connection_file
#s = get_connection_file()
# debug("########## " + str(s))
-
+ super(DyalogKernel, self).__init__(**kwargs)
self._port = DYALOG_PORT
# lets find first available port, starting from default DYALOG_PORT (:4502)
# this makes sense only if Dyalog APL and Jupyter executables are on the same host (localhost)
@@ -254,8 +214,6 @@ def __init__(self, **kwargs):
self.dyalog_subprocess = subprocess.Popen([dyalog, '+s', '-q', os.path.dirname(os.path.abspath(
__file__)) + '/init.dws'], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=dyalog_env)
- Kernel.__init__(self, **kwargs)
-
self.dyalog_ride_connect()
def recv_all(self, msg_len):
@@ -327,8 +285,9 @@ def ride_send(self, d):
self.dyalogTCP.sendall(_data)
debug("SEND " + _data[8:].decode("utf-8"))
-
- def do_execute(self, code, silent, store_history=True, user_expressions=None,
+
+ #renamed to _do_execute to avoid overriding the do_execute method in MetaKernel
+ def _do_execute(self, code, silent=False, store_history=True, user_expressions=None,
allow_stdin=True):
global SUSPEND
code = code.strip()
@@ -355,7 +314,7 @@ def do_execute(self, code, silent, store_history=True, user_expressions=None,
'JUPYTER NOTEBOOK: UNDEFINED ARGUMENT TO %suspend, USE EITHER on OR off')
lines = lines[1:]
elif lines[0].lower() == ']dinput':
- lines = lines[1:]
+ lines = lines[1:]
try:
# the windows interpreter can only handle ~125 chacaters at a time, so we do one line at a time
pt = None
@@ -452,6 +411,10 @@ def do_execute(self, code, silent, store_history=True, user_expressions=None,
}
return reply_content
+
+ def do_execute_direct(self, code, silent=False):
+ #defers non-magic code execution to the do_execute function defined by Dyalog
+ return self._do_execute(code, silent)
def execute_line(self, line):
self.ride_send(["Execute", {"trace": 0, "text": line}])
@@ -463,7 +426,7 @@ def define_function(self, lines):
self.execute_line("⎕SE.Dyalog.ipyFn,←⊂," + quoted + "\n")
self.ride_receive_wait()
dq.clear()
- if re.match('^\\s*:namespace|:class|:interface',lines[0].lower()):
+ if re.match('^\\s*:namespace|:class|:interface',lines[0].lower()):
self.execute_line("{0::'DEFN ERROR'⋄⎕FIX ⍵}⎕SE.Dyalog.ipyFn\n")
else:
self.execute_line("{''≢0⍴r←⎕FX ⍵:511 ⎕SIGNAL⍨'DEFN ERROR: Issue on line ',⍕r}⎕SE.Dyalog.ipyFn\n")
diff --git a/setup.py b/setup.py
index d53a3db..f39e6d5 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@
],
python_requires=">=3.8",
install_requires=[
- "ipykernel>=6.20.0",
+ "metakernel>=0.30.3"
],
entry_points={
'console_scripts': [