Skip to content

Commit

Permalink
Fix updating choices in gr.Dropdown and updates related to other co…
Browse files Browse the repository at this point in the history
…mponents (#6309)

* postprocess fix

* add changeset

* add changeset

* blocks

* formatting

* demo

* add changeset

* Add code

* reduce

* trigger ci

* Update gradio/blocks.py

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>
  • Loading branch information
3 people committed Nov 7, 2023
1 parent 3cdeabc commit c561287
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/wet-crabs-film.md
@@ -0,0 +1,5 @@
---
"gradio": patch
---

fix:Fix updating choices in `gr.Dropdown` and updates related to other components
2 changes: 1 addition & 1 deletion demo/blocks_essay/run.ipynb
@@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: blocks_essay"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "\n", "def change_textbox(choice):\n", " if choice == \"short\":\n", " return gr.Textbox(lines=2, visible=True), gr.Button(interactive=True)\n", " elif choice == \"long\":\n", " return gr.Textbox(lines=8, visible=True, value=\"Lorem ipsum dolor sit amet\"), gr.Button(interactive=True)\n", " else:\n", " return gr.Textbox(visible=False), gr.Button(interactive=False)\n", "\n", "\n", "with gr.Blocks() as demo:\n", " radio = gr.Radio(\n", " [\"short\", \"long\", \"none\"], label=\"What kind of essay would you like to write?\"\n", " )\n", " text = gr.Textbox(lines=2, interactive=True, show_copy_button=True)\n", "\n", " with gr.Row():\n", " num = gr.Number(minimum=0, maximum=100, label=\"input\")\n", " out = gr.Number(label=\"output\")\n", " minimum_slider = gr.Slider(0, 100, 0, label=\"min\")\n", " maximum_slider = gr.Slider(0, 100, 100, label=\"max\")\n", " submit_btn = gr.Button(\"Submit\", variant=\"primary\")\n", "\n", " def reset_bounds(minimum, maximum):\n", " return gr.Number(minimum=minimum, maximum=maximum)\n", "\n", " radio.change(fn=change_textbox, inputs=radio, outputs=[text, submit_btn])\n", " gr.on(\n", " [minimum_slider.change, maximum_slider.change],\n", " reset_bounds,\n", " [minimum_slider, maximum_slider],\n", " outputs=num,\n", " )\n", " num.submit(lambda x: x, num, out)\n", "\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: blocks_essay"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "countries_cities_dict = {\n", " \"USA\": [\"New York\", \"Los Angeles\", \"Chicago\"],\n", " \"Canada\": [\"Toronto\", \"Montreal\", \"Vancouver\"],\n", " \"Pakistan\": [\"Karachi\", \"Lahore\", \"Islamabad\"],\n", "}\n", "\n", "\n", "def change_textbox(choice):\n", " if choice == \"short\":\n", " return gr.Textbox(lines=2, visible=True), gr.Button(interactive=True)\n", " elif choice == \"long\":\n", " return gr.Textbox(lines=8, visible=True, value=\"Lorem ipsum dolor sit amet\"), gr.Button(interactive=True)\n", " else:\n", " return gr.Textbox(visible=False), gr.Button(interactive=False)\n", "\n", "\n", "with gr.Blocks() as demo:\n", " radio = gr.Radio(\n", " [\"short\", \"long\", \"none\"], label=\"What kind of essay would you like to write?\"\n", " )\n", " text = gr.Textbox(lines=2, interactive=True, show_copy_button=True)\n", "\n", " with gr.Row():\n", " num = gr.Number(minimum=0, maximum=100, label=\"input\")\n", " out = gr.Number(label=\"output\")\n", " minimum_slider = gr.Slider(0, 100, 0, label=\"min\")\n", " maximum_slider = gr.Slider(0, 100, 100, label=\"max\")\n", " submit_btn = gr.Button(\"Submit\", variant=\"primary\")\n", "\n", " with gr.Row():\n", " country = gr.Dropdown(list(countries_cities_dict.keys()), label=\"Country\")\n", " cities = gr.Dropdown([], label=\"Cities\")\n", " \n", " @country.change(inputs=country, outputs=cities)\n", " def update_cities(country):\n", " cities = list(countries_cities_dict[country])\n", " return gr.Dropdown(choices=cities, value=cities[0], interactive=True)\n", "\n", " def reset_bounds(minimum, maximum):\n", " return gr.Number(minimum=minimum, maximum=maximum)\n", "\n", " radio.change(fn=change_textbox, inputs=radio, outputs=[text, submit_btn])\n", " gr.on(\n", " [minimum_slider.change, maximum_slider.change],\n", " reset_bounds,\n", " [minimum_slider, maximum_slider],\n", " outputs=num,\n", " )\n", " num.submit(lambda x: x, num, out)\n", "\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
15 changes: 15 additions & 0 deletions demo/blocks_essay/run.py
@@ -1,5 +1,11 @@
import gradio as gr

countries_cities_dict = {
"USA": ["New York", "Los Angeles", "Chicago"],
"Canada": ["Toronto", "Montreal", "Vancouver"],
"Pakistan": ["Karachi", "Lahore", "Islamabad"],
}


def change_textbox(choice):
if choice == "short":
Expand All @@ -23,6 +29,15 @@ def change_textbox(choice):
maximum_slider = gr.Slider(0, 100, 100, label="max")
submit_btn = gr.Button("Submit", variant="primary")

with gr.Row():
country = gr.Dropdown(list(countries_cities_dict.keys()), label="Country")
cities = gr.Dropdown([], label="Cities")

@country.change(inputs=country, outputs=cities)
def update_cities(country):
cities = list(countries_cities_dict[country])
return gr.Dropdown(choices=cities, value=cities[0], interactive=True)

def reset_bounds(minimum, maximum):
return gr.Number(minimum=minimum, maximum=maximum)

Expand Down
30 changes: 16 additions & 14 deletions gradio/blocks.py
Expand Up @@ -382,13 +382,15 @@ def postprocess_update_dict(
update_dict: The original update dictionary
postprocess: Whether to postprocess the "value" key of the update dictionary.
"""
update_dict = {k: update_dict[k] for k in update_dict if hasattr(block, k)}
if update_dict.get("value") is components._Keywords.NO_VALUE:
update_dict.pop("value")
elif "value" in update_dict and postprocess:
update_dict["value"] = block.postprocess(update_dict["value"])
if isinstance(update_dict["value"], (GradioModel, GradioRootModel)):
update_dict["value"] = update_dict["value"].model_dump()
value = update_dict.pop("value", components._Keywords.NO_VALUE)
update_dict = {k: getattr(block, k) for k in update_dict if hasattr(block, k)}
if value is not components._Keywords.NO_VALUE:
if postprocess:
update_dict["value"] = block.postprocess(value)
if isinstance(update_dict["value"], (GradioModel, GradioRootModel)):
update_dict["value"] = update_dict["value"].model_dump()
else:
update_dict["value"] = value
update_dict["__type__"] = "update"
return update_dict

Expand Down Expand Up @@ -1360,14 +1362,14 @@ def postprocess_data(
prediction_value["__type__"] = "update"
if utils.is_update(prediction_value):
if output_id in state:
args = state[output_id].constructor_args.copy()
kwargs = state[output_id].constructor_args.copy()
else:
args = self.blocks[output_id].constructor_args.copy()
args.update(prediction_value)
args.pop("value", None)
args.pop("__type__")
args["render"] = False
state[output_id] = self.blocks[output_id].__class__(**args)
kwargs = self.blocks[output_id].constructor_args.copy()
kwargs.update(prediction_value)
kwargs.pop("value", None)
kwargs.pop("__type__")
kwargs["render"] = False
state[output_id] = self.blocks[output_id].__class__(**kwargs)

prediction_value = postprocess_update_dict(
block=state[output_id],
Expand Down
13 changes: 13 additions & 0 deletions js/app/test/blocks_essay.spec.ts
Expand Up @@ -50,3 +50,16 @@ test("updates backend correctly", async ({ page }) => {
await num.press("Enter");
await expect(output).toHaveValue("25");
});

test("updates dropdown choices correctly", async ({ page }) => {
const country = await page.getByLabel("Country").first();
const city = await page.getByLabel("Cities").first();

await country.fill("Canada");
await country.press("Enter");
await expect(city).toHaveValue("Toronto");

await country.fill("Pakistan");
await country.press("Enter");
await expect(city).toHaveValue("Karachi");
});
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions test/test_blocks.py
Expand Up @@ -1543,3 +1543,35 @@ def test_deprecation_warning_emitted_when_concurrency_count_set():
gr.Interface(lambda x: x, gr.Textbox(), gr.Textbox()).queue(
concurrency_count=12
)


def test_postprocess_update_dict():
block = gr.Textbox()
update_dict = {"value": 2.0, "visible": True, "invalid_arg": "hello"}
assert gr.blocks.postprocess_update_dict(block, update_dict, True) == {
"__type__": "update",
"value": "2.0",
"visible": True,
}

block = gr.Textbox(lines=10)
update_dict = {"value": 2.0, "lines": 10}
assert gr.blocks.postprocess_update_dict(block, update_dict, False) == {
"__type__": "update",
"value": 2.0,
"lines": 10,
}

block = gr.Dropdown(choices=["New Country A", "New Country B"])
update_dict = {
"value": "New Country A",
"choices": ["New Country A", "New Country B"],
}
assert gr.blocks.postprocess_update_dict(block, update_dict, False) == {
"__type__": "update",
"value": "New Country A",
"choices": [
("New Country A", "New Country A"),
("New Country B", "New Country B"),
],
}

0 comments on commit c561287

Please sign in to comment.