diff --git a/.changeset/hungry-baths-roll.md b/.changeset/hungry-baths-roll.md new file mode 100644 index 0000000000..c3ea7055fb --- /dev/null +++ b/.changeset/hungry-baths-roll.md @@ -0,0 +1,5 @@ +--- +"gradio": patch +--- + +fix:Support event + request data in gr.render triggers diff --git a/demo/render_tests/run.ipynb b/demo/render_tests/run.ipynb index 5fbd9c4493..99bbccf1a0 100644 --- a/demo/render_tests/run.ipynb +++ b/demo/render_tests/run.ipynb @@ -1 +1 @@ -{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: render_tests"]}, {"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": ["from datetime import datetime\n", "\n", "import gradio as gr\n", "\n", "def update_log():\n", " return datetime.now().timestamp()\n", "\n", "def get_target(evt: gr.EventData):\n", " return evt.target\n", "\n", "def get_select_index(evt: gr.SelectData):\n", " return evt.index\n", "\n", "with gr.Blocks() as demo:\n", " gr.Textbox(value=update_log, every=0.2, label=\"Time\")\n", " \n", " slider = gr.Slider(1, 10, step=1)\n", " @gr.render(inputs=[slider])\n", " def show_log(s):\n", " with gr.Row():\n", " for i in range(s):\n", " gr.Textbox(value=update_log, every=0.2, label=f\"Render {i + 1}\")\n", "\n", " with gr.Row():\n", " selected_btn = gr.Textbox(label=\"Selected Button\")\n", " selected_chat = gr.Textbox(label=\"Selected Chat\")\n", " @gr.render(inputs=[slider])\n", " def show_buttons(s):\n", " with gr.Row():\n", " with gr.Column():\n", " for i in range(s):\n", " btn = gr.Button(f\"Button {i + 1}\")\n", " btn.click(get_target, None, selected_btn)\n", " chatbot = gr.Chatbot([[\"Hello\", \"Hi\"], [\"How are you?\", \"I'm good.\"]])\n", " chatbot.select(get_select_index, None, selected_chat)\n", "\n", " @gr.render()\n", " def examples_in_interface():\n", " gr.Interface(lambda x:x, gr.Textbox(label=\"input\"), gr.Textbox(), examples=[[\"test\"]])\n", "\n", " @gr.render()\n", " def examples_in_blocks():\n", " a = gr.Textbox(label=\"little textbox\")\n", " gr.Examples([[\"abc\"], [\"def\"]], [a])\n", "\n", "\n", "if __name__ == '__main__':\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file +{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: render_tests"]}, {"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": ["from datetime import datetime\n", "\n", "import gradio as gr\n", "\n", "def update_log():\n", " return datetime.now().timestamp()\n", "\n", "def get_target(evt: gr.EventData):\n", " return evt.target\n", "\n", "def get_select_index(evt: gr.SelectData):\n", " return evt.index\n", "\n", "with gr.Blocks() as demo:\n", " gr.Textbox(value=update_log, every=0.2, label=\"Time\")\n", " \n", " slider = gr.Slider(1, 10, step=1)\n", " @gr.render(inputs=[slider])\n", " def show_log(s):\n", " with gr.Row():\n", " for i in range(s):\n", " gr.Textbox(value=update_log, every=0.2, label=f\"Render {i + 1}\")\n", "\n", " with gr.Row():\n", " selected_btn = gr.Textbox(label=\"Selected Button\")\n", " selected_chat = gr.Textbox(label=\"Selected Chat\")\n", " @gr.render(inputs=[slider])\n", " def show_buttons(s):\n", " with gr.Row():\n", " with gr.Column():\n", " for i in range(s):\n", " btn = gr.Button(f\"Button {i + 1}\")\n", " btn.click(get_target, None, selected_btn)\n", " chatbot = gr.Chatbot([[\"Hello\", \"Hi\"], [\"How are you?\", \"I'm good.\"]])\n", " chatbot.select(get_select_index, None, selected_chat)\n", "\n", " selectable_chat = gr.Chatbot([[\"chat1\", \"chat2\"], [\"chat3\", \"chat4\"]])\n", " \n", " @gr.render(triggers=[selectable_chat.select])\n", " def show_selected_chat(selection: gr.SelectData):\n", " gr.Textbox(label=\"Trigger Index\", value=selection.index)\n", "\n", " @gr.render()\n", " def examples_in_interface():\n", " gr.Interface(lambda x:x, gr.Textbox(label=\"input\"), gr.Textbox(), examples=[[\"test\"]])\n", "\n", " @gr.render()\n", " def examples_in_blocks():\n", " a = gr.Textbox(label=\"little textbox\")\n", " gr.Examples([[\"abc\"], [\"def\"]], [a])\n", "\n", "\n", "if __name__ == '__main__':\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file diff --git a/demo/render_tests/run.py b/demo/render_tests/run.py index ab536c386a..e4260fc114 100644 --- a/demo/render_tests/run.py +++ b/demo/render_tests/run.py @@ -34,6 +34,12 @@ with gr.Blocks() as demo: chatbot = gr.Chatbot([["Hello", "Hi"], ["How are you?", "I'm good."]]) chatbot.select(get_select_index, None, selected_chat) + selectable_chat = gr.Chatbot([["chat1", "chat2"], ["chat3", "chat4"]]) + + @gr.render(triggers=[selectable_chat.select]) + def show_selected_chat(selection: gr.SelectData): + gr.Textbox(label="Trigger Index", value=selection.index) + @gr.render() def examples_in_interface(): gr.Interface(lambda x:x, gr.Textbox(label="input"), gr.Textbox(), examples=[["test"]]) diff --git a/gradio/blocks.py b/gradio/blocks.py index 066c7d64fc..9b6ede9ed7 100644 --- a/gradio/blocks.py +++ b/gradio/blocks.py @@ -792,8 +792,9 @@ class BlocksConfig: f"Invalid value for parameter `trigger_mode`: {trigger_mode}. Please choose from: {['once', 'multiple', 'always_last']}" ) + fn_to_analyze = renderable.fn if renderable else fn _, progress_index, event_data_index = ( - special_args(fn) if fn else (None, None, None) + special_args(fn_to_analyze) if fn_to_analyze else (None, None, None) ) # If api_name is None or empty string, use the function name @@ -1573,8 +1574,11 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta): dict(zip(block_fn.inputs, processed_input, strict=False)) ] + fn_to_analyze = ( + block_fn.renderable.fn if block_fn.renderable else block_fn.fn + ) processed_input, progress_index, _ = special_args( - block_fn.fn, processed_input, request, event_data + fn_to_analyze, processed_input, request, event_data ) progress_tracker = ( processed_input[progress_index] if progress_index is not None else None diff --git a/gradio/renderable.py b/gradio/renderable.py index 07f11fce66..bc12cdef7b 100644 --- a/gradio/renderable.py +++ b/gradio/renderable.py @@ -144,6 +144,10 @@ def render( for t in new_triggers ] + if new_triggers: + for trigger in new_triggers: # type: ignore + trigger.callback(trigger.__self__) # type: ignore + def wrapper_function(fn): Renderable( fn, diff --git a/js/spa/test/render_tests.spec.ts b/js/spa/test/render_tests.spec.ts index 40976bb7ee..d5707a9ec9 100644 --- a/js/spa/test/render_tests.spec.ts +++ b/js/spa/test/render_tests.spec.ts @@ -35,6 +35,12 @@ test("Test event/selection data works in render", async ({ page }) => { await expect(selected_chat).toHaveValue("[0, 1]"); }); +test("Test event/selection data can trigger render", async ({ page }) => { + await page.getByText("chat3").click(); + const selected_chat = page.getByLabel("Trigger Index"); + await expect(selected_chat).toHaveValue("[1, 0]"); +}); + test("Test examples work in render", async ({ page }) => { await page.getByRole("button", { name: "test" }).click(); await expect(page.getByLabel("input", { exact: true })).toHaveValue("test");