from __future__ import annotations import shutil import subprocess from pathlib import Path from typing import Annotated, Optional import typer from rich import print import gradio from gradio.analytics import custom_component_analytics from gradio.cli.commands.components.install_component import _get_executable_path gradio_template_path = Path(gradio.__file__).parent / "templates" / "frontend" def _dev( app: Annotated[ Path, typer.Argument( help="The path to the app. By default, looks for demo/app.py in the current directory." ), ] = Path("demo") / "app.py", component_directory: Annotated[ Path, typer.Option( help="The directory with the custom component source code. By default, uses the current directory." ), ] = Path("."), host: Annotated[ str, typer.Option( help="The host to run the front end server on. Defaults to localhost.", ), ] = "localhost", python_path: Annotated[ Optional[str], typer.Option( help="Path to python executable. If None, will use the default path found by `which python3`. If python3 is not found, `which python` will be tried. If both fail an error will be raised." ), ] = None, gradio_path: Annotated[ Optional[str], typer.Option( help="Path to gradio executable. If None, will use the default path found by `shutil.which`." ), ] = None, ): custom_component_analytics( "dev", None, None, None, None, python_path=python_path, gradio_path=gradio_path, ) component_directory = component_directory.resolve() print(f":recycle: [green]Launching[/] {app} in reload mode\n") node = shutil.which("node") if not node: raise ValueError("node must be installed in order to run dev mode.") python_path = _get_executable_path( "python", python_path, cli_arg_name="--python-path", check_3=True ) gradio_path = _get_executable_path( "gradio", gradio_path, cli_arg_name="--gradio-path" ) gradio_node_path = subprocess.run( [node, "-e", "console.log(require.resolve('@gradio/preview'))"], cwd=Path(component_directory / "frontend"), check=False, capture_output=True, ) if gradio_node_path.returncode != 0: raise ValueError( "Could not find `@gradio/preview`. Run `npm i -D @gradio/preview` in your frontend folder." ) gradio_node_path = gradio_node_path.stdout.decode("utf-8").strip() proc = subprocess.Popen( [ node, gradio_node_path, "--component-directory", component_directory, "--root", gradio_template_path, "--app", str(app), "--mode", "dev", "--host", host, "--python-path", python_path, "--gradio-path", gradio_path, ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) while True: proc.poll() text = proc.stdout.readline() # type: ignore err = None if proc.stderr: err = proc.stderr.readline() text = ( text.decode("utf-8") .replace("Changes detected in:", "[orange3]Changed detected in:[/]") .replace("Watching:", "[orange3]Watching:[/]") .replace("Running on local URL", "[orange3]Backend Server[/]") ) if "[orange3]Watching:[/]" in text: text += f"'{str(component_directory / 'frontend').strip()}'," if "To create a public link" in text: continue print(text) if err: print(err.decode("utf-8")) if proc.returncode is not None: print("Backend server failed to launch. Exiting.") return