Skip to content

Commit c2a0d05

Browse files
freddyaboultongradio-pr-botaliabd
authored
Control Display of Error, Info, Warning (#8489)
* first draft * handle animation * No animation * Add code * add changeset * Only use duration * lint * lint * Add docs * add changeset * Fix default * sample usage * formatting * Add visible parameters * float --------- Co-authored-by: gradio-pr-bot <[email protected]> Co-authored-by: aliabd <[email protected]>
1 parent b03da67 commit c2a0d05

File tree

18 files changed

+149
-30
lines changed

18 files changed

+149
-30
lines changed

.changeset/neat-roses-tan.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@gradio/app": minor
3+
"@gradio/client": minor
4+
"@gradio/statustracker": minor
5+
"gradio": minor
6+
"website": minor
7+
---
8+
9+
feat:Control Display of Error, Info, Warning

client/js/src/helpers/api_info.ts

+2
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ export function handle_message(
318318
status: {
319319
queue,
320320
message: data.output.error as string,
321+
visible: data.output.visible as boolean,
322+
duration: data.output.duration as number,
321323
stage: "error",
322324
code: data.code,
323325
success: data.success

client/js/src/types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ export interface Status {
329329
code?: string;
330330
success?: boolean;
331331
stage: "pending" | "error" | "complete" | "generating";
332+
duration?: number;
333+
visible?: boolean;
332334
broken?: boolean;
333335
size?: number;
334336
position?: number;
@@ -361,6 +363,8 @@ export interface LogMessage extends Log {
361363
type: "log";
362364
endpoint: string;
363365
fn_index: number;
366+
duration: number | null;
367+
visible: boolean;
364368
}
365369

366370
export interface RenderMessage extends Render {

client/js/src/utils/submit.ts

+6
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,8 @@ export function submit(
343343
log: data.log,
344344
level: data.level,
345345
endpoint: _endpoint,
346+
duration: data.duration,
347+
visible: data.visible,
346348
fn_index
347349
});
348350
} else if (type === "generating") {
@@ -474,6 +476,8 @@ export function submit(
474476
log: data.log,
475477
level: data.level,
476478
endpoint: _endpoint,
479+
duration: data.duration,
480+
visible: data.visible,
477481
fn_index
478482
});
479483
} else if (type === "generating") {
@@ -630,6 +634,8 @@ export function submit(
630634
log: data.log,
631635
level: data.level,
632636
endpoint: _endpoint,
637+
duration: data.duration,
638+
visible: data.visible,
633639
fn_index
634640
});
635641
return;

gradio/exceptions.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
from gradio_client.documentation import document
24

35

@@ -73,12 +75,21 @@ def divide(numerator, denominator):
7375
Demos: calculator, blocks_chained_events
7476
"""
7577

76-
def __init__(self, message: str = "Error raised."):
78+
def __init__(
79+
self,
80+
message: str = "Error raised.",
81+
duration: float | None = 10,
82+
visible: bool = True,
83+
):
7784
"""
7885
Parameters:
7986
message: The error message to be displayed to the user.
87+
duration: The duration in seconds to display the error message. If None or 0, the error message will be displayed until the user closes it.
88+
visible: Whether the error message should be displayed in the UI.
8089
"""
8190
self.message = message
91+
self.duration = duration
92+
self.visible = visible
8293
super().__init__(self.message)
8394

8495
def __str__(self):

gradio/helpers.py

+23-6
Original file line numberDiff line numberDiff line change
@@ -1226,7 +1226,12 @@ def _animate(_):
12261226
return output_mp4.name
12271227

12281228

1229-
def log_message(message: str, level: Literal["info", "warning"] = "info"):
1229+
def log_message(
1230+
message: str,
1231+
level: Literal["info", "warning"] = "info",
1232+
duration: float | None = 10,
1233+
visible: bool = True,
1234+
):
12301235
from gradio.context import LocalContext
12311236

12321237
blocks = LocalContext.blocks.get()
@@ -1239,16 +1244,22 @@ def log_message(message: str, level: Literal["info", "warning"] = "info"):
12391244
elif level == "warning":
12401245
warnings.warn(message)
12411246
return
1242-
blocks._queue.log_message(event_id=event_id, log=message, level=level)
1247+
blocks._queue.log_message(
1248+
event_id=event_id, log=message, level=level, duration=duration, visible=visible
1249+
)
12431250

12441251

12451252
@document(documentation_group="modals")
1246-
def Warning(message: str = "Warning issued."): # noqa: N802
1253+
def Warning( # noqa: N802
1254+
message: str = "Warning issued.", duration: float | None = 10, visible: bool = True
1255+
):
12471256
"""
12481257
This function allows you to pass custom warning messages to the user. You can do so simply by writing `gr.Warning('message here')` in your function, and when that line is executed the custom message will appear in a modal on the demo. The modal is yellow by default and has the heading: "Warning." Queue must be enabled for this behavior; otherwise, the warning will be printed to the console using the `warnings` library.
12491258
Demos: blocks_chained_events
12501259
Parameters:
12511260
message: The warning message to be displayed to the user.
1261+
duration: The duration in seconds that the warning message should be displayed for. If None or 0, the message will be displayed indefinitely until the user closes it.
1262+
visible: Whether the error message should be displayed in the UI.
12521263
Example:
12531264
import gradio as gr
12541265
def hello_world():
@@ -1259,16 +1270,22 @@ def hello_world():
12591270
demo.load(hello_world, inputs=None, outputs=[md])
12601271
demo.queue().launch()
12611272
"""
1262-
log_message(message, level="warning")
1273+
log_message(message, level="warning", duration=duration, visible=visible)
12631274

12641275

12651276
@document(documentation_group="modals")
1266-
def Info(message: str = "Info issued."): # noqa: N802
1277+
def Info( # noqa: N802
1278+
message: str = "Info issued.",
1279+
duration: float | None = 10,
1280+
visible: bool = True,
1281+
):
12671282
"""
12681283
This function allows you to pass custom info messages to the user. You can do so simply by writing `gr.Info('message here')` in your function, and when that line is executed the custom message will appear in a modal on the demo. The modal is gray by default and has the heading: "Info." Queue must be enabled for this behavior; otherwise, the message will be printed to the console.
12691284
Demos: blocks_chained_events
12701285
Parameters:
12711286
message: The info message to be displayed to the user.
1287+
duration: The duration in seconds that the info message should be displayed for. If None or 0, the message will be displayed indefinitely until the user closes it.
1288+
visible: Whether the error message should be displayed in the UI.
12721289
Example:
12731290
import gradio as gr
12741291
def hello_world():
@@ -1279,4 +1296,4 @@ def hello_world():
12791296
demo.load(hello_world, inputs=None, outputs=[md])
12801297
demo.queue().launch()
12811298
"""
1282-
log_message(message, level="info")
1299+
log_message(message, level="info", duration=duration, visible=visible)

gradio/queueing.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from gradio.data_classes import (
1919
PredictBody,
2020
)
21-
from gradio.exceptions import Error
2221
from gradio.helpers import TrackedIterable
2322
from gradio.server_messages import (
2423
EstimationMessage,
@@ -30,7 +29,13 @@
3029
ProgressMessage,
3130
ProgressUnit,
3231
)
33-
from gradio.utils import LRUCache, run_coro_in_background, safe_get_lock, set_task_name
32+
from gradio.utils import (
33+
LRUCache,
34+
error_payload,
35+
run_coro_in_background,
36+
safe_get_lock,
37+
set_task_name,
38+
)
3439

3540
if TYPE_CHECKING:
3641
from gradio.blocks import BlockFunction, Blocks
@@ -376,6 +381,8 @@ def log_message(
376381
event_id: str,
377382
log: str,
378383
level: Literal["info", "warning"],
384+
duration: float | None = 10,
385+
visible: bool = True,
379386
):
380387
events = [
381388
evt for job in self.active_jobs if job is not None for evt in job
@@ -385,6 +392,8 @@ def log_message(
385392
log_message = LogMessage(
386393
log=log,
387394
level=level,
395+
duration=duration,
396+
visible=visible,
388397
)
389398
self.send_message(event, log_message)
390399

@@ -538,15 +547,15 @@ async def process_events(
538547
)
539548
err = None
540549
except Exception as e:
541-
show_error = app.get_blocks().show_error or isinstance(e, Error)
542550
traceback.print_exc()
543551
response = None
544552
err = e
545553
for event in awake_events:
554+
content = error_payload(err, app.get_blocks().show_error)
546555
self.send_message(
547556
event,
548557
ProcessCompletedMessage(
549-
output={"error": str(e) if show_error else None},
558+
output=content,
550559
success=False,
551560
),
552561
)
@@ -586,8 +595,7 @@ async def process_events(
586595
else:
587596
success = False
588597
error = err or old_err
589-
show_error = app.get_blocks().show_error or isinstance(error, Error)
590-
output = {"error": str(error) if show_error else None}
598+
output = error_payload(error, app.get_blocks().show_error)
591599
for event in awake_events:
592600
self.send_message(
593601
event, ProcessCompletedMessage(output=output, success=success)

gradio/routes.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
ResetBody,
7777
SimplePredictBody,
7878
)
79-
from gradio.exceptions import Error
8079
from gradio.oauth import attach_oauth
8180
from gradio.route_utils import ( # noqa: F401
8281
CustomCORSMiddleware,
@@ -737,10 +736,10 @@ async def predict(
737736
root_path=root_path,
738737
)
739738
except BaseException as error:
740-
show_error = app.get_blocks().show_error or isinstance(error, Error)
739+
content = utils.error_payload(error, app.get_blocks().show_error)
741740
traceback.print_exc()
742741
return JSONResponse(
743-
content={"error": str(error) if show_error else None},
742+
content=content,
744743
status_code=500,
745744
)
746745
return output

gradio/server_messages.py

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class LogMessage(BaseMessage):
3131
msg: Literal[ServerMessage.log] = ServerMessage.log
3232
log: str
3333
level: Literal["info", "warning"]
34+
duration: Optional[float] = 10
35+
visible: bool = True
3436

3537

3638
class EstimationMessage(BaseMessage):

gradio/utils.py

+14
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import gradio
5454
from gradio.context import get_blocks_context
5555
from gradio.data_classes import FileData
56+
from gradio.exceptions import Error
5657
from gradio.strings import en
5758

5859
if TYPE_CHECKING: # Only import for type checking (is False at runtime).
@@ -1417,3 +1418,16 @@ def deep_hash(obj):
14171418
items = str(id(obj)).encode("utf-8")
14181419
hasher.update(repr(items).encode("utf-8"))
14191420
return hasher.hexdigest()
1421+
1422+
1423+
def error_payload(
1424+
error: BaseException | None, show_error: bool
1425+
) -> dict[str, bool | str | float | None]:
1426+
content: dict[str, bool | str | float | None] = {"error": None}
1427+
show_error = show_error or isinstance(error, Error)
1428+
if show_error:
1429+
content["error"] = str(error)
1430+
if isinstance(error, Error):
1431+
content["duration"] = error.duration
1432+
content["visible"] = error.visible
1433+
return content

js/_website/src/lib/assets/style.css

+6
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,12 @@ strong {
278278
font-weight: 600;
279279
}
280280

281+
.obj a {
282+
color: var(--tw-prose-links);
283+
text-decoration: underline;
284+
font-weight: 500;
285+
}
286+
281287
.codeblock > pre {
282288
font-size: 1em;
283289
}

js/_website/src/lib/templates/gradio/05_modals/error.svx

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@
1717

1818
<!--- Usage -->
1919
```python
20-
gradio.Error(···)
20+
raise gradio.Error("An error occured 💥!", duration=5)
2121
```
2222

2323
<!--- Description -->
2424
### Description
2525
## {@html style_formatted_text(obj.description)}
2626

27+
## You can control for how long the error message is displayed with the `duration` parameter. If it's `None`, the message will be displayed forever until the user closes it. If it's a number, it will be shown for that many seconds.
28+
## You can also hide the error modal from being shown in the UI by setting `visible=False`.
29+
## Below is a demo of how different values of duration control the error, info, and warning messages. You can see the code [here](https://huggingface.co/spaces/freddyaboulton/gradio-error-duration/blob/244331cf53f6b5fa2fd406ece3bf55c6ccb9f5f2/app.py#L17).
30+
31+
![modal_control](https://github.com/gradio-app/gradio/assets/41651716/f0977bcd-eaec-4eca-a2fd-ede95fdb8fd2)
32+
2733
<!-- Example Usage -->
2834

2935
{#if obj.example}

js/_website/src/lib/templates/gradio/05_modals/info.svx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<!--- Usage -->
1919
```python
20-
gradio.Info(···)
20+
gradio.Info("Helpful info message ℹ️", duration=5)
2121
```
2222

2323
<!--- Description -->

js/_website/src/lib/templates/gradio/05_modals/warning.svx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<!--- Usage -->
1919
```python
20-
gradio.Warning(···)
20+
gradio.Warning("A warning occured ⛔️!", duration=5)
2121
```
2222

2323
<!--- Description -->

js/app/src/Blocks.svelte

+21-5
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,17 @@
141141
function new_message(
142142
message: string,
143143
fn_index: number,
144-
type: ToastMessage["type"]
144+
type: ToastMessage["type"],
145+
duration: number | null = 10,
146+
visible = true
145147
): ToastMessage & { fn_index: number } {
146148
return {
147149
message,
148150
fn_index,
149151
type,
150-
id: ++_error_id
152+
id: ++_error_id,
153+
duration,
154+
visible
151155
};
152156
}
153157
@@ -344,8 +348,11 @@
344348
}
345349
346350
function handle_log(msg: LogMessage): void {
347-
const { log, fn_index, level } = msg;
348-
messages = [new_message(log, fn_index, level), ...messages];
351+
const { log, fn_index, level, duration, visible } = msg;
352+
messages = [
353+
new_message(log, fn_index, level, duration, visible),
354+
...messages
355+
];
349356
}
350357
351358
function handle_status_update(message: StatusMessage): void {
@@ -416,7 +423,16 @@
416423
MESSAGE_QUOTE_RE,
417424
(_, b) => b
418425
);
419-
messages = [new_message(_message, fn_index, "error"), ...messages];
426+
messages = [
427+
new_message(
428+
_message,
429+
fn_index,
430+
"error",
431+
status.duration,
432+
status.visible
433+
),
434+
...messages
435+
];
420436
}
421437
dependencies.map(async (dep) => {
422438
if (

0 commit comments

Comments
 (0)