3
from pathlib import Path
6
from fastapi.testclient import TestClient
12
def test_clear_event(self):
14
print("image cleared")
16
with gr.Blocks() as demo:
18
type="pil", label="Start by uploading an image", elem_id="input_image"
21
img.clear(fn_img_cleared, [], [])
23
assert demo.config["dependencies"][0]["targets"][0][1] == "clear"
25
def test_event_data(self):
26
with gr.Blocks() as demo:
28
gallery = gr.Gallery()
30
def fn_img_index(evt: gr.SelectData):
33
gallery.select(fn_img_index, None, text)
35
app, _, _ = demo.launch(prevent_thread_lock=True)
36
client = TestClient(app)
39
f"{demo.local_url}run/predict",
40
json={"fn_index": 0, "data": [], "event_data": {"index": 1, "value": None}},
42
assert resp.status_code == 200
43
assert resp.json()["data"][0] == "1"
45
def test_consecutive_events(self):
55
with gr.Blocks() as child:
60
txt1.submit(double, txt1, txt2).then(reverse, txt2, txt3).success(
64
with gr.Blocks() as parent:
66
txt0.submit(lambda x: x, txt0, txt0)
69
assert parent.config["dependencies"][1]["trigger_after"] is None
70
assert parent.config["dependencies"][2]["trigger_after"] == 1
71
assert parent.config["dependencies"][3]["trigger_after"] == 2
73
assert not parent.config["dependencies"][2]["trigger_only_on_success"]
74
assert parent.config["dependencies"][3]["trigger_only_on_success"]
76
def test_on_listener(self):
77
with gr.Blocks() as demo:
78
name = gr.Textbox(label="Name")
79
output = gr.Textbox(label="Output Box")
80
greet_btn = gr.Button("Greet")
83
return "Hello " + name + "!"
86
triggers=[name.submit, greet_btn.click, demo.load],
93
num1 = gr.Slider(1, 10)
94
num2 = gr.Slider(1, 10)
95
num3 = gr.Slider(1, 10)
96
output = gr.Number(label="Sum")
98
@gr.on(inputs=[num1, num2, num3], outputs=output)
102
assert demo.config["dependencies"][0]["targets"] == [
103
(name._id, "submit"),
104
(greet_btn._id, "click"),
107
assert demo.config["dependencies"][1]["targets"] == [
108
(num1._id, "change"),
109
(num2._id, "change"),
110
(num3._id, "change"),
113
def test_load_chaining(self):
121
with gr.Blocks() as demo:
122
out = gr.Textbox(label="Call counter")
123
demo.load(increment, inputs=None, outputs=out).then(
124
increment, inputs=None, outputs=out
127
assert demo.config["dependencies"][0]["targets"][0][1] == "load"
128
assert demo.config["dependencies"][0]["trigger_after"] is None
129
assert demo.config["dependencies"][1]["targets"][0][1] == "then"
130
assert demo.config["dependencies"][1]["trigger_after"] == 0
132
def test_load_chaining_reuse(self):
140
with gr.Blocks() as demo:
141
out = gr.Textbox(label="Call counter")
142
demo.load(increment, inputs=None, outputs=out).then(
143
increment, inputs=None, outputs=out
146
with gr.Blocks() as demo2:
149
assert demo2.config["dependencies"][0]["targets"][0][1] == "load"
150
assert demo2.config["dependencies"][0]["trigger_after"] is None
151
assert demo2.config["dependencies"][1]["targets"][0][1] == "then"
152
assert demo2.config["dependencies"][1]["trigger_after"] == 0
155
class TestEventErrors:
156
def test_event_defined_invalid_scope(self):
157
with gr.Blocks() as demo:
158
textbox = gr.Textbox()
159
textbox.blur(lambda x: x + x, textbox, textbox)
161
with pytest.raises(AttributeError):
162
demo.load(lambda: "hello", None, textbox)
164
with pytest.raises(AttributeError):
165
textbox.change(lambda x: x + x, textbox, textbox)
168
def test_event_pyi_file_matches_source_code():
169
"""Test that the template used to create pyi files (search INTERFACE_TEMPLATE in component_meta) matches the source code of EventListener._setup."""
171
Path(__file__).parent / ".." / "gradio" / "components" / "button.pyi"
173
mod = ast.parse(code)
175
for node in ast.walk(mod):
176
if isinstance(node, ast.FunctionDef) and node.name == "click":
177
segment = ast.get_source_segment(code, node)
181
sig = inspect.signature(gr.Button.click)
182
for param in sig.parameters.values():
183
if param.name == "block":
185
assert param.name in segment