Skip to content

Instantly share code, notes, and snippets.

@dsblank
Last active August 29, 2015 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsblank/dd03a2d030b13f5bad3d to your computer and use it in GitHub Desktop.
Save dsblank/dd03a2d030b13f5bad3d to your computer and use it in GitHub Desktop.
Abstract class for subprocess-based kernels
from metakernel import MetaKernel
from pexpect import replwrap, EOF
import signal
from subprocess import check_output
import re
__version__ = '0.0'
version_pat = re.compile(r'version (\d+(\.\d+)+)')
class ProcessKernel(MetaKernel):
implementation = 'process_kernel'
implementation_version = __version__
language = 'process'
@property
def language_version(self):
m = version_pat.search(self.banner)
return m.group(1)
_banner = "Process"
@property
def banner(self):
return self._banner
def __init__(self, **kwargs):
MetaKernel.__init__(self, **kwargs)
self._start()
def _start(self):
# Signal handlers are inherited by forked processes, and we can't easily
# reset it from the subprocess. Since kernelapp ignores SIGINT except in
# message handlers, we need to temporarily reset the SIGINT handler here
# so that command and its children are interruptible.
sig = signal.signal(signal.SIGINT, signal.SIG_DFL)
try:
self.wrapper = self.makeWrapper()
finally:
signal.signal(signal.SIGINT, sig)
def do_execute(self, code, silent, store_history=True, user_expressions=None,
allow_stdin=False):
### FIXME: need to handle magics here -----------------------------------
if not code.strip():
return {'status': 'ok', 'execution_count': self.execution_count,
'payload': [], 'user_expressions': {}}
interrupted = False
try:
output = self.wrapper.run_command(code.rstrip(), timeout=None)
except KeyboardInterrupt:
self.wrapper.child.sendintr()
interrupted = True
self.wrapper._expect_prompt()
output = self.wrapper.child.before
except EOF:
output = self.wrapper.child.before + 'Restarting'
self._start()
if not silent:
stream_content = {'name': 'stdout', 'text': output}
self.send_response(self.iopub_socket, 'stream', stream_content)
if interrupted:
return {'status': 'abort', 'execution_count': self.execution_count}
exitcode, trace = self.check_exitcode()
if exitcode:
return {'status': 'error', 'execution_count': self.execution_count,
'ename': '', 'evalue': str(exitcode), 'traceback': trace}
else:
return {'status': 'ok', 'execution_count': self.execution_count,
'payload': [], 'user_expressions': {}}
def check_exitcode(self):
"""
Return (1, ["trace"]) if error.
"""
return (0, None)
def makeWrapper(self):
return replwrap.REPLWrap(self.command, self.prompt, self.prompt_change,
self.kwargs)
class BashKernel(ProcessKernel):
# Identifiers:
implementation = 'bash_kernel'
language = 'bash'
_banner = "Bash Kernel"
# REPL:
command = "bash"
prompt = re.compile('[$#]')
prompt_change = u("PS1='{0}' PS2='{1}' PROMPT_COMMAND=''")
kwargs = {"extra_init_cmd": "export PAGER=cat"}
def check_exitcode(self):
return (int(self.wrapper.run_command('echo $?').rstrip()), [])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment