Skip to content

Latest commit

 

History

History
193 lines (133 loc) · 7.13 KB

wrapperkernels.rst

File metadata and controls

193 lines (133 loc) · 7.13 KB

Making simple Python wrapper kernels

You can re-use IPython's kernel machinery to easily make new kernels. This is useful for languages that have Python bindings, such as Hy (see Calysto Hy), or languages where the REPL can be controlled in a tty using pexpect, such as bash.

bash_kernel

A simple kernel for bash, written using this machinery

The Metakernel library makes it easier to write a wrapper kernel that includes a base set of line and cell magics. It also has a ProcessKernel subclass that makes it easy to write kernels that use pexpect. See Octave Kernel as an example.

Required steps

Subclass ipykernel.kernelbase.Kernel, and implement the following methods and attributes:

implementation implementation_version banner

Information for msging_kernel_info replies. 'Implementation' refers to the kernel (e.g. IPython), rather than the language (e.g. Python). The 'banner' is displayed to the user in console UIs before the first prompt. All of these values are strings.

language_info

Language information for msging_kernel_info replies, in a dictionary. This should contain the key mimetype with the mimetype of code in the target language (e.g. 'text/x-python'), the name of the language being implemented (e.g. 'python'), and file_extension (e.g. '.py'). It may also contain keys codemirror_mode and pygments_lexer if they need to differ from language.

Other keys may be added to this later.

do_execute(code, silent, store_history=True, user_expressions=None, allow_stdin=False)

Execute user code.

param str code

The code to be executed.

param bool silent

Whether to display output.

param bool store_history

Whether to record this code in history and increase the execution count. If silent is True, this is implicitly False.

param dict user_expressions

Mapping of names to expressions to evaluate after the code has run. You can ignore this if you need to.

param bool allow_stdin

Whether the frontend can provide input on request (e.g. for Python's raw_input).

Your method should return a dict containing the fields described in execution_results. To display output, it can send messages using ~ipykernel.kernelbase.Kernel.send_response. If an error occurs during execution, an message of type error should be sent through ~ipykernel.kernelbase.Kernel.send_response in addition to an execution_results with an status of error. See messaging for details of the different message types.

ipykernel.kernelbase.Kernel.send_response

To launch your kernel, add this at the end of your module:

if __name__ == '__main__':
    from ipykernel.kernelapp import IPKernelApp
    IPKernelApp.launch_instance(kernel_class=MyKernel)

Now create a JSON kernel spec file and install it using jupyter kernelspec install </path/to/kernel>. Place your kernel module anywhere Python can import it (try current directory for testing). Finally, you can run your kernel using jupyter console --kernel <mykernelname>. Note that <mykernelname> in the below example is echo.

Example

echo_kernel

A packaged, installable version of the condensed example below.

echokernel.py will simply echo any input it's given to stdout:

from ipykernel.kernelbase import Kernel

class EchoKernel(Kernel):
    implementation = 'Echo'
    implementation_version = '1.0'
    language = 'no-op'
    language_version = '0.1'
    language_info = {
        'name': 'Any text',
        'mimetype': 'text/plain',
        'file_extension': '.txt',
    }
    banner = "Echo kernel - as useful as a parrot"

    def do_execute(self, code, silent, store_history=True, user_expressions=None,
                   allow_stdin=False):
        if not silent:
            stream_content = {'name': 'stdout', 'text': code}
            self.send_response(self.iopub_socket, 'stream', stream_content)

        return {'status': 'ok',
                # The base class increments the execution count
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {},
               }

if __name__ == '__main__':
    from ipykernel.kernelapp import IPKernelApp
    IPKernelApp.launch_instance(kernel_class=EchoKernel)

Here's the Kernel spec kernel.json file for this:

{"argv":["python","-m","echokernel", "-f", "{connection_file}"],
 "display_name":"Echo"
}

Optional steps

You can override a number of other methods to improve the functionality of your kernel. All of these methods should return a dictionary as described in the relevant section of the messaging spec <messaging>.

do_complete(code, cursor_pos)

Code completion

param str code

The code already present

param int cursor_pos

The position in the code where completion is requested

msging_completion messages

do_inspect(code, cursor_pos, detail_level=0)

Object introspection

param str code

The code

param int cursor_pos

The position in the code where introspection is requested

param int detail_level

0 or 1 for more or less detail. In IPython, 1 gets the source code.

msging_inspection messages

do_history(hist_access_type, output, raw, session=None, start=None, stop=None, n=None, pattern=None, unique=False)

History access. Only the relevant parameters for the type of history request concerned will be passed, so your method definition must have defaults for all the arguments shown with defaults here.

msging_history messages

do_is_complete(code)

Is code entered in a console-like interface complete and ready to execute, or should a continuation prompt be shown?

param str code

The code entered so far - possibly multiple lines

msging_is_complete messages

do_shutdown(restart)

Shutdown the kernel. You only need to handle your own clean up - the kernel machinery will take care of cleaning up its own things before stopping.

param bool restart

Whether the kernel will be started again afterwards

msging_shutdown messages