@@ -120,7 +120,7 @@ async def recv(self, multipart=False):
120120 # _LOGGER.debug(f"recv: got cmd={cmd}, params={params}")
121121 else :
122122 parts .append (msg_body )
123- if cmd == 0x0 or cmd == 0x2 :
123+ if cmd in ( 0x0 , 0x2 ) :
124124 # _LOGGER.debug(f"recv: got msg {parts}")
125125 if not multipart :
126126 return b'' .join (parts )
@@ -311,218 +311,205 @@ def encode(msg):
311311 # else:
312312 # _LOGGER.debug("send skipping msg_type %s since socket is None", msg_type)
313313
314- async def shell_handler (self , shell_socket , full_msg ):
314+ async def shell_handler (self , shell_socket , wire_msg ):
315315 """Handle shell messages."""
316- #
317- # Jupyter extensions like black can send several execute requests back-to-back, so
318- # we need to handle multiple messages separated by DELIM
319- #
320- msg_list = None
321- for this_msg in full_msg :
322- if this_msg == DELIM :
323- if msg_list is None :
324- msg_list = [[this_msg ]]
325- else :
326- msg_list .append ([this_msg ])
327- else :
328- msg_list [- 1 ].append (this_msg ) # pylint: disable=unsubscriptable-object
329- for this_msg in msg_list : # pylint: disable=too-many-nested-blocks
330- identities , msg = self .deserialize_wire_msg (this_msg )
331- # _LOGGER.debug("shell received %s: %s", msg.get('header', {}).get('msg_type', 'UNKNOWN'), msg)
332316
333- content = {
334- 'execution_state' : "busy" ,
335- }
336- await self .send (self .iopub_socket , 'status' , content , parent_header = msg ['header' ])
317+ identities , msg = self .deserialize_wire_msg (wire_msg )
318+ # _LOGGER.debug("shell received %s: %s", msg.get('header', {}).get('msg_type', 'UNKNOWN'), msg)
319+ self .parent_header = msg ['header' ]
337320
338- self .parent_header = msg ['header' ]
339-
340- # process request:
321+ content = {
322+ 'execution_state' : "busy" ,
323+ }
324+ await self .send (self .iopub_socket , 'status' , content , parent_header = msg ['header' ])
341325
342- if msg ['header' ]["msg_type" ] == "execute_request" :
326+ if msg ['header' ]["msg_type" ] == "execute_request" :
343327
344- content = {
345- 'execution_count' : self .execution_count ,
346- 'code' : msg ['content' ]["code" ],
347- }
348- await self .send (self .iopub_socket , 'execute_input' , content , parent_header = msg ['header' ])
328+ content = {
329+ 'execution_count' : self .execution_count ,
330+ 'code' : msg ['content' ]["code" ],
331+ }
332+ await self .send (self .iopub_socket , 'execute_input' , content , parent_header = msg ['header' ])
349333
350- code = msg ['content' ]["code" ]
351- self .ast_ctx .parse (code )
334+ code = msg ['content' ]["code" ]
335+ self .ast_ctx .parse (code )
336+ exc = self .ast_ctx .get_exception_obj ()
337+ if exc is None :
338+ result = await self .ast_ctx .eval ()
352339 exc = self .ast_ctx .get_exception_obj ()
353- if exc is None :
354- result = await self .ast_ctx .eval ()
355- exc = self .ast_ctx .get_exception_obj ()
356- if exc :
357- traceback_mesg = self .ast_ctx .get_exception_long ().split ("\n " )
358-
359- if msg ['content' ].get ("store_history" , True ):
360- self .execution_count += 1
361-
362- metadata = {
363- "dependencies_met" : True ,
364- "engine" : self .engine_id ,
365- "status" : "error" ,
366- "started" : datetime .datetime .now ().isoformat (),
367- }
368- content = {
369- 'execution_count' : self .execution_count ,
370- 'status' : 'error' ,
371- 'ename' : type (exc ).__name__ , # Exception name, as a string
372- 'evalue' : str (exc ), # Exception value, as a string
373- 'traceback' : traceback_mesg ,
374- }
375- _LOGGER .debug ("Executing '%s' got exception: %s" , code , content )
376- await self .send (shell_socket , 'execute_reply' , content , metadata = metadata ,
377- parent_header = msg ['header' ], identities = identities )
378- del content ["execution_count" ], content ["status" ]
379- await self .send (self .iopub_socket , 'error' , content , parent_header = msg ['header' ])
380-
381- content = {
382- 'execution_state' : "idle" ,
383- }
384- await self .send (self .iopub_socket , 'status' , content , parent_header = msg ['header' ])
385- return
386-
387- # if True or isinstance(self.ast_ctx.ast, ast.Expr):
388- _LOGGER .debug ("Executing: '%s' got result %s" , code , result )
389- if result is not None :
390- content = {
391- 'execution_count' : self .execution_count ,
392- 'data' : {"text/plain" : repr (result )},
393- 'metadata' : {}
394- }
395- await self .send (self .iopub_socket , 'execute_result' , content , parent_header = msg ['header' ])
396-
340+ if exc :
341+ traceback_mesg = self .ast_ctx .get_exception_long ().split ("\n " )
397342
398343 metadata = {
399344 "dependencies_met" : True ,
400345 "engine" : self .engine_id ,
401- "status" : "ok " ,
346+ "status" : "error " ,
402347 "started" : datetime .datetime .now ().isoformat (),
403348 }
404349 content = {
405- "status" : "ok" ,
406- "execution_count" : self . execution_count ,
407- "user_variables" : {},
408- "payload" : [],
409- "user_expressions" : {} ,
350+ 'execution_count' : self . execution_count ,
351+ 'status' : 'error' ,
352+ 'ename' : type ( exc ). __name__ , # Exception name, as a string
353+ 'evalue' : str ( exc ), # Exception value, as a string
354+ 'traceback' : traceback_mesg ,
410355 }
356+ _LOGGER .debug ("Executing '%s' got exception: %s" , code , content )
411357 await self .send (shell_socket , 'execute_reply' , content , metadata = metadata ,
412358 parent_header = msg ['header' ], identities = identities )
413- if msg [ ' content' ]. get ( "store_history" , True ):
414- self .execution_count += 1
415- elif msg [ 'header' ][ "msg_type" ] == "kernel_info_request" :
359+ del content [ "execution_count" ], content [ "status" ]
360+ await self .send ( self . iopub_socket , 'error' , content , parent_header = msg [ 'header' ])
361+
416362 content = {
417- "protocol_version" : "5.3" ,
418- "ipython_version" : [1 , 1 , 0 , "" ],
419- "language_version" : [0 , 0 , 1 ],
420- "language" : "python" ,
421- "implementation" : "python" ,
422- "implementation_version" : "3.7" ,
423- "language_info" : {
424- "name" : "python" ,
425- "version" : "1.0" ,
426- 'mimetype' : "" ,
427- 'file_extension' : ".py" ,
428- #'pygments_lexer': "",
429- 'codemirror_mode' : "" ,
430- 'nbconvert_exporter' : "" ,
431- },
432- "banner" : ""
363+ 'execution_state' : "idle" ,
433364 }
434- await self .send (shell_socket , 'kernel_info_reply' , content , parent_header = msg ['header' ], identities = identities )
435- elif msg ['header' ]["msg_type" ] == "complete_request" :
436365 await self .send (self .iopub_socket , 'status' , content , parent_header = msg ['header' ])
366+ if msg ['content' ].get ("store_history" , True ):
367+ self .execution_count += 1
368+ return
437369
438- code = msg ["content" ]["code" ]
439- posn = msg ["content" ]["cursor_pos" ]
440- match = self .completion_re .match (code [0 :posn ].lower ())
441- if match :
442- root = match [1 ].lower ()
443- words = self .ast_ctx .state .completions (root )
444- words = words .union (await self .ast_ctx .handler .service_completions (root ))
445- words = words .union (await self .ast_ctx .handler .func_completions (root ))
446- words = words .union (self .ast_ctx .completions (root ))
447- else :
448- root = ""
449- words = set ()
450- # _LOGGER.debug(f"complete_request code={code}, posn={posn}, root={root}, words={words}")
370+ # if True or isinstance(self.ast_ctx.ast, ast.Expr):
371+ _LOGGER .debug ("Executing: '%s' got result %s" , code , result )
372+ if result is not None :
451373 content = {
452- "status" : "ok" ,
453- "matches" : sorted (list (words )),
454- "cursor_start" : msg ["content" ]["cursor_pos" ] - len (root ),
455- "cursor_end" : msg ["content" ]["cursor_pos" ],
456- "metadata" : {},
374+ 'execution_count' : self .execution_count ,
375+ 'data' : {"text/plain" : repr (result )},
376+ 'metadata' : {}
457377 }
458- await self .send (shell_socket , 'complete_reply ' , content , parent_header = msg ['header' ], identities = identities )
378+ await self .send (self . iopub_socket , 'execute_result ' , content , parent_header = msg ['header' ])
459379
460- elif msg ['header' ]["msg_type" ] == "is_complete_request" :
461- code = msg ['content' ]["code" ]
462- self .ast_ctx .parse (code )
463- exc = self .ast_ctx .get_exception_obj ()
380+ metadata = {
381+ "dependencies_met" : True ,
382+ "engine" : self .engine_id ,
383+ "status" : "ok" ,
384+ "started" : datetime .datetime .now ().isoformat (),
385+ }
386+ content = {
387+ "status" : "ok" ,
388+ "execution_count" : self .execution_count ,
389+ "user_variables" : {},
390+ "payload" : [],
391+ "user_expressions" : {},
392+ }
393+ await self .send (shell_socket , 'execute_reply' , content , metadata = metadata ,
394+ parent_header = msg ['header' ], identities = identities )
395+ if msg ['content' ].get ("store_history" , True ):
396+ self .execution_count += 1
397+
398+ elif msg ['header' ]["msg_type" ] == "kernel_info_request" :
399+ content = {
400+ "protocol_version" : "5.3" ,
401+ "ipython_version" : [1 , 1 , 0 , "" ],
402+ "language_version" : [0 , 0 , 1 ],
403+ "language" : "python" ,
404+ "implementation" : "python" ,
405+ "implementation_version" : "3.7" ,
406+ "language_info" : {
407+ "name" : "python" ,
408+ "version" : "1.0" ,
409+ 'mimetype' : "" ,
410+ 'file_extension' : ".py" ,
411+ #'pygments_lexer': "",
412+ 'codemirror_mode' : "" ,
413+ 'nbconvert_exporter' : "" ,
414+ },
415+ "banner" : ""
416+ }
417+ await self .send (shell_socket , 'kernel_info_reply' , content , parent_header = msg ['header' ], identities = identities )
464418
465- # determine indent of last line
466- indent = 0
467- i = code .rfind ("\n " )
468- if i >= 0 :
469- while i + 1 < len (code ) and code [i + 1 ] == " " :
470- i += 1
471- indent += 1
472- if exc is None :
473- if indent == 0 :
474- content = {
475- # One of 'complete', 'incomplete', 'invalid', 'unknown'
476- "status" : 'complete' ,
477- # If status is 'incomplete', indent should contain the characters to use
478- # to indent the next line. This is only a hint: frontends may ignore it
479- # and use their own autoindentation rules. For other statuses, this
480- # field does not exist.
481- #"indent": str,
482- }
483- else :
484- content = {
485- "status" : 'incomplete' ,
486- "indent" : " " * indent ,
487- }
419+ elif msg ['header' ]["msg_type" ] == "complete_request" :
420+ await self .send (self .iopub_socket , 'status' , content , parent_header = msg ['header' ])
421+
422+ code = msg ["content" ]["code" ]
423+ posn = msg ["content" ]["cursor_pos" ]
424+ match = self .completion_re .match (code [0 :posn ].lower ())
425+ if match :
426+ root = match [1 ].lower ()
427+ words = self .ast_ctx .state .completions (root )
428+ words = words .union (await self .ast_ctx .handler .service_completions (root ))
429+ words = words .union (await self .ast_ctx .handler .func_completions (root ))
430+ words = words .union (self .ast_ctx .completions (root ))
431+ else :
432+ root = ""
433+ words = set ()
434+ # _LOGGER.debug(f"complete_request code={code}, posn={posn}, root={root}, words={words}")
435+ content = {
436+ "status" : "ok" ,
437+ "matches" : sorted (list (words )),
438+ "cursor_start" : msg ["content" ]["cursor_pos" ] - len (root ),
439+ "cursor_end" : msg ["content" ]["cursor_pos" ],
440+ "metadata" : {},
441+ }
442+ await self .send (shell_socket , 'complete_reply' , content , parent_header = msg ['header' ], identities = identities )
443+
444+ elif msg ['header' ]["msg_type" ] == "is_complete_request" :
445+ code = msg ['content' ]["code" ]
446+ self .ast_ctx .parse (code )
447+ exc = self .ast_ctx .get_exception_obj ()
448+
449+ # determine indent of last line
450+ indent = 0
451+ i = code .rfind ("\n " )
452+ if i >= 0 :
453+ while i + 1 < len (code ) and code [i + 1 ] == " " :
454+ i += 1
455+ indent += 1
456+ if exc is None :
457+ if indent == 0 :
458+ content = {
459+ # One of 'complete', 'incomplete', 'invalid', 'unknown'
460+ "status" : 'complete' ,
461+ # If status is 'incomplete', indent should contain the characters to use
462+ # to indent the next line. This is only a hint: frontends may ignore it
463+ # and use their own autoindentation rules. For other statuses, this
464+ # field does not exist.
465+ #"indent": str,
466+ }
488467 else :
489- #
490- # if the syntax error is right at the end, then we label it incomplete,
491- # otherwise it's invalid
492- #
493- if str (exc ).find ("EOF while" ) >= 0 :
494- # if error is at ":" then increase indent
495- if hasattr (exc , "lineno" ):
496- line = code .split ("\n " )[exc .lineno - 1 ]
497- if self .colon_end_re .match (line ):
498- indent += 4
499- content = {
500- "status" : 'incomplete' ,
501- "indent" : " " * indent ,
502- }
503- else :
504- content = {
505- "status" : 'invalid' ,
506- }
507- # _LOGGER.debug(f"is_complete_request code={code}, exc={exc}, content={content}")
508- await self .send (shell_socket , 'is_complete_reply' , content , parent_header = msg ['header' ], identities = identities )
509- elif msg ['header' ]["msg_type" ] == "comm_info_request" :
510- content = {
511- "comms" : {}
512- }
513- await self .send (shell_socket , 'comm_info_reply' , content , parent_header = msg ['header' ], identities = identities )
514- elif msg ['header' ]["msg_type" ] == "history_request" :
515- content = {
516- "history" : []
517- }
518- await self .send (shell_socket , 'history_reply' , content , parent_header = msg ['header' ], identities = identities )
468+ content = {
469+ "status" : 'incomplete' ,
470+ "indent" : " " * indent ,
471+ }
519472 else :
520- _LOGGER .error ("unknown msg_type: %s" , msg ['header' ]["msg_type" ])
473+ #
474+ # if the syntax error is right at the end, then we label it incomplete,
475+ # otherwise it's invalid
476+ #
477+ if str (exc ).find ("EOF while" ) >= 0 :
478+ # if error is at ":" then increase indent
479+ if hasattr (exc , "lineno" ):
480+ line = code .split ("\n " )[exc .lineno - 1 ]
481+ if self .colon_end_re .match (line ):
482+ indent += 4
483+ content = {
484+ "status" : 'incomplete' ,
485+ "indent" : " " * indent ,
486+ }
487+ else :
488+ content = {
489+ "status" : 'invalid' ,
490+ }
491+ # _LOGGER.debug(f"is_complete_request code={code}, exc={exc}, content={content}")
492+ await self .send (shell_socket , 'is_complete_reply' , content , parent_header = msg ['header' ], identities = identities )
521493
494+ elif msg ['header' ]["msg_type" ] == "comm_info_request" :
522495 content = {
523- 'execution_state' : "idle" ,
496+ "comms" : {}
524497 }
525- await self .send (self .iopub_socket , 'status' , content , parent_header = msg ['header' ])
498+ await self .send (shell_socket , 'comm_info_reply' , content , parent_header = msg ['header' ], identities = identities )
499+
500+ elif msg ['header' ]["msg_type" ] == "history_request" :
501+ content = {
502+ "history" : []
503+ }
504+ await self .send (shell_socket , 'history_reply' , content , parent_header = msg ['header' ], identities = identities )
505+
506+ else :
507+ _LOGGER .error ("unknown msg_type: %s" , msg ['header' ]["msg_type" ])
508+
509+ content = {
510+ 'execution_state' : "idle" ,
511+ }
512+ await self .send (self .iopub_socket , 'status' , content , parent_header = msg ['header' ])
526513
527514 async def control_listen (self , reader , writer ):
528515 """Task that listens to control messages."""
0 commit comments