Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/wtforms/fields/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class Choice(NamedTuple):
label: str
selected: bool
render_kw: dict
disabled: bool = False


@dataclass
Expand All @@ -82,6 +83,7 @@ class SelectChoice:
label: str = None # type: ignore[assignment]
render_kw: dict = field(default_factory=dict)
optgroup: str | None = None
disabled: bool = False

def __post_init__(self):
if self.label is None:
Expand Down Expand Up @@ -365,6 +367,7 @@ def iter_choices(self):
label=c.label,
selected=self.coerce(c.value) == self.data,
render_kw=c.render_kw,
disabled=c.disabled,
)
for c in choices
]
Expand Down
2 changes: 2 additions & 0 deletions src/wtforms/widgets/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@ def render_option(cls, choice, **kwargs):
options = {"value": value, **(choice.render_kw or {}), **kwargs}
if choice.selected:
options["selected"] = True
if choice.disabled:
options["disabled"] = True
label = escape(choice.label or choice.value)
return Markup(f"<option {html_params(**options)}>{label}</option>")

Expand Down
33 changes: 29 additions & 4 deletions tests/fields/test_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,14 @@ def test_iter_groups_items_unpack_as_3_2_tuples():
)
form = F(a="a")
for _label, items in form.a.iter_groups():
for value, label, selected, render_kw in items:
assert (value, label, selected, render_kw) == ("a", "Foo", True, {})
for value, label, selected, render_kw, disabled in items:
assert (value, label, selected, render_kw, disabled) == (
"a",
"Foo",
True,
{},
False,
)


def test_dict_str_str_flat_choices():
Expand Down Expand Up @@ -707,12 +713,31 @@ def test_iter_choices_tuple_unpacking():
a=SelectField(choices=[SelectChoice("a", "Foo"), SelectChoice("b", "Bar")])
)
form = F(a="a")
unpacked = [(v, lab, sel, rk) for v, lab, sel, rk in form.a.iter_choices()]
assert unpacked == [("a", "Foo", True, {}), ("b", "Bar", False, {})]
unpacked = [
(v, lab, sel, rk, disabled)
for v, lab, sel, rk, disabled in form.a.iter_choices()
]
assert unpacked == [("a", "Foo", True, {}, False), ("b", "Bar", False, {}, False)]


def test_select_field_enum_renders_selected():
"""Pre-selecting a member highlights the right option."""
F = make_form(a=SelectField(choices=SelectChoice.from_enum(_Plain), coerce=_Plain))
form = F(a=_Plain.GREEN)
assert '<option selected value="GREEN">GREEN</option>' in form.a()


def test_disabled_option():
"""SelectChoice supports disable=True, rendering <option disabled>."""
F = make_form(
a=SelectField(
choices=[
SelectChoice("a", "Foo"),
SelectChoice("b", "Bar", disabled=True),
]
)
)
form = F(a="a")
html = form.a()
assert "disabled" in html
assert html.count("disabled") == 1
Loading