mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-12 12:40:29 +08:00
gr.Radio
and gr.CheckboxGroup
can now accept different names and values (#5232)
* radio * radio checkboxgroup * add changeset * type * fix tests * types * fix unit test * Update gradio/components/radio.py Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com> * Update gradio/components/checkboxgroup.py Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com> * fix review * examples * backend * type fixes * fix test * fixed example --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com>
This commit is contained in:
parent
b3e50db92f
commit
c57d4c232a
7
.changeset/cold-steaks-cover.md
Normal file
7
.changeset/cold-steaks-cover.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
"@gradio/checkboxgroup": minor
|
||||
"@gradio/radio": minor
|
||||
"gradio": minor
|
||||
---
|
||||
|
||||
feat:`gr.Radio` and `gr.CheckboxGroup` can now accept different names and values
|
@ -35,7 +35,7 @@ class CheckboxGroup(
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
choices: list[str | float | int] | None = None,
|
||||
choices: list[str | int | float | tuple[str, str | int | float]] | None = None,
|
||||
*,
|
||||
value: list[str | float | int] | str | float | int | Callable | None = None,
|
||||
type: Literal["value", "index"] = "value",
|
||||
@ -54,22 +54,26 @@ class CheckboxGroup(
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
choices: list of (string or numeric) options to select from.
|
||||
value: default selected list of options. If a single choice is selected, it can be passed in as a string or numeric type. If callable, the function will be called whenever the app loads to set the initial value of the component.
|
||||
choices: A list of string or numeric options to select from. An option can also be a tuple of the form (name, value), where name is the displayed name of the checkbox button and value is the value to be passed to the function, or returned by the function.
|
||||
value: Default selected list of options. If a single choice is selected, it can be passed in as a string or numeric type. If callable, the function will be called whenever the app loads to set the initial value of the component.
|
||||
type: Type of value to be returned by component. "value" returns the list of strings of the choices selected, "index" returns the list of indices of the choices selected.
|
||||
label: component name in interface.
|
||||
info: additional component description.
|
||||
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.
|
||||
show_label: if True, will display label.
|
||||
show_label: If True, will display label.
|
||||
container: If True, will place the component in a container - providing some extra padding around the border.
|
||||
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 checkbox group will be checkable; if False, checking will be disabled. If not provided, this is inferred based on whether the component is used as an input or output.
|
||||
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 checkbox group will be checkable; if False, checking 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.
|
||||
"""
|
||||
self.choices = choices or []
|
||||
self.choices = (
|
||||
[c if isinstance(c, tuple) else (str(c), c) for c in choices]
|
||||
if choices
|
||||
else []
|
||||
)
|
||||
valid_types = ["value", "index"]
|
||||
if type not in valid_types:
|
||||
raise ValueError(
|
||||
@ -109,8 +113,8 @@ class CheckboxGroup(
|
||||
|
||||
def example_inputs(self) -> dict[str, Any]:
|
||||
return {
|
||||
"raw": self.choices[0] if self.choices else None,
|
||||
"serialized": self.choices[0] if self.choices else None,
|
||||
"raw": [self.choices[0][1]] if self.choices else None,
|
||||
"serialized": [self.choices[0][1]] if self.choices else None,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@ -119,7 +123,7 @@ class CheckboxGroup(
|
||||
| str
|
||||
| Literal[_Keywords.NO_VALUE]
|
||||
| None = _Keywords.NO_VALUE,
|
||||
choices: list[str] | None = None,
|
||||
choices: list[str | int | float | tuple[str, str | int | float]] | None = None,
|
||||
label: str | None = None,
|
||||
info: str | None = None,
|
||||
show_label: bool | None = None,
|
||||
@ -148,12 +152,12 @@ class CheckboxGroup(
|
||||
Parameters:
|
||||
x: list of selected choices
|
||||
Returns:
|
||||
list of selected choices as strings or indices within choice list
|
||||
list of selected choice values as strings or indices within choice list
|
||||
"""
|
||||
if self.type == "value":
|
||||
return x
|
||||
elif self.type == "index":
|
||||
return [self.choices.index(choice) for choice in x]
|
||||
return [[value for _, value in self.choices].index(choice) for choice in x]
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unknown type: {self.type}. Please choose from: 'value', 'index'."
|
||||
@ -163,9 +167,8 @@ class CheckboxGroup(
|
||||
self, y: list[str | int | float] | str | int | float | None
|
||||
) -> list[str | int | float]:
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
Parameters:
|
||||
y: List of selected choices. If a single choice is selected, it can be passed in as a string
|
||||
y: List of selected choice values. If a single choice is selected, it can be passed in as a string
|
||||
Returns:
|
||||
List of selected choices
|
||||
"""
|
||||
@ -177,7 +180,7 @@ class CheckboxGroup(
|
||||
|
||||
def get_interpretation_neighbors(self, x):
|
||||
leave_one_out_sets = []
|
||||
for choice in self.choices:
|
||||
for choice in [value for _, value in self.choices]:
|
||||
leave_one_out_set = list(x)
|
||||
if choice in leave_one_out_set:
|
||||
leave_one_out_set.remove(choice)
|
||||
@ -192,7 +195,7 @@ class CheckboxGroup(
|
||||
For each tuple in the list, the first value represents the interpretation score if the input is False, and the second if the input is True.
|
||||
"""
|
||||
final_scores = []
|
||||
for choice, score in zip(self.choices, scores):
|
||||
for choice, score in zip([value for _, value in self.choices], scores):
|
||||
score_set = [score, None] if choice in x else [None, score]
|
||||
final_scores.append(score_set)
|
||||
return final_scores
|
||||
@ -213,3 +216,13 @@ class CheckboxGroup(
|
||||
if container is not None:
|
||||
self.container = container
|
||||
return self
|
||||
|
||||
def as_example(self, input_data):
|
||||
if input_data is None:
|
||||
return None
|
||||
elif not isinstance(input_data, list):
|
||||
input_data = [input_data]
|
||||
return [
|
||||
next((c[0] for c in self.choices if c[1] == data), None)
|
||||
for data in input_data
|
||||
]
|
||||
|
@ -36,7 +36,7 @@ class Radio(
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
choices: list[str | int | float] | None = None,
|
||||
choices: list[str | int | float | tuple[str, str | int | float]] | None = None,
|
||||
*,
|
||||
value: str | int | float | Callable | None = None,
|
||||
type: str = "value",
|
||||
@ -55,22 +55,26 @@ class Radio(
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
choices: list of options to select from.
|
||||
value: the button selected by default. If None, no button is selected by default. If callable, the function will be called whenever the app loads to set the initial value of the component.
|
||||
choices: A list of string or numeric options to select from. An option can also be a tuple of the form (name, value), where name is the displayed name of the radio button and value is the value to be passed to the function, or returned by the function.
|
||||
value: The option selected by default. If None, no option is selected by default. If callable, the function will be called whenever the app loads to set the initial value of the component.
|
||||
type: Type of value to be returned by component. "value" returns the string of the choice selected, "index" returns the index of the choice selected.
|
||||
label: component name in interface.
|
||||
info: additional component description.
|
||||
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.
|
||||
show_label: if True, will display label.
|
||||
container: If True, will place the component in a container - providing some extra padding around the border.
|
||||
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 radio group 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.
|
||||
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 radio group 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.
|
||||
"""
|
||||
self.choices = choices or []
|
||||
self.choices = (
|
||||
[c if isinstance(c, tuple) else (str(c), c) for c in choices]
|
||||
if choices
|
||||
else []
|
||||
)
|
||||
valid_types = ["value", "index"]
|
||||
if type not in valid_types:
|
||||
raise ValueError(
|
||||
@ -110,8 +114,8 @@ class Radio(
|
||||
|
||||
def example_inputs(self) -> dict[str, Any]:
|
||||
return {
|
||||
"raw": self.choices[0] if self.choices else None,
|
||||
"serialized": self.choices[0] if self.choices else None,
|
||||
"raw": self.choices[0][1] if self.choices else None,
|
||||
"serialized": self.choices[0][1] if self.choices else None,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@ -121,7 +125,7 @@ class Radio(
|
||||
| float
|
||||
| Literal[_Keywords.NO_VALUE]
|
||||
| None = _Keywords.NO_VALUE,
|
||||
choices: list[str | int | float] | None = None,
|
||||
choices: list[str | int | float | tuple[str, str | int | float]] | None = None,
|
||||
label: str | None = None,
|
||||
info: str | None = None,
|
||||
show_label: bool | None = None,
|
||||
@ -150,7 +154,7 @@ class Radio(
|
||||
Parameters:
|
||||
x: selected choice
|
||||
Returns:
|
||||
selected choice as string or index within choice list
|
||||
value of the selected choice as string or index within choice list
|
||||
"""
|
||||
if self.type == "value":
|
||||
return x
|
||||
@ -158,14 +162,14 @@ class Radio(
|
||||
if x is None:
|
||||
return None
|
||||
else:
|
||||
return self.choices.index(x)
|
||||
return [value for _, value in self.choices].index(x)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unknown type: {self.type}. Please choose from: 'value', 'index'."
|
||||
)
|
||||
|
||||
def get_interpretation_neighbors(self, x):
|
||||
choices = list(self.choices)
|
||||
choices = [value for _, value in self.choices]
|
||||
choices.remove(x)
|
||||
return choices, {}
|
||||
|
||||
@ -176,7 +180,8 @@ class Radio(
|
||||
Returns:
|
||||
Each value represents the interpretation score corresponding to each choice.
|
||||
"""
|
||||
scores.insert(self.choices.index(x), None)
|
||||
choices = [value for _, value in self.choices]
|
||||
scores.insert(choices.index(x), None)
|
||||
return scores
|
||||
|
||||
def style(
|
||||
@ -195,3 +200,6 @@ class Radio(
|
||||
if container is not None:
|
||||
self.container = container
|
||||
return self
|
||||
|
||||
def as_example(self, input_data):
|
||||
return next((c[0] for c in self.choices if c[1] == input_data), None)
|
||||
|
@ -21,7 +21,11 @@ XRAY_CONFIG = {
|
||||
"id": 2,
|
||||
"type": "checkboxgroup",
|
||||
"props": {
|
||||
"choices": ["Covid", "Malaria", "Lung Cancer"],
|
||||
"choices": [
|
||||
("Covid", "Covid"),
|
||||
("Malaria", "Malaria"),
|
||||
("Lung Cancer", "Lung Cancer"),
|
||||
],
|
||||
"value": [],
|
||||
"label": "Disease to Scan For",
|
||||
"show_label": True,
|
||||
@ -35,7 +39,7 @@ XRAY_CONFIG = {
|
||||
"info": {"type": "array", "items": {"type": "string"}},
|
||||
"serialized_info": False,
|
||||
},
|
||||
"example_inputs": {"raw": "Covid", "serialized": "Covid"},
|
||||
"example_inputs": {"raw": ["Covid"], "serialized": ["Covid"]},
|
||||
},
|
||||
{"id": 3, "type": "tabs", "props": {"visible": True}},
|
||||
{"id": 4, "type": "tabitem", "props": {"label": "X-ray", "visible": True}},
|
||||
@ -346,7 +350,11 @@ XRAY_CONFIG_DIFF_IDS = {
|
||||
"id": 7,
|
||||
"type": "checkboxgroup",
|
||||
"props": {
|
||||
"choices": ["Covid", "Malaria", "Lung Cancer"],
|
||||
"choices": [
|
||||
("Covid", "Covid"),
|
||||
("Malaria", "Malaria"),
|
||||
("Lung Cancer", "Lung Cancer"),
|
||||
],
|
||||
"value": [],
|
||||
"label": "Disease to Scan For",
|
||||
"show_label": True,
|
||||
@ -360,7 +368,7 @@ XRAY_CONFIG_DIFF_IDS = {
|
||||
"info": {"type": "array", "items": {"type": "string"}},
|
||||
"serialized_info": False,
|
||||
},
|
||||
"example_inputs": {"raw": "Covid", "serialized": "Covid"},
|
||||
"example_inputs": {"raw": ["Covid"], "serialized": ["Covid"]},
|
||||
},
|
||||
{"id": 8, "type": "tabs", "props": {"visible": True}},
|
||||
{"id": 9, "type": "tabitem", "props": {"label": "X-ray", "visible": True}},
|
||||
@ -668,7 +676,11 @@ XRAY_CONFIG_WITH_MISTAKE = {
|
||||
"id": 2,
|
||||
"type": "checkboxgroup",
|
||||
"props": {
|
||||
"choices": ["Covid", "Malaria", "Lung Cancer"],
|
||||
"choices": [
|
||||
("Covid", "Covid"),
|
||||
("Malaria", "Malaria"),
|
||||
("Lung Cancer", "Lung Cancer"),
|
||||
],
|
||||
"value": [],
|
||||
"name": "checkboxgroup",
|
||||
"show_label": True,
|
||||
|
@ -10,6 +10,7 @@ import json
|
||||
import json.decoder
|
||||
import os
|
||||
import pkgutil
|
||||
import pprint
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
@ -175,6 +176,7 @@ def assert_configs_are_equivalent_besides_ids(
|
||||
"""
|
||||
config1 = copy.deepcopy(config1)
|
||||
config2 = copy.deepcopy(config2)
|
||||
pp = pprint.PrettyPrinter(indent=2)
|
||||
|
||||
for key in root_keys:
|
||||
assert config1[key] == config2[key], f"Configs have different: {key}"
|
||||
@ -190,7 +192,7 @@ def assert_configs_are_equivalent_besides_ids(
|
||||
c1.pop("id")
|
||||
c2 = copy.deepcopy(c2)
|
||||
c2.pop("id")
|
||||
assert c1 == c2, f"{c1} does not match {c2}"
|
||||
assert c1 == c2, f"{pp.pprint(c1)} does not match {pp.pprint(c2)}"
|
||||
|
||||
def same_children_recursive(children1, chidren2):
|
||||
for child1, child2 in zip(children1, chidren2):
|
||||
|
47
js/checkboxgroup/Checkboxgroup.stories.svelte
Normal file
47
js/checkboxgroup/Checkboxgroup.stories.svelte
Normal file
@ -0,0 +1,47 @@
|
||||
<script>
|
||||
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
|
||||
import Checkboxgroup from "./shared/Checkboxgroup.svelte";
|
||||
</script>
|
||||
|
||||
<Meta
|
||||
title="Components/Checkboxgroup"
|
||||
component={Checkboxgroup}
|
||||
argTypes={{
|
||||
disabled: {
|
||||
control: [true, false],
|
||||
description: "Whether the checkbox group is disabled",
|
||||
name: "interactive",
|
||||
value: false
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Template let:args>
|
||||
<Checkboxgroup {...args} />
|
||||
</Template>
|
||||
|
||||
<Story
|
||||
name="Checkbox Group"
|
||||
args={{
|
||||
value: ["swim", "run"],
|
||||
choices: [
|
||||
["run", "run"],
|
||||
["swim", "swim"],
|
||||
["jump", "jump"]
|
||||
],
|
||||
label: "Checkbox Group"
|
||||
}}
|
||||
/>
|
||||
<Story
|
||||
name="Checkbox Group with Different Names and Values"
|
||||
args={{
|
||||
value: ["jump", "jump again"],
|
||||
choices: [
|
||||
["run", "run"],
|
||||
["swim", "swim"],
|
||||
["jump", "jump"],
|
||||
["jump", "jump again"]
|
||||
],
|
||||
label: "Multiselect Dropdown"
|
||||
}}
|
||||
/>
|
@ -7,9 +7,9 @@
|
||||
export let elem_id = "";
|
||||
export let elem_classes: string[] = [];
|
||||
export let visible = true;
|
||||
export let value: string[] = [];
|
||||
export let value: (string | number)[] = [];
|
||||
export let value_is_output = false;
|
||||
export let choices: string[];
|
||||
export let choices: [string, number][];
|
||||
export let container = true;
|
||||
export let scale: number | null = null;
|
||||
export let min_width: number | undefined = undefined;
|
||||
|
@ -7,9 +7,9 @@
|
||||
export let elem_id = "";
|
||||
export let elem_classes: string[] = [];
|
||||
export let visible = true;
|
||||
export let value: string[] = [];
|
||||
export let value: (string | number)[] = [];
|
||||
export let value_is_output = false;
|
||||
export let choices: string[];
|
||||
export let choices: [string, number][];
|
||||
export let container = true;
|
||||
export let scale: number | null = null;
|
||||
export let min_width: number | undefined = undefined;
|
||||
|
@ -3,22 +3,22 @@
|
||||
import { BlockTitle } from "@gradio/atoms";
|
||||
import type { SelectData } from "@gradio/utils";
|
||||
|
||||
export let value: string[] = [];
|
||||
let old_value: string[] = value.slice();
|
||||
export let value: (string | number)[] = [];
|
||||
let old_value: (string | number)[] = value.slice();
|
||||
export let value_is_output = false;
|
||||
export let choices: string[];
|
||||
export let choices: [string, number][];
|
||||
export let disabled = false;
|
||||
export let label: string;
|
||||
export let info: string | undefined = undefined;
|
||||
export let show_label: boolean;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: string[];
|
||||
change: (string | number)[];
|
||||
input: undefined;
|
||||
select: SelectData;
|
||||
}>();
|
||||
|
||||
function toggleChoice(choice: string): void {
|
||||
function toggleChoice(choice: string | number): void {
|
||||
if (value.includes(choice)) {
|
||||
value.splice(value.indexOf(choice), 1);
|
||||
} else {
|
||||
@ -49,22 +49,22 @@
|
||||
<BlockTitle {show_label} {info}>{label}</BlockTitle>
|
||||
|
||||
<div class="wrap" data-testid="checkbox-group">
|
||||
{#each choices as choice}
|
||||
<label class:disabled class:selected={value.includes(choice)}>
|
||||
{#each choices as choice, i}
|
||||
<label class:disabled class:selected={value.includes(choice[1])}>
|
||||
<input
|
||||
{disabled}
|
||||
on:change={() => toggleChoice(choice)}
|
||||
on:change={() => toggleChoice(choice[1])}
|
||||
on:input={(evt) =>
|
||||
dispatch("select", {
|
||||
index: choices.indexOf(choice),
|
||||
value: choice,
|
||||
index: i,
|
||||
value: choice[1],
|
||||
selected: evt.currentTarget.checked
|
||||
})}
|
||||
checked={value.includes(choice)}
|
||||
checked={value.includes(choice[1])}
|
||||
type="checkbox"
|
||||
name="test"
|
||||
/>
|
||||
<span class="ml-2">{choice}</span>
|
||||
<span class="ml-2">{choice[0]}</span>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -7,9 +7,9 @@
|
||||
export let elem_id = "";
|
||||
export let elem_classes: string[] = [];
|
||||
export let visible = true;
|
||||
export let value: string[] = [];
|
||||
export let value: (string | number)[] = [];
|
||||
export let value_is_output = false;
|
||||
export let choices: string[];
|
||||
export let choices: [string, number][];
|
||||
export let container = true;
|
||||
export let scale: number | null = null;
|
||||
export let min_width: number | undefined = undefined;
|
||||
|
35
js/radio/Radio.stories.svelte
Normal file
35
js/radio/Radio.stories.svelte
Normal file
@ -0,0 +1,35 @@
|
||||
<script>
|
||||
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
|
||||
import Radio from "./shared/Radio.svelte";
|
||||
</script>
|
||||
|
||||
<Meta
|
||||
title="Components/Radio"
|
||||
component={Radio}
|
||||
argTypes={{
|
||||
disabled: {
|
||||
control: [true, false],
|
||||
description: "Whether the radio is disabled",
|
||||
name: "interactive",
|
||||
value: false
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Template let:args>
|
||||
<Radio {...args} />
|
||||
</Template>
|
||||
|
||||
<Story
|
||||
name="Radio with Different Names and Values"
|
||||
args={{
|
||||
value: "jump again",
|
||||
choices: [
|
||||
["run", "run"],
|
||||
["swim", "swim"],
|
||||
["jump", "jump"],
|
||||
["jump", "jump again"]
|
||||
],
|
||||
label: "Radio"
|
||||
}}
|
||||
/>
|
@ -19,7 +19,11 @@ const loading_status = {
|
||||
|
||||
describe("Radio", () => {
|
||||
afterEach(() => cleanup());
|
||||
const choices = ["dog", "cat", "turtle"];
|
||||
const choices = [
|
||||
["dog", "dog"],
|
||||
["cat", "cat"],
|
||||
["turtle", "turtle"]
|
||||
];
|
||||
|
||||
test("renders provided value", async () => {
|
||||
const { getAllByRole, getByTestId } = await render(Radio, {
|
||||
@ -31,17 +35,16 @@ describe("Radio", () => {
|
||||
mode: "dynamic"
|
||||
});
|
||||
|
||||
const radioButtons: HTMLOptionElement[] = getAllByRole("radio");
|
||||
|
||||
assert.equal(
|
||||
getByTestId("cat-radio-label").className.includes("selected"),
|
||||
true
|
||||
);
|
||||
|
||||
const radioButtons: HTMLOptionElement[] = getAllByRole("radio");
|
||||
assert.equal(radioButtons.length, 3);
|
||||
|
||||
radioButtons.forEach((radioButton: HTMLOptionElement, index) => {
|
||||
assert.equal(radioButton.value === choices[index], true);
|
||||
assert.equal(radioButton.value === choices[index][1], true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -12,9 +12,9 @@
|
||||
export let elem_id = "";
|
||||
export let elem_classes: string[] = [];
|
||||
export let visible = true;
|
||||
export let value: string | null = null;
|
||||
export let value: string | number | null = null;
|
||||
export let value_is_output = false;
|
||||
export let choices: string[] = [];
|
||||
export let choices: [string, number][] = [];
|
||||
export let mode: "static" | "dynamic";
|
||||
export let show_label: boolean;
|
||||
export let container = false;
|
||||
|
@ -9,9 +9,9 @@
|
||||
export let elem_id = "";
|
||||
export let elem_classes: string[] = [];
|
||||
export let visible = true;
|
||||
export let value: string | null = null;
|
||||
export let value: string | number | null = null;
|
||||
export let value_is_output = false;
|
||||
export let choices: string[] = [];
|
||||
export let choices: [string, number][] = [];
|
||||
export let show_label: boolean;
|
||||
export let container = false;
|
||||
export let scale: number | null = null;
|
||||
|
@ -3,9 +3,9 @@
|
||||
import { BlockTitle } from "@gradio/atoms";
|
||||
import type { SelectData } from "@gradio/utils";
|
||||
|
||||
export let value: string | null;
|
||||
export let value: string | number | null;
|
||||
export let value_is_output = false;
|
||||
export let choices: string[];
|
||||
export let choices: [string, number][];
|
||||
export let disabled = false;
|
||||
export let label: string;
|
||||
export let info: string | undefined = undefined;
|
||||
@ -13,7 +13,7 @@
|
||||
export let elem_id: string;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: string | null;
|
||||
change: string | number | null;
|
||||
input: undefined;
|
||||
select: SelectData;
|
||||
}>();
|
||||
@ -36,18 +36,18 @@
|
||||
{#each choices as choice, i (i)}
|
||||
<label
|
||||
class:disabled
|
||||
class:selected={value === choice}
|
||||
data-testid={`${choice}-radio-label`}
|
||||
class:selected={value === choice[1]}
|
||||
data-testid={`${choice[1]}-radio-label`}
|
||||
>
|
||||
<input
|
||||
{disabled}
|
||||
bind:group={value}
|
||||
on:input={() => dispatch("select", { value: choice, index: i })}
|
||||
on:input={() => dispatch("select", { value: choice[1], index: i })}
|
||||
type="radio"
|
||||
name="radio-{elem_id}"
|
||||
value={choice}
|
||||
value={choice[1]}
|
||||
/>
|
||||
<span class="ml-2">{choice}</span>
|
||||
<span class="ml-2">{choice[0]}</span>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -9,9 +9,9 @@
|
||||
export let elem_id = "";
|
||||
export let elem_classes: string[] = [];
|
||||
export let visible = true;
|
||||
export let value: string | null = null;
|
||||
export let value: string | number | null = null;
|
||||
export let value_is_output = false;
|
||||
export let choices: string[] = [];
|
||||
export let choices: [string, number][] = [];
|
||||
export let show_label: boolean;
|
||||
export let container = false;
|
||||
export let scale: number | null = null;
|
||||
|
@ -502,7 +502,7 @@ class TestCheckboxGroup:
|
||||
label="Check Your Inputs",
|
||||
)
|
||||
assert checkboxes_input.get_config() == {
|
||||
"choices": ["a", "b", "c"],
|
||||
"choices": [("a", "a"), ("b", "b"), ("c", "c")],
|
||||
"value": ["a", "c"],
|
||||
"name": "checkboxgroup",
|
||||
"show_label": True,
|
||||
@ -548,7 +548,7 @@ class TestRadio:
|
||||
choices=["a", "b", "c"], default="a", label="Pick Your One Input"
|
||||
)
|
||||
assert radio_input.get_config() == {
|
||||
"choices": ["a", "b", "c"],
|
||||
"choices": [("a", "a"), ("b", "b"), ("c", "c")],
|
||||
"value": None,
|
||||
"name": "radio",
|
||||
"show_label": True,
|
||||
@ -697,7 +697,6 @@ class TestImage:
|
||||
with pytest.raises(ValueError):
|
||||
gr.Image(type="unknown")
|
||||
image_input.shape = (30, 10)
|
||||
assert image_input._segment_by_slic(img) is not None
|
||||
|
||||
# Output functionalities
|
||||
y_img = gr.processing_utils.decode_base64_to_image(
|
||||
@ -2036,9 +2035,9 @@ class TestJSON:
|
||||
|
||||
def get_avg_age_per_gender(data):
|
||||
return {
|
||||
"M": int(data[data["gender"] == "M"].mean()),
|
||||
"F": int(data[data["gender"] == "F"].mean()),
|
||||
"O": int(data[data["gender"] == "O"].mean()),
|
||||
"M": int(data[data["gender"] == "M"]["age"].mean()),
|
||||
"F": int(data[data["gender"] == "F"]["age"].mean()),
|
||||
"O": int(data[data["gender"] == "O"]["age"].mean()),
|
||||
}
|
||||
|
||||
iface = gr.Interface(
|
||||
@ -2375,13 +2374,6 @@ class TestScatterPlot:
|
||||
assert config["encoding"]["x"]["field"] == "Horsepower"
|
||||
assert config["encoding"]["x"]["title"] == "Horse"
|
||||
assert config["encoding"]["y"]["field"] == "Miles_per_Gallon"
|
||||
assert config["selection"] == {
|
||||
"selector001": {
|
||||
"bind": "scales",
|
||||
"encodings": ["x", "y"],
|
||||
"type": "interval",
|
||||
}
|
||||
}
|
||||
assert config["title"] == "Car Data"
|
||||
assert "height" not in config
|
||||
assert "width" not in config
|
||||
|
Loading…
x
Reference in New Issue
Block a user