WTForms 3.3.1__tar.gz → 3.3.2__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.
Files changed (181) hide show
  1. {wtforms-3.3.1 → wtforms-3.3.2}/CHANGES.rst +9 -0
  2. {wtforms-3.3.1 → wtforms-3.3.2}/PKG-INFO +4 -1
  3. {wtforms-3.3.1 → wtforms-3.3.2}/README.rst +3 -0
  4. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/__init__.py +1 -1
  5. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/list.py +2 -3
  6. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_list.py +47 -0
  7. {wtforms-3.3.1 → wtforms-3.3.2}/.gitignore +0 -0
  8. {wtforms-3.3.1 → wtforms-3.3.2}/LICENSE.rst +0 -0
  9. {wtforms-3.3.1 → wtforms-3.3.2}/docs/Makefile +0 -0
  10. {wtforms-3.3.1 → wtforms-3.3.2}/docs/_static/logo_joined.svg +0 -0
  11. {wtforms-3.3.1 → wtforms-3.3.2}/docs/_static/logo_split.svg +0 -0
  12. {wtforms-3.3.1 → wtforms-3.3.2}/docs/_static/logo_square.svg +0 -0
  13. {wtforms-3.3.1 → wtforms-3.3.2}/docs/changes.rst +0 -0
  14. {wtforms-3.3.1 → wtforms-3.3.2}/docs/conf.py +0 -0
  15. {wtforms-3.3.1 → wtforms-3.3.2}/docs/contributing.rst +0 -0
  16. {wtforms-3.3.1 → wtforms-3.3.2}/docs/crash_course.rst +0 -0
  17. {wtforms-3.3.1 → wtforms-3.3.2}/docs/csrf.rst +0 -0
  18. {wtforms-3.3.1 → wtforms-3.3.2}/docs/ext.rst +0 -0
  19. {wtforms-3.3.1 → wtforms-3.3.2}/docs/faq.rst +0 -0
  20. {wtforms-3.3.1 → wtforms-3.3.2}/docs/fields.rst +0 -0
  21. {wtforms-3.3.1 → wtforms-3.3.2}/docs/forms.rst +0 -0
  22. {wtforms-3.3.1 → wtforms-3.3.2}/docs/i18n.rst +0 -0
  23. {wtforms-3.3.1 → wtforms-3.3.2}/docs/index.rst +0 -0
  24. {wtforms-3.3.1 → wtforms-3.3.2}/docs/license.rst +0 -0
  25. {wtforms-3.3.1 → wtforms-3.3.2}/docs/make.bat +0 -0
  26. {wtforms-3.3.1 → wtforms-3.3.2}/docs/meta.rst +0 -0
  27. {wtforms-3.3.1 → wtforms-3.3.2}/docs/specific_problems.rst +0 -0
  28. {wtforms-3.3.1 → wtforms-3.3.2}/docs/validators.rst +0 -0
  29. {wtforms-3.3.1 → wtforms-3.3.2}/docs/whats_new.rst +0 -0
  30. {wtforms-3.3.1 → wtforms-3.3.2}/docs/widgets.rst +0 -0
  31. {wtforms-3.3.1 → wtforms-3.3.2}/hatch_build.py +0 -0
  32. {wtforms-3.3.1 → wtforms-3.3.2}/pyproject.toml +0 -0
  33. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/_compat.py +0 -0
  34. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/csrf/__init__.py +0 -0
  35. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/csrf/core.py +0 -0
  36. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/csrf/session.py +0 -0
  37. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/datalist.py +0 -0
  38. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/__init__.py +0 -0
  39. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/choices.py +0 -0
  40. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/core.py +0 -0
  41. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/datetime.py +0 -0
  42. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/form.py +0 -0
  43. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/numeric.py +0 -0
  44. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/fields/simple.py +0 -0
  45. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/form.py +0 -0
  46. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/i18n.py +0 -0
  47. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/README.md +0 -0
  48. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ar/LC_MESSAGES/wtforms.mo +0 -0
  49. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ar/LC_MESSAGES/wtforms.po +0 -0
  50. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/bg/LC_MESSAGES/wtforms.mo +0 -0
  51. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/bg/LC_MESSAGES/wtforms.po +0 -0
  52. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ca/LC_MESSAGES/wtforms.mo +0 -0
  53. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ca/LC_MESSAGES/wtforms.po +0 -0
  54. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo +0 -0
  55. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po +0 -0
  56. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/cy/LC_MESSAGES/wtforms.mo +0 -0
  57. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/cy/LC_MESSAGES/wtforms.po +0 -0
  58. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/de/LC_MESSAGES/wtforms.mo +0 -0
  59. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/de/LC_MESSAGES/wtforms.po +0 -0
  60. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo +0 -0
  61. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/de_CH/LC_MESSAGES/wtforms.po +0 -0
  62. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/el/LC_MESSAGES/wtforms.mo +0 -0
  63. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/el/LC_MESSAGES/wtforms.po +0 -0
  64. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/en/LC_MESSAGES/wtforms.mo +0 -0
  65. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/en/LC_MESSAGES/wtforms.po +0 -0
  66. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/es/LC_MESSAGES/wtforms.mo +0 -0
  67. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/es/LC_MESSAGES/wtforms.po +0 -0
  68. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/et/LC_MESSAGES/wtforms.mo +0 -0
  69. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/et/LC_MESSAGES/wtforms.po +0 -0
  70. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/fa/LC_MESSAGES/wtforms.mo +0 -0
  71. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/fa/LC_MESSAGES/wtforms.po +0 -0
  72. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/fi/LC_MESSAGES/wtforms.mo +0 -0
  73. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/fi/LC_MESSAGES/wtforms.po +0 -0
  74. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/fr/LC_MESSAGES/wtforms.mo +0 -0
  75. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/fr/LC_MESSAGES/wtforms.po +0 -0
  76. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/he/LC_MESSAGES/wtforms.mo +0 -0
  77. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/he/LC_MESSAGES/wtforms.po +0 -0
  78. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/hu/LC_MESSAGES/wtforms.mo +0 -0
  79. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/hu/LC_MESSAGES/wtforms.po +0 -0
  80. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/it/LC_MESSAGES/wtforms.mo +0 -0
  81. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/it/LC_MESSAGES/wtforms.po +0 -0
  82. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ja/LC_MESSAGES/wtforms.mo +0 -0
  83. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ja/LC_MESSAGES/wtforms.po +0 -0
  84. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/kk/LC_MESSAGES/wtforms.mo +0 -0
  85. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/kk/LC_MESSAGES/wtforms.po +0 -0
  86. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ko/LC_MESSAGES/wtforms.mo +0 -0
  87. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ko/LC_MESSAGES/wtforms.po +0 -0
  88. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/nb/LC_MESSAGES/wtforms.mo +0 -0
  89. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/nb/LC_MESSAGES/wtforms.po +0 -0
  90. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/nl/LC_MESSAGES/wtforms.mo +0 -0
  91. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/nl/LC_MESSAGES/wtforms.po +0 -0
  92. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/pl/LC_MESSAGES/wtforms.mo +0 -0
  93. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/pl/LC_MESSAGES/wtforms.po +0 -0
  94. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/pt/LC_MESSAGES/wtforms.mo +0 -0
  95. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/pt/LC_MESSAGES/wtforms.po +0 -0
  96. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ro/LC_MESSAGES/wtforms.mo +0 -0
  97. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ro/LC_MESSAGES/wtforms.po +0 -0
  98. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ru/LC_MESSAGES/wtforms.mo +0 -0
  99. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ru/LC_MESSAGES/wtforms.po +0 -0
  100. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/sk/LC_MESSAGES/wtforms.mo +0 -0
  101. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/sk/LC_MESSAGES/wtforms.po +0 -0
  102. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/sr/LC_MESSAGES/wtforms.mo +0 -0
  103. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/sr/LC_MESSAGES/wtforms.po +0 -0
  104. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/sv/LC_MESSAGES/wtforms.mo +0 -0
  105. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/sv/LC_MESSAGES/wtforms.po +0 -0
  106. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ta/LC_MESSAGES/wtforms.mo +0 -0
  107. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/ta/LC_MESSAGES/wtforms.po +0 -0
  108. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/tr/LC_MESSAGES/wtforms.mo +0 -0
  109. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/tr/LC_MESSAGES/wtforms.po +0 -0
  110. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/uk/LC_MESSAGES/wtforms.mo +0 -0
  111. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/uk/LC_MESSAGES/wtforms.po +0 -0
  112. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/wtforms.pot +0 -0
  113. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/zh/LC_MESSAGES/wtforms.mo +0 -0
  114. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/zh/LC_MESSAGES/wtforms.po +0 -0
  115. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo +0 -0
  116. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po +0 -0
  117. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/meta.py +0 -0
  118. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/utils.py +0 -0
  119. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/validators.py +0 -0
  120. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/widgets/__init__.py +0 -0
  121. {wtforms-3.3.1 → wtforms-3.3.2}/src/wtforms/widgets/core.py +0 -0
  122. {wtforms-3.3.1 → wtforms-3.3.2}/tests/__init__.py +0 -0
  123. {wtforms-3.3.1 → wtforms-3.3.2}/tests/common.py +0 -0
  124. {wtforms-3.3.1 → wtforms-3.3.2}/tests/conftest.py +0 -0
  125. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/__init__.py +0 -0
  126. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_boolean.py +0 -0
  127. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_button.py +0 -0
  128. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_color.py +0 -0
  129. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_custom.py +0 -0
  130. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_date.py +0 -0
  131. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_datetime.py +0 -0
  132. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_datetimelocal.py +0 -0
  133. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_decimal.py +0 -0
  134. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_defaults.py +0 -0
  135. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_field.py +0 -0
  136. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_file.py +0 -0
  137. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_filters.py +0 -0
  138. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_flags.py +0 -0
  139. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_float.py +0 -0
  140. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_form.py +0 -0
  141. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_hidden.py +0 -0
  142. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_html5.py +0 -0
  143. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_integer.py +0 -0
  144. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_label.py +0 -0
  145. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_month.py +0 -0
  146. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_password.py +0 -0
  147. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_radio.py +0 -0
  148. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_select.py +0 -0
  149. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_selectmultiple.py +0 -0
  150. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_string.py +0 -0
  151. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_submit.py +0 -0
  152. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_textarea.py +0 -0
  153. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_time.py +0 -0
  154. {wtforms-3.3.1 → wtforms-3.3.2}/tests/fields/test_week.py +0 -0
  155. {wtforms-3.3.1 → wtforms-3.3.2}/tests/test_csrf.py +0 -0
  156. {wtforms-3.3.1 → wtforms-3.3.2}/tests/test_datalist.py +0 -0
  157. {wtforms-3.3.1 → wtforms-3.3.2}/tests/test_form.py +0 -0
  158. {wtforms-3.3.1 → wtforms-3.3.2}/tests/test_i18n.py +0 -0
  159. {wtforms-3.3.1 → wtforms-3.3.2}/tests/test_locale_babel.py +0 -0
  160. {wtforms-3.3.1 → wtforms-3.3.2}/tests/test_webob.py +0 -0
  161. {wtforms-3.3.1 → wtforms-3.3.2}/tests/test_widgets.py +0 -0
  162. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/__init__.py +0 -0
  163. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_anyof.py +0 -0
  164. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_data_required.py +0 -0
  165. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_date_range.py +0 -0
  166. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_disabled.py +0 -0
  167. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_email.py +0 -0
  168. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_equal_to.py +0 -0
  169. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_input_required.py +0 -0
  170. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_ipaddress.py +0 -0
  171. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_lazy_proxy.py +0 -0
  172. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_length.py +0 -0
  173. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_mac_address.py +0 -0
  174. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_noneof.py +0 -0
  175. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_number_range.py +0 -0
  176. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_optional.py +0 -0
  177. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_readonly.py +0 -0
  178. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_regexp.py +0 -0
  179. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_url.py +0 -0
  180. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_uuid.py +0 -0
  181. {wtforms-3.3.1 → wtforms-3.3.2}/tests/validators/test_validators.py +0 -0
@@ -1,5 +1,14 @@
1
1
  .. currentmodule:: wtforms
2
2
 
3
+ Version 3.3.2
4
+ -------------
5
+
6
+ Released 2026-11-01
7
+
8
+ - Fix nested :class:`~fields.FieldList` entries getting the old index of
9
+ their parent entry when they are appended after the parent list
10
+ renumbers its entries. :issue:`948`
11
+
3
12
  Version 3.3.1
4
13
  -------------
5
14
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: WTForms
3
- Version: 3.3.1
3
+ Version: 3.3.2
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
@@ -92,6 +92,8 @@ with frameworks even better.
92
92
  framework, based on the features of Flask-WTF.
93
93
  - `Bootstrap-Flask`_ Bootstrap-Flask is a collection of Jinja macros
94
94
  for Bootstrap 4 & 5 and Flask using Flask-WTF.
95
+ - `WTForms-htmx`_ Interactive WTForms forms with no hand-written
96
+ JavaScript, powered by htmx and dark magic.
95
97
 
96
98
  .. _Flask-WTF: https://flask-wtf.readthedocs.io/
97
99
  .. _WTForms-Alchemy: https://wtforms-alchemy.readthedocs.io/
@@ -99,6 +101,7 @@ with frameworks even better.
99
101
  .. _WTForms-Bootstrap5: https://github.com/LaunchPlatform/wtforms-bootstrap5
100
102
  .. _Starlette-WTF: https://github.com/muicss/starlette-wtf
101
103
  .. _Bootstrap-Flask: https://github.com/helloflask/bootstrap-flask
104
+ .. _WTForms-htmx: https://github.com/yaal-coop/wtforms-htmx
102
105
 
103
106
 
104
107
  Links
@@ -40,6 +40,8 @@ with frameworks even better.
40
40
  framework, based on the features of Flask-WTF.
41
41
  - `Bootstrap-Flask`_ Bootstrap-Flask is a collection of Jinja macros
42
42
  for Bootstrap 4 & 5 and Flask using Flask-WTF.
43
+ - `WTForms-htmx`_ Interactive WTForms forms with no hand-written
44
+ JavaScript, powered by htmx and dark magic.
43
45
 
44
46
  .. _Flask-WTF: https://flask-wtf.readthedocs.io/
45
47
  .. _WTForms-Alchemy: https://wtforms-alchemy.readthedocs.io/
@@ -47,6 +49,7 @@ with frameworks even better.
47
49
  .. _WTForms-Bootstrap5: https://github.com/LaunchPlatform/wtforms-bootstrap5
48
50
  .. _Starlette-WTF: https://github.com/muicss/starlette-wtf
49
51
  .. _Bootstrap-Flask: https://github.com/helloflask/bootstrap-flask
52
+ .. _WTForms-htmx: https://github.com/yaal-coop/wtforms-htmx
50
53
 
51
54
 
52
55
  Links
@@ -42,7 +42,7 @@ from wtforms.fields.simple import URLField
42
42
  from wtforms.form import Form
43
43
  from wtforms.validators import ValidationError
44
44
 
45
- __version__ = "3.3.1"
45
+ __version__ = "3.3.2"
46
46
 
47
47
  __all__ = [
48
48
  "validators",
@@ -57,7 +57,6 @@ class FieldList(Field):
57
57
  self.min_entries = min_entries
58
58
  self.max_entries = max_entries
59
59
  self.last_index = -1
60
- self._prefix = kwargs.get("_prefix", "")
61
60
  self._separator = separator
62
61
  self._field_separator = unbound_field.kwargs.get("separator", "-")
63
62
 
@@ -170,17 +169,17 @@ class FieldList(Field):
170
169
  if index is None:
171
170
  index = self.last_index + 1
172
171
  self.last_index = index
173
- name = f"{self.short_name}{self._separator}{index}"
172
+ name = f"{self.name}{self._separator}{index}"
174
173
  id = f"{self.id}{self._separator}{index}"
175
174
  options = dict(
176
175
  name=name,
177
- prefix=self._prefix,
178
176
  id=id,
179
177
  _meta=self.meta,
180
178
  translations=self._translations,
181
179
  )
182
180
  field = self.meta.bind_field(self._form, self.unbound_field, options)
183
181
  field.index = index
182
+ field.short_name = str(index)
184
183
  field.process(formdata, data)
185
184
  self.entries.append(field)
186
185
  return field
@@ -264,6 +264,53 @@ def test_renumbered_entries_in_a_subform_keep_the_subform_prefix():
264
264
  assert form.sub.a[0].foo.name == "sub-a-0-foo"
265
265
 
266
266
 
267
+ @pytest.mark.parametrize("prefix", ["", "p"])
268
+ def test_renumbered_entries_append_to_their_nested_list(prefix):
269
+ """A list inside a renumbered entry appends entries under the new
270
+ index."""
271
+
272
+ class Component(Form):
273
+ code = StringField()
274
+
275
+ class Block(Form):
276
+ components = FieldList(FormField(Component), min_entries=1)
277
+
278
+ F = make_form(blocks=FieldList(FormField(Block), min_entries=2))
279
+ p = f"{prefix}-" if prefix else ""
280
+
281
+ form = F(DummyPostData({f"{p}blocks-1-components-0-code": "A"}), prefix=prefix)
282
+ appended = form.blocks[0].components.append_entry()
283
+ assert appended.code.name == f"{p}blocks-0-components-1-code"
284
+
285
+ form = F(prefix=prefix)
286
+ form.blocks.pop_entry(0)
287
+ appended = form.blocks[0].components.append_entry()
288
+ assert appended.code.name == f"{p}blocks-0-components-1-code"
289
+
290
+ form = F(prefix=prefix)
291
+ form.blocks.insert_entry(0)
292
+ appended = form.blocks[1].components.append_entry()
293
+ assert appended.code.name == f"{p}blocks-1-components-1-code"
294
+
295
+
296
+ @pytest.mark.parametrize("prefix", ["", "p"])
297
+ def test_renumbered_entries_append_to_their_directly_nested_list(prefix):
298
+ """A list directly inside a renumbered list entry appends entries under
299
+ the new index, at any depth."""
300
+ F = make_form(
301
+ a=FieldList(
302
+ FieldList(FieldList(StringField(), min_entries=1), min_entries=1),
303
+ min_entries=2,
304
+ )
305
+ )
306
+ p = f"{prefix}-" if prefix else ""
307
+
308
+ form = F(prefix=prefix)
309
+ form.a.pop_entry(0)
310
+ assert form.a[0].append_entry()[0].name == f"{p}a-0-1-0"
311
+ assert form.a[0][0].append_entry().name == f"{p}a-0-0-1"
312
+
313
+
267
314
  def test_gap_compacted_through_formdata_round_trip():
268
315
  """A formdata with gaps in indices is compacted on read: entries are
269
316
  rebuilt with consecutive indices, preserving formdata key order."""
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes