Skip to content

Commit

Permalink
Document the gr.ParamViewer component, and fix component preprocess…
Browse files Browse the repository at this point in the history
…ing/postprocessing docstrings (#7116)

* add paramviewer to docs

* add changeset

* type fixing

* round to

* format

* revert to make test pass

* remove msg

* add changeset

* annotated image

* annotated image
push

* audio

* changes

* changes

* audio

* audio

* changes

* remove borders from code

* working

* fixes

* add changeset

* formatting

* build fix

* changes

* ls

* more components

* format

* some more

* more

* component

* plots

* buttons

* simple backend

* number

* more

* more

* simple templates

* format

* fixes

* backend

* fix tests

* fix test

* fixes

* formatting

---------

Co-authored-by: gradio-pr-bot <[email protected]>
Co-authored-by: aliabd <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2024
1 parent 60078df commit 3c8c4ac
Show file tree
Hide file tree
Showing 54 changed files with 833 additions and 382 deletions.
7 changes: 7 additions & 0 deletions .changeset/ninety-bobcats-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"gradio": minor
"gradio_client": minor
"website": minor
---

feat:Document the `gr.ParamViewer` component, and fix component preprocessing/postprocessing docstrings
30 changes: 29 additions & 1 deletion client/python/gradio_client/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ def document_fn(fn: Callable, cls) -> tuple[str, list[dict], dict, str | None]:
for param_name, param in signature.parameters.items():
if param_name.startswith("_"):
continue
if param_name == "self":
continue
if param_name in ["kwargs", "args"] and param_name not in parameters:
continue
parameter_doc = {
Expand All @@ -147,7 +149,7 @@ def document_fn(fn: Callable, cls) -> tuple[str, list[dict], dict, str | None]:
parameter_docs.append(parameter_doc)
assert (
len(parameters) == 0
), f"Documentation format for {fn.__name__} documents nonexistent parameters: {''.join(parameters.keys())}"
), f"Documentation format for {fn.__name__} documents nonexistent parameters: {', '.join(parameters.keys())}. Valid parameters: {', '.join(signature.parameters.keys())}"
if len(returns) == 0:
return_docs = {}
elif len(returns) == 1:
Expand Down Expand Up @@ -203,6 +205,24 @@ def generate_documentation():
for cls, fns in class_list:
fn_to_document = cls if inspect.isfunction(cls) else cls.__init__
_, parameter_doc, return_doc, _ = document_fn(fn_to_document, cls)
if (
hasattr(cls, "preprocess")
and callable(cls.preprocess) # type: ignore
and hasattr(cls, "postprocess")
and callable(cls.postprocess) # type: ignore
):
preprocess_doc = document_fn(cls.preprocess, cls) # type: ignore
postprocess_doc = document_fn(cls.postprocess, cls) # type: ignore
preprocess_doc, postprocess_doc = (
{
"parameter_doc": preprocess_doc[1],
"return_doc": preprocess_doc[2],
},
{
"parameter_doc": postprocess_doc[1],
"return_doc": postprocess_doc[2],
},
)
cls_description, cls_tags, cls_example = document_cls(cls)
cls_documentation = {
"class": cls,
Expand All @@ -214,6 +234,14 @@ def generate_documentation():
"example": cls_example,
"fns": [],
}
if (
hasattr(cls, "preprocess")
and callable(cls.preprocess) # type: ignore
and hasattr(cls, "postprocess")
and callable(cls.postprocess) # type: ignore
):
cls_documentation["preprocess"] = preprocess_doc # type: ignore
cls_documentation["postprocess"] = postprocess_doc # type: ignore
for fn_name in fns:
instance_attribute_fn = fn_name.startswith("*")
if instance_attribute_fn:
Expand Down
1 change: 1 addition & 0 deletions demo/paramviewer_component/run.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: paramviewer_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.Markdown(\"The `round()` function in Python takes two parameters\")\n", " gr.ParamViewer(\n", " {\n", " \"number\": { \n", " \"type\": \"int | float\", \n", " \"description\": \"The number to round\", \n", " \"default\": None\n", " },\n", " \"ndigits\": { \n", " \"type\": \"int\", \n", " \"description\": \"The number of digits to round to\", \n", " \"default\": \"0\"\n", " }\n", " }\n", " )\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
21 changes: 21 additions & 0 deletions demo/paramviewer_component/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import gradio as gr

with gr.Blocks() as demo:
gr.Markdown("The `round()` function in Python takes two parameters")
gr.ParamViewer(
{
"number": {
"type": "int | float",
"description": "The number to round",
"default": None
},
"ndigits": {
"type": "int",
"description": "The number of digits to round to",
"default": "0"
}
}
)

if __name__ == "__main__":
demo.launch()
32 changes: 16 additions & 16 deletions gradio/_simple_templates/simpledropdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
class SimpleDropdown(FormComponent):
"""
Creates a very simple dropdown listing choices from which entries can be selected.
Preprocessing: Preprocessing: passes the value of the selected dropdown entry as a {str}.
Postprocessing: expects a {str} corresponding to the value of the dropdown entry to be selected.
Examples-format: a {str} representing the drop down value to select.
Demos: sentence_builder, titanic_survival
"""

EVENTS = [Events.change, Events.input, Events.select]
Expand Down Expand Up @@ -41,19 +37,17 @@ def __init__(
value: default value selected in dropdown. If None, no value is selected by default. If callable, the function will be called whenever the app loads to set the initial value of the component.
label: component name in interface.
info: additional component description.
every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
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.
scale: relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.
min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
interactive: if True, choices in this dropdown will be selectable; if False, selection will be disabled. If not provided, this is inferred based on whether the component is used as an input or output.
visible: If False, component will be hidden.
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: bool = True,
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
"""
self.choices = (
# Although we expect choices to be a list of lists, it can be a list of tuples if the Gradio app
# is loaded with gr.load() since Python tuples are converted to lists in JSON.
[tuple(c) if isinstance(c, (tuple, list)) else (str(c), c) for c in choices]
if choices
else []
Expand Down Expand Up @@ -82,26 +76,32 @@ def api_info(self) -> dict[str, Any]:
def example_inputs(self) -> Any:
return self.choices[0][1] if self.choices else None

def preprocess(self, x: str | int | float | None) -> str | int | float | None:
def preprocess(self, payload: str | int | float | None) -> str | int | float | None:
"""
Parameters:
x: selected choice
payload: the value of the selected dropdown choice
Returns:
selected choice
Passes the value of the selected dropdown choice as a `str | int | float`.
"""
return x
return payload

def _warn_if_invalid_choice(self, y):
if y not in [value for _, value in self.choices]:
warnings.warn(
f"The value passed into gr.Dropdown() is not in the list of choices. Please update the list of choices to include: {y}."
)

def postprocess(self, y):
if y is None:
def postprocess(self, value):
"""
Parameters:
value: Expects a `str | int | float` corresponding to the value of the dropdown entry to be selected.
Returns:
Returns the value of the selected dropdown entry.
"""
if value is None:
return None
self._warn_if_invalid_choice(y)
return y
self._warn_if_invalid_choice(value)
return value

def process_example(self, input_data):
return next((c[0] for c in self.choices if c[1] == input_data), None)
7 changes: 2 additions & 5 deletions gradio/_simple_templates/simpleimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
class SimpleImage(Component):
"""
Creates an image component that can be used to upload images (as an input) or display images (as an output).
Preprocessing: passes the uploaded image as a {str} filepath.
Postprocessing: expects a {str} or {pathlib.Path} filepath to an image and displays the image.
Examples-format: a {str} local filepath or URL to an image.
"""

EVENTS = [
Expand Down Expand Up @@ -85,7 +82,7 @@ def preprocess(self, payload: FileData | None) -> str | None:
Parameters:
payload: A FileData object containing the image data.
Returns:
A string containing the path to the image.
A `str` containing the path to the image.
"""
if payload is None:
return None
Expand All @@ -94,7 +91,7 @@ def preprocess(self, payload: FileData | None) -> str | None:
def postprocess(self, value: str | Path | None) -> FileData | None:
"""
Parameters:
value: A string or pathlib.Path object containing the path to the image.
value: Expects a `str` or `pathlib.Path` object containing the path to the image.
Returns:
A FileData object containing the image data.
"""
Expand Down
23 changes: 9 additions & 14 deletions gradio/_simple_templates/simpletextbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
class SimpleTextbox(FormComponent):
"""
Creates a very simple textbox for user to enter string input or display string output.
Preprocessing: passes textbox value as a {str} into the function.
Postprocessing: expects a {str} returned from function and sets textbox value to it.
Examples-format: a {str} representing the textbox input.
"""

EVENTS = [
Expand Down Expand Up @@ -42,7 +39,7 @@ def __init__(
value: default text to provide in textbox. If callable, the function will be called whenever the app loads to set the initial value of the component.
placeholder: placeholder hint to provide behind textbox.
label: component name in interface.
every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
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.
scale: relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.
min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
Expand All @@ -69,25 +66,23 @@ def __init__(
render=render,
)

def preprocess(self, x: str | None) -> str | None:
def preprocess(self, payload: str | None) -> str | None:
"""
Preprocesses input (converts it to a string) before passing it to the function.
Parameters:
x: text
payload: the text entered in the textarea.
Returns:
text
Passes text value as a {str} into the function.
"""
return None if x is None else str(x)
return None if payload is None else str(payload)

def postprocess(self, y: str | None) -> str | None:
def postprocess(self, value: str | None) -> str | None:
"""
Postproccess the function output y by converting it to a str before passing it to the frontend.
Parameters:
y: function output to postprocess.
value: Expects a {str} returned from function and sets textarea value to it.
Returns:
text
The value to display in the textarea.
"""
return None if y is None else str(y)
return None if value is None else str(value)

def api_info(self) -> dict[str, Any]:
return {"type": "string"}
Expand Down
2 changes: 1 addition & 1 deletion gradio/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ def set_event_trigger(
batch: whether this function takes in a batch of inputs
max_batch_size: the maximum batch size to send to the function
cancels: a list of other events to cancel when this event is triggered. For example, setting cancels=[click_event] will cancel the click_event, where click_event is the return value of another components .click method.
every: Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds. Queue must be enabled.
every: Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds.
collects_event_data: whether to collect event data for this event
trigger_after: if set, this event will be triggered after 'trigger_after' function index
trigger_only_on_success: if True, this event will only be triggered if the previous event was successful (only applies if `trigger_after` is set)
Expand Down
2 changes: 1 addition & 1 deletion gradio/component_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def {{ event }}(self,
preprocess: If False, will not run preprocessing of component data before running 'fn' (e.g. leaving it as a base64 string if this method is called with the `Image` component).
postprocess: If False, will not run postprocessing of component data before returning 'fn' output to the browser.
cancels: A list of other events to cancel when this listener is triggered. For example, setting cancels=[click_event] will cancel the click_event, where click_event is the return value of another components .click method. Functions that have not yet run (or generators that are iterating) will be cancelled, but functions that are currently running will be allowed to finish.
every: Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds. Queue must be enabled.
every: Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds.
trigger_mode: If "once" (default for all events except `.change()`) would not allow any submissions while an event is pending. If set to "multiple", unlimited submissions are allowed while pending, and "always_last" (default for `.change()` event) would allow a second submission after the pending event is complete.
js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
concurrency_limit: If set, this is the maximum number of this event that can be running simultaneously. Can be set to None to mean no concurrency_limit (any number of this event can be running simultaneously). Set to "default" to use the default concurrency limit (defined by the `default_concurrency_limit` parameter in `Blocks.queue()`, which itself is 1 by default).
Expand Down
Loading

0 comments on commit 3c8c4ac

Please sign in to comment.