mirror of
https://github.com/gradio-app/gradio.git
synced 2025-01-30 11:00:11 +08:00
Use orjson to serialize dict including np.array (#8041)
* Use orjson to serialize dict including np.array * add changeset * Update json_component demo and add an E2E test using it * Rename demo/json_component -> demo/json_component_blocks * Add json_component_interface demo and an E2E test using it * Fix to await assertion promises * Revert renaming of json_component demo * add changeset * Rename js/app/test/json_component_blocks.spec.ts -> js/app/test/json_component.spec.ts * Revert changes in routes.py and add orjson to json_component.py * Update gr.Checkbox.postprocess to ensure a bool value is returned * add changeset * Remove the if-block in gr.Checkbox.postprocess handling NumPy arrays as they are not reasonable values to be interpreted as checkbox's value * Update gr.JSON's docstring * Add test/components/test_json_component.py * Remove JSON component E2E tests * Update gr.JSON's docstring * docstring --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
parent
e089e4cb4a
commit
937c858371
5
.changeset/free-trams-nail.md
Normal file
5
.changeset/free-trams-nail.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"gradio": patch
|
||||
---
|
||||
|
||||
fix:Use orjson to serialize dict including np.array
|
@ -1 +1 @@
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: json_component"]}, {"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", "with gr.Blocks() as demo:\n", " gr.JSON(value={\"Key 1\": \"Value 1\", \"Key 2\": {\"Key 3\": \"Value 2\", \"Key 4\": \"Value 3\"}, \"Key 5\": [\"Item 1\", \"Item 2\", \"Item 3\"]})\n", "\n", "demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: json_component"]}, {"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", "import numpy as np\n", "\n", "with gr.Blocks() as demo:\n", " inp = gr.JSON(\n", " label=\"InputJSON\",\n", " value={\n", " \"Key 1\": \"Value 1\",\n", " \"Key 2\": {\"Key 3\": \"Value 2\", \"Key 4\": \"Value 3\"},\n", " \"Key 5\": [\"Item 1\", \"Item 2\", \"Item 3\"],\n", " \"Key 6\": 123,\n", " \"Key 7\": 123.456,\n", " \"Key 8\": True,\n", " \"Key 9\": False,\n", " \"Key 10\": None,\n", " \"Key 11\": np.array([1, 2, 3]),\n", " }\n", " )\n", " out = gr.JSON(label=\"OutputJSON\")\n", " btn = gr.Button(\"Submit\")\n", " btn.click(lambda x: x, inp, out)\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -1,6 +1,25 @@
|
||||
import gradio as gr
|
||||
import gradio as gr
|
||||
import numpy as np
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
gr.JSON(value={"Key 1": "Value 1", "Key 2": {"Key 3": "Value 2", "Key 4": "Value 3"}, "Key 5": ["Item 1", "Item 2", "Item 3"]})
|
||||
inp = gr.JSON(
|
||||
label="InputJSON",
|
||||
value={
|
||||
"Key 1": "Value 1",
|
||||
"Key 2": {"Key 3": "Value 2", "Key 4": "Value 3"},
|
||||
"Key 5": ["Item 1", "Item 2", "Item 3"],
|
||||
"Key 6": 123,
|
||||
"Key 7": 123.456,
|
||||
"Key 8": True,
|
||||
"Key 9": False,
|
||||
"Key 10": None,
|
||||
"Key 11": np.array([1, 2, 3]),
|
||||
}
|
||||
)
|
||||
out = gr.JSON(label="OutputJSON")
|
||||
btn = gr.Button("Submit")
|
||||
btn.click(lambda x: x, inp, out)
|
||||
|
||||
demo.launch()
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo.launch()
|
||||
|
@ -95,4 +95,4 @@ class Checkbox(FormComponent):
|
||||
Returns:
|
||||
The same `bool` value that is set as the status of the checkbox
|
||||
"""
|
||||
return value
|
||||
return bool(value)
|
||||
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import json
|
||||
from typing import Any, Callable
|
||||
|
||||
import orjson
|
||||
from gradio_client.documentation import document
|
||||
|
||||
from gradio.components.base import Component
|
||||
@ -38,7 +39,7 @@ class JSON(Component):
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
value: Default value. If callable, the function will be called whenever the app loads to set the initial value of the component.
|
||||
value: Default value as a valid JSON `str` -- or a `list` or `dict` that can be serialized to a JSON string. If callable, the function will be called whenever the app loads to set the initial value of the component.
|
||||
label: The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.
|
||||
every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
|
||||
show_label: if True, will display label.
|
||||
@ -76,16 +77,25 @@ class JSON(Component):
|
||||
def postprocess(self, value: dict | list | str | None) -> dict | list | None:
|
||||
"""
|
||||
Parameters:
|
||||
value: Expects a `str` filepath to a file containing valid JSON -- or a `list` or `dict` that is valid JSON
|
||||
value: Expects a valid JSON `str` -- or a `list` or `dict` that can be serialized to a JSON string. The `list` or `dict` value can contain numpy arrays.
|
||||
Returns:
|
||||
Returns the JSON as a `list` or `dict`.
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, str):
|
||||
return json.loads(value)
|
||||
return orjson.loads(value)
|
||||
else:
|
||||
return value
|
||||
# Use orjson to convert NumPy arrays and datetime objects to JSON.
|
||||
# This ensures a backward compatibility with the previous behavior.
|
||||
# See https://github.com/gradio-app/gradio/pull/8041
|
||||
return orjson.loads(
|
||||
orjson.dumps(
|
||||
value,
|
||||
option=orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_PASSTHROUGH_DATETIME,
|
||||
default=str,
|
||||
)
|
||||
)
|
||||
|
||||
def example_payload(self) -> Any:
|
||||
return {"foo": "bar"}
|
||||
|
25
test/components/test_json_component.py
Normal file
25
test/components/test_json_component.py
Normal file
@ -0,0 +1,25 @@
|
||||
import json
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from gradio.components.json_component import JSON
|
||||
|
||||
|
||||
class TestJSON:
|
||||
@pytest.mark.parametrize(
|
||||
"value, expected",
|
||||
[
|
||||
(None, None),
|
||||
(True, True),
|
||||
([1, 2, 3], [1, 2, 3]),
|
||||
([np.array([1, 2, 3])], [[1, 2, 3]]),
|
||||
({"foo": [1, 2, 3]}, {"foo": [1, 2, 3]}),
|
||||
({"foo": np.array([1, 2, 3])}, {"foo": [1, 2, 3]}),
|
||||
],
|
||||
)
|
||||
def test_postprocess_returns_json_serializable_value(self, value, expected):
|
||||
json_component = JSON()
|
||||
postprocessed_value = json_component.postprocess(value)
|
||||
assert postprocessed_value == expected
|
||||
assert json.loads(json.dumps(postprocessed_value)) == expected
|
Loading…
Reference in New Issue
Block a user