WTForms 3.2.0__tar.gz → 3.2.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 (179) hide show
  1. {wtforms-3.2.0 → wtforms-3.2.2}/.gitignore +1 -0
  2. wtforms-3.2.2/.hgignore +1 -0
  3. {wtforms-3.2.0 → wtforms-3.2.2}/CHANGES.rst +16 -0
  4. {wtforms-3.2.0 → wtforms-3.2.2}/PKG-INFO +5 -12
  5. {wtforms-3.2.0 → wtforms-3.2.2}/README.rst +0 -7
  6. {wtforms-3.2.0 → wtforms-3.2.2}/docs/faq.rst +1 -1
  7. {wtforms-3.2.0 → wtforms-3.2.2}/pyproject.toml +68 -4
  8. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/__init__.py +3 -1
  9. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/__init__.py +2 -0
  10. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/choices.py +5 -7
  11. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/form.py +1 -2
  12. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/list.py +7 -7
  13. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/numeric.py +1 -1
  14. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/README.md +6 -1
  15. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ar/LC_MESSAGES/wtforms.mo +0 -0
  16. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/bg/LC_MESSAGES/wtforms.mo +0 -0
  17. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ca/LC_MESSAGES/wtforms.mo +0 -0
  18. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.mo +0 -0
  19. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/cy/LC_MESSAGES/wtforms.mo +0 -0
  20. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/de/LC_MESSAGES/wtforms.mo +0 -0
  21. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/de_CH/LC_MESSAGES/wtforms.mo +0 -0
  22. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/el/LC_MESSAGES/wtforms.mo +0 -0
  23. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/en/LC_MESSAGES/wtforms.mo +0 -0
  24. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/es/LC_MESSAGES/wtforms.mo +0 -0
  25. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/et/LC_MESSAGES/wtforms.mo +0 -0
  26. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/fa/LC_MESSAGES/wtforms.mo +0 -0
  27. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/fi/LC_MESSAGES/wtforms.mo +0 -0
  28. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/fr/LC_MESSAGES/wtforms.mo +0 -0
  29. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/he/LC_MESSAGES/wtforms.mo +0 -0
  30. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/hu/LC_MESSAGES/wtforms.mo +0 -0
  31. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/it/LC_MESSAGES/wtforms.mo +0 -0
  32. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ja/LC_MESSAGES/wtforms.mo +0 -0
  33. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/kk/LC_MESSAGES/wtforms.mo +0 -0
  34. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ko/LC_MESSAGES/wtforms.mo +0 -0
  35. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/nb/LC_MESSAGES/wtforms.mo +0 -0
  36. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/nl/LC_MESSAGES/wtforms.mo +0 -0
  37. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/pl/LC_MESSAGES/wtforms.mo +0 -0
  38. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/pt/LC_MESSAGES/wtforms.mo +0 -0
  39. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ro/LC_MESSAGES/wtforms.mo +0 -0
  40. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ru/LC_MESSAGES/wtforms.mo +0 -0
  41. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/sk/LC_MESSAGES/wtforms.mo +0 -0
  42. wtforms-3.2.2/src/wtforms/locale/sr/LC_MESSAGES/wtforms.mo +0 -0
  43. wtforms-3.2.2/src/wtforms/locale/sr/LC_MESSAGES/wtforms.po +184 -0
  44. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/sv/LC_MESSAGES/wtforms.mo +0 -0
  45. wtforms-3.2.2/src/wtforms/locale/ta/LC_MESSAGES/wtforms.mo +0 -0
  46. wtforms-3.2.2/src/wtforms/locale/ta/LC_MESSAGES/wtforms.po +186 -0
  47. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/tr/LC_MESSAGES/wtforms.mo +0 -0
  48. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/uk/LC_MESSAGES/wtforms.mo +0 -0
  49. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/zh/LC_MESSAGES/wtforms.mo +0 -0
  50. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.mo +0 -0
  51. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/validators.py +4 -4
  52. {wtforms-3.2.0 → wtforms-3.2.2}/tests/common.py +1 -1
  53. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_html5.py +7 -8
  54. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_label.py +2 -4
  55. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_list.py +1 -1
  56. {wtforms-3.2.0 → wtforms-3.2.2}/tests/test_locale_babel.py +3 -3
  57. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_disabled.py +3 -0
  58. wtforms-3.2.0/docs/requirements.txt +0 -5
  59. wtforms-3.2.0/tox.ini +0 -37
  60. {wtforms-3.2.0 → wtforms-3.2.2}/LICENSE.rst +0 -0
  61. {wtforms-3.2.0 → wtforms-3.2.2}/docs/Makefile +0 -0
  62. {wtforms-3.2.0 → wtforms-3.2.2}/docs/_static/logo_joined.svg +0 -0
  63. {wtforms-3.2.0 → wtforms-3.2.2}/docs/_static/logo_split.svg +0 -0
  64. {wtforms-3.2.0 → wtforms-3.2.2}/docs/_static/logo_square.svg +0 -0
  65. {wtforms-3.2.0 → wtforms-3.2.2}/docs/changes.rst +0 -0
  66. {wtforms-3.2.0 → wtforms-3.2.2}/docs/conf.py +0 -0
  67. {wtforms-3.2.0 → wtforms-3.2.2}/docs/contributing.rst +0 -0
  68. {wtforms-3.2.0 → wtforms-3.2.2}/docs/crash_course.rst +0 -0
  69. {wtforms-3.2.0 → wtforms-3.2.2}/docs/csrf.rst +0 -0
  70. {wtforms-3.2.0 → wtforms-3.2.2}/docs/ext.rst +0 -0
  71. {wtforms-3.2.0 → wtforms-3.2.2}/docs/fields.rst +0 -0
  72. {wtforms-3.2.0 → wtforms-3.2.2}/docs/forms.rst +0 -0
  73. {wtforms-3.2.0 → wtforms-3.2.2}/docs/i18n.rst +0 -0
  74. {wtforms-3.2.0 → wtforms-3.2.2}/docs/index.rst +0 -0
  75. {wtforms-3.2.0 → wtforms-3.2.2}/docs/license.rst +0 -0
  76. {wtforms-3.2.0 → wtforms-3.2.2}/docs/make.bat +0 -0
  77. {wtforms-3.2.0 → wtforms-3.2.2}/docs/meta.rst +0 -0
  78. {wtforms-3.2.0 → wtforms-3.2.2}/docs/specific_problems.rst +0 -0
  79. {wtforms-3.2.0 → wtforms-3.2.2}/docs/validators.rst +0 -0
  80. {wtforms-3.2.0 → wtforms-3.2.2}/docs/whats_new.rst +0 -0
  81. {wtforms-3.2.0 → wtforms-3.2.2}/docs/widgets.rst +0 -0
  82. {wtforms-3.2.0 → wtforms-3.2.2}/hatch_build.py +0 -0
  83. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/csrf/__init__.py +0 -0
  84. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/csrf/core.py +0 -0
  85. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/csrf/session.py +0 -0
  86. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/core.py +0 -0
  87. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/datetime.py +0 -0
  88. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/fields/simple.py +0 -0
  89. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/form.py +0 -0
  90. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/i18n.py +0 -0
  91. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ar/LC_MESSAGES/wtforms.po +0 -0
  92. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/bg/LC_MESSAGES/wtforms.po +0 -0
  93. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ca/LC_MESSAGES/wtforms.po +0 -0
  94. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/cs_CZ/LC_MESSAGES/wtforms.po +0 -0
  95. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/cy/LC_MESSAGES/wtforms.po +0 -0
  96. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/de/LC_MESSAGES/wtforms.po +0 -0
  97. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/de_CH/LC_MESSAGES/wtforms.po +0 -0
  98. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/el/LC_MESSAGES/wtforms.po +0 -0
  99. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/en/LC_MESSAGES/wtforms.po +0 -0
  100. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/es/LC_MESSAGES/wtforms.po +0 -0
  101. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/et/LC_MESSAGES/wtforms.po +0 -0
  102. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/fa/LC_MESSAGES/wtforms.po +0 -0
  103. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/fi/LC_MESSAGES/wtforms.po +0 -0
  104. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/fr/LC_MESSAGES/wtforms.po +0 -0
  105. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/he/LC_MESSAGES/wtforms.po +0 -0
  106. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/hu/LC_MESSAGES/wtforms.po +0 -0
  107. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/it/LC_MESSAGES/wtforms.po +0 -0
  108. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ja/LC_MESSAGES/wtforms.po +0 -0
  109. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/kk/LC_MESSAGES/wtforms.po +0 -0
  110. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ko/LC_MESSAGES/wtforms.po +0 -0
  111. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/nb/LC_MESSAGES/wtforms.po +0 -0
  112. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/nl/LC_MESSAGES/wtforms.po +0 -0
  113. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/pl/LC_MESSAGES/wtforms.po +0 -0
  114. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/pt/LC_MESSAGES/wtforms.po +0 -0
  115. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ro/LC_MESSAGES/wtforms.po +0 -0
  116. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/ru/LC_MESSAGES/wtforms.po +0 -0
  117. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/sk/LC_MESSAGES/wtforms.po +0 -0
  118. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/sv/LC_MESSAGES/wtforms.po +0 -0
  119. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/tr/LC_MESSAGES/wtforms.po +0 -0
  120. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/uk/LC_MESSAGES/wtforms.po +0 -0
  121. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/wtforms.pot +0 -0
  122. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/zh/LC_MESSAGES/wtforms.po +0 -0
  123. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/locale/zh_TW/LC_MESSAGES/wtforms.po +0 -0
  124. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/meta.py +0 -0
  125. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/utils.py +0 -0
  126. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/widgets/__init__.py +0 -0
  127. {wtforms-3.2.0 → wtforms-3.2.2}/src/wtforms/widgets/core.py +0 -0
  128. {wtforms-3.2.0 → wtforms-3.2.2}/tests/__init__.py +0 -0
  129. {wtforms-3.2.0 → wtforms-3.2.2}/tests/conftest.py +0 -0
  130. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/__init__.py +0 -0
  131. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_boolean.py +0 -0
  132. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_color.py +0 -0
  133. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_custom.py +0 -0
  134. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_date.py +0 -0
  135. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_datetime.py +0 -0
  136. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_datetimelocal.py +0 -0
  137. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_decimal.py +0 -0
  138. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_defaults.py +0 -0
  139. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_field.py +0 -0
  140. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_file.py +0 -0
  141. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_filters.py +0 -0
  142. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_flags.py +0 -0
  143. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_float.py +0 -0
  144. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_form.py +0 -0
  145. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_hidden.py +0 -0
  146. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_integer.py +0 -0
  147. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_month.py +0 -0
  148. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_password.py +0 -0
  149. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_radio.py +0 -0
  150. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_select.py +0 -0
  151. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_selectmultiple.py +0 -0
  152. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_string.py +0 -0
  153. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_submit.py +0 -0
  154. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_textarea.py +0 -0
  155. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_time.py +0 -0
  156. {wtforms-3.2.0 → wtforms-3.2.2}/tests/fields/test_week.py +0 -0
  157. {wtforms-3.2.0 → wtforms-3.2.2}/tests/test_csrf.py +0 -0
  158. {wtforms-3.2.0 → wtforms-3.2.2}/tests/test_form.py +0 -0
  159. {wtforms-3.2.0 → wtforms-3.2.2}/tests/test_i18n.py +0 -0
  160. {wtforms-3.2.0 → wtforms-3.2.2}/tests/test_webob.py +0 -0
  161. {wtforms-3.2.0 → wtforms-3.2.2}/tests/test_widgets.py +0 -0
  162. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/__init__.py +0 -0
  163. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_anyof.py +0 -0
  164. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_data_required.py +0 -0
  165. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_email.py +0 -0
  166. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_equal_to.py +0 -0
  167. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_input_required.py +0 -0
  168. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_ipaddress.py +0 -0
  169. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_lazy_proxy.py +0 -0
  170. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_length.py +0 -0
  171. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_mac_address.py +0 -0
  172. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_noneof.py +0 -0
  173. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_number_range.py +0 -0
  174. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_optional.py +0 -0
  175. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_readonly.py +0 -0
  176. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_regexp.py +0 -0
  177. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_url.py +0 -0
  178. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_uuid.py +0 -0
  179. {wtforms-3.2.0 → wtforms-3.2.2}/tests/validators/test_validators.py +0 -0
@@ -15,3 +15,4 @@ __pycache__/
15
15
  /htmlcov/
16
16
  /docs/_build/
17
17
  /src/wtforms/locale/**/wtforms.mo
18
+ uv.lock
@@ -0,0 +1 @@
1
+ .dotfiles/mercurial/.hgignore
@@ -1,5 +1,21 @@
1
1
  .. currentmodule:: wtforms
2
2
 
3
+ Version 3.2.2
4
+ -------------
5
+
6
+ Released 2026-05-03
7
+
8
+ - Fix :class:`~validators.Disabled` validation with provided formdata. :pr:`880`
9
+ - End support for Python 3.9, start support for Python 3.14. :pr:`883`
10
+ - Add Tamil and Serbian translations.
11
+
12
+ Version 3.2.1
13
+ -------------
14
+
15
+ Released 2024-10-21
16
+
17
+ - Fix :class:`~fields.SelectMultipleBase` import. :issue:`861` :pr:`862`
18
+
3
19
  Version 3.2.0
4
20
  -------------
5
21
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: WTForms
3
- Version: 3.2.0
3
+ Version: 3.2.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
@@ -44,10 +44,10 @@ Classifier: License :: OSI Approved :: BSD License
44
44
  Classifier: Operating System :: OS Independent
45
45
  Classifier: Programming Language :: Python
46
46
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
47
- Requires-Python: >=3.9
48
- Requires-Dist: markupsafe
47
+ Requires-Python: >=3.10
48
+ Requires-Dist: markupsafe>=1.1.1
49
49
  Provides-Extra: email
50
- Requires-Dist: email-validator; extra == 'email'
50
+ Requires-Dist: email-validator>=2.0; extra == 'email'
51
51
  Description-Content-Type: text/x-rst
52
52
 
53
53
  WTForms
@@ -86,11 +86,6 @@ with frameworks even better.
86
86
  validators.
87
87
  - `WTForms-SQLAlchemy`_ provides ORM-backed fields and form generation
88
88
  from SQLAlchemy models.
89
- - `WTForms-AppEngine`_ provides ORM-backed fields and form generation
90
- from AppEnding db/ndb schema
91
- - `WTForms-Django`_ provides ORM-backed fields and form generation
92
- from Django models, as well as integration with Django's I18N
93
- support.
94
89
  - `WTForms-Bootstrap5`_ provides Bootstrap 5 favor renderer with
95
90
  great customizability.
96
91
  - `Starlette-WTF`_ integrates with Starlette and the FastAPI
@@ -101,8 +96,6 @@ with frameworks even better.
101
96
  .. _Flask-WTF: https://flask-wtf.readthedocs.io/
102
97
  .. _WTForms-Alchemy: https://wtforms-alchemy.readthedocs.io/
103
98
  .. _WTForms-SQLAlchemy: https://github.com/pallets-eco/wtforms-sqlalchemy
104
- .. _WTForms-AppEngine: https://github.com/pallets-eco/wtforms-appengine
105
- .. _WTForms-Django: https://github.com/pallets-eco/wtforms-django
106
99
  .. _WTForms-Bootstrap5: https://github.com/LaunchPlatform/wtforms-bootstrap5
107
100
  .. _Starlette-WTF: https://github.com/muicss/starlette-wtf
108
101
  .. _Bootstrap-Flask: https://github.com/helloflask/bootstrap-flask
@@ -34,11 +34,6 @@ with frameworks even better.
34
34
  validators.
35
35
  - `WTForms-SQLAlchemy`_ provides ORM-backed fields and form generation
36
36
  from SQLAlchemy models.
37
- - `WTForms-AppEngine`_ provides ORM-backed fields and form generation
38
- from AppEnding db/ndb schema
39
- - `WTForms-Django`_ provides ORM-backed fields and form generation
40
- from Django models, as well as integration with Django's I18N
41
- support.
42
37
  - `WTForms-Bootstrap5`_ provides Bootstrap 5 favor renderer with
43
38
  great customizability.
44
39
  - `Starlette-WTF`_ integrates with Starlette and the FastAPI
@@ -49,8 +44,6 @@ with frameworks even better.
49
44
  .. _Flask-WTF: https://flask-wtf.readthedocs.io/
50
45
  .. _WTForms-Alchemy: https://wtforms-alchemy.readthedocs.io/
51
46
  .. _WTForms-SQLAlchemy: https://github.com/pallets-eco/wtforms-sqlalchemy
52
- .. _WTForms-AppEngine: https://github.com/pallets-eco/wtforms-appengine
53
- .. _WTForms-Django: https://github.com/pallets-eco/wtforms-django
54
47
  .. _WTForms-Bootstrap5: https://github.com/LaunchPlatform/wtforms-bootstrap5
55
48
  .. _Starlette-WTF: https://github.com/muicss/starlette-wtf
56
49
  .. _Bootstrap-Flask: https://github.com/helloflask/bootstrap-flask
@@ -57,7 +57,7 @@ you should have no unicode issues.
57
57
  What versions of Python are supported?
58
58
  --------------------------------------
59
59
 
60
- WTForms supports Python 3.9+
60
+ WTForms supports Python 3.10+
61
61
 
62
62
 
63
63
  How can I contribute to WTForms?
@@ -13,9 +13,9 @@ classifiers = [
13
13
  "Programming Language :: Python",
14
14
  "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
15
15
  ]
16
- requires-python = ">=3.9"
16
+ requires-python = ">=3.10"
17
17
  dependencies = [
18
- "MarkupSafe",
18
+ "MarkupSafe>=1.1.1",
19
19
  ]
20
20
  dynamic = ["version"]
21
21
 
@@ -27,7 +27,72 @@ Changes = "https://wtforms.readthedocs.io/changes"
27
27
  Chat = "https://discord.gg/pallets"
28
28
 
29
29
  [project.optional-dependencies]
30
- email = ["email_validator"]
30
+ email = ["email_validator>=2.0"]
31
+
32
+ [dependency-groups]
33
+ docs = [
34
+ "Sphinx~=7.0.0",
35
+ "Pallets-Sphinx-Themes~=2.2.0",
36
+ "sphinx-issues~=4.0.0",
37
+ "sphinxcontrib-log-cabinet~=1.0.1",
38
+ "python-dateutil~=2.8.2",
39
+ ]
40
+ dev = [
41
+ "pytest>=7.0",
42
+ "babel>=2.8",
43
+ "email_validator>=2.0",
44
+ "coverage>=6.0",
45
+ "prek>=0.3.9",
46
+ "tox-uv>=1.35.1",
47
+ ]
48
+
49
+ [tool.tox]
50
+ env_list = [
51
+ "style",
52
+ "minversions",
53
+ "py314",
54
+ "py313",
55
+ "py312",
56
+ "py311",
57
+ "py310",
58
+ "pypy310",
59
+ "docs",
60
+ ]
61
+ skip_missing_interpreters = true
62
+
63
+ [tool.tox.env_run_base]
64
+ dependency_groups = ["dev"]
65
+ commands = [
66
+ ["pytest", "--tb=short", "-l", "--basetemp={envtmpdir}", { replace = "posargs", extend = true }],
67
+ ]
68
+
69
+ [tool.tox.env.coverage]
70
+ dependency_groups = ["dev"]
71
+ commands = [
72
+ ["coverage", "erase"],
73
+ ["coverage", "run", "--parallel", "--module", "pytest", "--tb=short", "--basetemp={envtmpdir}", { replace = "posargs", extend = true }],
74
+ ["coverage", "combine"],
75
+ ["coverage", "html"],
76
+ ["coverage", "report"],
77
+ ]
78
+
79
+ [tool.tox.env.style]
80
+ skip_install = true
81
+ dependency_groups = []
82
+ deps = ["prek>=0.3.9"]
83
+ commands = [["prek", "run", "--all-files", "--show-diff-on-failure"]]
84
+
85
+ [tool.tox.env.docs]
86
+ dependency_groups = ["docs"]
87
+ commands = [["sphinx-build", "-W", "-b", "html", "-d", "{envtmpdir}/doctrees", "docs", "{envtmpdir}/html"]]
88
+
89
+ [tool.tox.env.minversions]
90
+ base_python = ["py3.10"]
91
+ uv_resolution = "lowest-direct"
92
+ dependency_groups = ["dev"]
93
+ commands = [
94
+ ["pytest", "--tb=short", "-l", "--basetemp={envtmpdir}", { replace = "posargs", extend = true }],
95
+ ]
31
96
 
32
97
  [build-system]
33
98
  requires = ["hatchling"]
@@ -45,7 +110,6 @@ include = [
45
110
  "docs/",
46
111
  "tests/",
47
112
  "CHANGES.rst",
48
- "tox.ini",
49
113
  ]
50
114
  exclude = [
51
115
  "docs/_build/",
@@ -2,6 +2,7 @@ from wtforms import validators
2
2
  from wtforms import widgets
3
3
  from wtforms.fields.choices import RadioField
4
4
  from wtforms.fields.choices import SelectField
5
+ from wtforms.fields.choices import SelectFieldBase
5
6
  from wtforms.fields.choices import SelectMultipleField
6
7
  from wtforms.fields.core import Field
7
8
  from wtforms.fields.core import Flags
@@ -35,7 +36,7 @@ from wtforms.fields.simple import URLField
35
36
  from wtforms.form import Form
36
37
  from wtforms.validators import ValidationError
37
38
 
38
- __version__ = "3.2.0"
39
+ __version__ = "3.2.2"
39
40
 
40
41
  __all__ = [
41
42
  "validators",
@@ -44,6 +45,7 @@ __all__ = [
44
45
  "ValidationError",
45
46
  "SelectField",
46
47
  "SelectMultipleField",
48
+ "SelectFieldBase",
47
49
  "RadioField",
48
50
  "Field",
49
51
  "Flags",
@@ -1,5 +1,6 @@
1
1
  from wtforms.fields.choices import RadioField
2
2
  from wtforms.fields.choices import SelectField
3
+ from wtforms.fields.choices import SelectFieldBase
3
4
  from wtforms.fields.choices import SelectMultipleField
4
5
  from wtforms.fields.core import Field
5
6
  from wtforms.fields.core import Flags
@@ -38,6 +39,7 @@ __all__ = [
38
39
  "Label",
39
40
  "SelectField",
40
41
  "SelectMultipleField",
42
+ "SelectFieldBase",
41
43
  "RadioField",
42
44
  "DateTimeField",
43
45
  "DateField",
@@ -56,9 +56,7 @@ class SelectFieldBase(Field):
56
56
  value, label, checked = choice
57
57
  render_kw = {}
58
58
 
59
- opt = self._Option(
60
- label=label, id="%s-%d" % (self.id, i), **opts, **render_kw
61
- )
59
+ opt = self._Option(label=label, id=f"{self.id}-{i}", **opts, **render_kw)
62
60
  opt.process(None, value)
63
61
  opt.checked = checked
64
62
  yield opt
@@ -114,11 +112,11 @@ class SelectField(SelectFieldBase):
114
112
  if not choices:
115
113
  _choices = []
116
114
 
117
- elif isinstance(choices[0], (list, tuple)):
115
+ elif isinstance(choices[0], list | tuple):
118
116
  _choices = choices
119
117
 
120
118
  else:
121
- _choices = zip(choices, choices)
119
+ _choices = zip(choices, choices, strict=False)
122
120
 
123
121
  for value, label, *other_args in _choices:
124
122
  selected = self.coerce(value) == self.data
@@ -168,11 +166,11 @@ class SelectMultipleField(SelectField):
168
166
  if not choices:
169
167
  _choices = []
170
168
 
171
- elif isinstance(choices[0], (list, tuple)):
169
+ elif isinstance(choices[0], list | tuple):
172
170
  _choices = choices
173
171
 
174
172
  else:
175
- _choices = zip(choices, choices)
173
+ _choices = zip(choices, choices, strict=False)
176
174
 
177
175
  for value, label, *other_args in _choices:
178
176
  selected = self.data is not None and self.coerce(value) in self.data
@@ -40,8 +40,7 @@ class FormField(Field):
40
40
  def process(self, formdata, data=unset_value, extra_filters=None):
41
41
  if extra_filters:
42
42
  raise TypeError(
43
- "FormField cannot take filters, as the encapsulated"
44
- "data is not mutable."
43
+ "FormField cannot take filters, as the encapsulateddata is not mutable."
45
44
  )
46
45
 
47
46
  if data is unset_value:
@@ -50,9 +50,9 @@ class FieldList(Field):
50
50
  "FieldList does not accept any filters. Instead, define"
51
51
  " them on the enclosed field."
52
52
  )
53
- assert isinstance(
54
- unbound_field, UnboundField
55
- ), "Field must be unbound, not a field class"
53
+ assert isinstance(unbound_field, UnboundField), (
54
+ "Field must be unbound, not a field class"
55
+ )
56
56
  self.unbound_field = unbound_field
57
57
  self.min_entries = min_entries
58
58
  self.max_entries = max_entries
@@ -144,7 +144,7 @@ class FieldList(Field):
144
144
  candidates = itertools.chain(ivalues, itertools.repeat(None))
145
145
  _fake = type("_fake", (object,), {})
146
146
  output = []
147
- for field, data in zip(self.entries, candidates):
147
+ for field, data in zip(self.entries, candidates, strict=False):
148
148
  fake_obj = _fake()
149
149
  fake_obj.data = data
150
150
  field.populate_obj(fake_obj, "data")
@@ -153,9 +153,9 @@ class FieldList(Field):
153
153
  setattr(obj, name, output)
154
154
 
155
155
  def _add_entry(self, formdata=None, data=unset_value, index=None):
156
- assert (
157
- not self.max_entries or len(self.entries) < self.max_entries
158
- ), "You cannot have more than max_entries entries in this FieldList"
156
+ assert not self.max_entries or len(self.entries) < self.max_entries, (
157
+ "You cannot have more than max_entries entries in this FieldList"
158
+ )
159
159
  if index is None:
160
160
  index = self.last_index + 1
161
161
  self.last_index = index
@@ -144,7 +144,7 @@ class DecimalField(LocaleAwareNumberField):
144
144
  if not hasattr(self.data, "quantize"):
145
145
  # If for some reason, data is a float or int, then format
146
146
  # as we would for floats using string formatting.
147
- format = "%%0.%df" % self.places
147
+ format = f"%.{self.places}f"
148
148
  return format % self.data
149
149
 
150
150
  exp = decimal.Decimal(".1") ** self.places
@@ -6,6 +6,10 @@ strings rendered by WTForms are created and updated by the community. If
6
6
  you notice that your locale is missing, or find a translation error,
7
7
  please submit a fix.
8
8
 
9
+ > **Note:** Translations should be contributed via
10
+ > [Weblate](https://hosted.weblate.org/projects/wtforms/wtforms/). The
11
+ > commands below are intended for local development and maintenance only.
12
+
9
13
 
10
14
  Create
11
15
  ------
@@ -59,4 +63,5 @@ correct.
59
63
  Submit
60
64
  ------
61
65
 
62
- To submit your translation, create a pull request on GitHub.
66
+ To submit your translation, please use
67
+ [Weblate](https://hosted.weblate.org/projects/wtforms/wtforms/).
@@ -0,0 +1,184 @@
1
+ # Translations template for WTForms.
2
+ # Copyright (C) 2024 WTForms Team
3
+ # This file is distributed under the same license as the WTForms project.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: WTForms 3.0.0\n"
9
+ "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
10
+ "POT-Creation-Date: 2024-01-11 08:20+0100\n"
11
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12
+ "Last-Translator: Automatically generated\n"
13
+ "Language-Team: none\n"
14
+ "Language: sr\n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=utf-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
19
+ "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
20
+ "Generated-By: Babel 2.12.1\n"
21
+
22
+ #: src/wtforms/validators.py:86
23
+ #, python-format
24
+ msgid "Invalid field name '%s'."
25
+ msgstr ""
26
+
27
+ #: src/wtforms/validators.py:99
28
+ #, python-format
29
+ msgid "Field must be equal to %(other_name)s."
30
+ msgstr ""
31
+
32
+ #: src/wtforms/validators.py:145
33
+ #, python-format
34
+ msgid "Field must be at least %(min)d character long."
35
+ msgid_plural "Field must be at least %(min)d characters long."
36
+ msgstr[0] ""
37
+ msgstr[1] ""
38
+
39
+ #: src/wtforms/validators.py:151
40
+ #, python-format
41
+ msgid "Field cannot be longer than %(max)d character."
42
+ msgid_plural "Field cannot be longer than %(max)d characters."
43
+ msgstr[0] ""
44
+ msgstr[1] ""
45
+
46
+ #: src/wtforms/validators.py:157
47
+ #, python-format
48
+ msgid "Field must be exactly %(max)d character long."
49
+ msgid_plural "Field must be exactly %(max)d characters long."
50
+ msgstr[0] ""
51
+ msgstr[1] ""
52
+
53
+ #: src/wtforms/validators.py:163
54
+ #, python-format
55
+ msgid "Field must be between %(min)d and %(max)d characters long."
56
+ msgstr ""
57
+
58
+ #: src/wtforms/validators.py:216
59
+ #, python-format
60
+ msgid "Number must be at least %(min)s."
61
+ msgstr ""
62
+
63
+ #: src/wtforms/validators.py:219
64
+ #, python-format
65
+ msgid "Number must be at most %(max)s."
66
+ msgstr ""
67
+
68
+ #: src/wtforms/validators.py:222
69
+ #, python-format
70
+ msgid "Number must be between %(min)s and %(max)s."
71
+ msgstr ""
72
+
73
+ #: src/wtforms/validators.py:293 src/wtforms/validators.py:323
74
+ msgid "This field is required."
75
+ msgstr ""
76
+
77
+ #: src/wtforms/validators.py:358
78
+ msgid "Invalid input."
79
+ msgstr ""
80
+
81
+ #: src/wtforms/validators.py:422
82
+ msgid "Invalid email address."
83
+ msgstr ""
84
+
85
+ #: src/wtforms/validators.py:460
86
+ msgid "Invalid IP address."
87
+ msgstr ""
88
+
89
+ #: src/wtforms/validators.py:503
90
+ msgid "Invalid Mac address."
91
+ msgstr ""
92
+
93
+ #: src/wtforms/validators.py:540
94
+ msgid "Invalid URL."
95
+ msgstr ""
96
+
97
+ #: src/wtforms/validators.py:561
98
+ msgid "Invalid UUID."
99
+ msgstr ""
100
+
101
+ #: src/wtforms/validators.py:594
102
+ #, python-format
103
+ msgid "Invalid value, must be one of: %(values)s."
104
+ msgstr ""
105
+
106
+ #: src/wtforms/validators.py:629
107
+ #, python-format
108
+ msgid "Invalid value, can't be any of: %(values)s."
109
+ msgstr ""
110
+
111
+ #: src/wtforms/validators.py:698
112
+ msgid "This field cannot be edited."
113
+ msgstr ""
114
+
115
+ #: src/wtforms/validators.py:714
116
+ msgid "This field is disabled and cannot have a value."
117
+ msgstr ""
118
+
119
+ #: src/wtforms/csrf/core.py:96
120
+ msgid "Invalid CSRF Token."
121
+ msgstr ""
122
+
123
+ #: src/wtforms/csrf/session.py:63
124
+ msgid "CSRF token missing."
125
+ msgstr ""
126
+
127
+ #: src/wtforms/csrf/session.py:71
128
+ msgid "CSRF failed."
129
+ msgstr ""
130
+
131
+ #: src/wtforms/csrf/session.py:76
132
+ msgid "CSRF token expired."
133
+ msgstr ""
134
+
135
+ #: src/wtforms/fields/choices.py:142
136
+ msgid "Invalid Choice: could not coerce."
137
+ msgstr ""
138
+
139
+ #: src/wtforms/fields/choices.py:149 src/wtforms/fields/choices.py:203
140
+ msgid "Choices cannot be None."
141
+ msgstr ""
142
+
143
+ #: src/wtforms/fields/choices.py:155
144
+ msgid "Not a valid choice."
145
+ msgstr ""
146
+
147
+ #: src/wtforms/fields/choices.py:193
148
+ msgid "Invalid choice(s): one or more data inputs could not be coerced."
149
+ msgstr ""
150
+
151
+ #: src/wtforms/fields/choices.py:214
152
+ #, python-format
153
+ msgid "'%(value)s' is not a valid choice for this field."
154
+ msgid_plural "'%(value)s' are not valid choices for this field."
155
+ msgstr[0] ""
156
+ msgstr[1] ""
157
+
158
+ #: src/wtforms/fields/datetime.py:51
159
+ msgid "Not a valid datetime value."
160
+ msgstr ""
161
+
162
+ #: src/wtforms/fields/datetime.py:77
163
+ msgid "Not a valid date value."
164
+ msgstr ""
165
+
166
+ #: src/wtforms/fields/datetime.py:103
167
+ msgid "Not a valid time value."
168
+ msgstr ""
169
+
170
+ #: src/wtforms/fields/datetime.py:148
171
+ msgid "Not a valid week value."
172
+ msgstr ""
173
+
174
+ #: src/wtforms/fields/numeric.py:82 src/wtforms/fields/numeric.py:92
175
+ msgid "Not a valid integer value."
176
+ msgstr ""
177
+
178
+ #: src/wtforms/fields/numeric.py:168
179
+ msgid "Not a valid decimal value."
180
+ msgstr ""
181
+
182
+ #: src/wtforms/fields/numeric.py:197
183
+ msgid "Not a valid float value."
184
+ msgstr ""