Make exceptions in the Client more specific (#8264)

* more specific exceptions

* format

* add changeset

* fix

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
Abubakar Abid 2024-05-13 12:06:06 -07:00 committed by GitHub
parent 0bf3d1a992
commit a9e1a8ac56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 50 additions and 24 deletions

View File

@ -0,0 +1,6 @@
---
"gradio": patch
"gradio_client": patch
---
feat:Make exceptions in the Client more specific

View File

@ -38,7 +38,7 @@ from gradio_client import utils
from gradio_client.compatibility import EndpointV3Compatibility
from gradio_client.data_classes import ParameterInfo
from gradio_client.documentation import document
from gradio_client.exceptions import AuthenticationError
from gradio_client.exceptions import AppError, AuthenticationError
from gradio_client.utils import (
Communicator,
JobStatus,
@ -1216,7 +1216,16 @@ class Endpoint:
raise ValueError(f"Unsupported protocol: {self.protocol}")
if "error" in result:
raise ValueError(result["error"])
if result["error"] is None:
raise AppError(
"The upstream Gradio app has raised an exception but has not enabled "
"verbose error reporting. To enable, set show_error=True in launch()."
)
else:
raise AppError(
"The upstream Gradio app has raised an exception: "
+ result["error"]
)
try:
output = result["data"]

View File

@ -8,3 +8,7 @@ class AuthenticationError(ValueError):
"""Raised when the client is unable to authenticate itself to a Gradio app due to invalid or missing credentials."""
pass
class AppError(ValueError):
"""Raised when the upstream Gradio app throws an error because of the value submitted by the client."""

View File

@ -1126,18 +1126,18 @@ def construct_args(
for key, value in kwargs.items():
if key in kwarg_arg_mapping:
if kwarg_arg_mapping[key] < num_args:
raise ValueError(
raise TypeError(
f"Parameter `{key}` is already set as a positional argument. Please click on 'view API' in the footer of the Gradio app to see usage."
)
else:
_args[kwarg_arg_mapping[key]] = value
else:
raise ValueError(
raise TypeError(
f"Parameter `{key}` is not a valid key-word argument. Please click on 'view API' in the footer of the Gradio app to see usage."
)
if _Keywords.NO_VALUE in _args:
raise ValueError(
raise TypeError(
f"No value provided for required argument: {kwarg_names[_args.index(_Keywords.NO_VALUE)]}"
)

View File

@ -242,7 +242,7 @@ def count_generator_no_api():
def count_generator_demo_exception():
def count(n):
for i in range(int(n)):
time.sleep(0.1)
time.sleep(0.01)
if i == 5:
raise ValueError("Oh no!")
yield i

View File

@ -22,7 +22,7 @@ from huggingface_hub.utils import RepositoryNotFoundError
from gradio_client import Client, file
from gradio_client.client import DEFAULT_TEMP_DIR
from gradio_client.exceptions import AuthenticationError
from gradio_client.exceptions import AppError, AuthenticationError
from gradio_client.utils import (
Communicator,
ProgressUnit,
@ -39,9 +39,9 @@ def connect(
demo: gr.Blocks,
serialize: bool = True,
output_dir: str = DEFAULT_TEMP_DIR,
max_file_size=None,
**kwargs,
):
_, local_url, _ = demo.launch(prevent_thread_lock=True, max_file_size=max_file_size)
_, local_url, _ = demo.launch(prevent_thread_lock=True, **kwargs)
try:
yield Client(local_url, serialize=serialize, output_dir=output_dir)
finally:
@ -228,17 +228,6 @@ class TestClientPredictions:
outputs.append(o)
assert outputs == [str(i) for i in range(3)]
@pytest.mark.flaky
def test_intermediate_outputs_with_exception(self, count_generator_demo_exception):
with connect(count_generator_demo_exception) as client:
with pytest.raises(Exception):
client.predict(7, api_name="/count")
with pytest.raises(
ValueError, match="Cannot call predict on this function"
):
client.predict(5, api_name="/count_forever")
def test_break_in_loop_if_error(self, calculator_demo):
with connect(calculator_demo) as client:
job = client.submit("foo", "add", 4, fn_index=0)
@ -682,7 +671,7 @@ class TestClientPredictionsWithKwargs:
def test_missing_params(self, calculator_demo):
with connect(calculator_demo) as client:
with pytest.raises(
ValueError, match="No value provided for required argument: num2"
TypeError, match="No value provided for required argument: num2"
):
client.predict(num1=3, operation="add", api_name="/predict")
@ -1371,3 +1360,21 @@ class TestDuplication:
"test_value2",
token=HF_TOKEN,
)
def test_upstream_exceptions(count_generator_demo_exception):
with connect(count_generator_demo_exception, show_error=True) as client:
with pytest.raises(
AppError, match="The upstream Gradio app has raised an exception: Oh no!"
):
client.predict(7, api_name="/count")
with connect(count_generator_demo_exception) as client:
with pytest.raises(
AppError,
match="The upstream Gradio app has raised an exception but has not enabled verbose error reporting.",
):
client.predict(7, api_name="/count")
with pytest.raises(ValueError, match="Cannot call predict on this function"):
client.predict(5, api_name="/count_forever")

View File

@ -230,20 +230,20 @@ class TestConstructArgs:
def test_positional_arg_and_kwarg_for_same_parameter(self):
parameters_info = [{"label": "param1", "parameter_name": "a"}]
with pytest.raises(
ValueError, match="Parameter `a` is already set as a positional argument."
TypeError, match="Parameter `a` is already set as a positional argument."
):
utils.construct_args(parameters_info, (1,), {"a": 2})
def test_invalid_kwarg(self):
parameters_info = [{"label": "param1", "parameter_name": "a"}]
with pytest.raises(
ValueError, match="Parameter `b` is not a valid key-word argument."
TypeError, match="Parameter `b` is not a valid key-word argument."
):
utils.construct_args(parameters_info, (), {"b": 1})
def test_required_arg_missing(self):
parameters_info = [{"label": "param1", "parameter_name": "a"}]
with pytest.raises(
ValueError, match="No value provided for required argument: a"
TypeError, match="No value provided for required argument: a"
):
utils.construct_args(parameters_info, (), {})