66import subprocess
77import re
88import html
9+ import inspect
910
1011from collections import deque
1112
12-
13- from ipykernel . kernelbase import Kernel
13+ from metakernel import MetaKernel
14+ from IPython . display import HTML , Image
1415from dyalog_kernel import __version__
1516
1617if sys .platform .lower ().startswith ('win' ):
@@ -49,7 +50,7 @@ def writeln(s):
4950 sys .stdout = tmp_stdout
5051
5152
52- class DyalogKernel (Kernel ):
53+ class DyalogKernel (MetaKernel ):
5354
5455 implementation = 'Dyalog'
5556 implementation_version = __version__
@@ -72,60 +73,19 @@ class DyalogKernel(Kernel):
7273 dyalog_subprocess = None
7374
7475 def out_error (self , s ):
75- _content = {
76- 'output_type' : 'stream' ,
77- 'name' : 'stderr' , # stdin or stderr
78- 'text' : s
79- }
80- self .send_response (self .iopub_socket , 'stream' , _content )
76+ self .Error (s )
8177
8278 def out_png (self , s ):
83- _content = {
84- 'output_type' : 'display_data' ,
85- 'data' : {
86- #'text/plain' : ['multiline text data'],
87- 'image/png' : s ,
88- #'application/json':{
89- # JSON data is included as-is
90- # 'json':'data',
91- #},
92- },
93- 'metadata' : {
94- 'image/svg' : {
95- 'width' : 120 ,
96- 'height' : 80 ,
97- },
98- },
99- }
100- self .send_response (self .iopub_socket , 'display_data' , _content )
79+ #width and height values are fixed to maintain consistency with original implementation
80+ self .Display (Image (data = s , width = 120 , height = 80 ))
10181
10282 def out_html (self , s ):
103- _content = {
104- # 'output_type': 'display_data',
105- 'data' : {'text/html' : s },
106- 'execution_count' : self .execution_count ,
107- 'metadata' : ''
108- # 'transient': ''
109- }
110- self .send_response (self .iopub_socket , 'execute_result' , _content )
83+ self .Display (HTML (s ))
11184
11285 def out_result (self , s ):
113- # injecting css: white-space:pre. Means no wrapping, RIDE SetPW will take care about line wrapping
114-
11586 html_start = '<pre class="language-APL">'
11687 html_end = '</pre>'
117-
118- _content = {
119- # 'output_type': 'display_data',
120- # 'data': {'text/plain': s},
121- 'data' : {'text/html' : html_start + html .escape (s , False ) + html_end },
122- 'execution_count' : self .execution_count ,
123- 'metadata' : {},
124-
125- # 'transient': ''
126- }
127-
128- self .send_response (self .iopub_socket , 'execute_result' , _content )
88+ self .Display (HTML (html_start + html .escape (s , False ) + html_end ))
12989
13090 def out_stream (self , s ):
13191 _content = {
@@ -195,7 +155,7 @@ def __init__(self, **kwargs):
195155 #from ipykernel import get_connection_file
196156 #s = get_connection_file()
197157 # debug("########## " + str(s))
198-
158+ super ( DyalogKernel , self ). __init__ ( ** kwargs )
199159 self ._port = DYALOG_PORT
200160 # lets find first available port, starting from default DYALOG_PORT (:4502)
201161 # this makes sense only if Dyalog APL and Jupyter executables are on the same host (localhost)
@@ -254,8 +214,6 @@ def __init__(self, **kwargs):
254214 self .dyalog_subprocess = subprocess .Popen ([dyalog , '+s' , '-q' , os .path .dirname (os .path .abspath (
255215 __file__ )) + '/init.dws' ], stdin = subprocess .PIPE , stdout = subprocess .DEVNULL , stderr = subprocess .DEVNULL , env = dyalog_env )
256216
257- Kernel .__init__ (self , ** kwargs )
258-
259217 self .dyalog_ride_connect ()
260218
261219 def recv_all (self , msg_len ):
@@ -327,8 +285,9 @@ def ride_send(self, d):
327285
328286 self .dyalogTCP .sendall (_data )
329287 debug ("SEND " + _data [8 :].decode ("utf-8" ))
330-
331- def do_execute (self , code , silent , store_history = True , user_expressions = None ,
288+
289+ #renamed to _do_execute to avoid overriding the do_execute method in MetaKernel
290+ def _do_execute (self , code , silent = False , store_history = True , user_expressions = None ,
332291 allow_stdin = True ):
333292 global SUSPEND
334293 code = code .strip ()
@@ -366,9 +325,8 @@ def do_execute(self, code, silent, store_history=True, user_expressions=None,
366325 self .define_function (lines )
367326 lines = []
368327 elif lines [0 ].lower () == ']dinput' :
369- lines = lines [1 :]
328+ lines = lines [1 :]
370329 try :
371- # the windows interpreter can only handle ~125 chacaters at a time, so we do one line at a time
372330 pt = None
373331 for line in lines :
374332 line = line + '\n '
@@ -463,6 +421,10 @@ def do_execute(self, code, silent, store_history=True, user_expressions=None,
463421 }
464422
465423 return reply_content
424+
425+ def do_execute_direct (self , code , silent = False ):
426+ #defers non-magic code execution to the do_execute function defined by Dyalog
427+ self ._do_execute (code , silent )
466428
467429 def execute_line (self , line ):
468430 self .ride_send (["Execute" , {"trace" : 0 , "text" : line }])
@@ -474,7 +436,7 @@ def define_function(self, lines):
474436 self .execute_line ("⎕SE.Dyalog.ipyFn,←⊂," + quoted + "\n " )
475437 self .ride_receive_wait ()
476438 dq .clear ()
477- if re .match ('^\\ s*:namespace|:class|:interface' ,lines [0 ].lower ()):
439+ if re .match ('^\\ s*:namespace|:class|:interface' ,lines [0 ].lower ()):
478440 self .execute_line ("{0::'DEFN ERROR'⋄⎕FIX ⍵}⎕SE.Dyalog.ipyFn\n " )
479441 else :
480442 self .execute_line ("{''≢0⍴r←⎕FX ⍵:511 ⎕SIGNAL⍨'DEFN ERROR: Issue on line ',⍕r}⎕SE.Dyalog.ipyFn\n " )
0 commit comments