制作简单的 Python 包装器内核

你可以复用 IPython 的内核机制来轻松制作新的内核。这对有 Python 绑定的语言很有用,比如 Hy (见 Calysto Hy),或者可以在 tty 中使用 pexpect 控制 REPL 的语言,如 bash。

参见

bash_kernel

一个简单的 bash 的内核,用这个机制写的

Metakernel 库使编写一个封装的内核更容易,其中包括一套基本的行和单元格魔法。它还有一个 ProcessKernel 子类,使得编写使用 pexpect 的内核变得容易。请看 Octave 内核 作为一个例子。

所需步骤

子类化 ipykernel.kernelbase.Kernel,并实现以下方法和属性:

class MyKernel
implementation
implementation_version
banner

Kernel info 回复的信息。’Implementation’ 指的是内核(如 IPython),而不是语言(如 Python)。’banner’ 是在控制台 UI 中在第一个提示前显示给用户的。所有这些值都是字符串。

language_info

Kernel info 回复的语言信息,在一个字典中。这应该包含键 mimetype 和目标语言的代码 mimetype(例如:'text/x-python'),正在实现的语言的 name (例如: 'python')和 file_extension (例如: '.py')。如果需要与 language 不同,它也可以包含键 codemirror_modepygments_lexer

以后还可以在此基础上增加其他键。

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

执行用户代码。

参数
  • code (str) – 要执行的代码。

  • silent (bool) – 是否显示输出。

  • store_history (bool) – 是否在历史中记录这段代码并增加执行次数。如果 silent 为 True,则隐含为 False。

  • user_expressions (dict) – 名称与表达式的映射,以便在代码运行后进行评估。如果你需要,你可以忽略这一点。

  • allow_stdin (bool) – 前端是否可以按要求提供输入(例如对于 Python 的 raw_input())。

你的方法应该返回一个包含 Execution results 中描述的字段的 dict。为了显示输出,它可以使用 send_response() 来发送消息。如果在执行过程中发生了错误,除了 send_response() 之外,还应该通过 Execution results 发送一个 error 类型的消息,其 statuserror。参见 Jupyter 中的消息传递 了解不同消息类型的细节。

为了启动你的内核,在你的模块末尾添加以下内容

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

现在创建一个 JSON 内核规格文件,并使用 jupyter kernelspec install </path/to/kernel> 安装它。将你的内核模块放置在 Python 可以导入的任何地方(测试时试试当前目录)。最后,你可以使用 jupyter console --kernel <mykernelname> 来运行你的内核。注意,在下面的例子中 <mykernelname>echo

例子

参见

echo_kernel

下面是一个打包的、可安装的浓缩例子的版本。

echokernel.py 会简单地将任何输入的信息回传到 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)

这是内核规格 kernel.json 文件,用于此

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

可选步骤

你可以覆盖一些其他的方法来改善你的内核的功能。所有这些方法都应该返回一个字典,如 messaging spec 的相关部分所描述的。

class MyKernel
do_complete(code, cursor_pos)

代码自动补全

参数
  • code (str) – 已经存在的代码

  • cursor_pos (int) – 要求补全的代码中的位置

参见

Completion 消息

do_inspect(code, cursor_pos, detail_level=0)

对象自省

参数
  • code (str) – 代码

  • cursor_pos (int) – 代码中要求自省的位置

  • detail_level (int) – 0 或 1 代表更多或更少的细节。在 IPython 中,1 得到的是源代码。

参见

Introspection 消息

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

历史访问。只有相关的历史请求类型的相关参数才会被传递,所以你的方法定义必须有这里显示的所有参数的默认值。

参见

History 消息

do_is_complete(code)

在类似于控制台的界面中输入的代码是否已经完成并准备执行,还是应该显示一个继续提示?

参数

code (str) – 到目前为止输入的代码 —— 可能有多行

参见

Code completeness 消息

do_shutdown(restart)

关闭内核。你只需要处理你自己的清理工作 ——— 内核机器会在停止前处理好自己的事情。

参数

restart (bool) – 事后是否会再次启动内核

参见

Kernel shutdown 消息