-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
General cleanup take #2 #30
Changes from all commits
f1001c8
988f9f3
40f950b
9a7acbe
9fc9cc8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,14 +3,17 @@ | |
|
||
from metakernel import MetaKernel | ||
from .init_spark_magic import InitSparkMagic | ||
from .scala_interpreter import ScalaException, SparkInterpreter | ||
from .scala_interpreter import ScalaException, ScalaInterpreter | ||
from .scala_magic import ScalaMagic | ||
from ._version import get_versions | ||
|
||
|
||
class SpylonKernel(MetaKernel): | ||
"""Jupyter kernel that supports code evaluation using the Scala REPL | ||
via py4j. | ||
|
||
Currently uses a ScalaMagic instance as a bridge to a `ScalaInterpreter` | ||
to let that functionality remain separate for reuse outside the kernel. | ||
""" | ||
implementation = 'spylon-kernel' | ||
implementation_version = get_versions()['version'] | ||
|
@@ -41,42 +44,99 @@ class SpylonKernel(MetaKernel): | |
def __init__(self, *args, **kwargs): | ||
self._scalamagic = None | ||
super(SpylonKernel, self).__init__(*args, **kwargs) | ||
# Register the %%scala and %%init_spark magics | ||
# The %%scala one is here only because this classes uses it | ||
# to interact with the ScalaInterpreter instance | ||
self.register_magics(ScalaMagic) | ||
self.register_magics(InitSparkMagic) | ||
self._scalamagic = self.line_magics['scala'] | ||
|
||
@property | ||
def scala_interpreter(self): | ||
"""Gets the `ScalaInterpreter` instance associated with the ScalaMagic | ||
for direct use. | ||
|
||
Returns | ||
------- | ||
ScalaInterpreter | ||
""" | ||
# noinspection PyProtectedMember | ||
intp = self._scalamagic._get_scala_interpreter() | ||
assert isinstance(intp, SparkInterpreter) | ||
assert isinstance(intp, ScalaInterpreter) | ||
return intp | ||
|
||
def get_usage(self): | ||
"""Gets usage information about the kernel itself. | ||
|
||
Implements the expected MetaKernel interface for this method. | ||
""" | ||
return "This is spylon-kernel. It implements a Scala interpreter." | ||
|
||
def set_variable(self, name, value): | ||
"""Sets a variable in the kernel language. | ||
|
||
Implements the expected MetaKernel interface for this method. | ||
|
||
Parameters | ||
---------- | ||
name : str | ||
Variable name | ||
value : any | ||
Variable value to set | ||
|
||
Notes | ||
----- | ||
Since metakernel calls this to bind kernel into the remote space we | ||
don't actually want that to happen. Simplest is just to have this | ||
flag as None initially. Furthermore the metakernel will attempt to | ||
set things like _i1, _i, _ii etc. These we dont want in the kernel | ||
for now. | ||
""" | ||
Set a variable in the kernel language. | ||
""" | ||
# Since metakernel calls this to bind kernel into the remote space we | ||
# don't actually want that to happen. Simplest is just to have this | ||
# flag as None initially. Furthermore the metakernel will attempt to | ||
# set things like _i1, _i, _ii etc. These we dont want in the kernel | ||
# for now. | ||
if self._scalamagic and (not name.startswith("_i")): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are your feelings on logging attempts to set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will happen after almost every cell execution as MetaKernel will update the FIFO queue of commands and outputs, so the logs will get pretty chatty. We could log at the debug level. |
||
self.scala_interpreter.bind(name, value) | ||
else: | ||
self.log.debug('Not setting variable %s', name) | ||
|
||
def get_variable(self, name): | ||
""" | ||
Get a variable from the kernel as a Python-typed value. | ||
"""Get a variable from the kernel as a Python-typed value. | ||
|
||
Implements the expected MetaKernel interface for this method. | ||
|
||
Parameters | ||
---------- | ||
name : str | ||
Scala variable name | ||
|
||
Returns | ||
------- | ||
value : any | ||
Scala variable value, tranformed to a Python type | ||
""" | ||
if self._scalamagic: | ||
intp = self.scala_interpreter | ||
intp.interpret(name) | ||
return intp.last_result() | ||
|
||
def do_execute_direct(self, code, silent=False): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this extra kwarg? |
||
"""Executes code in the kernel language. | ||
|
||
Implements the expected MetaKernel interface for this method, | ||
including all positional and keyword arguments. | ||
|
||
Parameters | ||
---------- | ||
code : str | ||
Scala code to execute | ||
silent : bool, optional | ||
Silence output from this execution, ignored | ||
|
||
Returns | ||
------- | ||
any | ||
Result of the execution to be formatted for inclusion in | ||
a `execute_result` or `error` message from the kernel to | ||
frontends | ||
""" | ||
try: | ||
res = self._scalamagic.eval(code.strip(), raw=False) | ||
if res: | ||
|
@@ -85,14 +145,48 @@ def do_execute_direct(self, code, silent=False): | |
return self.Error(e.scala_message) | ||
|
||
def get_completions(self, info): | ||
"""Gets completions from the kernel based on the provided info. | ||
|
||
Implements the expected MetaKernel interface for this method. | ||
|
||
Parameters | ||
---------- | ||
info : dict | ||
Information returned by `metakernel.parser.Parser.parse_code` | ||
including `code`, `help_pos`, `start`, etc. | ||
|
||
Returns | ||
------- | ||
list of str | ||
Possible completions for the code | ||
""" | ||
return self._scalamagic.get_completions(info) | ||
|
||
def get_kernel_help_on(self, info, level=0, none_on_fail=False): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another spurious kwarg? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed in person, will doc how these are all implementing the expected MetaKernel interface. |
||
"""Gets help text for the `info['help_obj']` identifier. | ||
|
||
Implements the expected MetaKernel interface for this method, | ||
including all positional and keyword arguments. | ||
|
||
Parameters | ||
---------- | ||
info : dict | ||
Information returned by `metakernel.parser.Parser.parse_code` | ||
including `help_obj`, etc. | ||
level : int, optional | ||
Level of help to request, 0 for basic, 1 for more, etc. | ||
none_on_fail : bool, optional | ||
Return none when code excution fails | ||
|
||
Returns | ||
------- | ||
str | ||
Help text | ||
""" | ||
return self._scalamagic.get_help_on(info, level, none_on_fail) | ||
|
||
def do_is_complete(self, code): | ||
""" | ||
Given code as string, returns dictionary with 'status' representing | ||
"""Given code as string, returns a dictionary with 'status' representing | ||
whether code is ready to evaluate. Possible values for status are: | ||
|
||
'complete' - ready to evaluate | ||
|
@@ -103,20 +197,29 @@ def do_is_complete(self, code): | |
Optionally, if 'status' is 'incomplete', you may indicate | ||
an indentation string. | ||
|
||
Example: | ||
Parameters | ||
---------- | ||
code : str | ||
Scala code to check for completion | ||
|
||
Returns | ||
------- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delete blank returns? |
||
dict | ||
Status of the completion | ||
|
||
return {'status' : 'incomplete', | ||
'indent': ' ' * 4} | ||
Example | ||
------- | ||
return {'status' : 'incomplete', 'indent': ' ' * 4} | ||
""" | ||
# Handle magics and the case where the interpreter is not yet | ||
# instantiated. We don't want to create it just to do completion | ||
# since it will take a while to initialize and appear hung to the user. | ||
if code.startswith(self.magic_prefixes['magic']) or not self._scalamagic._is_complete_ready: | ||
# force requirement to end with an empty line | ||
if code.endswith("\n"): | ||
return {'status': 'complete', 'indent': ''} | ||
else: | ||
return {'status': 'incomplete', 'indent': ''} | ||
# The scala interpreter can take a while to be alive, only use the | ||
# fancy method when we don't need to lazily instantiate the | ||
# interpreter. | ||
status = self.scala_interpreter.is_complete(code) | ||
# TODO: We can probably do a better job of detecting a good indent | ||
# level here by making use of a code parser such as pygments | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks almost fully qualified. Should this be:
py4j.java_gateway.JVMView. scala.tools.nsc.interpreter.PresentationCompilerCompleter
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scala.tools.nsc.interpreter.PresentationCompilerCompleter
is the Scala type.py4j.java_gateway.JVMView
is a made up namespace which allows Python code to reference them I believe. There is no real Python module+typepy4j.java_gateway.JVMView. scala.tools.nsc.interpreter.PresentationCompilerCompleter
.What to do, what to do ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah alright well fair enough then. Made up object paths, yey