Как получить идентификатор ячейки в ядре Jupyter? - PullRequest
1 голос
/ 06 марта 2019

Я пытаюсь собрать ядро ​​Jupyter для языка, который на самом деле не поддерживает REPL, и переопределение переменной или функции вызывает ошибку в этом языке.К сожалению, это означает, что я не могу просто продолжать выполнять код в том порядке, в котором его отправляет пользователь, но вместо этого мне нужно заменить его, если они повторно посещают старую ячейку.Допустим, у пользователя есть следующие две ячейки:

Ячейка 1:

int foo = 1;

Ячейка 2:

vec4(foo);

В моем идеальном сценарии я просто хочу сшитьячейки объединяются в один виртуальный исходный файл, который находится в порядке ячеек, а затем выполняют это.Таким образом, полученный виртуальный исходный файл должен иметь следующий вид:

int foo = 1;
vec4(foo);

Теперь предположим, что пользователь возвращается к ячейке 1 и редактирует foo до 4, как я могу узнать, что пользователь отредактировал ячейку 1?Поэтому в идеале я хочу обновить виртуальный исходный файл, чтобы он выглядел следующим образом:

int foo = 4;
vec4(foo);

Вместо этого:

int foo = 1;
vec4(foo);
int foo = 4; // This would throw an error in the language compiler

Я использую this в качестве моегобазы, и я просмотрел источник, но не смог найти ничего, что могло бы мне помочь.Я что-то пропустил?Что-нибудь еще, что я должен сделать вместо этого?

1 Ответ

2 голосов
/ 19 марта 2019

Есть возможное решение с использованием messaging_api (https://jupyter -client.readthedocs.io / en / latest / messaging.html # history ).

import asyncio
import os
from uuid import uuid4
import json
from dataclasses import dataclass

from tornado.escape import json_encode, json_decode, url_escape
from tornado.websocket import websocket_connect
from tornado.httpclient import AsyncHTTPClient, HTTPRequest

client = AsyncHTTPClient()
session_id = 'faf69f76-6667-45d6-a38f-32460e5d7f24'
token = 'e9e267d0c802017c22bc31d276b675b4f5b3e0f180eb5c8b'
kernel_id = 'fad149a5-1f78-4827-ba7c-f1fde844f0b2'

@dataclass
class Cell:
    code: str
    index: int
    execution_count: int

# We keep track of all cells to matain an updated index
cells = []

async def get_sessions():
    url = 'http://localhost:8888/api/sessions?token={}'.format(token)
    req = HTTPRequest(url=url)
    resp = await client.fetch(req)
    print(resp)
    print(resp.body)

async def get_notebook_content(path):
    url = 'http://localhost:8888/api/contents/{}?token={}'.format(path, token)

    req = HTTPRequest(url=url)
    resp = await client.fetch(req)
    return json_decode(resp.body)

async def get_session(session_id):
    ses_url = 'http://localhost:8888/api/sessions/{}?token={}'.format(session_id, token)
    ses_req = HTTPRequest(url=ses_url)
    resp = await client.fetch(ses_req)
    return json_decode(resp.body)

# return the list of notebook cells as Cell @dataclass
def parse_cells(content):
    res = []
    # we iterate over notebook cells
    cells = content['content']['cells']
    # search the cell
    for index, c in enumerate(cells):
        cell_execution_count = c['execution_count']
        code = c['source']
        cell = Cell(code=code, index=index, execution_count=cell_execution_count)

        res.append(cell)

    return res

# listen to all notebook messages
async def listen():
    session_data = await get_session(session_id)
    notebook_path = session_data['notebook']['path']
    notebook_content = await get_notebook_content(notebook_path)

    # parse existing cells
    cells = parse_cells(notebook_content)

    # listen to all messages
    req = HTTPRequest(
        url='ws://localhost:8888/api/kernels/{}/channels?token={}'.format(
            kernel_id,
            token))
    ws = await websocket_connect(req)
    print('Connected to kernel websocket')
    hist_msg_id = None

    while True:
        msg = await ws.read_message()
        msg = json_decode(msg)
        msg_type = msg['msg_type']
        parent_msg_id = msg['parent_header']['msg_id']

        if msg_type == 'execute_input':
            # after a executed cell we request the history (only of the last executed cell)
            hist_msg_id = uuid4().hex
            ws.write_message(json_encode({
                'header': {
                    'username': '',
                    'version': '5.3',
                    'session': '',
                    'msg_id': hist_msg_id,
                    'msg_type': 'history_request'
                },
                'parent_header': {},
                'channel': 'shell',
                'content': {
                    'output': False,
                    'raw': True,
                    'hist_access_type': 'tail',
                    'n': 1
                },
                'metadata': {
                },
                'buffers': {}
            }))
        elif parent_msg_id == hist_msg_id and msg_type == 'history_reply':
            # we receive the history of the last executed cell with his execution_count
            hist_msg_id = None # we dont expect more replies
            # see message type 'history_result': https://jupyter-client.readthedocs.io/en/latest/messaging.html#history
            execution_count = msg['content']['history'][0][1]
            code = msg['content']['history'][0][2]
            # update the existing cell
            for c in cells:
                if c.execution_count + 1 == execution_count:
                    c.code = code
                    c.execution_count = execution_count

                    print('# Cell changed: {}'.format(c))

if __name__ == '__main__':
    asyncio.run(listen())

Позвольте мне попробоватьчтобы объяснить это ...

  • Мы отслеживаем все ячейки записной книжки и его индекс в списке (ячейках) класса данных ячейки (код, индекс и число_процесса)

  • Мы прослушиваем каждое сообщение из желаемого сеанса (метод прослушивания)

  • Когда выполняется получение ячейки, мы запрашиваем его историю через сообщение API, чтобы получить коди execute_count

  • Мы сопоставляем ячейку с существующей через его execute_count и обновляем ее

Я знаю, что это очень своеобразное решение, но когданоутбук соединяется с сообщениями api, не содержит никакой информации о каком-либо идентификаторе ячейки, только его код.

Важное примечание

Это решение не помогаетвставляя или удаляя ячейки, мы должны найти какрешение, использующее историю ядра или что-то в этом роде ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...