Jupyter: напишите собственное волшебство, которое изменяет содержимое ячейки в

В ноутбуке Jupyter есть встроенные магии, которые меняют содержимое ячейки ноутбука. Например, магия %load заменяет содержимое текущей ячейки содержимым файла в файловой системе.

Как я могу написать пользовательскую магическую команду, которая делает что-то подобное?

Что я до сих пор печатает что-то в stdout

def tutorial_asset(line):
    print('hello world')


def load_ipython_extension(ipython):
    ipython.register_magic_function(tutorial_asset, 'line')

И я могу загрузить его с помощью %load_ext tutorial_asset. Но оттуда я потерялся.

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

Я нашел способ добраться до экземпляра интерактивной оболочки:

  @magics_class
  class MyMagics(Magics):

      @line_magic
      def tutorial_asset(self, parameters):
          self.shell

Объект self.shell кажется, дает полный доступ к набору ячеек в записной книжке, но единственным способом, который я могу найти для изменения ячеек, является сделать self.shell.set_next_input('print("hello world")'). Этого недостаточно, потому что в ноутбуке Jupyter эта входная ячейка пропускается, и она не перезаписывает входную ячейку, а вместо нее создает новую ячейку ввода после нее.

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

Ответ 1

EDIT: После небольшого дальнейшего копания, я обнаружил, что нынешняя сборка ноутбуков не может обойти оба.

Ну, это немного сложно... Глядя на код IPython, похоже, вам нужно использовать set_next_input если вы хотите заменить ячейку, и run_cell если вы действительно хотите запустить какой-то код. Однако я не могу заставить обоих работать сразу - похоже, что set_next_input всегда выигрывает.

Копаясь в коде, веб-интерфейс поддерживает дополнительную очистку вывода на set_next_input. Однако ядро еще не поддерживает установку этого флага (и поэтому вывод всегда будет очищен как действие по умолчанию). Чтобы сделать лучше, потребуется патч для ipykernel.

Лучшее, что у меня есть, это следующий код, используя версию jupyter notebook 4.2.1:

from __future__ import print_function
from IPython.core.magic import Magics, magics_class, line_magic

@magics_class
class MyMagics(Magics):

    @line_magic
    def lmagic(self, line):
        "Replace current line with new output"
        raw_code = 'print("Hello world!")'
        # Comment out this line if you actually want to run the code.
        self.shell.set_next_input('# %lmagic\n{}'.format(raw_code), replace=True)
        # Uncomment this line if you want to run the code instead.
        # self.shell.run_cell(raw_code, store_history=False)

ip = get_ipython()
ip.register_magics(MyMagics)

Это дает вам волшебную команду lmagic, которая либо заменит текущую ячейку, либо запустит raw_code зависимости от того, какой бит кода вы закомментировали.