WTForms 3.3.0b1__tar.gz → 3.3.0b2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/CHANGES.rst +55 -25
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/PKG-INFO +1 -1
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/fields.rst +32 -18
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/widgets.rst +2 -3
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/__init__.py +3 -1
- wtforms-3.3.0b2/src/wtforms/_compat.py +15 -0
- wtforms-3.3.0b2/src/wtforms/datalist.py +122 -0
- wtforms-3.3.0b2/src/wtforms/fields/choices.py +550 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/fields/core.py +13 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/fields/form.py +17 -2
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/fields/list.py +5 -1
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/form.py +24 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/widgets/core.py +55 -16
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/conftest.py +14 -6
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_form.py +98 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_radio.py +11 -7
- wtforms-3.3.0b2/tests/fields/test_select.py +718 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_selectmultiple.py +39 -22
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/test_datalist.py +16 -48
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/test_widgets.py +68 -16
- wtforms-3.3.0b1/.hgignore +0 -1
- wtforms-3.3.0b1/src/wtforms/datalist.py +0 -52
- wtforms-3.3.0b1/src/wtforms/fields/choices.py +0 -338
- wtforms-3.3.0b1/tests/fields/test_select.py +0 -478
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/.gitignore +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/LICENSE.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/README.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/Makefile +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/_static/logo_joined.svg +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/_static/logo_split.svg +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/_static/logo_square.svg +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/changes.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/conf.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/contributing.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/crash_course.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/csrf.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/ext.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/faq.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/forms.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/i18n.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/index.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/license.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/make.bat +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/meta.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/specific_problems.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/validators.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/docs/whats_new.rst +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/hatch_build.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/pyproject.toml +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/csrf/__init__.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/csrf/core.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/csrf/session.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/fields/__init__.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/fields/datetime.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/fields/numeric.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/fields/simple.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/i18n.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/README.md +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ar/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ar/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/bg/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/bg/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ca/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ca/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/cy/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/cy/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/de/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/de/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/de_CH/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/el/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/el/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/en/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/en/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/es/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/es/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/et/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/et/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/fa/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/fa/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/fi/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/fi/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/fr/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/fr/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/he/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/he/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/hu/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/hu/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/it/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/it/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ja/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ja/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/kk/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/kk/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ko/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ko/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/nb/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/nb/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/nl/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/nl/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/pl/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/pl/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/pt/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/pt/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ro/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ro/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ru/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ru/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/sk/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/sk/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/sr/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/sr/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/sv/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/sv/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ta/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/ta/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/tr/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/tr/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/uk/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/uk/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/wtforms.pot +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/zh/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/zh/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/meta.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/utils.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/validators.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/src/wtforms/widgets/__init__.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/__init__.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/common.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/__init__.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_boolean.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_button.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_color.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_custom.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_date.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_datetime.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_datetimelocal.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_decimal.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_defaults.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_field.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_file.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_filters.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_flags.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_float.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_hidden.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_html5.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_integer.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_label.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_list.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_month.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_password.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_string.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_submit.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_textarea.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_time.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/fields/test_week.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/test_csrf.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/test_form.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/test_i18n.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/test_locale_babel.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/test_webob.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/__init__.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_anyof.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_data_required.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_date_range.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_disabled.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_email.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_equal_to.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_input_required.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_ipaddress.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_lazy_proxy.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_length.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_mac_address.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_noneof.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_number_range.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_optional.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_readonly.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_regexp.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_url.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_uuid.py +0 -0
- {wtforms-3.3.0b1 → wtforms-3.3.0b2}/tests/validators/test_validators.py +0 -0
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
.. currentmodule:: wtforms
|
|
2
2
|
|
|
3
|
+
Version 3.3.0b2
|
|
4
|
+
---------------
|
|
5
|
+
|
|
6
|
+
Released 2026-05-24
|
|
7
|
+
|
|
8
|
+
- :class:`~fields.SelectField` ``choices`` accepts a shorthand dict
|
|
9
|
+
syntax: ``{value: label}`` for flat options and
|
|
10
|
+
``{label: {value: label}}`` for optgroups. :issue:`886`
|
|
11
|
+
- Split choice types by role: :class:`~fields.SelectChoice` and
|
|
12
|
+
:class:`~fields.DataListChoice` to declare options via ``choices=``,
|
|
13
|
+
:class:`~fields.Choice` for what ``iter_choices`` / ``iter_groups``
|
|
14
|
+
yield. :issue:`922`
|
|
15
|
+
- ``choices`` callables on :class:`~fields.SelectField` and
|
|
16
|
+
:class:`~datalist.DataList` may accept ``(form, field)``. Resolved
|
|
17
|
+
once per processing cycle. :issue:`922`
|
|
18
|
+
- Add :meth:`fields.Field.post_process` and
|
|
19
|
+
:meth:`form.BaseForm.post_process` hooks, propagated through
|
|
20
|
+
:class:`~fields.FormField` and :class:`~fields.FieldList` for
|
|
21
|
+
cross-field finalization. :issue:`922`
|
|
22
|
+
- Add ``Field._form`` and ``BaseForm._parent_form`` so fields and nested
|
|
23
|
+
forms can reach their enclosing form. Fix :class:`~fields.FieldList`
|
|
24
|
+
entries and :class:`~fields.SelectField` option subfields which
|
|
25
|
+
previously got ``form=None``. :issue:`922`
|
|
26
|
+
- Restore 3.2 compatibility for :class:`~fields.SelectField` subclasses:
|
|
27
|
+
tuple yields from :meth:`~fields.SelectFieldBase.iter_choices` /
|
|
28
|
+
:meth:`~fields.SelectFieldBase.iter_groups`,
|
|
29
|
+
3-positional :meth:`widgets.Select.render_option` overrides,
|
|
30
|
+
:meth:`~fields.SelectFieldBase.has_groups` /
|
|
31
|
+
:meth:`~fields.SelectFieldBase.iter_groups`, and ``self.choices``
|
|
32
|
+
keeping the user-supplied shape. Each emits a ``DeprecationWarning``;
|
|
33
|
+
will be removed in WTForms 4.0. :issue:`922`
|
|
34
|
+
|
|
3
35
|
Version 3.3.0b1
|
|
4
36
|
---------------
|
|
5
37
|
|
|
@@ -12,66 +44,64 @@ Released 2026-05-10
|
|
|
12
44
|
``step="any"``. :issue:`677` :pr:`679`
|
|
13
45
|
- :meth:`~fields.FieldList._add_entry` now routes through :meth:`~meta.DefaultMeta.bind_field`,
|
|
14
46
|
consistent with how the form constructor binds top-level fields. Custom ``Meta.bind_field``
|
|
15
|
-
overrides were silently bypassed for all ``FieldList`` entries.
|
|
16
|
-
- Add `test_environment` support to :class:`~validators.Email`. :issue:`869`
|
|
17
|
-
- Reset :class:`~fields.FieldList` index state when reprocessing entries. :issue:`874`
|
|
18
|
-
- Let :class:`~widgets.RangeInput` accept `min` and `max` at construction time. :issue:`693`
|
|
47
|
+
overrides were silently bypassed for all ``FieldList`` entries. :pr:`891`
|
|
48
|
+
- Add `test_environment` support to :class:`~validators.Email`. :issue:`869` :pr:`894`
|
|
49
|
+
- Reset :class:`~fields.FieldList` index state when reprocessing entries. :issue:`874` :pr:`895`
|
|
50
|
+
- Let :class:`~widgets.RangeInput` accept `min` and `max` at construction time. :issue:`693` :pr:`898`
|
|
19
51
|
- Do not render a ``for`` attribute on the main label of :class:`~fields.RadioField`.
|
|
20
|
-
:issue:`775`
|
|
21
|
-
- Deprecate :class:`~fields.DateTimeField`, which will be removed in WTForms 3.4. :issue:`831`
|
|
52
|
+
:issue:`775` :pr:`900`
|
|
53
|
+
- Deprecate :class:`~fields.DateTimeField`, which will be removed in WTForms 3.4. :issue:`831` :pr:`897`
|
|
22
54
|
- Clarify that :class:`~fields.SelectField` ``choices`` is re-evaluated at
|
|
23
|
-
every form instantiation, including callables, in the documentation. :issue:`875`
|
|
55
|
+
every form instantiation, including callables, in the documentation. :issue:`875` :pr:`909`
|
|
24
56
|
- Render ``False`` as ``value="False"`` in :class:`~fields.SelectField` options
|
|
25
|
-
instead of omitting the attribute. :issue:`878`
|
|
57
|
+
instead of omitting the attribute. :issue:`878` :pr:`908`
|
|
26
58
|
- Accept :class:`uuid.UUID` instances in the :class:`~validators.UUID` validator,
|
|
27
59
|
and translate unexpected types into :class:`~validators.ValidationError`
|
|
28
60
|
instead of letting :class:`TypeError` escape. :issue:`549` :pr:`769`
|
|
29
61
|
- Escape double quotes in :class:`~markupsafe.Markup` attribute values
|
|
30
62
|
passed to :func:`~widgets.html_params`, and return a
|
|
31
|
-
:class:`~markupsafe.Markup`. :issue:`801`
|
|
32
|
-
- Clarify documentation about filters. :issue:`859`
|
|
63
|
+
:class:`~markupsafe.Markup`. :issue:`801` :pr:`906` :pr:`907`
|
|
64
|
+
- Clarify documentation about filters. :issue:`859` :pr:`896`
|
|
33
65
|
- Let render-time ``checked`` kwargs take precedence over the field's value
|
|
34
66
|
in :class:`~widgets.CheckboxInput` and :class:`~widgets.RadioInput`.
|
|
35
|
-
:issue:`706`
|
|
67
|
+
:issue:`706` :pr:`910`
|
|
36
68
|
- Add a ``tz`` parameter to :class:`~fields.DateTimeLocalField` to associate a
|
|
37
|
-
timezone with the input. :issue:`833`
|
|
69
|
+
timezone with the input. :issue:`833` :pr:`905`
|
|
38
70
|
- Add :class:`~fields.FieldList` ``insert_entry`` and indexed ``pop_entry``.
|
|
39
|
-
:issue:`256`
|
|
40
|
-
- :class:`~fields.FieldList` builds entries in the order keys appear in
|
|
41
|
-
``formdata``, instead of sorting them by numeric index. :issue:`256`
|
|
71
|
+
:issue:`256` :pr:`901` :pr:`912`
|
|
42
72
|
- Add :class:`~fields.ButtonField` to render ``<button type="submit">``
|
|
43
|
-
controls with string values. :issue:`784`
|
|
73
|
+
controls with string values. :issue:`784` :pr:`892`
|
|
44
74
|
- :class:`~fields.SelectField` refactor. Choices tuples and dicts are
|
|
45
|
-
deprecated in favor of :class:`~fields.Choice`. :pr:`739`
|
|
75
|
+
deprecated in favor of :class:`~fields.Choice`. :pr:`739` :pr:`889`
|
|
46
76
|
- ``<option>`` HTML attributes can be passed using
|
|
47
|
-
:class:`~fields.Choice`. :issue:`692` :pr:`739`
|
|
77
|
+
:class:`~fields.Choice`. :issue:`692` :pr:`739` :pr:`889`
|
|
48
78
|
- Add :meth:`fields.Choice.from_enum` to build choices from an
|
|
49
79
|
:class:`enum.Enum` class, and let :class:`~fields.SelectField` accept an
|
|
50
|
-
Enum class as ``coerce``. :issue:`338`
|
|
80
|
+
Enum class as ``coerce``. :issue:`338` :pr:`916`
|
|
51
81
|
- Defer to ``email_validator``'s module-level defaults for the
|
|
52
82
|
:class:`~validators.Email` ``test_environment``, ``allow_smtputf8`` and
|
|
53
|
-
``allow_empty_local`` options. :issue:`915`
|
|
83
|
+
``allow_empty_local`` options. :issue:`915` :pr:`917`
|
|
54
84
|
- Add ``invalid_value_message`` and ``invalid_choice_message`` keyword
|
|
55
85
|
arguments for customizing built-in field error messages. On
|
|
56
86
|
``SelectMultipleField``, ``invalid_choice_message`` may also be a callable
|
|
57
|
-
for custom pluralization. :issue:`39` :issue:`832`
|
|
87
|
+
for custom pluralization. :issue:`39` :issue:`832` :pr:`902`
|
|
58
88
|
- :class:`~fields.SelectField` and :class:`~fields.SelectMultipleField`
|
|
59
89
|
``pre_validate`` now short-circuits when ``process_formdata`` already
|
|
60
90
|
produced an error, so a single coercion failure no longer surfaces as both
|
|
61
|
-
an "invalid value" and an "invalid choice" error.
|
|
91
|
+
an "invalid value" and an "invalid choice" error. :pr:`902`
|
|
62
92
|
- Add a ``matcher`` keyword argument to :class:`~validators.Regexp` to
|
|
63
93
|
override the matching function. Defaults to :func:`re.match`; pass
|
|
64
94
|
:func:`re.search` or :func:`re.fullmatch` to change the anchoring
|
|
65
|
-
behaviour. :issue:`867`
|
|
95
|
+
behaviour. :issue:`867` :pr:`918`
|
|
66
96
|
- Add an ``html_pattern`` keyword argument to :class:`~validators.Regexp`
|
|
67
97
|
to control the HTML ``pattern`` attribute emitted on supporting widgets.
|
|
68
|
-
:
|
|
98
|
+
:pr:`759`
|
|
69
99
|
- :class:`~validators.URL` validator is based on ``urllib.parse.urlparse``
|
|
70
100
|
instead of a regex. New keyword arguments: ``allow_userinfo`` for
|
|
71
101
|
accepting ``user:password@host`` URLs; ``schemes``
|
|
72
102
|
(default ``("http", "https")``) is the allowlist of accepted schemes
|
|
73
103
|
:pr:`847`
|
|
74
|
-
- Add native :class:`DataList` support. :issue:`653`
|
|
104
|
+
- Add native :class:`DataList` support. :issue:`653` :pr:`921`
|
|
75
105
|
|
|
76
106
|
Version 3.2.2
|
|
77
107
|
-------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: WTForms
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.0b2
|
|
4
4
|
Summary: Form validation and rendering for Python web development.
|
|
5
5
|
Project-URL: Documentation, https://wtforms.readthedocs.io
|
|
6
6
|
Project-URL: Changes, https://wtforms.readthedocs.io/changes
|
|
@@ -287,10 +287,10 @@ refer to a single input from the form.
|
|
|
287
287
|
Choice Fields
|
|
288
288
|
-------------
|
|
289
289
|
|
|
290
|
-
.. autoclass:: Choice
|
|
291
|
-
|
|
292
290
|
.. autoclass:: SelectChoice
|
|
293
291
|
|
|
292
|
+
.. autoclass:: Choice
|
|
293
|
+
|
|
294
294
|
.. autoclass:: RadioField(default field arguments, choices=None, coerce=str)
|
|
295
295
|
|
|
296
296
|
.. code-block:: jinja
|
|
@@ -310,23 +310,23 @@ Choice Fields
|
|
|
310
310
|
|
|
311
311
|
Select fields take a ``choices`` parameter which is either:
|
|
312
312
|
|
|
313
|
-
* a list of :class:`
|
|
313
|
+
* a list of :class:`SelectChoice`.
|
|
314
314
|
It can also be a list of only values, in which case the value is used
|
|
315
|
-
as the label. The :class:`
|
|
315
|
+
as the label. The :class:`SelectChoice` ``render_kw`` mapping is rendered as
|
|
316
316
|
HTML :mdn-tag:`option` parameters. The value can be of any
|
|
317
317
|
type, but because form data is sent to the browser as strings, you
|
|
318
318
|
will need to provide a ``coerce`` function that converts a string
|
|
319
319
|
back to the expected type.
|
|
320
|
-
* a function taking no argument, and returning a list of :class:`
|
|
320
|
+
* a function taking no argument, and returning a list of :class:`SelectChoice`.
|
|
321
321
|
|
|
322
322
|
|
|
323
323
|
**Select fields with static choice values**::
|
|
324
324
|
|
|
325
325
|
class PastebinEntry(Form):
|
|
326
326
|
language = SelectField('Programming Language', choices=[
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
327
|
+
SelectChoice('cpp', 'C++'),
|
|
328
|
+
SelectChoice('py', 'Python'),
|
|
329
|
+
SelectChoice('text', 'Plain Text'),
|
|
330
330
|
])
|
|
331
331
|
|
|
332
332
|
Note that the `choices` keyword is evaluated each time the form is
|
|
@@ -352,7 +352,7 @@ Choice Fields
|
|
|
352
352
|
**Select fields with dynamic choice values**::
|
|
353
353
|
|
|
354
354
|
def available_groups():
|
|
355
|
-
return [
|
|
355
|
+
return [SelectChoice(g.id, g.name) for g in Group.query.order_by('name')]
|
|
356
356
|
|
|
357
357
|
class UserDetails(Form):
|
|
358
358
|
group_id = SelectField('Group', coerce=int, choices=available_groups)
|
|
@@ -368,6 +368,18 @@ Choice Fields
|
|
|
368
368
|
keyword arg to :class:`~wtforms.fields.SelectField` says that we use
|
|
369
369
|
:func:`int()` to coerce form data. The default coerce is :func:`str()`.
|
|
370
370
|
|
|
371
|
+
The callable may optionally accept ``(form, field)`` as positional
|
|
372
|
+
arguments. When this signature is used, the callable is invoked after the
|
|
373
|
+
whole form has been processed, so it can read ``field.data`` and the data
|
|
374
|
+
of any other field on the form::
|
|
375
|
+
|
|
376
|
+
def available_groups(form, field):
|
|
377
|
+
return [SelectChoice(g.id, g.name) for g in form.tenant.data.groups]
|
|
378
|
+
|
|
379
|
+
class UserDetails(Form):
|
|
380
|
+
tenant = QuerySelectField('Tenant', ...)
|
|
381
|
+
group_id = SelectField('Group', coerce=int, choices=available_groups)
|
|
382
|
+
|
|
371
383
|
**Coerce function example**::
|
|
372
384
|
|
|
373
385
|
def coerce_none(value):
|
|
@@ -377,9 +389,9 @@ Choice Fields
|
|
|
377
389
|
|
|
378
390
|
class NonePossible(Form):
|
|
379
391
|
my_select_field = SelectField('Select an option', choices=[
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
392
|
+
SelectChoice('1', 'Option 1'),
|
|
393
|
+
SelectChoice('2', 'Option 2'),
|
|
394
|
+
SelectChoice('None', 'No option'),
|
|
383
395
|
], coerce=coerce_none)
|
|
384
396
|
|
|
385
397
|
Note when the option None is selected a 'None' str will be passed. By using a coerce
|
|
@@ -395,9 +407,9 @@ Choice Fields
|
|
|
395
407
|
BLUE = 3
|
|
396
408
|
|
|
397
409
|
class PaintForm(Form):
|
|
398
|
-
color = SelectField(choices=
|
|
410
|
+
color = SelectField(choices=SelectChoice.from_enum(Color), coerce=Color)
|
|
399
411
|
|
|
400
|
-
:meth:`
|
|
412
|
+
:meth:`SelectChoice.from_enum` builds the option list from the Enum items;
|
|
401
413
|
the HTML ``value`` of each option is the item's ``name``. Passing the
|
|
402
414
|
Enum class itself as ``coerce`` installs the matching coercion, so
|
|
403
415
|
``form.color.data`` is a ``Color`` item after submit. Pre-selecting
|
|
@@ -408,8 +420,8 @@ Choice Fields
|
|
|
408
420
|
``item.name``. To customise, pass a ``label`` callable taking an Enum
|
|
409
421
|
item and returning the label string::
|
|
410
422
|
|
|
411
|
-
|
|
412
|
-
# → [
|
|
423
|
+
SelectChoice.from_enum(Color, label=lambda item: item.name.title())
|
|
424
|
+
# → [SelectChoice('RED', 'Red'), SelectChoice('GREEN', 'Green'), SelectChoice('BLUE', 'Blue')]
|
|
413
425
|
|
|
414
426
|
**Skipping choice validation**::
|
|
415
427
|
|
|
@@ -554,7 +566,7 @@ complex data structures such as lists and nested objects can be represented.
|
|
|
554
566
|
FormField::
|
|
555
567
|
|
|
556
568
|
class IMForm(Form):
|
|
557
|
-
protocol = SelectField(choices=[
|
|
569
|
+
protocol = SelectField(choices=[SelectChoice('aim', 'AIM'), SelectChoice('msn', 'MSN')])
|
|
558
570
|
username = StringField()
|
|
559
571
|
|
|
560
572
|
class ContactForm(Form):
|
|
@@ -568,6 +580,8 @@ Data Lists
|
|
|
568
580
|
|
|
569
581
|
.. currentmodule:: wtforms
|
|
570
582
|
|
|
583
|
+
.. autoclass:: DataListChoice
|
|
584
|
+
|
|
571
585
|
.. class:: DataList(choices=None, *, render_kw=None, widget=None)
|
|
572
586
|
|
|
573
587
|
A :mdn-tag:`datalist` of suggestions. Unlike
|
|
@@ -576,7 +590,7 @@ Data Lists
|
|
|
576
590
|
suggestions but the user may type any value. Combine with
|
|
577
591
|
:class:`~wtforms.validators.AnyOf` if you need a closed set.
|
|
578
592
|
|
|
579
|
-
``choices`` is either a list of :class:`~wtforms.
|
|
593
|
+
``choices`` is either a list of :class:`~wtforms.DataListChoice`
|
|
580
594
|
(or plain strings, in which case the string is used as both value
|
|
581
595
|
and label), or a callable invoked at render time. The callable
|
|
582
596
|
may take no argument (``fn()``) for a static list, or ``(field)``
|
|
@@ -85,9 +85,8 @@ Inside the widget, the following ``field`` attributes are commonly used:
|
|
|
85
85
|
- ``field._value()`` — the string representation of the current value, used
|
|
86
86
|
for the ``value=`` attribute of inputs.
|
|
87
87
|
- ``field.iter_choices()`` — for :class:`~wtforms.fields.SelectField` and
|
|
88
|
-
similar; yields :class:`~wtforms.fields.
|
|
89
|
-
``value``, ``label``, ``
|
|
90
|
-
current selection.
|
|
88
|
+
similar; yields :class:`~wtforms.fields.Choice` objects with
|
|
89
|
+
``value``, ``label``, ``selected`` and ``render_kw``.
|
|
91
90
|
|
|
92
91
|
To assemble the HTML, use :func:`~wtforms.widgets.html_params` for attribute
|
|
93
92
|
strings, :class:`markupsafe.Markup` to mark the result as safe, and
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from wtforms import validators
|
|
2
2
|
from wtforms import widgets
|
|
3
3
|
from wtforms.datalist import DataList
|
|
4
|
+
from wtforms.datalist import DataListChoice
|
|
4
5
|
from wtforms.fields.choices import Choice
|
|
5
6
|
from wtforms.fields.choices import RadioField
|
|
6
7
|
from wtforms.fields.choices import SelectChoice
|
|
@@ -40,7 +41,7 @@ from wtforms.fields.simple import URLField
|
|
|
40
41
|
from wtforms.form import Form
|
|
41
42
|
from wtforms.validators import ValidationError
|
|
42
43
|
|
|
43
|
-
__version__ = "3.3.
|
|
44
|
+
__version__ = "3.3.0b2"
|
|
44
45
|
|
|
45
46
|
__all__ = [
|
|
46
47
|
"validators",
|
|
@@ -84,4 +85,5 @@ __all__ = [
|
|
|
84
85
|
"ColorField",
|
|
85
86
|
"Choice",
|
|
86
87
|
"SelectChoice",
|
|
88
|
+
"DataListChoice",
|
|
87
89
|
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Compatibility helpers for different Python versions."""
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
if sys.version_info >= (3, 14):
|
|
7
|
+
from annotationlib import Format
|
|
8
|
+
|
|
9
|
+
def get_signature(callable):
|
|
10
|
+
return inspect.signature(callable, annotation_format=Format.FORWARDREF)
|
|
11
|
+
|
|
12
|
+
else:
|
|
13
|
+
|
|
14
|
+
def get_signature(callable):
|
|
15
|
+
return inspect.signature(callable)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import field
|
|
4
|
+
|
|
5
|
+
from wtforms import widgets
|
|
6
|
+
from wtforms._compat import get_signature
|
|
7
|
+
from wtforms.fields.choices import Choice
|
|
8
|
+
|
|
9
|
+
__all__ = ("DataList", "DataListChoice")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class DataListChoice:
|
|
14
|
+
"""
|
|
15
|
+
An option declared via :class:`~wtforms.DataList`'s ``choices=``
|
|
16
|
+
parameter.
|
|
17
|
+
|
|
18
|
+
:param value:
|
|
19
|
+
The value rendered as the ``<option>``'s ``value`` attribute.
|
|
20
|
+
:param label:
|
|
21
|
+
The label of the option. Defaults to ``value`` when omitted.
|
|
22
|
+
:param render_kw:
|
|
23
|
+
A dict containing HTML attributes that will be rendered
|
|
24
|
+
with the option. Defaults to an empty dict when omitted.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
value: str
|
|
28
|
+
label: str | None = None
|
|
29
|
+
render_kw: dict = field(default_factory=dict)
|
|
30
|
+
|
|
31
|
+
def __post_init__(self):
|
|
32
|
+
if self.label is None:
|
|
33
|
+
self.label = self.value
|
|
34
|
+
|
|
35
|
+
def __iter__(self):
|
|
36
|
+
return iter((self.value, self.label, self.render_kw))
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_enum(cls, enum_cls, *, label=None):
|
|
40
|
+
"""Build a list of choices from an :class:`enum.Enum` class.
|
|
41
|
+
|
|
42
|
+
See :meth:`SelectChoice.from_enum` for details.
|
|
43
|
+
"""
|
|
44
|
+
if label is None:
|
|
45
|
+
label = str if "__str__" in enum_cls.__dict__ else lambda m: m.name
|
|
46
|
+
return [cls(value=m.name, label=label(m)) for m in enum_cls]
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def from_input(cls, input):
|
|
50
|
+
"""Coerce a value passed by the user into a :class:`DataListChoice`."""
|
|
51
|
+
if isinstance(input, DataListChoice):
|
|
52
|
+
return input
|
|
53
|
+
|
|
54
|
+
if isinstance(input, Choice):
|
|
55
|
+
warnings.warn(
|
|
56
|
+
"Passing Choice to a DataList is deprecated; Choice is the "
|
|
57
|
+
"output type returned by iter_choices(). Use DataListChoice "
|
|
58
|
+
"instead. Support for Choice as input will be removed in "
|
|
59
|
+
"WTForms 4.0.",
|
|
60
|
+
DeprecationWarning,
|
|
61
|
+
stacklevel=4,
|
|
62
|
+
)
|
|
63
|
+
return cls(
|
|
64
|
+
value=input.value,
|
|
65
|
+
label=input.label,
|
|
66
|
+
render_kw=input.render_kw,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if isinstance(input, str):
|
|
70
|
+
return cls(value=input)
|
|
71
|
+
|
|
72
|
+
if isinstance(input, tuple):
|
|
73
|
+
return cls(*input)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class DataList:
|
|
77
|
+
"""A ``<datalist>`` of suggestions attached to a single field.
|
|
78
|
+
|
|
79
|
+
Passed to a :class:`~wtforms.Field` via its ``datalist=`` parameter
|
|
80
|
+
to add an autocomplete-style list of choices. See the WTForms
|
|
81
|
+
fields documentation for usage.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
widget = widgets.DataListWidget()
|
|
85
|
+
|
|
86
|
+
def __init__(self, choices=None, *, render_kw=None, widget=None):
|
|
87
|
+
self._raw_choices = choices
|
|
88
|
+
self._choices = None if callable(choices) else choices
|
|
89
|
+
self.render_kw = render_kw or {}
|
|
90
|
+
if widget is not None:
|
|
91
|
+
self.widget = widget
|
|
92
|
+
self.id = None
|
|
93
|
+
|
|
94
|
+
def _clone(self, id):
|
|
95
|
+
clone = DataList.__new__(DataList)
|
|
96
|
+
clone._raw_choices = self._raw_choices
|
|
97
|
+
clone._choices = None if callable(self._raw_choices) else self._raw_choices
|
|
98
|
+
clone.render_kw = self.render_kw
|
|
99
|
+
clone.widget = self.widget
|
|
100
|
+
clone.id = id
|
|
101
|
+
return clone
|
|
102
|
+
|
|
103
|
+
def _resolve(self, field):
|
|
104
|
+
raw = self._raw_choices
|
|
105
|
+
if not callable(raw):
|
|
106
|
+
return
|
|
107
|
+
try:
|
|
108
|
+
sig = get_signature(raw)
|
|
109
|
+
sig.bind(field._form, field)
|
|
110
|
+
except TypeError:
|
|
111
|
+
self._choices = raw()
|
|
112
|
+
return
|
|
113
|
+
self._choices = raw(field._form, field)
|
|
114
|
+
|
|
115
|
+
def iter_choices(self, field=None):
|
|
116
|
+
raw = self._choices
|
|
117
|
+
if raw is None:
|
|
118
|
+
return []
|
|
119
|
+
return [DataListChoice.from_input(item) for item in raw]
|
|
120
|
+
|
|
121
|
+
def __call__(self, field=None, **kwargs):
|
|
122
|
+
return self.widget(self, field=field, **kwargs)
|