diff --git a/src/wtforms/fields/choices.py b/src/wtforms/fields/choices.py index 66a9719d..0682d30e 100644 --- a/src/wtforms/fields/choices.py +++ b/src/wtforms/fields/choices.py @@ -59,6 +59,7 @@ class Choice(NamedTuple): label: str selected: bool render_kw: dict + disabled: bool = False @dataclass @@ -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: @@ -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 ] diff --git a/src/wtforms/widgets/core.py b/src/wtforms/widgets/core.py index 9b95bd0e..fb125825 100644 --- a/src/wtforms/widgets/core.py +++ b/src/wtforms/widgets/core.py @@ -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"") diff --git a/tests/fields/test_select.py b/tests/fields/test_select.py index 7618118c..a5ac0840 100644 --- a/tests/fields/test_select.py +++ b/tests/fields/test_select.py @@ -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(): @@ -707,8 +713,11 @@ 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(): @@ -716,3 +725,19 @@ def test_select_field_enum_renders_selected(): F = make_form(a=SelectField(choices=SelectChoice.from_enum(_Plain), coerce=_Plain)) form = F(a=_Plain.GREEN) assert '' in form.a() + + +def test_disabled_option(): + """SelectChoice supports disable=True, rendering