try: from IPython.core.magic import ( needs_local_scope, register_cell_magic, ) from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring except ImportError: pass import gradio as gr from gradio.routes import App from gradio.utils import BaseReloader class CellIdTracker: """Determines the most recently run cell in the notebook. Needed to keep track of which demo the user is updating. """ def __init__(self, ipython): ipython.events.register("pre_run_cell", self.pre_run_cell) self.shell = ipython self.current_cell: str = "" def pre_run_cell(self, info): self._current_cell = info.cell_id class JupyterReloader(BaseReloader): """Swap a running blocks class in a notebook with the latest cell contents.""" def __init__(self, ipython) -> None: super().__init__() self._cell_tracker = CellIdTracker(ipython) self._running: dict[str, gr.Blocks] = {} @property def current_cell(self): return self._cell_tracker.current_cell @property def running_app(self) -> App: if not self.running_demo.server: raise RuntimeError("Server not running") return self.running_demo.server.running_app # type: ignore @property def running_demo(self): return self._running[self.current_cell] def demo_tracked(self) -> bool: return self.current_cell in self._running def track(self, demo: gr.Blocks): self._running[self.current_cell] = demo def load_ipython_extension(ipython): reloader = JupyterReloader(ipython) @magic_arguments() # type: ignore @argument("--demo-name", default="demo", help="Name of gradio blocks instance.") # type: ignore @argument( # type: ignore "--share", default=False, const=True, nargs="?", help="Whether to launch with sharing. Will slow down reloading.", ) @register_cell_magic # type: ignore @needs_local_scope # type: ignore def blocks(line, cell, local_ns): """Launch a demo defined in a cell in reload mode.""" args = parse_argstring(blocks, line) # type: ignore exec(cell, None, local_ns) demo: gr.Blocks = local_ns[args.demo_name] if not reloader.demo_tracked(): demo.launch(share=args.share) reloader.track(demo) else: reloader.swap_blocks(demo) return reloader.running_demo.artifact