Преобразование кода Python на основе exec () в IPython API

#python #jupyter-notebook #ipython #jupyter

#python #jupyter-notebook #ipython #jupyter

Вопрос:

Я работаю над личным проектом, который включает в себя что-то вроде клона записной книжки Jupyter. Прямо сейчас у меня есть Cell класс, который хранит введенный пользователем код и выполняет этот код, когда ему говорят. Каждый Cell выполняется в своем собственном потоке с помощью exec() функции Python.

Я хотел бы заменить эту функциональность, реализовав структуру ячеек IPython по нескольким причинам, в первую очередь потому, что трудно / невозможно прервать поток из скрипта Python, поэтому я не могу прервать выполнение кода, не прервав основной поток.

Однако API IPython, похоже, не имеет какой-либо интеграции для ячеек, выполнения, прерывания или любых других функций, предоставляемых пользовательским интерфейсом Jupyter. С чего бы мне начать, если бы я хотел начать конвертировать свою программу для использования API IPython вместо моего метода janky?

Вот сокращенный код:

 import networkx as nx
import matplotlib.pyplot as plt
from io import StringIO
from networkx import algorithmse


class Cell:

    def __init__(self,
                 name_,
                 content_type_="python",
                 content_=" ",
                 top_=10,
                 left_=10):
        """
        :param name_: The cell's name
        :param content_type_: The type of content in the cell (markdown or python)
        :param content_: The contents of the cell, either markdown or python code
        :param top_: Cell's top position for the frontend
        :param left_: Cell's left position for the frontend
        """
        self.name = name_
        self.content_type = content_type_
        self.content = content_
        self.output = ""

        self.top = top_
        self.left = left_

    def execute(self):
        # Execute this cell's content

        if not self.content_type == "python":
            return

        global exec_vars
        ex_vars_copy = exec_vars.copy()

        try:
            print("<"   self.name   ">")
            exec(self.content, ex_vars_copy)
        except Exception as exception:
            print("Exception occurred in cell "   self.name)
            print(exception)

        exec_vars.update(ex_vars_copy)


class Graph:

    def __init__(self, parent):
        """Contains Cell objects and traverses them for execution."""
        # Networkx Directed graph
        self.graph = nx.DiGraph()
        self.parent = parent
        # Dict to keep track of cell names vs networkx node names
        self.names_to_indeces = {}
        # Dictionaries for variables created by cells
        global exec_vars
        exec_vars = {}
        # TextIO object
        self.ti = TextIO()

        self.executing = False

    def bfs_traversal_execute(self):
        import time
        if len(self.get_all_cells_edges()[0]) == 0:
            return

        self.executing = True

        root_cell = self.get_cell("", 0)

        root = threading.Thread(target=root_cell.execute)

        std_file_out = root_cell.name

        root.start()
        root.join()

        std_file_out  = root_cell.output

        n_ = self.graph.neighbors(0)
        neighbors = [n for n in n_]

        while neighbors:
            new_neighbors = []
            processes = []
            for n in neighbors:
                neighbor_cell = self.get_cell(self.get_lookup_table()[n].strip())

                neighbor = threading.Thread(target=neighbor_cell.execute)

                neighbor.start()
                processes.append(neighbor)

                new_neighbors.extend([i for i in self.graph.neighbors(n)])

            for proc in processes:
                proc.join()

            for n in neighbors:
                time.sleep(.05)
                neighbor = self.get_cell(self.get_lookup_table()[n])
                std_file_out  = "<"   neighbor.name   ">n"
                std_file_out  = neighbor.output

            neighbors = new_neighbors

        self.executing = False

  

Ссылка на код

Комментарии:

1. Очень круто! Я делаю что-то очень похожее, хотя я использую cytoscape для редактирования графика. Посмотрите, это очень круто. Я в основном просто выполнял все новое (без резидентного ядра), но теперь решаю что-то более iPythonish. К сожалению, API IPython действительно плохо документирован. Прямо сейчас я ищу примеры использования

Ответ №1:

Я немного подумал об этом. Я думаю, что IPython API кажется немного раздутым и не особенно хорошо спроектированным — по крайней мере, для моего варианта использования (аналогичного вашему). Реализация простой очереди обмена сообщениями, доступной для внешних процессов, довольно тривиальна, и вы можете просто выполнить код из нее с помощью нескольких различных подходов pythonic.

Существует также довольно много вспомогательных библиотек python, которые могут имитировать некоторые операции завершения / форматирования, которые могут быть выполнены в Jupyter.

т. Е., я думаю, что ваш метод janky отлично подходит.

Что касается потоковой обработки, я использую asyncio / сопрограммы, поэтому прерывание довольно естественно и просто сделать. В общем, потоки имеют меньше смысла в python, поскольку они имеют плохой параллелизм и тратят время на блокировку и освобождение GIL.

Если мне нужен многоядерный доступ, я обычно всегда использую многопроцессорный процесс, но это выходит за рамки этого q / a.

Комментарии:

1. Этот ответ вообще не оценивает проблему, которую я изложил. Мне нужно конвертировать в IPython, несмотря ни на что, exec() не получается.

2. Хм, как это не работает? Я нахожу, что это работает очень хорошо, хотя я использую import / reload для своей базы данных, поскольку сначала сохраняю код в файлах. Я использую changeStream / mongodb для прослушивания асинхронных задач для выполнения. Я провел поиск на github, кроме jupyter, я действительно не вижу, чтобы кто-то еще использовал IPython api, что неудивительно. Я думаю, что на данный момент это скорее внутренний API для jupyter. Существует также prompt-toolkit, bpython, mypython, ptpython, xonsh