Actual Behavior
from wtforms import Form, SelectField
class MyForm(Form):
foo = SelectField()
def test_construct():
form = MyForm()
assert form.foo.choices == []
When you run the test, it fails because form.foo.choices is None, not []:
./src/dyk_tools/test_select_form.py::test_construct Failed: [undefined]assert None == []
+ where None = <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0>.choices
+ where <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0> = <dyk_tools.test_select_form.MyForm object at 0x7fac5325fa90>.foo
def test_construct():
form = MyForm()
> assert form.foo.choices == []
E assert None == []
E + where None = <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0>.choices
E + where <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0> = <dyk_tools.test_select_form.MyForm object at 0x7fac5325fa90>.foo
Expected Behavior
form.foo.choices should be [] as is documented at https://wtforms.readthedocs.io/en/3.0.x/fields/#wtforms.fields.SelectField
As a more practical example with this Flask code:
class TemplateForm(Form):
name = SelectField(validate_choice=False)
def home_page():
form = TemplateForm(request.form)
if request.method == "POST" and form.validate():
return redirect(url_for("display", template_name=form.name.data))
form.name.choices = get_pending_nominations()
return render_template("home_page.html", form=form)
It fails on the POST branch with:
Traceback (most recent call last):
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 2548, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 2528, in wsgi_app
response = self.handle_exception(e)
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "/Users/roy/dev/dyk-tools/src/dyk_tools/flask_app/app.py", line 14, in home_page
if request.method == "POST" and form.validate():
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/form.py", line 329, in validate
return super().validate(extra)
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/form.py", line 146, in validate
if not field.validate(self, extra):
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/fields/core.py", line 231, in validate
self.pre_validate(form)
File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/fields/choices.py", line 136, in pre_validate
raise TypeError(self.gettext("Choices cannot be None."))
TypeError: Choices cannot be None.
Explicitly setting choices to []:
name = SelectField(validate_choice=False, choices=[])
makes things work as expected.
Environment
- Python version: 3.9.13
- wtforms version: 3.0.1