Last active
August 29, 2015 14:09
-
-
Save dsblank/dd03a2d030b13f5bad3d to your computer and use it in GitHub Desktop.
Abstract class for subprocess-based kernels
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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