import shutil import textwrap from pathlib import Path import pytest from gradio.cli.commands.components.build import _build from gradio.cli.commands.components.create import _create, _create_utils from gradio.cli.commands.components.install_component import _get_executable_path from gradio.cli.commands.components.publish import _get_version_from_file from gradio.cli.commands.components.show import _show from gradio.utils import core_gradio_components core = [ c.__name__ for c in core_gradio_components() if not getattr(c, "is_template", False) and c.__name__ not in ["Tab", "Form", "FormComponent"] ] @pytest.mark.parametrize( "template", core, ) def test_template_override_component(template, tmp_path): """When you add a new component this test will likely fail locally because the js files have not been moved to the _frontend_code directory. Just build the python package (python -m build -w) to move the latest state of the js directory to _frontend_code. """ _create( "MyComponent", tmp_path, template=template, overwrite=True, install=False, configure_metadata=False, ) app = (tmp_path / "demo" / "app.py").read_text() component_files = _create_utils._get_component_code(template) answer = textwrap.dedent( f""" import gradio as gr from gradio_mycomponent import MyComponent {component_files.demo_code.format(name="MyComponent")} if __name__ == "__main__": demo.launch() """ ) assert app.strip() == answer.strip() assert (tmp_path / "backend" / "gradio_mycomponent" / "mycomponent.py").exists() source_code = ( tmp_path / "backend" / "gradio_mycomponent" / "mycomponent.py" ).read_text() assert "@document()" not in source_code def test_get_executable_path(): assert _get_executable_path( "pip", None, "--pip-path", check_3=True ) == shutil.which("pip3") assert _get_executable_path("pip", None, "--pip-path") == shutil.which("pip") assert _get_executable_path( "pip", shutil.which("pip"), "--pip-path" ) == shutil.which("pip") assert _get_executable_path( "gradio", None, "--pip-path", check_3=True ) == shutil.which("gradio") with pytest.raises( ValueError, match=r"Could not find foo. Please ensure it is installed and in your PATH or pass the --foo-path parameter.", ): _get_executable_path("foo", None, "--foo-path") with pytest.raises( ValueError, match=r"The provided foo path \(/foo/bar/fum\) does not exist or is not a file.", ): _get_executable_path("foo", "/foo/bar/fum", "--foo-path") def test_raise_error_component_template_does_not_exist(tmp_path): with pytest.raises( ValueError, match="Cannot find NonExistentComponent in gradio.components, gradio.layouts, or gradio._simple_templates", ): _create( "MyComponent", tmp_path, template="NonExistentComponent", overwrite=True, install=False, configure_metadata=False, ) def test_do_not_replace_class_name_in_import_statement(tmp_path): _create( "MyImage", template="Image", directory=tmp_path, overwrite=True, install=False, configure_metadata=False, ) code = (tmp_path / "backend" / "gradio_myimage" / "myimage.py").read_text() assert "import PIL.Image" in code assert "class MyImage" in code assert "PIL.Image.Image" in code def test_raises_if_directory_exists(tmp_path): with pytest.raises( Exception ): # Keeping it a general exception since the specific exception seems to differ between operating systems _create("MyComponent", tmp_path, configure_metadata=False) def test_show(capsys): _show() stdout, _ = capsys.readouterr() assert "Form Component" in stdout assert "Beginner Friendly" in stdout assert "Layout" in stdout assert "Dataframe" not in stdout assert "Dataset" not in stdout @pytest.mark.xfail @pytest.mark.parametrize("template", ["Image"]) def test_build(template, virtualenv): # Copy pnpm-lock.yaml to not cause unintended changes tracked by git pnpm_lock = Path(__file__).parent / ".." / "pnpm-lock.yaml" pnpm_copy = Path(__file__).parent / ".." / "pnpm-lock-copy.yaml" shutil.copy(str(pnpm_lock), str(pnpm_copy)) # Using the js/preview/test directory will use the workspace code dir_ = ( Path(__file__).parent / ".." / "js" / "preview" / "test" / "testtextbox" ).resolve() shutil.rmtree(str(dir_), ignore_errors=True) try: # Local installs of gradio and gradio-client gradio_dir = Path(__file__).parent / ".." client = Path(__file__).parent / ".." / "client" / "python" virtualenv.run("pip install build") virtualenv.run(f"pip install -e {str(gradio_dir)}") virtualenv.run(f"pip install -e {str(client)}") virtualenv.run( f"{shutil.which('gradio')} cc create TestTextbox --template {template} --no-configure-metadata --directory {str(dir_)}", ) assert (dir_ / "frontend" / "node_modules").exists() # need to reinstall local client because installing the custom component # will pull latest stable version from pypi virtualenv.run(f"pip install -e {str(client)}") virtualenv.run(f"{shutil.which('gradio')} cc build {str(dir_)}") template_dir: Path = dir_ / "backend" / "gradio_testtextbox" / "templates" assert template_dir.exists() and template_dir.is_dir() assert list(template_dir.glob("**/index.js")) assert (dir_ / "dist").exists() and list((dir_ / "dist").glob("*.whl")) finally: shutil.move(str(pnpm_copy), str(pnpm_lock)) shutil.rmtree(str(dir_), ignore_errors=True) def test_build_fails_if_component_not_installed(tmp_path): _create( "MyComponent", tmp_path, template="SimpleTextbox", overwrite=True, install=False, configure_metadata=False, ) with pytest.raises( ValueError, match=r"Your custom component package \(gradio_mycomponent\) is not installed!", ): _build(tmp_path) def test_fallback_template_app(tmp_path): _create( "SimpleComponent2", directory=tmp_path, overwrite=True, install=False, configure_metadata=False, ) app = (tmp_path / "demo" / "app.py").read_text() answer = textwrap.dedent( """ import gradio as gr from gradio_simplecomponent2 import SimpleComponent2 with gr.Blocks() as demo: gr.Markdown("# Change the value (keep it JSON) and the front-end will update automatically.") SimpleComponent2(value={"message": "Hello from Gradio!"}, label="Static") if __name__ == "__main__": demo.launch() """ ) assert app.strip() == answer.strip() def test_get_version_from_wheel(): assert ( _get_version_from_file(Path("gradio_textwithattachments-0.0.3-py3-none.whl")) == "0.0.3" ) assert ( _get_version_from_file(Path("gradio_textwithattachments-1.0.3b12-py3-none.whl")) == "1.0.3b12" )