Flask-Exts 0.1.9__tar.gz → 0.2.0__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 (245) hide show
  1. {flask_exts-0.1.9 → flask_exts-0.2.0}/CHANGES.rst +8 -2
  2. {flask_exts-0.1.9 → flask_exts-0.2.0}/PKG-INFO +3 -3
  3. flask_exts-0.1.9/docs/usage.rst → flask_exts-0.2.0/docs/configure.rst +6 -36
  4. flask_exts-0.1.9/docs/translation.rst → flask_exts-0.2.0/docs/develop.rst +53 -12
  5. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/index.rst +22 -5
  6. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/README.rst +10 -14
  7. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/app.py +1 -1
  8. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/app.py +3 -3
  9. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/demo/make_app.py +2 -6
  10. flask_exts-0.2.0/examples/demo/sample.sqlite +0 -0
  11. {flask_exts-0.1.9/examples/demo/templates → flask_exts-0.2.0/examples/demo/templates/my}/index.html +1 -1
  12. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/demo/user_center.py +1 -1
  13. flask_exts-0.1.9/examples/demo/views/index_view.py → flask_exts-0.2.0/examples/demo/views/my_view.py +2 -2
  14. {flask_exts-0.1.9 → flask_exts-0.2.0}/pyproject.toml +0 -1
  15. flask_exts-0.2.0/src/flask_exts/__about__.py +1 -0
  16. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/file_admin/base_file_admin.py +4 -4
  17. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/views/user_view.py +5 -5
  18. flask_exts-0.2.0/src/flask_exts/forms/fields/__init__.py +4 -0
  19. flask_exts-0.2.0/src/flask_exts/forms/fields/datetime.py +100 -0
  20. flask_exts-0.2.0/src/flask_exts/forms/fields/json.py +19 -0
  21. flask_exts-0.2.0/src/flask_exts/forms/fields/select.py +123 -0
  22. flask_exts-0.2.0/src/flask_exts/forms/fields/switch.py +10 -0
  23. flask_exts-0.2.0/src/flask_exts/forms/fields/taglist.py +9 -0
  24. flask_exts-0.2.0/src/flask_exts/forms/form/__init__.py +2 -0
  25. flask_exts-0.2.0/src/flask_exts/forms/form/base_form.py +16 -0
  26. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/form/csrf.py +5 -7
  27. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/form/flask_form.py +1 -11
  28. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/form/meta.py +9 -5
  29. flask_exts-0.2.0/src/flask_exts/forms/form/session_csrf.py +31 -0
  30. flask_exts-0.2.0/src/flask_exts/forms/utils.py +32 -0
  31. flask_exts-0.2.0/src/flask_exts/forms/widgets/datetime.py +30 -0
  32. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/widgets/recaptcha.py +1 -5
  33. flask_exts-0.2.0/src/flask_exts/forms/widgets/select.py +77 -0
  34. flask_exts-0.2.0/src/flask_exts/forms/widgets/xeditable.py +115 -0
  35. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/manager.py +2 -2
  36. flask_exts-0.2.0/src/flask_exts/template/__init__.py +35 -0
  37. flask_exts-0.2.0/src/flask_exts/template/theme.py +56 -0
  38. flask_exts-0.2.0/src/flask_exts/template/utils.py +61 -0
  39. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/actions.html +6 -2
  40. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/base.html +5 -4
  41. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/file/list.html +8 -15
  42. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/layout.html +0 -20
  43. flask_exts-0.2.0/src/flask_exts/templates/admin/master.html +1 -0
  44. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/bootstrap4/form.html +2 -2
  45. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/bootstrap5/form.html +4 -4
  46. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/layout.html +4 -5
  47. flask_exts-0.2.0/src/flask_exts/templates/macro/form.html +16 -0
  48. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/macro/icon.html +1 -1
  49. flask_exts-0.2.0/src/flask_exts/templates/macro/message.html +17 -0
  50. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/macro/table.html +5 -4
  51. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/users/__init__.py +2 -2
  52. flask_exts-0.1.9/src/flask_exts/users/user_center.py → flask_exts-0.2.0/src/flask_exts/users/default_usercenter.py +3 -21
  53. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/users/forms/login.py +1 -1
  54. flask_exts-0.2.0/src/flask_exts/users/forms/mixins.py +29 -0
  55. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/users/forms/profile.py +0 -2
  56. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/users/forms/register.py +1 -1
  57. flask_exts-0.2.0/src/flask_exts/users/usercenter.py +19 -0
  58. flask_exts-0.2.0/src/flask_exts/utils/__init__.py +9 -0
  59. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/admin/test_user_view.py +1 -0
  60. flask_exts-0.2.0/tests/forms/test_fields.py +76 -0
  61. flask_exts-0.2.0/tests/forms/test_form.py +37 -0
  62. flask_exts-0.1.9/tests/forms/test_upload_file.py → flask_exts-0.2.0/tests/forms/test_uploadfile.py +24 -17
  63. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/funcs.py +1 -1
  64. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_form.py +1 -1
  65. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap5/conftest.py +2 -3
  66. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap5/test_base.py +1 -2
  67. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap5/test_render_form.py +4 -4
  68. {flask_exts-0.1.9/tests/templating/element → flask_exts-0.2.0/tests/template/macros}/test_render_nav_item.py +0 -1
  69. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/test_base.py +2 -3
  70. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/test_babel.py +19 -13
  71. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/test_base.py +3 -2
  72. flask_exts-0.1.9/docs/api.rst +0 -4
  73. flask_exts-0.1.9/docs/develop.rst +0 -46
  74. flask_exts-0.1.9/docs/fields.rst +0 -36
  75. flask_exts-0.1.9/docs/forms.rst +0 -9
  76. flask_exts-0.1.9/docs/templating.rst +0 -29
  77. flask_exts-0.1.9/requirements/develop.in +0 -1
  78. flask_exts-0.1.9/src/flask_exts/__about__.py +0 -1
  79. flask_exts-0.1.9/src/flask_exts/forms/fields/__init__.py +0 -1
  80. flask_exts-0.1.9/src/flask_exts/forms/form/__init__.py +0 -2
  81. flask_exts-0.1.9/src/flask_exts/forms/form/base_form.py +0 -5
  82. flask_exts-0.1.9/src/flask_exts/forms/form/secure_form.py +0 -33
  83. flask_exts-0.1.9/src/flask_exts/templates/admin/master.html +0 -1
  84. flask_exts-0.1.9/src/flask_exts/templates/demo.html +0 -7
  85. flask_exts-0.1.9/src/flask_exts/templates/macro/form.html +0 -26
  86. flask_exts-0.1.9/src/flask_exts/templating/__init__.py +0 -43
  87. flask_exts-0.1.9/src/flask_exts/templating/theme.py +0 -137
  88. flask_exts-0.1.9/src/flask_exts/utils/__init__.py +0 -6
  89. flask_exts-0.1.9/src/flask_exts/utils/csrf.py +0 -130
  90. flask_exts-0.1.9/src/flask_exts/utils/form.py +0 -81
  91. flask_exts-0.1.9/tests/forms/test_field_list.py +0 -41
  92. flask_exts-0.1.9/tests/forms/test_form.py +0 -59
  93. flask_exts-0.1.9/tests/templating/bootstrap5/__init__.py +0 -0
  94. flask_exts-0.1.9/tests/utils/test_csrf.py +0 -17
  95. {flask_exts-0.1.9 → flask_exts-0.2.0}/.github/workflows/release.yml +0 -0
  96. {flask_exts-0.1.9 → flask_exts-0.2.0}/.gitignore +0 -0
  97. {flask_exts-0.1.9 → flask_exts-0.2.0}/.readthedocs.yaml +0 -0
  98. {flask_exts-0.1.9 → flask_exts-0.2.0}/LICENSE.rst +0 -0
  99. {flask_exts-0.1.9 → flask_exts-0.2.0}/README.rst +0 -0
  100. {flask_exts-0.1.9 → flask_exts-0.2.0}/babel/babel.cfg +0 -0
  101. {flask_exts-0.1.9 → flask_exts-0.2.0}/babel/babel.sh +0 -0
  102. {flask_exts-0.1.9 → flask_exts-0.2.0}/babel/crowdin_pull.sh +0 -0
  103. {flask_exts-0.1.9 → flask_exts-0.2.0}/babel/crowdin_push.sh +0 -0
  104. {flask_exts-0.1.9 → flask_exts-0.2.0}/babel/messages.pot +0 -0
  105. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/Makefile +0 -0
  106. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/_static/logo.png +0 -0
  107. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/changes.rst +0 -0
  108. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/conf.py +0 -0
  109. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/examples.rst +0 -0
  110. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/make.bat +0 -0
  111. {flask_exts-0.1.9 → flask_exts-0.2.0}/docs/requirements.txt +0 -0
  112. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/admin/fileadmin/__init__.py +0 -0
  113. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/admin/fileadmin/admin_app.py +0 -0
  114. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/admin/fileadmin/make_app.py +0 -0
  115. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/admin/fileadmin/tmp/bbb/a.txt +0 -0
  116. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/static/favicon.ico +0 -0
  117. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/bootswatch.html +0 -0
  118. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/flash.html +0 -0
  119. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/form.html +0 -0
  120. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/icon.html +0 -0
  121. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/icons.html +0 -0
  122. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/index.html +0 -0
  123. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/mybase.html +0 -0
  124. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/nav.html +0 -0
  125. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/pagination.html +0 -0
  126. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap4/templates/table.html +0 -0
  127. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/static/favicon.ico +0 -0
  128. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/bootswatch.html +0 -0
  129. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/flash.html +0 -0
  130. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/form.html +0 -0
  131. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/icon.html +0 -0
  132. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/icons.html +0 -0
  133. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/index.html +0 -0
  134. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/mybase.html +0 -0
  135. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/nav.html +0 -0
  136. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/pagination.html +0 -0
  137. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/bootstrap5/templates/table.html +0 -0
  138. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/demo/__init__.py +0 -0
  139. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/demo/models/__init__.py +0 -0
  140. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/demo/models/user.py +0 -0
  141. {flask_exts-0.1.9 → flask_exts-0.2.0}/examples/simple.py +0 -0
  142. {flask_exts-0.1.9 → flask_exts-0.2.0}/requirements/build.in +0 -0
  143. {flask_exts-0.1.9 → flask_exts-0.2.0}/requirements/test.in +0 -0
  144. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/__init__.py +0 -0
  145. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/__init__.py +0 -0
  146. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/actions.py +0 -0
  147. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/admin.py +0 -0
  148. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/file_admin/__init__.py +0 -0
  149. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/file_admin/local_file_admin.py +0 -0
  150. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/file_admin/local_file_storage.py +0 -0
  151. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/menu.py +0 -0
  152. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/view.py +0 -0
  153. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/views/index_view.py +0 -0
  154. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/admin/wraps.py +0 -0
  155. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/babel/__init__.py +0 -0
  156. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/babel/selector.py +0 -0
  157. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/__init__.py +0 -0
  158. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/fields/file.py +0 -0
  159. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/fields/recaptcha.py +0 -0
  160. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/rules.py +0 -0
  161. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/validators/__init__.py +0 -0
  162. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/validators/field_list.py +0 -0
  163. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/validators/file.py +0 -0
  164. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/validators/recaptcha.py +0 -0
  165. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/widgets/__init__.py +0 -0
  166. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/forms/widgets/file.py +0 -0
  167. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/css/admin.css +0 -0
  168. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/css/rediscli.css +0 -0
  169. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/css/submenu.css +0 -0
  170. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/actions.js +0 -0
  171. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/bs4_filters.js +0 -0
  172. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/details_filter.js +0 -0
  173. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/filters.js +0 -0
  174. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/form.js +0 -0
  175. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/helpers.js +0 -0
  176. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/modal.js +0 -0
  177. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/admin/js/rediscli.js +0 -0
  178. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/logo.png +0 -0
  179. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/vendor/bootstrap-icons/bootstrap-icons.svg +0 -0
  180. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/vendor/bootstrap4/bootstrap.bundle.min.js +0 -0
  181. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/vendor/bootstrap4/bootstrap.min.css +0 -0
  182. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/vendor/bootstrap5/bootstrap.bundle.min.js +0 -0
  183. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/vendor/bootstrap5/bootstrap.min.css +0 -0
  184. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/static/vendor/jquery/jquery.min.js +0 -0
  185. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/admin.html +0 -0
  186. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/file/form.html +0 -0
  187. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/file/modals/form.html +0 -0
  188. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/index.html +0 -0
  189. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/lib.html +0 -0
  190. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/user/index.html +0 -0
  191. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/user/list.html +0 -0
  192. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/user/login.html +0 -0
  193. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/admin/user/register.html +0 -0
  194. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/base.html +0 -0
  195. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/bootstrap4/message.html +0 -0
  196. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/bootstrap5/message.html +0 -0
  197. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/macro/nav.html +0 -0
  198. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/macro/pagination.html +0 -0
  199. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/templates/macro/static.html +0 -0
  200. {flask_exts-0.1.9/src/flask_exts/plugins → flask_exts-0.2.0/src/flask_exts/translations}/__init__.py +0 -0
  201. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/translations/en/LC_MESSAGES/messages.mo +0 -0
  202. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/translations/en/LC_MESSAGES/messages.po +0 -0
  203. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
  204. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
  205. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/users/forms/__init__.py +0 -0
  206. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/utils/g.py +0 -0
  207. {flask_exts-0.1.9 → flask_exts-0.2.0}/src/flask_exts/utils/url.py +0 -0
  208. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/__init__.py +0 -0
  209. {flask_exts-0.1.9/src/flask_exts/translations → flask_exts-0.2.0/tests/admin}/__init__.py +0 -0
  210. {flask_exts-0.1.9/tests/admin → flask_exts-0.2.0/tests/admin/fileadmin}/__init__.py +0 -0
  211. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/admin/fileadmin/files/dummy.txt +0 -0
  212. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/admin/fileadmin/test_fileadmin.py +0 -0
  213. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/admin/test_base.py +0 -0
  214. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/conftest.py +0 -0
  215. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/data/copyleft.gif +0 -0
  216. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/data/copyleft.jpeg +0 -0
  217. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/data/copyleft.jpg +0 -0
  218. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/data/copyleft.png +0 -0
  219. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/data/copyleft.tiff +0 -0
  220. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/forms/test_filefield.py +0 -0
  221. {flask_exts-0.1.9/tests/admin/fileadmin → flask_exts-0.2.0/tests/template}/__init__.py +0 -0
  222. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template/bootstrap4}/__init__.py +0 -0
  223. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/conftest.py +0 -0
  224. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_field.py +0 -0
  225. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_form_row.py +0 -0
  226. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_hidden_errors.py +0 -0
  227. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_icon.py +0 -0
  228. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_messages.py +0 -0
  229. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_pager.py +0 -0
  230. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_pagination.py +0 -0
  231. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap4/test_render_table.py +0 -0
  232. {flask_exts-0.1.9/tests/templating/bootstrap4 → flask_exts-0.2.0/tests/template/bootstrap5}/__init__.py +0 -0
  233. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap5/test_pagination.py +0 -0
  234. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap5/test_render_form_row.py +0 -0
  235. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/bootstrap5/test_render_messages.py +0 -0
  236. {flask_exts-0.1.9/tests/templating → flask_exts-0.2.0/tests/template}/conftest.py +0 -0
  237. {flask_exts-0.1.9/tests/templating/element → flask_exts-0.2.0/tests/template/macros}/test_render_breadcrumb_item.py +0 -0
  238. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/templates/method.html +0 -0
  239. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/templates/mock.html +0 -0
  240. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/translations/en/LC_MESSAGES/messages.mo +0 -0
  241. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/translations/en/LC_MESSAGES/messages.po +0 -0
  242. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/translations/messages.pot +0 -0
  243. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
  244. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
  245. {flask_exts-0.1.9 → flask_exts-0.2.0}/tests/utils/test_url.py +0 -0
@@ -1,3 +1,10 @@
1
+ v0.2.0
2
+ ------
3
+
4
+ Released 2025-01-07
5
+
6
+ - update templates.macros
7
+
1
8
  v0.1.9
2
9
  ------
3
10
 
@@ -17,7 +24,7 @@ v0.1.7
17
24
 
18
25
  Released 2024-10-13
19
26
 
20
- - add theme for templating
27
+ - add theme for template
21
28
  - admin view framework
22
29
 
23
30
  v0.1.6
@@ -28,7 +35,6 @@ Released 2024-09-14
28
35
  - merge translations of wtforms, flask_exts and app into flask_babel.get_translations()
29
36
  - update FileField and ImageField
30
37
  - add url for template.static
31
- - use namespace ns.bootstrap to control bootstrap's css and js
32
38
 
33
39
  v0.1.5
34
40
  ------
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: Flask-Exts
3
- Version: 0.1.9
3
+ Version: 0.2.0
4
4
  Summary: Flask extensions with admin, SQLAlchemy, babel, forms, fields, widgets, and so on.
5
5
  Project-URL: Documentation, https://flask-exts.readthedocs.io
6
6
  Project-URL: Source, https://github.com/ojso/flask-exts
@@ -28,6 +28,7 @@ License: MIT License
28
28
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
29
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
30
  SOFTWARE.
31
+ License-File: LICENSE.rst
31
32
  Keywords: admin,babel,flask,form,sql,widget
32
33
  Classifier: Development Status :: 3 - Alpha
33
34
  Classifier: Environment :: Web Environment
@@ -44,7 +45,6 @@ Requires-Dist: flask-babel>=4.0
44
45
  Requires-Dist: flask-login>=0.6
45
46
  Requires-Dist: flask-sqlalchemy>=3.0
46
47
  Requires-Dist: flask>=3.0
47
- Requires-Dist: python-plugins>=0.2
48
48
  Requires-Dist: wtforms>=3.0
49
49
  Description-Content-Type: text/x-rst
50
50
 
@@ -1,17 +1,6 @@
1
- =====
2
- Usage
3
- =====
4
-
5
- .. _installation:
6
-
7
- Installation
8
- ==============
9
-
10
- To use Flask-Exts, first install it using pip:
11
-
12
- .. code-block:: console
13
-
14
- (.venv) $ pip install flask-exts
1
+ ==========
2
+ Configure
3
+ ==========
15
4
 
16
5
  Configuration
17
6
  ==============
@@ -23,16 +12,8 @@ Configuration
23
12
  Default is ``None``.
24
13
  ``BABEL_DEFAULT_TIMEZONE`` Set to ``Asia/Shanghai`` to babel's default timezone.
25
14
  Default is ``None``.
26
- ``JQUERY_JS_URL`` Set to ``jquery js url`` to active ``jquery``.
27
- Default is in ``template.static``.
28
- ``BOOTSTRAP_CSS_URL`` Set to ``bootstrap css url`` to active ``bootstrap css``.
29
- Default is in ``template.static``.
30
- ``BOOTSTRAP_JS_URL`` Set to ``bootstrap js url`` to active ``bootstrap js``.
31
- Default is in ``template.static``.
32
- ``ICON_SPRITE_URL`` Set to ``icon url`` to active ``icon``.
33
- Default is in ``template.static``.
34
- ``CSRF_ENABLED`` Set to ``True`` to enable form's CSRF .
35
- Default is ``False``.
15
+ ``CSRF_ENABLED`` Set to ``False`` to enable form's CSRF .
16
+ Default is ``True``.
36
17
  ``CSRF_SECRET_KEY`` Random data for generating secure tokens.
37
18
  If this is not set then ``SECRET_KEY`` is used.
38
19
  ``CSRF_FIELD_NAME`` Name of the form field and session key that holds the CSRF token.
@@ -42,7 +23,7 @@ Configuration
42
23
  ``TEMPLATE_ENABLED`` Set to ``False`` to disable templating extension.
43
24
  Default is ``True``.
44
25
  ``TEMPLATE_THEME`` Set to ``theme`` to create custom theme
45
- Default is ``templating.theme.DefaultTheme()``
26
+ Default is ``template.theme.BootstrapTheme(4)``
46
27
  ``USER_ENABLED`` Set to ``False`` to disable ``User`` support.
47
28
  Default is ``True``.
48
29
  ``USER_CENTER`` set to ``user center`` to create custom user_center
@@ -51,14 +32,3 @@ Configuration
51
32
  Default is ``True``.
52
33
  ========================== =====================================================================
53
34
 
54
- Examples
55
- ===========
56
-
57
- ``python simple.py`` to run a simple example.
58
-
59
- .. literalinclude:: ../examples/simple.py
60
- :language: python
61
-
62
- More examples, please click :doc:`examples`.
63
-
64
-
@@ -1,10 +1,56 @@
1
- Translations
2
- ============
1
+ =======
2
+ Develop
3
+ =======
3
4
 
4
- src
5
- ---
5
+ Install
6
+ =======
6
7
 
7
- pybabel::
8
+ .. code-block:: console
9
+
10
+ $ pip install -e .
11
+ $ pip install -r requirements/develop.in
12
+
13
+ Test
14
+ ====
15
+ Tests are run with `pytest <https://pytest.org/>`_.
16
+ To run the tests, from the project directory:
17
+
18
+ .. code-block:: console
19
+
20
+ # requirements
21
+ $ pip install -r requirements/test.in
22
+
23
+ # update translation
24
+ $ pybabel compile -d src/flask_exts/translations -D messages
25
+ $ pybabel compile -d tests/translations
26
+
27
+ # test
28
+ $ pytest
29
+
30
+ Docs
31
+ ====
32
+
33
+ .. code-block:: console
34
+
35
+ $ pip install -r docs/requirements.txt
36
+ $ cd docs
37
+ $ make html
38
+
39
+ Publish
40
+ =======
41
+
42
+ .. code-block:: console
43
+
44
+ $ pip install -r requirements/build.in
45
+ $ python -m build
46
+
47
+ Translation
48
+ =============
49
+
50
+ pybabel
51
+ -------------
52
+
53
+ .. code-block:: console
8
54
 
9
55
  # extract messages from source files and generate a POT file
10
56
  pybabel extract -F babel.cfg -o babel/messages.pot src/
@@ -27,7 +73,7 @@ pybabel::
27
73
  tests
28
74
  -----
29
75
 
30
- pybabel::
76
+ .. code-block:: console
31
77
 
32
78
 
33
79
  cd tests/
@@ -47,9 +93,4 @@ pybabel::
47
93
 
48
94
  # compile message catalogs to MO files
49
95
 
50
- pybabel compile -d translations
51
-
52
-
53
-
54
-
55
-
96
+ pybabel compile -d translations
@@ -8,16 +8,33 @@ Welcome to Flask-Exts's documentation!
8
8
 
9
9
  **Flask-Exts** is a Flask extensions with admin, SQLAlchemy, babel, forms, fields, widgets, and so on.
10
10
 
11
+ .. _installation:
12
+
13
+ Installation
14
+ ==============
15
+
16
+ To use Flask-Exts, first install it using pip:
17
+
18
+ .. code-block:: console
19
+
20
+ (.venv) $ pip install flask-exts
21
+
22
+ Examples
23
+ ===========
24
+
25
+ ``python simple.py`` to run a simple example.
26
+
27
+ .. literalinclude:: ../examples/simple.py
28
+ :language: python
29
+
30
+ More examples, please click :doc:`examples`.
31
+
11
32
  .. toctree::
12
33
  :maxdepth: 2
13
34
  :caption: Contents:
14
35
 
15
- usage
16
- api
17
- forms
18
- templating
36
+ configure
19
37
  develop
20
- translation
21
38
  examples
22
39
  changes
23
40
 
@@ -2,7 +2,7 @@
2
2
  Examples
3
3
  ========================
4
4
 
5
- Install
5
+ Download
6
6
  =========
7
7
 
8
8
  Type these commands in the terminal:
@@ -14,12 +14,14 @@ Type these commands in the terminal:
14
14
  $ python3 -m venv venv
15
15
  $ source venv/bin/activate
16
16
  $ pip install flask-exts
17
-
18
17
 
19
18
  Run the examples
20
19
  ===============================
21
20
 
22
- Type the command in the terminal:
21
+ Type the command in the terminal, then go to http://localhost:5000.
22
+
23
+ Start
24
+ ----------
23
25
 
24
26
  simple
25
27
  ---------
@@ -30,8 +32,6 @@ run only one file.
30
32
 
31
33
  $ python simple.py
32
34
 
33
- Now go to http://localhost:5000.
34
-
35
35
  demo
36
36
  -----------------
37
37
 
@@ -41,14 +41,6 @@ With sqlite db.
41
41
 
42
42
  $ flask --app demo run --debug --port=5000
43
43
 
44
-
45
- fileadmin
46
- -----------------
47
-
48
- .. code-block:: bash
49
-
50
- $ flask --app admin/fileadmin run
51
-
52
44
  Bootstrap 4
53
45
  -----------------
54
46
 
@@ -63,5 +55,9 @@ Bootstrap 5
63
55
 
64
56
  $ flask --app bootstrap5/app.py run
65
57
 
58
+ fileadmin
59
+ -----------------
66
60
 
67
-
61
+ .. code-block:: bash
62
+
63
+ $ flask --app admin/fileadmin run
@@ -6,7 +6,7 @@ from wtforms.validators import DataRequired, Length, Regexp
6
6
  from wtforms.fields import *
7
7
  from flask_sqlalchemy import SQLAlchemy
8
8
  from flask_exts.forms.form import FlaskForm
9
- from python_plugins.forms.fields.switch import SwitchField
9
+ from flask_exts.forms.fields import SwitchField
10
10
  from flask_exts import Manager
11
11
 
12
12
  manager = Manager()
@@ -7,11 +7,11 @@ from wtforms.fields import *
7
7
  from flask_sqlalchemy import SQLAlchemy
8
8
 
9
9
  from flask_exts.forms.form import FlaskForm
10
- from python_plugins.forms.fields.switch import SwitchField
10
+ from flask_exts.forms.fields import SwitchField
11
11
  from flask_exts import Manager
12
- from flask_exts.templating.theme import DefaultTheme
12
+ from flask_exts.template.theme import BootstrapTheme
13
13
 
14
- theme = DefaultTheme(bootstrap_version=5)
14
+ theme = BootstrapTheme(version=5)
15
15
 
16
16
  manager = Manager()
17
17
  app = Flask(__name__)
@@ -1,11 +1,10 @@
1
1
  import os.path
2
2
  from flask import Flask
3
- from flask import render_template
4
3
  from flask_exts import Manager
5
4
  from flask_exts.admin import Admin
6
5
  from .models import db
7
6
  from .user_center import UserCenter
8
- from .views.index_view import myview
7
+ from .views.my_view import myview
9
8
 
10
9
 
11
10
  def get_sqlite_path():
@@ -15,9 +14,6 @@ def get_sqlite_path():
15
14
 
16
15
 
17
16
  def build_sample_db(app):
18
- import string
19
- import random
20
-
21
17
  # db.drop_all()
22
18
  db.create_all()
23
19
  user_center = app.config["USER_CENTER"]
@@ -48,7 +44,7 @@ def init_app(app: Flask):
48
44
 
49
45
  admin = Admin(name="Demo")
50
46
  admin.init_app(app)
51
- admin.add_view(myview,is_menu=False)
47
+ admin.add_view(myview)
52
48
 
53
49
  if not os.path.exists(app.config["DATABASE_FILE"]):
54
50
  with app.app_context():
@@ -1,6 +1,6 @@
1
1
  {% extends 'admin/master.html' %}
2
2
  {% block main %}
3
3
  <div>
4
- Demo:Flask-Exts
4
+ Demo:my:index
5
5
  </div>
6
6
  {% endblock %}
@@ -1,5 +1,5 @@
1
1
  from werkzeug.security import generate_password_hash, check_password_hash
2
- from flask_exts.users.user_center import DefaultUserCenter
2
+ from flask_exts.users.default_usercenter import DefaultUserCenter
3
3
  from .models import db,select
4
4
  from .models.user import User
5
5
 
@@ -5,6 +5,6 @@ from flask_exts.admin import BaseView
5
5
  class MyView(BaseView):
6
6
  @expose("/")
7
7
  def index(self):
8
- return self.render("index.html")
8
+ return self.render("my/index.html")
9
9
 
10
- myview = MyView(name="Home",url="/")
10
+ myview = MyView(name="MyView")
@@ -31,7 +31,6 @@ dependencies = [
31
31
  "flask-babel>=4.0",
32
32
  "Flask-SQLAlchemy>=3.0",
33
33
  "Flask-Login>=0.6",
34
- "Python-Plugins>=0.2",
35
34
  ]
36
35
 
37
36
  [project.urls]
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"
@@ -3,16 +3,16 @@ import platform
3
3
  import re
4
4
  from operator import itemgetter
5
5
  from datetime import datetime
6
- from flask_babel import gettext,lazy_gettext
6
+ from flask_babel import gettext, lazy_gettext
7
7
  from flask import flash, redirect, abort, request
8
8
  from wtforms import fields, validators
9
9
  from werkzeug.utils import secure_filename
10
10
  from ..view import BaseView
11
11
  from ..wraps import expose
12
12
  from ..actions import action, ActionsMixin
13
- from ...forms.form import FlaskForm as BaseForm
13
+ from ...forms.form import BaseForm
14
14
  from ...utils import flash_errors
15
- from ...utils.form import validate_form_on_submit
15
+
16
16
 
17
17
  class BaseFileAdmin(BaseView, ActionsMixin):
18
18
  can_upload = True
@@ -466,7 +466,7 @@ class BaseFileAdmin(BaseView, ActionsMixin):
466
466
  :param form:
467
467
  Form to validate
468
468
  """
469
- return validate_form_on_submit(form)
469
+ return form.validate_on_submit()
470
470
 
471
471
  def _get_dir_url(self, endpoint, path=None, **kwargs):
472
472
  """
@@ -7,7 +7,6 @@ from flask_login import current_user
7
7
  from flask_login import login_user
8
8
  from flask_login import logout_user
9
9
  from flask_login import login_required
10
- from ...utils.form import validate_form_on_submit
11
10
  from ..wraps import expose
12
11
  from ..view import BaseView
13
12
  from flask import current_app
@@ -51,7 +50,7 @@ class UserView(BaseView):
51
50
 
52
51
  @property
53
52
  def usercenter(self):
54
- return current_app.extensions["usercenter"]
53
+ return current_app.extensions["user"]
55
54
 
56
55
  def get_login_form_class(self):
57
56
  return self.usercenter.login_form_class
@@ -93,10 +92,11 @@ class UserView(BaseView):
93
92
  if current_user.is_authenticated:
94
93
  return redirect(url_for(".index"))
95
94
  form = self.get_login_form_class()()
96
- if validate_form_on_submit(form):
95
+ if form.validate_on_submit():
97
96
  (user, error) = self.validate_login_and_get_user(form)
98
97
  if user is None:
99
- flash(error)
98
+ flash(error,'error')
99
+ # form.username.errors.append(error)
100
100
  else:
101
101
  if hasattr(form, "remember_me"):
102
102
  login_user(user, remember=form.remember_me.data)
@@ -113,7 +113,7 @@ class UserView(BaseView):
113
113
  if current_user.is_authenticated:
114
114
  return redirect(url_for(".index"))
115
115
  form = self.get_register_form_class()()
116
- if validate_form_on_submit(form):
116
+ if form.validate_on_submit():
117
117
  (user, error) = self.validate_register_and_create_user(form)
118
118
  if user is None:
119
119
  flash(error)
@@ -0,0 +1,4 @@
1
+ from .json import JSONField
2
+ from .datetime import DateTimeField
3
+ from .file import FileField, ImageField
4
+ from .switch import SwitchField
@@ -0,0 +1,100 @@
1
+ import time
2
+ import datetime
3
+ import wtforms.fields
4
+ from ..widgets.datetime import DateTimePickerWidget
5
+ from ..widgets.datetime import TimePickerWidget
6
+
7
+ class DateTimeField(wtforms.fields.DateTimeField):
8
+ """
9
+ Allows modifying the datetime format of a DateTimeField using form_args.
10
+ """
11
+
12
+ widget = DateTimePickerWidget()
13
+
14
+ def __init__(self, label=None, validators=None, format=None, **kwargs):
15
+ """Constructor
16
+
17
+ :param label:
18
+ Label
19
+ :param validators:
20
+ Field validators
21
+ :param format:
22
+ Format for text to date conversion. Defaults to '%Y-%m-%d %H:%M:%S'
23
+ :param kwargs:
24
+ Any additional parameters
25
+ """
26
+ super().__init__(
27
+ label, validators, format or "%Y-%m-%d %H:%M:%S", **kwargs
28
+ )
29
+
30
+
31
+ class TimeField(wtforms.fields.Field):
32
+ """
33
+ A text field which stores a `datetime.time` object.
34
+ Accepts time string in multiple formats: 20:10, 20:10:00, 10:00 am, 9:30pm, etc.
35
+ """
36
+
37
+ widget = TimePickerWidget()
38
+
39
+ def __init__(
40
+ self,
41
+ label=None,
42
+ validators=None,
43
+ formats=None,
44
+ default_format=None,
45
+ widget_format=None,
46
+ **kwargs
47
+ ):
48
+ """
49
+ Constructor
50
+
51
+ :param label:
52
+ Label
53
+ :param validators:
54
+ Field validators
55
+ :param formats:
56
+ Supported time formats, as a enumerable.
57
+ :param default_format:
58
+ Default time format. Defaults to '%H:%M:%S'
59
+ :param kwargs:
60
+ Any additional parameters
61
+ """
62
+ super().__init__(label, validators, **kwargs)
63
+
64
+ self.formats = formats or (
65
+ "%H:%M:%S",
66
+ "%H:%M",
67
+ "%I:%M:%S%p",
68
+ "%I:%M%p",
69
+ "%I:%M:%S %p",
70
+ "%I:%M %p",
71
+ )
72
+
73
+ self.default_format = default_format or "%H:%M:%S"
74
+
75
+ def _value(self):
76
+ if self.raw_data:
77
+ return " ".join(self.raw_data)
78
+ elif self.data is not None:
79
+ return self.data.strftime(self.default_format)
80
+ else:
81
+ return ""
82
+
83
+ def process_formdata(self, valuelist):
84
+ if valuelist:
85
+ date_str = " ".join(valuelist)
86
+
87
+ if date_str.strip():
88
+ for format in self.formats:
89
+ try:
90
+ timetuple = time.strptime(date_str, format)
91
+ self.data = datetime.time(
92
+ timetuple.tm_hour, timetuple.tm_min, timetuple.tm_sec
93
+ )
94
+ return
95
+ except ValueError:
96
+ pass
97
+
98
+ raise ValueError(self.gettext("Invalid time format"))
99
+ else:
100
+ self.data = None
@@ -0,0 +1,19 @@
1
+ import json
2
+ from wtforms.fields import TextAreaField
3
+
4
+ class JSONField(TextAreaField):
5
+ def process_formdata(self, valuelist):
6
+ if valuelist:
7
+ if not valuelist[0]:
8
+ self.data = None
9
+ return
10
+ try:
11
+ self.data = json.loads(valuelist[0])
12
+ except ValueError:
13
+ raise ValueError(self.gettext("Invalid JSON"))
14
+
15
+ def _value(self):
16
+ if self.data:
17
+ return json.dumps(self.data, ensure_ascii=False)
18
+ else:
19
+ return ""