gradio/test/test_interfaces.py

315 lines
11 KiB
Python
Raw Normal View History

import io
import sys
2021-10-26 03:29:55 +08:00
import unittest.mock as mock
2021-11-05 07:59:29 +08:00
from contextlib import contextmanager
from functools import partial
from string import capwords
2021-11-12 11:43:27 +08:00
import mlflow
import pytest
import requests
2021-11-12 11:43:27 +08:00
import wandb
from fastapi.testclient import TestClient
import gradio
Website Design Changes (#1015) * adding gallery * added netlify files * new navbar design * header section new design * used by section new design * cards section new design * integrates with section new design * customer stories section new design * footer and gradient * demos section new design * docs fixes * docs reorg * docs reorg * upgrading to tailwind 3 * tailwind config changes * navbar new design * fixing body on all pages * Updating Guides (#1012) * updating getting started * updated codecov version * tweaks to gs * added netlify file * added netlify file * website prebuild script * increased code size * blocks * edits * blocks_hello * hello world * guide * merge main * added flipper demo * guide * guide * add guides * tweak to refresh website * header section new design * demos section new design * cards design * used by section * tweets section * footer on all pages * mobile responsive fixes * mobile responsive fixes * https fonts * completed blocks guide * unify components * minor tweaks * docs headers styling and navigation pane * parameter code blocks * styling description and input type * parameter tables and other styling * only documenting interactive components when possible * guides * embedding not working * demos not working * fixing demo code * fixing demos * demo fix * updated demos * updated demos * ui update * updated docstrings * updated code snippets so they run * updating docs * Interface docs * updating interface * fixing parameters in interface.py * required and defaults for interface, and styling * fixing up interface (#1207) * fixing up interface * fixed interface methods * formatting * updating interface docs * updating interface docs * formatting * docstring to load from docstrings * fixed colors * finalize interface content * interface examples * fixed examples * added some blocks docs * blocks * component fixes * reorganized some files (#1210) * formatting * added info for every component * fixes * blocks docs * added blocks demos * adding combined interfaces * added parallel, series * Doc: layout update (#1216) * doc layout * home spacing Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * adding layouts * layouts done * added events for components * formatting and https * brings back dropdown and other components * fix header ids * moved ids and fixed nav * added parameters for remaining component * docstring fixes * landing page demos * demo window placeholder * demo nav * fixed test * formatting * demo code * correctly importing gradio css/js * remove keyvalues * modify launch script to move gradio assetS * components embedded test * correct demo name * hide try demo and embedding * local devserver changes * create embedding json with configs * changes * fixes * comment out layout docs * demo work * demo fixes * demo embedding fixes * typo * jinja fix * demo nav fix * hide demo button * formatting * removed whitespace * remove newline from parameter * reverting comments Co-authored-by: aliabd <ali.si3luwa@gmail.com> Co-authored-by: Victor Muštar <victor.mustar@gmail.com> Co-authored-by: Ali Abid <aabid94@gmail.com>
2022-05-14 10:48:46 +08:00
from gradio.blocks import Blocks
2022-04-08 17:13:56 +08:00
from gradio.interface import Interface, TabbedInterface, close_all, os
Website Design Changes (#1015) * adding gallery * added netlify files * new navbar design * header section new design * used by section new design * cards section new design * integrates with section new design * customer stories section new design * footer and gradient * demos section new design * docs fixes * docs reorg * docs reorg * upgrading to tailwind 3 * tailwind config changes * navbar new design * fixing body on all pages * Updating Guides (#1012) * updating getting started * updated codecov version * tweaks to gs * added netlify file * added netlify file * website prebuild script * increased code size * blocks * edits * blocks_hello * hello world * guide * merge main * added flipper demo * guide * guide * add guides * tweak to refresh website * header section new design * demos section new design * cards design * used by section * tweets section * footer on all pages * mobile responsive fixes * mobile responsive fixes * https fonts * completed blocks guide * unify components * minor tweaks * docs headers styling and navigation pane * parameter code blocks * styling description and input type * parameter tables and other styling * only documenting interactive components when possible * guides * embedding not working * demos not working * fixing demo code * fixing demos * demo fix * updated demos * updated demos * ui update * updated docstrings * updated code snippets so they run * updating docs * Interface docs * updating interface * fixing parameters in interface.py * required and defaults for interface, and styling * fixing up interface (#1207) * fixing up interface * fixed interface methods * formatting * updating interface docs * updating interface docs * formatting * docstring to load from docstrings * fixed colors * finalize interface content * interface examples * fixed examples * added some blocks docs * blocks * component fixes * reorganized some files (#1210) * formatting * added info for every component * fixes * blocks docs * added blocks demos * adding combined interfaces * added parallel, series * Doc: layout update (#1216) * doc layout * home spacing Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * adding layouts * layouts done * added events for components * formatting and https * brings back dropdown and other components * fix header ids * moved ids and fixed nav * added parameters for remaining component * docstring fixes * landing page demos * demo window placeholder * demo nav * fixed test * formatting * demo code * correctly importing gradio css/js * remove keyvalues * modify launch script to move gradio assetS * components embedded test * correct demo name * hide try demo and embedding * local devserver changes * create embedding json with configs * changes * fixes * comment out layout docs * demo work * demo fixes * demo embedding fixes * typo * jinja fix * demo nav fix * hide demo button * formatting * removed whitespace * remove newline from parameter * reverting comments Co-authored-by: aliabd <ali.si3luwa@gmail.com> Co-authored-by: Victor Muštar <victor.mustar@gmail.com> Co-authored-by: Ali Abid <aabid94@gmail.com>
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
2021-11-10 02:30:59 +08:00
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
2021-10-26 03:29:55 +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
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)
response = requests.get(local_url)
assert response.status_code == 200
2021-12-22 01:33:04 +08:00
io.close()
with pytest.raises(Exception):
2021-12-22 04:20:43 +08:00
response = requests.get(local_url)
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")
interface.close = mock.MagicMock()
2021-12-22 01:33:04 +08:00
close_all()
2021-11-04 05:30:36 +08:00
interface.close.assert_called()
def test_no_input_or_output(self):
with pytest.raises(TypeError):
2022-03-26 02:34:55 +08:00
Interface(lambda x: x, examples=1234)
2022-03-24 05:16:53 +08:00
def test_partial_functions(self):
def greet(name, formatter):
return formatter("Hello " + name + "!")
greet_upper_case = partial(greet, formatter=capwords)
demo = Interface(fn=greet_upper_case, inputs="text", outputs="text")
assert demo("abubakar") == "Hello Abubakar!"
2022-03-26 02:34:55 +08:00
def test_examples_valid_path(self):
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(
[c["type"] == "dataset" for c in interface.get_config_file()["components"]]
)
assert dataset_check
2021-11-05 07:59:29 +08:00
def test_test_launch(self):
with captured_output() as (out, err):
prediction_fn = lambda x: x
prediction_fn.__name__ = "prediction_fn"
interface = Interface(prediction_fn, "textbox", "label")
interface.test_launch()
output = out.getvalue().strip()
assert output == "Test launch: prediction_fn()... PASSED"
2021-11-05 07:59:29 +08:00
@mock.patch("time.sleep")
2022-01-05 01:58:37 +08:00
def test_block_thread(self, mock_sleep):
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()
assert (
output == "Keyboard interruption in main thread... closing server."
)
2020-09-22 02:51:39 +08:00
@mock.patch("gradio.utils.colab_check")
2021-11-06 08:10:37 +08:00
def test_launch_colab_share(self, mock_colab_check):
mock_colab_check.return_value = True
interface = Interface(lambda x: x, "textbox", "label")
_, _, share_url = interface.launch(prevent_thread_lock=True)
assert share_url is None
2021-11-10 11:34:08 +08:00
interface.close()
@mock.patch("gradio.utils.colab_check")
@mock.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)
assert share_url is None
2021-11-10 11:34:08 +08:00
interface.close()
2021-11-06 08:10:37 +08:00
def test_interface_representation(self):
prediction_fn = lambda x: x
prediction_fn.__name__ = "prediction_fn"
repr = str(Interface(prediction_fn, "textbox", "label")).split("\n")
assert prediction_fn.__name__ in repr[0]
assert len(repr[0]) == len(repr[1])
@pytest.mark.asyncio
async def test_interface_none_interp(self):
2021-11-10 11:34:08 +08:00
interface = Interface(lambda x: x, "textbox", "label", interpretation=[None])
scores = (await interface.interpret(["quickest brown fox"]))[0][
"interpretation"
]
assert scores is None
@mock.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()
2021-11-09 13:02:37 +08:00
def test_examples_list(self):
examples = ["test1", "test2"]
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)
assert len(interface.examples_handler.examples) == 2
assert len(interface.examples_handler.examples[0]) == 1
assert interface.examples_handler.dataset.get_config()["samples_per_page"] == 2
2021-11-10 11:34:08 +08:00
interface.close()
@mock.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()
interface.launch(inline=True, prevent_thread_lock=True)
assert mock_display.call_count == 2
2021-11-11 11:40:57 +08:00
interface.close()
@mock.patch("comet_ml.Experiment")
2021-11-12 11:43:27 +08:00
def test_integration_comet(self, mock_experiment):
experiment = mock_experiment()
experiment.log_text = mock.MagicMock()
experiment.log_other = mock.MagicMock()
interface = Interface(lambda x: x, "textbox", "label")
interface.launch(prevent_thread_lock=True)
interface.integrate(comet_ml=experiment)
experiment.log_text.assert_called_with("gradio: " + interface.local_url)
interface.share_url = "tmp" # used to avoid creating real share links.
2021-11-12 11:43:27 +08:00
interface.integrate(comet_ml=experiment)
experiment.log_text.assert_called_with("gradio: " + interface.share_url)
assert experiment.log_other.call_count == 2
2021-11-12 11:43:27 +08:00
interface.share_url = None
interface.close()
2021-11-12 11:43:27 +08:00
def test_integration_mlflow(self):
mlflow.log_param = mock.MagicMock()
interface = Interface(lambda x: x, "textbox", "label")
interface.launch(prevent_thread_lock=True)
interface.integrate(mlflow=mlflow)
mlflow.log_param.assert_called_with(
"Gradio Interface Local Link", interface.local_url
)
interface.share_url = "tmp" # used to avoid creating real share links.
2021-11-12 11:43:27 +08:00
interface.integrate(mlflow=mlflow)
mlflow.log_param.assert_called_with(
"Gradio Interface Share Link", interface.share_url
)
2021-11-12 11:43:27 +08:00
interface.share_url = None
interface.close()
2021-11-12 11:43:27 +08:00
def test_integration_wandb(self):
with captured_output() as (out, err):
wandb.log = mock.MagicMock()
wandb.Html = mock.MagicMock()
interface = Interface(lambda x: x, "textbox", "label")
interface.width = 500
interface.height = 500
2021-11-12 11:43:27 +08:00
interface.integrate(wandb=wandb)
assert (
out.getvalue().strip()
== "The WandB integration requires you to `launch(share=True)` first."
)
interface.share_url = "tmp"
2021-11-12 11:43:27 +08:00
interface.integrate(wandb=wandb)
wandb.log.assert_called_once()
@mock.patch("requests.post")
2021-11-12 11:43:27 +08:00
def test_integration_analytics(self, mock_post):
mlflow.log_param = mock.MagicMock()
interface = Interface(lambda x: x, "textbox", "label")
interface.analytics_enabled = True
interface.integrate(mlflow=mlflow)
mock_post.assert_called_once()
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")
with Blocks(mode="tabbed_interface") as demo:
2022-04-08 17:13:56 +08:00
with Tabs():
with TabItem(label="tab1"):
interface1.render()
2022-04-08 17:13:56 +08:00
with TabItem(label="tab2"):
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"])
assert assert_configs_are_equivalent_besides_ids(
demo.get_config_file(), tabbed_interface.get_config_file()
2022-04-08 17:13:56 +08:00
)
class TestDeprecatedInterface:
def test_deprecation_notice(self):
with pytest.warns(Warning):
_ = Interface(lambda x: x, "textbox", "textbox", verbose=True)
class TestInterfaceInterpretation:
def test_interpretation_from_interface(self):
def quadratic(num1: float, num2: float) -> float:
return 3 * num1**2 + num2
iface = Interface(
fn=quadratic,
inputs=["number", "number"],
outputs="number",
interpretation="default",
)
app, _, _ = iface.launch(prevent_thread_lock=True)
client = TestClient(app)
btn = next(
c["id"]
for c in iface.config["components"]
if c["props"].get("value") == "Interpret"
)
fn_index = next(
i
for i, d in enumerate(iface.config["dependencies"])
if d["targets"] == [btn]
)
response = client.post(
"/api/predict/", json={"fn_index": fn_index, "data": [10, 50, 350]}
)
assert response.json()["data"][0]["interpretation"] is not None
iface.close()
close_all()
@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