Add a stand-alone install command and tidy-up the fallback template (#6092)

* Add code

* add changeset

* Add test

* Make install default

* Better error message

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
Freddy Boulton 2023-10-25 22:12:30 -04:00 committed by GitHub
parent cd8146ba05
commit 11d67ae752
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 110 additions and 46 deletions

View File

@ -0,0 +1,6 @@
---
"@gradio/fallback": minor
"gradio": minor
---
feat:Add a stand-alone install command and tidy-up the fallback template

View File

@ -2,6 +2,7 @@ import sys
import typer
from gradio_client.cli import deploy_discord # type: ignore
from rich.console import Console
from .commands import custom_component, deploy, print_environment_info, reload
@ -27,5 +28,12 @@ def cli():
elif args[0] in {"cc", "component"}:
sys.argv = sys.argv[1:]
custom_component()
elif args[0] in {"build", "dev", "create", "show", "publish"}:
try:
error = f"gradio {args[0]} is not a valid command. Did you mean `gradio cc {args[0]}` or `gradio component {args[0]}`?."
raise ValueError(error)
except ValueError:
console = Console()
console.print_exception()
else:
typer.run(reload)

View File

@ -3,6 +3,7 @@ from typer import Typer
from .build import _build
from .create import _create
from .dev import _dev
from .install_component import _install
from .show import _show
app = Typer(help="Create and publish a new Gradio component")
@ -14,3 +15,6 @@ app.command(
)(_build)
app.command("dev", help="Launch the custom component demo in development mode.")(_dev)
app.command("show", help="Show the list of available templates")(_show)
app.command("install", help="Install the custom component in the current environment")(
_install
)

View File

@ -1,14 +1,12 @@
import shutil
import subprocess
from pathlib import Path
from typing import Optional
import typer
from rich.markup import escape
from typing_extensions import Annotated
from gradio.cli.commands.components.install_component import _get_npm, _install_command
from gradio.cli.commands.display import LivePanelDisplay
from gradio.utils import set_directory
from . import _create_utils
@ -41,7 +39,7 @@ def _create(
typer.Option(
help="Whether to install the component in your current environment as a development install. Recommended for development."
),
] = False,
] = True,
npm_install: Annotated[
str,
typer.Option(help="NPM install command to use. Default is 'npm install'."),
@ -69,17 +67,8 @@ def _create(
if _create_utils._in_test_dir():
npm_install = f"{shutil.which('pnpm')} i --ignore-scripts"
npm_install = npm_install.strip()
if npm_install == "npm install":
npm = shutil.which("npm")
if not npm:
raise ValueError(
"By default, the install command uses npm to install "
"the frontend dependencies. Please install npm or pass your own install command "
"via the --npm-install option."
)
npm_install = f"{npm} install"
else:
npm_install = _get_npm(npm_install)
with LivePanelDisplay() as live:
live.update(
@ -102,28 +91,4 @@ def _create(
live.update(":art: Created frontend code", add_sleep=0.2)
if install:
cmds = [shutil.which("pip"), "install", "-e", f"{str(directory)}[dev]"]
live.update(
f":construction_worker: Installing python... [grey37]({escape(' '.join(cmds))})[/]"
)
pipe = subprocess.run(cmds, capture_output=True, text=True)
if pipe.returncode != 0:
live.update(":red_square: Python installation [bold][red]failed[/][/]")
live.update(pipe.stderr)
else:
live.update(":white_check_mark: Python install succeeded!")
live.update(
f":construction_worker: Installing javascript... [grey37]({npm_install})[/]"
)
with set_directory(directory / "frontend"):
pipe = subprocess.run(
npm_install.split(), capture_output=True, text=True
)
if pipe.returncode != 0:
live.update(":red_square: NPM install [bold][red]failed[/][/]")
live.update(pipe.stdout)
live.update(pipe.stderr)
else:
live.update(":white_check_mark: NPM install succeeded!")
_install_command(directory, live, npm_install)

View File

@ -0,0 +1,63 @@
import shutil
import subprocess
from pathlib import Path
from rich.markup import escape
from typer import Argument, Option
from typing_extensions import Annotated
from gradio.cli.commands.display import LivePanelDisplay
from gradio.utils import set_directory
def _get_npm(npm_install: str):
npm_install = npm_install.strip()
if npm_install == "npm install":
npm = shutil.which("npm")
if not npm:
raise ValueError(
"By default, the install command uses npm to install "
"the frontend dependencies. Please install npm or pass your own install command "
"via the --npm-install option."
)
npm_install = f"{npm} install"
return npm_install
def _install_command(directory: Path, live: LivePanelDisplay, npm_install: str):
cmds = [shutil.which("pip"), "install", "-e", f"{str(directory)}[dev]"]
live.update(
f":construction_worker: Installing python... [grey37]({escape(' '.join(cmds))})[/]"
)
pipe = subprocess.run(cmds, capture_output=True, text=True)
if pipe.returncode != 0:
live.update(":red_square: Python installation [bold][red]failed[/][/]")
live.update(pipe.stderr)
else:
live.update(":white_check_mark: Python install succeeded!")
live.update(
f":construction_worker: Installing javascript... [grey37]({npm_install})[/]"
)
with set_directory(directory / "frontend"):
pipe = subprocess.run(npm_install.split(), capture_output=True, text=True)
if pipe.returncode != 0:
live.update(":red_square: NPM install [bold][red]failed[/][/]")
live.update(pipe.stdout)
live.update(pipe.stderr)
else:
live.update(":white_check_mark: NPM install succeeded!")
def _install(
directory: Annotated[
Path, Argument(help="The directory containing the custom components.")
] = Path("."),
npm_install: Annotated[
str, Option(help="NPM install command to use. Default is 'npm install'.")
] = "npm install",
):
npm_install = _get_npm(npm_install)
with LivePanelDisplay() as live:
_install_command(directory, live, npm_install)

View File

@ -11,9 +11,6 @@
export let elem_classes: string[] = [];
export let visible = true;
export let value = false;
// export let value_is_output = false;
// export let label = "Checkbox";
// export let info: string | undefined = undefined;
export let container = true;
export let scale: number | null = null;
export let min_width: number | undefined = undefined;

View File

@ -6,6 +6,7 @@ import pytest
from gradio.cli.commands.components._create_utils import OVERRIDES
from gradio.cli.commands.components.build import _build
from gradio.cli.commands.components.create import _create
from gradio.cli.commands.components.install_component import _install
from gradio.cli.commands.components.show import _show
@ -33,7 +34,7 @@ from gradio.cli.commands.components.show import _show
],
)
def test_template_override_component(template, tmp_path):
_create("MyComponent", tmp_path, template=template, overwrite=True)
_create("MyComponent", tmp_path, template=template, overwrite=True, install=False)
app = (tmp_path / "demo" / "app.py").read_text()
answer = textwrap.dedent(
f"""
@ -55,12 +56,18 @@ def test_raise_error_component_template_does_not_exist(tmp_path):
match="Cannot find NonExistentComponent in gradio.components or gradio.layouts",
):
_create(
"MyComponent", tmp_path, template="NonExistentComponent", overwrite=True
"MyComponent",
tmp_path,
template="NonExistentComponent",
overwrite=True,
install=False,
)
def test_do_not_replace_class_name_in_import_statement(tmp_path):
_create("MyImage", template="Image", directory=tmp_path, overwrite=True)
_create(
"MyImage", template="Image", directory=tmp_path, overwrite=True, install=False
)
code = (tmp_path / "backend" / "gradio_myimage" / "myimage.py").read_text()
assert "from PIL import Image as _Image" in code
assert "class MyImage" in code
@ -100,3 +107,17 @@ def test_build(tmp_path):
assert template_dir.exists() and template_dir.is_dir()
assert list(template_dir.glob("**/index.js"))
assert (tmp_path / "dist").exists() and list((tmp_path / "dist").glob("*.whl"))
def test_install(tmp_path):
_create(
"TestTextbox",
template="Textbox",
directory=tmp_path,
overwrite=True,
install=False,
)
assert not (tmp_path / "frontend" / "node_modules").exists()
_install(tmp_path)
assert (tmp_path / "frontend" / "node_modules").exists()