Source code for pyplugins.analysis.repl

import threading
import queue
import os
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.utils.path import ensure_dir_exists
from penguin import Plugin, plugins, getColoredLogger


[docs] class Repl(Plugin): def __init__(self, panda): self.panda = panda self.locals = {'plugins': plugins, 'panda': panda} self.logger = getColoredLogger("plugins.repl") self.proj_dir = self.get_arg("proj_dir") self.ipython_dir = os.path.join(self.proj_dir, ".ipython") ensure_dir_exists(self.ipython_dir) self.base_image = InteractiveShellEmbed(ipython_dir=self.ipython_dir) self.thread = None
[docs] def repl(self): """ Generator-capable IPython REPL Call with `yield from repl()`. Use `%yield_from` and `%yield_` line commands in place of `yield from` and `yield`. """ local = self.base_image.get_local_scope(1) # Spawn REPL in separate thread command_queue = queue.Queue(maxsize=1) result_queue = queue.Queue(maxsize=1) self.thread = threading.Thread( target=self.repl_thread, args=(command_queue, result_queue, local), ) self.thread.start() # Process commands from REPL and send back results while True: command, arg = command_queue.get() match command: case "exit": break case "yield_from": result = yield from arg result_queue.put(result) case "yield_": result = yield arg result_queue.put(result) # Wait for thread to exit self.thread.join()
[docs] def repl_thread(self, command_queue, result_queue, local): """ Function for running the IPython REPL in a separate thread. The command queue is for sending `yield` and `yield from` commands to the generator, and the result queue is for getting the results back. """ def y(gen): command_queue.put(("yield_from", gen)) return result_queue.get() ip = self.base_image.instance() local['y'] = y local['plugins'] = plugins # Actually start the REPL ip.mainloop(local_ns=local) # Send a special exit command to make it easier to clean up command_queue.put(("exit", None))