diff --git a/CHANGELOG.md b/CHANGELOG.md index b3fd8f5154..4460bbcd9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ No changes to highlight. * Mobile responsive iframes in themes guide by [@aliabd](https://github.com/aliabd) in [PR 3562](https://github.com/gradio-app/gradio/pull/3562) * Remove extra $demo from theme guide by [@aliabd](https://github.com/aliabd) in [PR 3563](https://github.com/gradio-app/gradio/pull/3563) * Set the theme name to be the upstream repo name when loading from the hub by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3595](https://github.com/gradio-app/gradio/pull/3595) +* Raise error when an event is queued but the queue is not configured by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3640](https://github.com/gradio-app/gradio/pull/3640) ## Contributors Shoutout: diff --git a/gradio/blocks.py b/gradio/blocks.py index cccb1c8ded..9ffdae2573 100644 --- a/gradio/blocks.py +++ b/gradio/blocks.py @@ -1332,6 +1332,33 @@ class Blocks(BlockContext): self.app = routes.App.create_app(self) return self + def validate_queue_settings(self): + if not self.enable_queue and self.progress_tracking: + raise ValueError("Progress tracking requires queuing to be enabled.") + + for fn_index, dep in enumerate(self.dependencies): + if not self.enable_queue and self.queue_enabled_for_fn(fn_index): + raise ValueError( + f"The queue is enabled for event {dep['api_name'] if dep['api_name'] else fn_index} " + "but the queue has not been enabled for the app. Please call .queue() " + "on your app. Consult https://gradio.app/docs/#blocks-queue for information on how " + "to configure the queue." + ) + for i in dep["cancels"]: + if not self.queue_enabled_for_fn(i): + raise ValueError( + "Queue needs to be enabled! " + "You may get this error by either 1) passing a function that uses the yield keyword " + "into an interface without enabling the queue or 2) defining an event that cancels " + "another event without enabling the queue. Both can be solved by calling .queue() " + "before .launch()" + ) + if dep["batch"] and ( + dep["queue"] is False + or (dep["queue"] is None and not self.enable_queue) + ): + raise ValueError("In order to use batching, the queue must be enabled.") + def launch( self, inline: bool | None = None, @@ -1450,24 +1477,7 @@ class Blocks(BlockContext): if not isinstance(self.file_directories, list): raise ValueError("file_directories must be a list of directories.") - if not self.enable_queue and self.progress_tracking: - raise ValueError("Progress tracking requires queuing to be enabled.") - - for dep in self.dependencies: - for i in dep["cancels"]: - if not self.queue_enabled_for_fn(i): - raise ValueError( - "In order to cancel an event, the queue for that event must be enabled! " - "You may get this error by either 1) passing a function that uses the yield keyword " - "into an interface without enabling the queue or 2) defining an event that cancels " - "another event without enabling the queue. Both can be solved by calling .queue() " - "before .launch()" - ) - if dep["batch"] and ( - dep["queue"] is False - or (dep["queue"] is None and not self.enable_queue) - ): - raise ValueError("In order to use batching, the queue must be enabled.") + self.validate_queue_settings() self.config = self.get_config_file() self.max_threads = max( diff --git a/gradio/routes.py b/gradio/routes.py index 3a017983c5..278085144c 100644 --- a/gradio/routes.py +++ b/gradio/routes.py @@ -757,6 +757,7 @@ def mount_gradio_app( blocks.dev_mode = False blocks.root = path[:-1] if path.endswith("/") else path blocks.config = blocks.get_config_file() + blocks.validate_queue_settings() gradio_app = App.create_app(blocks) @app.on_event("startup") diff --git a/test/test_blocks.py b/test/test_blocks.py index 4c761ae028..c0bd486ddb 100644 --- a/test/test_blocks.py +++ b/test/test_blocks.py @@ -342,6 +342,23 @@ class TestBlocksMethods: demo.launch(prevent_thread_lock=True) assert len(demo.get_config_file()["dependencies"]) == 1 + def test_raise_error_if_event_queued_but_queue_not_enabled(self): + with gr.Blocks() as demo: + with gr.Row(): + with gr.Column(): + input_ = gr.Textbox() + btn = gr.Button("Greet") + with gr.Column(): + output = gr.Textbox() + btn.click( + lambda x: f"Hello, {x}", inputs=input_, outputs=output, queue=True + ) + + with pytest.raises(ValueError, match="The queue is enabled for event 0"): + demo.launch(prevent_thread_lock=True) + + demo.close() + class TestComponentsInBlocks: def test_slider_random_value_config(self): @@ -1030,7 +1047,7 @@ class TestCancel: def iteration(a): yield a - msg = "In order to cancel an event, the queue for that event must be enabled!" + msg = "Queue needs to be enabled!" with pytest.raises(ValueError, match=msg): gr.Interface(iteration, inputs=gr.Number(), outputs=gr.Number()).launch( prevent_thread_lock=True diff --git a/test/test_routes.py b/test/test_routes.py index 374a48fe3a..75ab046eea 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -271,6 +271,27 @@ class TestRoutes: assert client.get("/ps").is_success assert client.get("/py").is_success + def test_mount_gradio_app_raises_error_if_event_queued_but_queue_disabled(self): + with gr.Blocks() as demo: + with gr.Row(): + with gr.Column(): + input_ = gr.Textbox() + btn = gr.Button("Greet") + with gr.Column(): + output = gr.Textbox() + btn.click( + lambda x: f"Hello, {x}", + inputs=input_, + outputs=output, + queue=True, + api_name="greet", + ) + + with pytest.raises(ValueError, match="The queue is enabled for event greet"): + demo.launch(prevent_thread_lock=True) + + demo.close() + class TestGeneratorRoutes: def test_generator(self):