99
1010from collections import deque
1111
12-
13- from ipykernel . kernelbase import Kernel
12+ from metakernel import MetaKernel
13+ from IPython . display import HTML , Image
1414from dyalog_kernel import __version__
1515
1616if sys .platform .lower ().startswith ('win' ):
@@ -49,7 +49,7 @@ def writeln(s):
4949 sys .stdout = tmp_stdout
5050
5151
52- class DyalogKernel (Kernel ):
52+ class DyalogKernel (MetaKernel ):
5353
5454 implementation = 'Dyalog'
5555 implementation_version = __version__
@@ -72,60 +72,19 @@ class DyalogKernel(Kernel):
7272 dyalog_subprocess = None
7373
7474 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 )
75+ self .Error (s )
8176
8277 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 )
78+ #width and height values are fixed to maintain consistency with original implementation
79+ self .Display (Image (data = s , width = 120 , height = 80 ))
10180
10281 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 )
82+ self .Display (HTML (s ))
11183
11284 def out_result (self , s ):
113- # injecting css: white-space:pre. Means no wrapping, RIDE SetPW will take care about line wrapping
114-
11585 html_start = '<pre class="language-APL">'
11686 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 )
87+ self .Display (HTML (html_start + html .escape (s , False ) + html_end ))
12988
13089 def out_stream (self , s ):
13190 _content = {
@@ -195,7 +154,7 @@ def __init__(self, **kwargs):
195154 #from ipykernel import get_connection_file
196155 #s = get_connection_file()
197156 # debug("########## " + str(s))
198-
157+ super ( DyalogKernel , self ). __init__ ( ** kwargs )
199158 self ._port = DYALOG_PORT
200159 # lets find first available port, starting from default DYALOG_PORT (:4502)
201160 # this makes sense only if Dyalog APL and Jupyter executables are on the same host (localhost)
@@ -254,8 +213,6 @@ def __init__(self, **kwargs):
254213 self .dyalog_subprocess = subprocess .Popen ([dyalog , '+s' , '-q' , os .path .dirname (os .path .abspath (
255214 __file__ )) + '/init.dws' ], stdin = subprocess .PIPE , stdout = subprocess .DEVNULL , stderr = subprocess .DEVNULL , env = dyalog_env )
256215
257- Kernel .__init__ (self , ** kwargs )
258-
259216 self .dyalog_ride_connect ()
260217
261218 def recv_all (self , msg_len ):
@@ -327,8 +284,9 @@ def ride_send(self, d):
327284
328285 self .dyalogTCP .sendall (_data )
329286 debug ("SEND " + _data [8 :].decode ("utf-8" ))
330-
331- def do_execute (self , code , silent , store_history = True , user_expressions = None ,
287+
288+ #renamed to _do_execute to avoid overriding the do_execute method in MetaKernel
289+ def _do_execute (self , code , silent = False , store_history = True , user_expressions = None ,
332290 allow_stdin = True ):
333291 global SUSPEND
334292 code = code .strip ()
@@ -355,9 +313,8 @@ def do_execute(self, code, silent, store_history=True, user_expressions=None,
355313 'JUPYTER NOTEBOOK: UNDEFINED ARGUMENT TO %suspend, USE EITHER on OR off' )
356314 lines = lines [1 :]
357315 elif lines [0 ].lower () == ']dinput' :
358- lines = lines [1 :]
316+ lines = lines [1 :]
359317 try :
360- # the windows interpreter can only handle ~125 chacaters at a time, so we do one line at a time
361318 pt = None
362319 for line in lines :
363320 line = line + '\n '
@@ -452,6 +409,10 @@ def do_execute(self, code, silent, store_history=True, user_expressions=None,
452409 }
453410
454411 return reply_content
412+
413+ def do_execute_direct (self , code , silent = False ):
414+ #defers non-magic code execution to the do_execute function defined by Dyalog
415+ self ._do_execute (code , silent )
455416
456417 def execute_line (self , line ):
457418 self .ride_send (["Execute" , {"trace" : 0 , "text" : line }])
@@ -463,7 +424,7 @@ def define_function(self, lines):
463424 self .execute_line ("⎕SE.Dyalog.ipyFn,←⊂," + quoted + "\n " )
464425 self .ride_receive_wait ()
465426 dq .clear ()
466- if re .match ('^\\ s*:namespace|:class|:interface' ,lines [0 ].lower ()):
427+ if re .match ('^\\ s*:namespace|:class|:interface' ,lines [0 ].lower ()):
467428 self .execute_line ("{0::'DEFN ERROR'⋄⎕FIX ⍵}⎕SE.Dyalog.ipyFn\n " )
468429 else :
469430 self .execute_line ("{''≢0⍴r←⎕FX ⍵:511 ⎕SIGNAL⍨'DEFN ERROR: Issue on line ',⍕r}⎕SE.Dyalog.ipyFn\n " )
0 commit comments