2021-11-05 07:59:29 +08:00
|
|
|
import io
|
|
|
|
import sys
|
|
|
|
from contextlib import contextmanager
|
2022-09-13 08:58:17 +08:00
|
|
|
from functools import partial
|
|
|
|
from string import capwords
|
2024-02-02 03:32:40 +08:00
|
|
|
from unittest.mock import MagicMock, patch
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2023-12-06 06:18:09 +08:00
|
|
|
import httpx
|
2022-08-11 06:29:14 +08:00
|
|
|
import pytest
|
2022-02-10 16:12:26 +08:00
|
|
|
|
2022-10-15 06:43:24 +08:00
|
|
|
import gradio
|
2023-10-31 12:46:02 +08:00
|
|
|
from gradio.blocks import Blocks
|
2023-03-07 03:27:47 +08:00
|
|
|
from gradio.components import Image, Textbox
|
2022-04-08 17:13:56 +08:00
|
|
|
from gradio.interface import Interface, TabbedInterface, close_all, os
|
2022-05-14 10:48:46 +08:00
|
|
|
from gradio.layouts import TabItem, Tabs
|
2022-04-08 17:13:56 +08:00
|
|
|
from gradio.utils import assert_configs_are_equivalent_besides_ids
|
2021-11-05 07:59:29 +08:00
|
|
|
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2021-11-05 07:59:29 +08:00
|
|
|
@contextmanager
|
|
|
|
def captured_output():
|
|
|
|
new_out, new_err = io.StringIO(), io.StringIO()
|
|
|
|
old_out, old_err = sys.stdout, sys.stderr
|
|
|
|
try:
|
|
|
|
sys.stdout, sys.stderr = new_out, new_err
|
|
|
|
yield sys.stdout, sys.stderr
|
|
|
|
finally:
|
|
|
|
sys.stdout, sys.stderr = old_out, old_err
|
2021-10-26 03:29:55 +08:00
|
|
|
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2022-11-08 08:37:55 +08:00
|
|
|
class TestInterface:
|
2021-12-22 01:33:04 +08:00
|
|
|
def test_close(self):
|
|
|
|
io = Interface(lambda input: None, "textbox", "label")
|
2021-12-22 04:20:43 +08:00
|
|
|
_, local_url, _ = io.launch(prevent_thread_lock=True)
|
2023-12-06 06:18:09 +08:00
|
|
|
response = httpx.get(local_url)
|
2022-11-08 08:37:55 +08:00
|
|
|
assert response.status_code == 200
|
2021-12-22 01:33:04 +08:00
|
|
|
io.close()
|
2022-11-08 08:37:55 +08:00
|
|
|
with pytest.raises(Exception):
|
2023-12-06 06:18:09 +08:00
|
|
|
response = httpx.get(local_url)
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2021-12-22 01:33:04 +08:00
|
|
|
def test_close_all(self):
|
2021-10-26 03:29:55 +08:00
|
|
|
interface = Interface(lambda input: None, "textbox", "label")
|
2024-02-02 03:32:40 +08:00
|
|
|
interface.close = MagicMock()
|
2021-12-22 01:33:04 +08:00
|
|
|
close_all()
|
2021-11-04 05:30:36 +08:00
|
|
|
interface.close.assert_called()
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2022-05-06 15:29:02 +08:00
|
|
|
def test_no_input_or_output(self):
|
2022-11-08 08:37:55 +08:00
|
|
|
with pytest.raises(TypeError):
|
2024-07-22 10:55:18 +08:00
|
|
|
Interface(lambda x: x, examples=1234) # type: ignore
|
2022-03-24 05:16:53 +08:00
|
|
|
|
2022-09-13 08:58:17 +08:00
|
|
|
def test_partial_functions(self):
|
|
|
|
def greet(name, formatter):
|
2023-04-28 04:09:50 +08:00
|
|
|
return formatter(f"Hello {name}!")
|
2022-09-13 08:58:17 +08:00
|
|
|
|
|
|
|
greet_upper_case = partial(greet, formatter=capwords)
|
|
|
|
demo = Interface(fn=greet_upper_case, inputs="text", outputs="text")
|
|
|
|
assert demo("abubakar") == "Hello Abubakar!"
|
|
|
|
|
2023-03-07 03:27:47 +08:00
|
|
|
def test_input_labels_extracted_from_method(self):
|
|
|
|
class A:
|
|
|
|
def test(self, parameter_name):
|
|
|
|
return parameter_name
|
|
|
|
|
|
|
|
t = Textbox()
|
|
|
|
Interface(A().test, t, "text")
|
|
|
|
assert t.label == "parameter_name"
|
|
|
|
|
|
|
|
def test(parameter_name1, parameter_name2):
|
|
|
|
return parameter_name1
|
|
|
|
|
|
|
|
t = Textbox()
|
|
|
|
i = Image()
|
|
|
|
Interface(test, [t, i], "text")
|
|
|
|
assert t.label == "parameter_name1"
|
|
|
|
assert i.label == "parameter_name2"
|
|
|
|
|
2023-07-19 22:54:39 +08:00
|
|
|
def special_args_test(req: gradio.Request, parameter_name):
|
|
|
|
return parameter_name
|
|
|
|
|
|
|
|
t = Textbox()
|
|
|
|
Interface(special_args_test, t, "text")
|
|
|
|
assert t.label == "parameter_name"
|
|
|
|
|
2022-03-26 02:34:55 +08:00
|
|
|
def test_examples_valid_path(self):
|
2022-04-06 20:55:51 +08:00
|
|
|
path = os.path.join(
|
|
|
|
os.path.dirname(__file__), "../gradio/test_data/flagged_with_log"
|
|
|
|
)
|
2022-03-26 02:34:55 +08:00
|
|
|
interface = Interface(lambda x: 3 * x, "number", "number", examples=path)
|
|
|
|
dataset_check = any(
|
2023-04-29 05:59:42 +08:00
|
|
|
c["type"] == "dataset" for c in interface.get_config_file()["components"]
|
2022-03-26 02:34:55 +08:00
|
|
|
)
|
2022-11-08 08:37:55 +08:00
|
|
|
assert dataset_check
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2024-02-02 03:32:40 +08:00
|
|
|
@patch("time.sleep")
|
2022-01-05 01:58:37 +08:00
|
|
|
def test_block_thread(self, mock_sleep):
|
2022-11-08 08:37:55 +08:00
|
|
|
with pytest.raises(KeyboardInterrupt):
|
2022-01-05 01:58:37 +08:00
|
|
|
with captured_output() as (out, _):
|
2021-11-05 07:59:29 +08:00
|
|
|
mock_sleep.side_effect = KeyboardInterrupt()
|
|
|
|
interface = Interface(lambda x: x, "textbox", "label")
|
2022-01-05 01:58:37 +08:00
|
|
|
interface.launch(prevent_thread_lock=False)
|
2021-11-05 07:59:29 +08:00
|
|
|
output = out.getvalue().strip()
|
2022-11-08 08:37:55 +08:00
|
|
|
assert (
|
2023-05-11 23:53:45 +08:00
|
|
|
"Keyboard interruption in main thread... closing server." in output
|
2021-11-05 07:59:29 +08:00
|
|
|
)
|
2020-09-22 02:51:39 +08:00
|
|
|
|
2024-02-02 03:32:40 +08:00
|
|
|
@patch("gradio.utils.colab_check")
|
|
|
|
@patch("gradio.networking.setup_tunnel")
|
2021-11-06 08:10:37 +08:00
|
|
|
def test_launch_colab_share_error(self, mock_setup_tunnel, mock_colab_check):
|
|
|
|
mock_setup_tunnel.side_effect = RuntimeError()
|
|
|
|
mock_colab_check.return_value = True
|
|
|
|
interface = Interface(lambda x: x, "textbox", "label")
|
|
|
|
_, _, share_url = interface.launch(prevent_thread_lock=True)
|
2022-11-08 08:37:55 +08:00
|
|
|
assert share_url is None
|
2021-11-10 11:34:08 +08:00
|
|
|
interface.close()
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2021-11-06 08:10:37 +08:00
|
|
|
def test_interface_representation(self):
|
2023-04-29 05:59:42 +08:00
|
|
|
def prediction_fn(x):
|
|
|
|
return x
|
|
|
|
|
2021-11-06 08:10:37 +08:00
|
|
|
prediction_fn.__name__ = "prediction_fn"
|
|
|
|
repr = str(Interface(prediction_fn, "textbox", "label")).split("\n")
|
2022-11-08 08:37:55 +08:00
|
|
|
assert prediction_fn.__name__ in repr[0]
|
|
|
|
assert len(repr[0]) == len(repr[1])
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2024-02-02 03:32:40 +08:00
|
|
|
@patch("webbrowser.open")
|
2021-11-06 08:10:37 +08:00
|
|
|
def test_interface_browser(self, mock_browser):
|
2021-11-10 11:34:08 +08:00
|
|
|
interface = Interface(lambda x: x, "textbox", "label")
|
|
|
|
interface.launch(inbrowser=True, prevent_thread_lock=True)
|
|
|
|
mock_browser.assert_called_once()
|
|
|
|
interface.close()
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2021-11-09 13:02:37 +08:00
|
|
|
def test_examples_list(self):
|
|
|
|
examples = ["test1", "test2"]
|
2022-12-21 06:10:23 +08:00
|
|
|
interface = Interface(
|
|
|
|
lambda x: x, "textbox", "label", examples=examples, examples_per_page=2
|
|
|
|
)
|
2021-11-09 13:02:37 +08:00
|
|
|
interface.launch(prevent_thread_lock=True)
|
2022-11-08 08:37:55 +08:00
|
|
|
assert len(interface.examples_handler.examples) == 2
|
|
|
|
assert len(interface.examples_handler.examples[0]) == 1
|
2022-12-21 06:10:23 +08:00
|
|
|
assert interface.examples_handler.dataset.get_config()["samples_per_page"] == 2
|
2021-11-10 11:34:08 +08:00
|
|
|
interface.close()
|
|
|
|
|
2024-02-02 03:32:40 +08:00
|
|
|
@patch("IPython.display.display")
|
2021-11-11 11:40:57 +08:00
|
|
|
def test_inline_display(self, mock_display):
|
|
|
|
interface = Interface(lambda x: x, "textbox", "label")
|
|
|
|
interface.launch(inline=True, prevent_thread_lock=True)
|
|
|
|
mock_display.assert_called_once()
|
2022-05-12 07:27:58 +08:00
|
|
|
interface.launch(inline=True, prevent_thread_lock=True)
|
2022-11-08 08:37:55 +08:00
|
|
|
assert mock_display.call_count == 2
|
2021-11-11 11:40:57 +08:00
|
|
|
interface.close()
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2023-05-31 00:22:03 +08:00
|
|
|
def test_setting_interactive_false(self):
|
|
|
|
output_textbox = Textbox()
|
|
|
|
Interface(lambda x: x, "textbox", output_textbox)
|
|
|
|
assert not output_textbox.get_config()["interactive"]
|
|
|
|
output_textbox = Textbox(interactive=True)
|
|
|
|
Interface(lambda x: x, "textbox", output_textbox)
|
|
|
|
assert output_textbox.get_config()["interactive"]
|
|
|
|
|
2023-06-30 03:05:25 +08:00
|
|
|
def test_get_api_info(self):
|
|
|
|
io = Interface(lambda x: x, Image(type="filepath"), "textbox")
|
2023-10-31 12:46:02 +08:00
|
|
|
api_info = io.get_api_info()
|
2024-07-22 10:55:18 +08:00
|
|
|
assert api_info
|
2023-06-30 03:05:25 +08:00
|
|
|
assert len(api_info["named_endpoints"]) == 1
|
|
|
|
assert len(api_info["unnamed_endpoints"]) == 0
|
|
|
|
|
2023-08-15 22:07:53 +08:00
|
|
|
def test_api_name(self):
|
|
|
|
io = Interface(lambda x: x, "textbox", "textbox", api_name="echo")
|
|
|
|
assert next(
|
2024-07-22 10:55:18 +08:00
|
|
|
(d for d in io.config["dependencies"] if d["api_name"] == "echo"), # type: ignore
|
|
|
|
None,
|
2023-08-15 22:07:53 +08:00
|
|
|
)
|
|
|
|
|
2024-08-08 01:12:04 +08:00
|
|
|
def test_show_progress(self):
|
|
|
|
io = Interface(
|
|
|
|
lambda x: x, "textbox", "textbox", api_name="echo", show_progress="hidden"
|
|
|
|
)
|
|
|
|
dependency = next(
|
|
|
|
(d for d in io.config["dependencies"] if d["api_name"] == "echo"), # type: ignore
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
assert dependency and dependency["show_progress"] == "hidden"
|
|
|
|
|
2023-09-13 03:25:46 +08:00
|
|
|
def test_interface_in_blocks_does_not_error(self):
|
|
|
|
with Blocks():
|
|
|
|
Interface(fn=lambda x: x, inputs=Textbox(), outputs=Image())
|
|
|
|
|
2023-11-07 04:12:28 +08:00
|
|
|
def test_interface_with_built_ins(self):
|
|
|
|
t = Textbox()
|
|
|
|
Interface(fn=str, inputs=t, outputs=Textbox())
|
|
|
|
assert t.label == "input 0"
|
|
|
|
|
2024-01-11 03:44:00 +08:00
|
|
|
def test_interface_additional_components_are_included_as_inputs(self):
|
|
|
|
t = Textbox()
|
|
|
|
s = gradio.Slider(0, 100)
|
|
|
|
io = Interface(fn=str, inputs=t, outputs=Textbox(), additional_inputs=s)
|
|
|
|
assert io.input_components == [t, s]
|
|
|
|
|
2022-01-21 21:44:12 +08:00
|
|
|
|
2022-11-08 08:37:55 +08:00
|
|
|
class TestTabbedInterface:
|
2022-04-08 17:13:56 +08:00
|
|
|
def test_tabbed_interface_config_matches_manual_tab(self):
|
|
|
|
interface1 = Interface(lambda x: x, "textbox", "textbox")
|
|
|
|
interface2 = Interface(lambda x: x, "image", "image")
|
|
|
|
|
2022-08-05 09:46:15 +08:00
|
|
|
with Blocks(mode="tabbed_interface") as demo:
|
2022-04-08 17:13:56 +08:00
|
|
|
with Tabs():
|
|
|
|
with TabItem(label="tab1"):
|
2022-04-28 16:51:54 +08:00
|
|
|
interface1.render()
|
2022-04-08 17:13:56 +08:00
|
|
|
with TabItem(label="tab2"):
|
2022-04-28 16:51:54 +08:00
|
|
|
interface2.render()
|
2022-04-08 17:13:56 +08:00
|
|
|
|
|
|
|
interface3 = Interface(lambda x: x, "textbox", "textbox")
|
|
|
|
interface4 = Interface(lambda x: x, "image", "image")
|
|
|
|
tabbed_interface = TabbedInterface([interface3, interface4], ["tab1", "tab2"])
|
|
|
|
|
2022-11-08 08:37:55 +08:00
|
|
|
assert assert_configs_are_equivalent_besides_ids(
|
2024-07-22 10:55:18 +08:00
|
|
|
demo.get_config_file(), # type: ignore
|
|
|
|
tabbed_interface.get_config_file(), # type: ignore
|
2022-04-08 17:13:56 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-10-15 06:43:24 +08:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"interface_type", ["standard", "input_only", "output_only", "unified"]
|
|
|
|
)
|
|
|
|
@pytest.mark.parametrize("live", [True, False])
|
|
|
|
@pytest.mark.parametrize("use_generator", [True, False])
|
|
|
|
def test_interface_adds_stop_button(interface_type, live, use_generator):
|
|
|
|
def gen_func(inp):
|
|
|
|
yield inp
|
|
|
|
|
|
|
|
def func(inp):
|
|
|
|
return inp
|
|
|
|
|
|
|
|
if interface_type == "standard":
|
|
|
|
interface = gradio.Interface(
|
|
|
|
gen_func if use_generator else func, "number", "number", live=live
|
|
|
|
)
|
|
|
|
elif interface_type == "input_only":
|
|
|
|
interface = gradio.Interface(
|
|
|
|
gen_func if use_generator else func, "number", None, live=live
|
|
|
|
)
|
|
|
|
elif interface_type == "output_only":
|
|
|
|
interface = gradio.Interface(
|
|
|
|
gen_func if use_generator else func, None, "number", live=live
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
num = gradio.Number()
|
|
|
|
interface = gradio.Interface(
|
|
|
|
gen_func if use_generator else func, num, num, live=live
|
|
|
|
)
|
|
|
|
has_stop = (
|
|
|
|
len(
|
|
|
|
[
|
|
|
|
c
|
|
|
|
for c in interface.config["components"]
|
|
|
|
if c["props"].get("variant", "") == "stop"
|
|
|
|
]
|
|
|
|
)
|
|
|
|
== 1
|
|
|
|
)
|
|
|
|
if use_generator and not live:
|
|
|
|
assert has_stop
|
|
|
|
else:
|
|
|
|
assert not has_stop
|
2024-03-23 07:00:52 +08:00
|
|
|
|
|
|
|
|
|
|
|
def test_live_interface_sets_always_last():
|
|
|
|
iface = gradio.Interface(
|
|
|
|
fn=lambda s: s,
|
|
|
|
inputs=gradio.Textbox(lines=2, placeholder="Hello 👋", label="Input Sentence"),
|
|
|
|
outputs=gradio.Markdown(),
|
|
|
|
live=True, # Set live to True for real-time feedback
|
|
|
|
)
|
|
|
|
config = iface.get_config_file()
|
2024-07-22 10:55:18 +08:00
|
|
|
assert "dependencies" in config
|
2024-03-23 07:00:52 +08:00
|
|
|
for dep in config["dependencies"]:
|
|
|
|
if dep["targets"][0][1] == "change":
|
|
|
|
assert dep["trigger_mode"] == "always_last"
|
|
|
|
return
|
|
|
|
raise AssertionError("No change dependency found")
|
2024-06-09 23:30:28 +08:00
|
|
|
|
|
|
|
|
|
|
|
def test_tabbed_interface_predictions(connect):
|
|
|
|
hello_world = gradio.Interface(lambda name: "Hello " + name, "text", "text")
|
|
|
|
bye_world = gradio.Interface(lambda name: "Bye " + name, "text", "text")
|
|
|
|
|
|
|
|
demo = gradio.TabbedInterface(
|
|
|
|
[hello_world, bye_world], ["Hello World", "Bye World"]
|
|
|
|
)
|
|
|
|
with connect(demo) as client:
|
|
|
|
assert client.predict("Emily", api_name="/predict") == "Hello Emily"
|
|
|
|
assert client.predict("Hannah", api_name="/predict") == "Hello Hannah"
|