Получение вывода из ядра jupyter в (i) скрипте Python

Я хотел бы открыть несколько ядер из одного сеанса ipython, запустить код для этих ядер, а затем собрать результаты. Но я не могу понять, как собрать результаты, или даже увидеть stdout / stderr. Как я могу сделать эти вещи?

Что у меня так далеко

Я справился с первыми двумя шагами (откройте ядра и запустите на них код) с помощью кода, подобного следующему:

from jupyter_client import MultiKernelManager
kernelmanager = MultiKernelManager()
remote_id = kernelmanager.start_kernel('python3')
remote_kernel = kernelmanager.get_kernel(remote_id)
remote = remote_kernel.client()
sent_msg_id = remote.execute('2+2')

[Я приветствую любые предложения о том, как улучшить это или как закрыть эти ядра и клиенты.]

Вот,python3 может быть именем любого ядра, которое я настроил (которое может быть указано в командной строке с помощьюjupyter-kernelspec list). И я, кажется, могу запустить любой разумный код вместо'2+2', Например, я могу записать в файл, и этот файл действительно создается.

Теперь проблема в том, как получить результат. Я могу получить какое-то сообщение, которое, по-видимому, связано как

reply = remote.get_shell_msg(sent_msg_id)

Этот ответ словарь, как это:

{'buffers': [],
 'content': {'execution_count': 2,
  'payload': [],
  'status': 'ok',
  'user_expressions': {}},
 'header': {'date': datetime.datetime(2015, 10, 19, 14, 34, 34, 378577),
  'msg_id': '98e216b4-3251-4085-8eb1-bfceedbae3b0',
  'msg_type': 'execute_reply',
  'session': 'ca4d615d-82b7-487f-88ff-7076c2bdd109',
  'username': 'me',
  'version': '5.0'},
 'metadata': {'dependencies_met': True,
  'engine': '868de9dd-054b-4630-99b7-0face61915a6',
  'started': '2015-10-19T14:34:34.265718',
  'status': 'ok'},
 'msg_id': '98e216b4-3251-4085-8eb1-bfceedbae3b0',
 'msg_type': 'execute_reply',
 'parent_header': {'date': datetime.datetime(2015, 10, 19, 14, 34, 34, 264508),
  'msg_id': '2674c61a-c79a-48a6-b88a-1f2e8da68a80',
  'msg_type': 'execute_request',
  'session': '767ae562-38d6-41a3-a9dc-6faf37d83222',
  'username': 'me',
  'version': '5.0'}}

Это задокументировано вОбмен сообщениями в Jupyter, Что не задокументировано, так это то, как на самом деле это использовать - то есть, какие функции я использую, когда и где я нахожу сообщения и т. Д. Я виделэтот вопрос и его ответ, который имеет полезную информацию, но не совсем дает мне ответ. А такжеэтот ответ также не получает никакого полезного вывода.

Так, например, я попытался также получить сообщение сmsg_id приведенный в результате выше, но он просто зависает. Я перепробовал все, что мог придумать, но не могу понять, как получить что-нибудь из ядра. Как мне это сделать? Могу ли я передать данные обратно из ядра в виде строки? Могу ли я увидеть его стандартный вывод и стандартный вывод?

Фон

Я пишу магию ipython для запуска фрагмента кода на удаленных ядрах. [Редактировать: это теперь существует и доступноВот.] Идея в том, что у меня на ноутбуке будет тетрадь, и я буду собирать данные с нескольких удаленных серверов, просто имея маленькую волшебную ячейку, подобную этой

%%remote_exec -kernels server1,server2
2+2
! hostname

я используюremote_ikernel подключаться к этим удаленным ядрам легко и автоматически. Это, кажется, работает просто отлично; У меня есть магическая команда со всеми ее функциями, прекрасно работающими, открывающими эти удаленные ядра и выполняющими код. Теперь я хочу получить часть этих данных с пульта дистанционного управления обратно на мой ноутбук - возможно, путем их сериализации. На данный момент я думаюpickle.dumps а такжеpickle.loads было бы идеально для этой части; Мне просто нужно, чтобы эти байты создавались и использовались этими функциями из одного ядра в другое. Я бы предпочел не использовать настоящие файлы для травления, хотя это было бы приемлемо.

Редактировать:

Похоже, это возможно с таким чудовищем, как это:

remote.get_shell_msg(remote.execute('import pickle'))
sent_msg_id = remote.execute('a=2+2', user_expressions={'output':'pickle.dumps({"a":a})'})
reply = remote.get_shell_msg(sent_msg_id)
output_bytes = reply['content']['user_expressions']['output']['data']['text/plain']
variable_dict = pickle.loads(eval(output_bytes))

И сейчас,variable_dict['a'] просто4, Обратите внимание, однако, чтоoutput_bytes строка, представляющая эти байты, поэтому она должна бытьevalредактор Это кажется смешным (и все еще не показывает, как я получу стандартный вывод). Есть ли способ лучше? И как мне получить стандартный вывод?

Изменить 2:

Хотя я недоволен своим хаком выше, я успешно использовал его для написания небольшого модуля под названиемremote_exec размещен на github, как описано выше. Модуль дает мне немного волшебства ipython, которое я могу использовать для удаленного запуска кода на одном или нескольких других ядрах. Это более или менее автоматический процесс, которым я определенно доволен - за исключением ноющего знания о том, что происходит под ним.

Ответы на вопрос(2)

Ваш ответ на вопрос