From 6986f79643282cb77d9c17e2044d8296ecf2c798 Mon Sep 17 00:00:00 2001 From: mondi04 <206898989+mondi04@users.noreply.github.com> Date: Sat, 6 Jun 2026 22:35:55 +0200 Subject: [PATCH 1/2] feat: add disabled support to SelectChoice and Select widget --- src/wtforms/fields/choices.py | 3 +++ src/wtforms/widgets/core.py | 2 ++ tests/fields/test_select.py | 23 +++++++++++++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) 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..e14606f8 100644 --- a/tests/fields/test_select.py +++ b/tests/fields/test_select.py @@ -445,8 +445,8 @@ 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 +707,8 @@ 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 +716,18 @@ 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, which renders the option with the disabled attribute.""" + 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 \ No newline at end of file From ba98f23f1983285b70b0d14da4cc954817583d3d Mon Sep 17 00:00:00 2001 From: mondi04 <206898989+mondi04@users.noreply.github.com> Date: Sat, 6 Jun 2026 22:52:21 +0200 Subject: [PATCH 2/2] fix: apply ruff formatting and line length fixes --- tests/fields/test_select.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/fields/test_select.py b/tests/fields/test_select.py index e14606f8..a5ac0840 100644 --- a/tests/fields/test_select.py +++ b/tests/fields/test_select.py @@ -446,7 +446,13 @@ 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, disabled in items: - assert (value, label, selected, render_kw, disabled) == ("a", "Foo", True, {}, False) + assert (value, label, selected, render_kw, disabled) == ( + "a", + "Foo", + True, + {}, + False, + ) def test_dict_str_str_flat_choices(): @@ -707,7 +713,10 @@ def test_iter_choices_tuple_unpacking(): a=SelectField(choices=[SelectChoice("a", "Foo"), SelectChoice("b", "Bar")]) ) form = F(a="a") - unpacked = [(v, lab, sel, rk, disabled) for v, lab, sel, rk, disabled in form.a.iter_choices()] + 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)] @@ -717,8 +726,9 @@ def test_select_field_enum_renders_selected(): form = F(a=_Plain.GREEN) assert '' in form.a() + def test_disabled_option(): - """SelectChoice supports disable=True, which renders the option with the disabled attribute.""" + """SelectChoice supports disable=True, rendering