Skip to content

Instantly share code, notes, and snippets.

@komeda-shinji
Last active April 7, 2018 12:48
Show Gist options
  • Save komeda-shinji/1c864e9b6f88c33d978647f71ed002e2 to your computer and use it in GitHub Desktop.
Save komeda-shinji/1c864e9b6f88c33d978647f71ed002e2 to your computer and use it in GitHub Desktop.
diff -u kernel.py.orig kernel.py
--- kernel.py.orig 2018-04-07 21:45:29.000000000 +0900
+++ kernel.py 2018-04-07 21:46:30.000000000 +0900
@@ -4,6 +4,7 @@
from subprocess import check_output
import os.path
+import os
import re
import signal
@@ -29,16 +30,22 @@
def __init__(self, cmd_or_spawn, orig_prompt, prompt_change,
extra_init_cmd=None, line_output_callback=None):
self.line_output_callback = line_output_callback
+ self.prompt_list = []
+ self.prompt_list_ext = []
+ self.newline_pattern = [re.compile(r'\r\n')]
replwrap.REPLWrapper.__init__(self, cmd_or_spawn, orig_prompt,
prompt_change, extra_init_cmd=extra_init_cmd)
+ self.prompt_list.append(re.compile(re.escape(self.prompt)))
+ self.prompt_list.append(re.compile(re.escape(self.continuation_prompt)))
+ self.prompt_list_ext.append(re.compile(r'(\w[-\d\w]*?(@\w[-\d\w]*(:.+?)?)?)(\[\d+\]|\(\d+\))?([$%#>]\s*)(\033\[[0-9;]*[JKm])*$'))
+ self.compile_pattern_list = self.prompt_list + self.newline_pattern + self.prompt_list_ext
def _expect_prompt(self, timeout=-1):
if timeout == None:
# "None" means we are executing code from a Jupyter cell by way of the run_command
# in the do_execute() code below, so do incremental output.
while True:
- pos = self.child.expect_exact([self.prompt, self.continuation_prompt, u'\r\n'],
- timeout=None)
+ pos = self.child.expect_list(self.compile_pattern_list, timeout=timeout)
if pos == 2:
# End of line received
self.line_output_callback(self.child.before + '\n')
@@ -46,14 +53,44 @@
if len(self.child.before) != 0:
# prompt received, but partial line precedes it
self.line_output_callback(self.child.before)
+ if pos >= 3:
+ pos = 0
break
else:
# Otherwise, use existing non-incremental code
- pos = replwrap.REPLWrapper._expect_prompt(self, timeout=timeout)
+ if self.prompt_list:
+ pos = self.child.expect_list(self.prompt_list + self.prompt_list_ext, timeout=timeout)
+ else:
+ pos = self.child.expect_exact([self.prompt, self.continuation_prompt], timeout=timeout)
# Prompt received, so return normally
return pos
+ def run_command(self, command, timeout=-1):
+ # Split up multiline commands and feed them in bit-by-bit
+ cmdlines = command.splitlines()
+ # splitlines ignores trailing newlines - add it back in manually
+ if command.endswith('\n'):
+ cmdlines.append('')
+ if not cmdlines:
+ raise ValueError("No command was given")
+
+ res = []
+ self.child.sendline(cmdlines[0])
+ for line in cmdlines[1:]:
+ self._expect_prompt(timeout=timeout)
+ res.append(self.child.before)
+ self.child.sendline(line)
+
+ # Command was fully submitted, now wait for the next prompt
+ if self._expect_prompt(timeout=timeout) == 1:
+ # We got the continuation prompt - command was incomplete
+ os.kill(os.tcgetpgrp(self.child.child_fd), signal.SIGINT)
+ self._expect_prompt(timeout=5)
+ raise ValueError("Continuation prompt found - input was incomplete:\n"
+ + command)
+ return u''.join(res + [self.child.before])
+
class BashKernel(Kernel):
implementation = 'bash_kernel'
implementation_version = __version__
@@ -151,6 +188,9 @@
output = self.bashwrapper.child.before + 'Restarting Bash'
self._start_bash()
self.process_output(output)
+ except ValueError as e:
+ output = self.bashwrapper.child.before + str(e)
+ self.process_output(output)
if interrupted:
return {'status': 'abort', 'execution_count': self.execution_count}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment