summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Silvester2014-08-01 20:24:25 -0500
committerSteven Silvester2014-08-01 20:24:25 -0500
commit6e96dceeb571b2076cab6aaeabe0e4282d5c4bad (patch)
tree7d8807ae05df69f6aafbc51373f2c07a2dc7d8f7
parent5649a246747dc466ecdfa4ecb2000fa03ea9c1b5 (diff)
downloadscilab_kernel-6e96dceeb571b2076cab6aaeabe0e4282d5c4bad.tar.gz
scilab_kernel-6e96dceeb571b2076cab6aaeabe0e4282d5c4bad.tar.bz2
scilab_kernel-6e96dceeb571b2076cab6aaeabe0e4282d5c4bad.zip
Improve help formatting and add docstring, refactor and cleanup
-rw-r--r--octave_kernel.py143
1 files changed, 123 insertions, 20 deletions
diff --git a/octave_kernel.py b/octave_kernel.py
index bd025ce..d634283 100644
--- a/octave_kernel.py
+++ b/octave_kernel.py
@@ -1,4 +1,5 @@
from IPython.kernel.zmq.kernelbase import Kernel
+from IPython.core.oinspect import Inspector, cast_unicode
from oct2py import octave, Oct2PyError
import os
@@ -43,38 +44,49 @@ class OctaveKernel(Kernel):
finally:
signal.signal(signal.SIGINT, sig)
+ self.inspector = Inspector()
+ self.inspector.set_active_scheme("Linux")
+
def do_execute(self, code, silent, store_history=True,
user_expressions=None, allow_stdin=False):
code = code.strip()
- abort_msg = {'status': 'abort',
+ abort_msg = {'status': 'abort',
'execution_count': self.execution_count}
+
if not code or code == 'keyboard' or code.startswith('keyboard('):
return {'status': 'ok', 'execution_count': self.execution_count,
'payload': [], 'user_expressions': {}}
+
elif (code == 'exit' or code.startswith('exit(')
or code == 'quit' or code.startswith('quit(')):
# TODO: exit gracefully here
self.do_shutdown(False)
return abort_msg
+
elif code == 'restart':
self.octavewrapper.restart()
return abort_msg
- elif code.endswith('?'):
- code = self._get_help(code)
- if not code:
- return abort_msg
+
+ elif code.endswith('?') or code.startswith('?'):
+ self._get_help(code)
+ return abort_msg
+
interrupted = False
try:
output = self.octavewrapper._eval([code])
+
except KeyboardInterrupt:
self.octavewrapper._session.proc.send_signal(signal.SIGINT)
interrupted = True
output = 'Octave Session Interrupted'
+
except Oct2PyError as e:
return self._handle_error(str(e))
+
except Exception:
self.octavewrapper.restart()
output = 'Uncaught Exception, Restarting Octave'
+
else:
if output is None:
output = ''
@@ -96,12 +108,14 @@ class OctaveKernel(Kernel):
default = {'matches': [], 'cursor_start': 0,
'cursor_end': cursor_pos, 'metadata': dict(),
'status': 'ok'}
+
if code[-1] == ' ':
return default
tokens = code.replace(';', ' ').split()
if not tokens:
return default
token = tokens[-1]
+
if os.sep in token:
dname = os.path.dirname(token)
rest = os.path.basename(token)
@@ -119,10 +133,24 @@ class OctaveKernel(Kernel):
for item in dir(self.octavewrapper):
if item.startswith(token) and not item in matches:
matches.append(item)
+
return {'matches': matches, 'cursor_start': start,
'cursor_end': cursor_pos, 'metadata': dict(),
'status': 'ok'}
+ def do_inspect(self, code, cursor_pos, detail_level=0):
+ data = dict()
+ if (not code or not len(code) >= cursor_pos or
+ not code[cursor_pos - 1] == '('):
+ return {'status': 'ok', 'data': data, 'metadata': dict()}
+
+ else:
+ token = code[:cursor_pos - 1].replace(';', '').split()[-1]
+ docstring = self._get_octave_info(token, detail_level)['docstring']
+ if docstring:
+ data = {'text/plain': docstring}
+ return {'status': 'ok', 'data': data, 'metadata': dict()}
+
def do_shutdown(self, restart):
if restart:
self.octavewrapper.restart()
@@ -131,36 +159,111 @@ class OctaveKernel(Kernel):
return Kernel.do_shutdown(self, restart)
def _get_help(self, code):
- if code[:-1] in dir(self.octavewrapper):
- output = getattr(self.octavewrapper, code[:-1]).__doc__
- stream_content = {'name': 'stdout', 'data': output}
- self.send_response(self.iopub_socket, 'stream', stream_content)
- code = None
- elif code.endswith('??') and code[:-2] in dir(self.octavewrapper):
- output = getattr(self.octavewrapper, code[:-2]).__doc__
- stream_content = {'name': 'stdout', 'data': output}
- self.send_response(self.iopub_socket, 'stream', stream_content)
- code = None
+ if code.startswith('??') or code.endswith('??'):
+ detail_level = 1
else:
- if code.endswith('??'):
- code = 'help("' + code[:-2] + '")\n\ntype ' + code[:-2]
- else:
- code = 'help("' + code[:-1] + '")'
- return code
+ detail_level = 0
+
+ code = code.replace('?', '')
+ info = self._get_octave_info(code, detail_level)
+ output = self._get_printable_info(info, detail_level)
+ stream_content = {'name': 'stdout', 'data': output}
+ self.send_response(self.iopub_socket, 'stream', stream_content)
def _handle_error(self, err):
if 'parse error:' in err:
err = 'Parse Error'
+
elif 'Octave returned:' in err:
err = err[err.index('Octave returned:'):]
err = err[len('Octave returned:'):].lstrip()
+
elif 'Syntax Error' in err:
err = 'Syntax Error'
+
stream_content = {'name': 'stdout', 'data': err.strip()}
self.send_response(self.iopub_socket, 'stream', stream_content)
+
return {'status': 'error', 'execution_count': self.execution_count,
'ename': '', 'evalue': err, 'traceback': []}
+ def _get_printable_info(self, info, detail_level=0):
+ inspector = self.inspector
+ displayfields = []
+
+ def add_fields(fields):
+ for title, key in fields:
+ field = info[key]
+ if field is not None:
+ displayfields.append((title, field.rstrip()))
+
+ add_fields(inspector.pinfo_fields1)
+ add_fields(inspector.pinfo_fields2)
+ add_fields(inspector.pinfo_fields3)
+
+ # Source or docstring, depending on detail level and whether
+ # source found.
+ if detail_level > 0 and info['source'] is not None:
+ source = cast_unicode(info['source'])
+ displayfields.append(("Source", source))
+
+ elif info['docstring'] is not None:
+ displayfields.append(("Docstring", info["docstring"]))
+
+ # Info for objects:
+ else:
+ add_fields(inspector.pinfo_fields_obj)
+
+ # Finally send to printer/pager:
+ if displayfields:
+ return inspector._format_fields(displayfields)
+
+ def _get_octave_info(self, obj, detail_level):
+ info_obj = dict(argspec=None, base_class=None, call_def=None,
+ call_docstring=None, class_docstring=None,
+ definition=None,
+ docstring=None, file=None, found=False,
+ init_definition=None, init_docstring=None, isalias=0,
+ isclass=None, ismagic=0, length=None, name='',
+ namespace=None, source=None, string_form=None,
+ type_name='')
+
+ oc = self.octavewrapper
+
+ if obj in dir(oc):
+ obj = getattr(oc, obj)
+ return self.inspector.info(obj, detail_level=detail_level)
+
+ exist = oc.run('exist "%s"' % obj)
+ if exist.endswith('0'):
+ return info_obj
+
+ try:
+ help_str = oc.run('help %s' % obj)
+ except Oct2PyError:
+ help_str = None
+ type_str = oc.type(obj)[0].strip()
+ cls_str = oc.run("class %s" % obj)[6:]
+
+ type_first_line = type_str.splitlines()[0]
+ type_str = '\n'.join(type_str.splitlines()[1:])
+ is_var = 'is a variable' in type_first_line
+
+ info_obj['found'] = True
+ info_obj['docstring'] = help_str or type_first_line
+ info_obj['type_name'] = cls_str if is_var else 'built-in function'
+ info_obj['source'] = help_str
+ info_obj['string_form'] = obj if not is_var else type_str.rstrip()
+
+ if type_first_line.rstrip().endswith('.m'):
+ info_obj['file'] = type_first_line.split()[-1]
+ info_obj['type_name'] = 'function'
+ info_obj['source'] = type_str
+ if not help_str:
+ info_obj['docstring'] = None
+
+ return info_obj
+
if __name__ == '__main__':
from IPython.kernel.zmq.kernelapp import IPKernelApp
IPKernelApp.launch_instance(kernel_class=OctaveKernel)