WuttaWeb 0.20.2__tar.gz → 0.20.4__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 (205) hide show
  1. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/CHANGELOG.md +14 -0
  2. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/PKG-INFO +1 -1
  3. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/pyproject.toml +1 -1
  4. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/forms/base.py +10 -6
  5. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/forms/schema.py +16 -3
  6. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/forms/widgets.py +39 -1
  7. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/grids/base.py +12 -0
  8. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/grids/vue_template.mako +3 -0
  9. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/index.mako +5 -1
  10. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/forms/test_base.py +14 -0
  11. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/forms/test_widgets.py +40 -0
  12. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/.gitignore +0 -0
  13. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/COPYING.txt +0 -0
  14. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/README.md +0 -0
  15. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/Makefile +0 -0
  16. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/_static/.keepme +0 -0
  17. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.app.rst +0 -0
  18. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.auth.rst +0 -0
  19. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.cli.rst +0 -0
  20. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.cli.webapp.rst +0 -0
  21. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.conf.rst +0 -0
  22. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.db.continuum.rst +0 -0
  23. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.db.rst +0 -0
  24. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.db.sess.rst +0 -0
  25. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.emails.rst +0 -0
  26. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.base.rst +0 -0
  27. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.rst +0 -0
  28. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.schema.rst +0 -0
  29. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.widgets.rst +0 -0
  30. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.grids.base.rst +0 -0
  31. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.grids.filters.rst +0 -0
  32. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.grids.rst +0 -0
  33. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.handler.rst +0 -0
  34. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.helpers.rst +0 -0
  35. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.menus.rst +0 -0
  36. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.progress.rst +0 -0
  37. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.rst +0 -0
  38. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.static.rst +0 -0
  39. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.subscribers.rst +0 -0
  40. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.util.rst +0 -0
  41. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.auth.rst +0 -0
  42. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.base.rst +0 -0
  43. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.batch.rst +0 -0
  44. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.common.rst +0 -0
  45. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.email.rst +0 -0
  46. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.essential.rst +0 -0
  47. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.master.rst +0 -0
  48. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.people.rst +0 -0
  49. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.progress.rst +0 -0
  50. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.reports.rst +0 -0
  51. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.roles.rst +0 -0
  52. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.rst +0 -0
  53. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.settings.rst +0 -0
  54. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.upgrades.rst +0 -0
  55. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.users.rst +0 -0
  56. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/conf.py +0 -0
  57. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/glossary.rst +0 -0
  58. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/index.rst +0 -0
  59. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/make.bat +0 -0
  60. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/narr/cli/builtin.rst +0 -0
  61. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/narr/cli/index.rst +0 -0
  62. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/narr/templates/base.rst +0 -0
  63. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/narr/templates/index.rst +0 -0
  64. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/narr/templates/lookup.rst +0 -0
  65. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/docs/narr/templates/overview.rst +0 -0
  66. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/__init__.py +0 -0
  67. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/_version.py +0 -0
  68. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/app.py +0 -0
  69. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/auth.py +0 -0
  70. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/cli/__init__.py +0 -0
  71. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/cli/webapp.py +0 -0
  72. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/conf.py +0 -0
  73. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/db/__init__.py +0 -0
  74. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/db/continuum.py +0 -0
  75. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/db/sess.py +0 -0
  76. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
  77. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
  78. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/emails.py +0 -0
  79. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/forms/__init__.py +0 -0
  80. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/grids/__init__.py +0 -0
  81. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/grids/filters.py +0 -0
  82. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/handler.py +0 -0
  83. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/helpers.py +0 -0
  84. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/menus.py +0 -0
  85. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/progress.py +0 -0
  86. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/static/__init__.py +0 -0
  87. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/static/img/favicon.ico +0 -0
  88. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/static/img/logo.png +0 -0
  89. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/static/img/testing.png +0 -0
  90. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/subscribers.py +0 -0
  91. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
  92. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/appinfo/index.mako +0 -0
  93. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/auth/change_password.mako +0 -0
  94. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/auth/login.mako +0 -0
  95. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/base.mako +0 -0
  96. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/base_meta.mako +0 -0
  97. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/batch/view.mako +0 -0
  98. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/configure.mako +0 -0
  99. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
  100. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
  101. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
  102. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
  103. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
  104. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
  105. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/password.pt +0 -0
  106. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/permissions.pt +0 -0
  107. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
  108. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
  109. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
  110. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
  111. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
  112. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
  113. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
  114. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/select.pt +0 -0
  115. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/textarea.pt +0 -0
  116. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/textinput.pt +0 -0
  117. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/email/settings/view.mako +0 -0
  118. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/forbidden.mako +0 -0
  119. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/form.mako +0 -0
  120. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
  121. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/grids/table_element.mako +0 -0
  122. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/home.mako +0 -0
  123. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/configure.mako +0 -0
  124. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/create.mako +0 -0
  125. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/delete.mako +0 -0
  126. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/edit.mako +0 -0
  127. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/form.mako +0 -0
  128. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/view.mako +0 -0
  129. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/notfound.mako +0 -0
  130. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/page.mako +0 -0
  131. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/people/view_profile.mako +0 -0
  132. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/progress.mako +0 -0
  133. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/reports/view.mako +0 -0
  134. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/setup.mako +0 -0
  135. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/upgrade.mako +0 -0
  136. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
  137. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/upgrades/view.mako +0 -0
  138. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/templates/wutta-components.mako +0 -0
  139. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/testing.py +0 -0
  140. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/util.py +0 -0
  141. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/__init__.py +0 -0
  142. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/auth.py +0 -0
  143. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/base.py +0 -0
  144. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/batch.py +0 -0
  145. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/common.py +0 -0
  146. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/email.py +0 -0
  147. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/essential.py +0 -0
  148. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/master.py +0 -0
  149. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/people.py +0 -0
  150. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/progress.py +0 -0
  151. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/reports.py +0 -0
  152. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/roles.py +0 -0
  153. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/settings.py +0 -0
  154. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/upgrades.py +0 -0
  155. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/src/wuttaweb/views/users.py +0 -0
  156. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tasks.py +0 -0
  157. {wuttaweb-0.20.2/tests/views → wuttaweb-0.20.4/tests}/__init__.py +0 -0
  158. {wuttaweb-0.20.2/tests/grids → wuttaweb-0.20.4/tests/cli}/__init__.py +0 -0
  159. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/cli/test_webapp.py +0 -0
  160. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/db/__init__.py +0 -0
  161. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/db/test_continuum.py +0 -0
  162. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/forms/test_schema.py +0 -0
  163. {wuttaweb-0.20.2/tests/cli → wuttaweb-0.20.4/tests/grids}/__init__.py +0 -0
  164. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/grids/test_base.py +0 -0
  165. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/grids/test_filters.py +0 -0
  166. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
  167. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
  168. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/bb_oruga.js +0 -0
  169. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/bb_oruga_bulma.css +0 -0
  170. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/bb_oruga_bulma.js +0 -0
  171. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/bb_vue.js +0 -0
  172. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/bb_vue_fontawesome.js +0 -0
  173. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/buefy.css +0 -0
  174. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/buefy.js +0 -0
  175. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/fontawesome.js +0 -0
  176. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/vue.js +0 -0
  177. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/libcache/vue_resource.js +0 -0
  178. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_app.py +0 -0
  179. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_auth.py +0 -0
  180. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_emails.py +0 -0
  181. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_handler.py +0 -0
  182. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_helpers.py +0 -0
  183. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_menus.py +0 -0
  184. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_progress.py +0 -0
  185. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_static.py +0 -0
  186. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_subscribers.py +0 -0
  187. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/test_util.py +0 -0
  188. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/util.py +0 -0
  189. {wuttaweb-0.20.2/tests → wuttaweb-0.20.4/tests/views}/__init__.py +0 -0
  190. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test___init__.py +0 -0
  191. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_auth.py +0 -0
  192. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_base.py +0 -0
  193. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_batch.py +0 -0
  194. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_common.py +0 -0
  195. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_email.py +0 -0
  196. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_essential.py +0 -0
  197. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_master.py +0 -0
  198. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_people.py +0 -0
  199. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_progress.py +0 -0
  200. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_reports.py +0 -0
  201. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_roles.py +0 -0
  202. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_settings.py +0 -0
  203. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_upgrades.py +0 -0
  204. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tests/views/test_users.py +0 -0
  205. {wuttaweb-0.20.2 → wuttaweb-0.20.4}/tox.ini +0 -0
@@ -5,6 +5,20 @@ All notable changes to wuttaweb will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## v0.20.4 (2025-01-15)
9
+
10
+ ### Fix
11
+
12
+ - add `WuttaDateWidget` and associated logic
13
+ - add `serialize_object()` method for `ObjectRef` schema node
14
+
15
+ ## v0.20.3 (2025-01-14)
16
+
17
+ ### Fix
18
+
19
+ - add `render_grid_tag()` as separate def block for index templates
20
+ - add `click_handler` attr for GridAction
21
+
8
22
  ## v0.20.2 (2025-01-14)
9
23
 
10
24
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: WuttaWeb
3
- Version: 0.20.2
3
+ Version: 0.20.4
4
4
  Summary: Web App for Wutta Framework
5
5
  Project-URL: Homepage, https://wuttaproject.org/
6
6
  Project-URL: Repository, https://forgejo.wuttaproject.org/wutta/wuttaweb
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "WuttaWeb"
9
- version = "0.20.2"
9
+ version = "0.20.4"
10
10
  description = "Web App for Wutta Framework"
11
11
  readme = "README.md"
12
12
  authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
@@ -546,10 +546,13 @@ class Form:
546
546
  This is generally only possible if :attr:`model_class` is set
547
547
  to a valid SQLAlchemy mapped class.
548
548
 
549
- As of writing this only looks for
550
- :class:`sqlalchemy:sqlalchemy.types.DateTime` fields and if
551
- any are found, they are configured to use
552
- :class:`~wuttaweb.forms.widgets.WuttaDateTimeWidget()`.
549
+ This only checks for a couple of data types, with mapping as
550
+ follows:
551
+
552
+ * :class:`sqlalchemy:sqlalchemy.types.Date` ->
553
+ :class:`~wuttaweb.forms.widgets.WuttaDateWidget`
554
+ * :class:`sqlalchemy:sqlalchemy.types.DateTime` ->
555
+ :class:`~wuttaweb.forms.widgets.WuttaDateTimeWidget`
553
556
  """
554
557
  from wuttaweb.forms import widgets
555
558
 
@@ -565,8 +568,9 @@ class Form:
565
568
  prop = getattr(attr, 'prop', None)
566
569
  if prop and isinstance(prop, orm.ColumnProperty):
567
570
  column = prop.columns[0]
568
- if isinstance(column.type, sa.DateTime):
569
- # self.set_renderer(key, self.render_datetime)
571
+ if isinstance(column.type, sa.Date):
572
+ self.set_widget(key, widgets.WuttaDateWidget(self.request))
573
+ elif isinstance(column.type, sa.DateTime):
570
574
  self.set_widget(key, widgets.WuttaDateTimeWidget(self.request))
571
575
 
572
576
  def set_grid(self, key, grid):
@@ -334,8 +334,21 @@ class ObjectRef(colander.SchemaType):
334
334
  # nb. keep a ref to this for later use
335
335
  node.model_instance = appstruct
336
336
 
337
- # serialize to uuid
338
- return appstruct.uuid.hex
337
+ # serialize to PK as string
338
+ return self.serialize_object(appstruct)
339
+
340
+ def serialize_object(self, obj):
341
+ """
342
+ Serialize the given object to its primary key as string.
343
+
344
+ Default logic assumes the object has a UUID; subclass can
345
+ override as needed.
346
+
347
+ :param obj: Object reference for the node.
348
+
349
+ :returns: Object primary key as string.
350
+ """
351
+ return obj.uuid.hex
339
352
 
340
353
  def deserialize(self, node, cstruct):
341
354
  """ """
@@ -417,7 +430,7 @@ class ObjectRef(colander.SchemaType):
417
430
  if 'values' not in kwargs:
418
431
  query = self.get_query()
419
432
  objects = query.all()
420
- values = [(obj.uuid.hex, str(obj))
433
+ values = [(self.serialize_object(obj), str(obj))
421
434
  for obj in objects]
422
435
  if self.empty_option:
423
436
  values.insert(0, self.empty_option)
@@ -36,6 +36,7 @@ in the namespace:
36
36
  * :class:`deform:deform.widget.CheckboxWidget`
37
37
  * :class:`deform:deform.widget.SelectWidget`
38
38
  * :class:`deform:deform.widget.CheckboxChoiceWidget`
39
+ * :class:`deform:deform.widget.DateInputWidget`
39
40
  * :class:`deform:deform.widget.DateTimeInputWidget`
40
41
  * :class:`deform:deform.widget.MoneyInputWidget`
41
42
  """
@@ -49,7 +50,7 @@ import humanize
49
50
  from deform.widget import (Widget, TextInputWidget, TextAreaWidget,
50
51
  PasswordWidget, CheckedPasswordWidget,
51
52
  CheckboxWidget, SelectWidget, CheckboxChoiceWidget,
52
- DateTimeInputWidget, MoneyInputWidget)
53
+ DateInputWidget, DateTimeInputWidget, MoneyInputWidget)
53
54
  from webhelpers2.html import HTML
54
55
 
55
56
  from wuttjamaican.conf import parse_list
@@ -153,6 +154,43 @@ class WuttaCheckboxChoiceWidget(CheckboxChoiceWidget):
153
154
  self.app = self.config.get_app()
154
155
 
155
156
 
157
+ class WuttaDateWidget(DateInputWidget):
158
+ """
159
+ Custom widget for :class:`python:datetime.date` fields.
160
+
161
+ The main purpose of this widget is to leverage
162
+ :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_date()`
163
+ for the readonly display.
164
+
165
+ It is automatically used for SQLAlchemy mapped classes where the
166
+ field maps to a :class:`sqlalchemy:sqlalchemy.types.Date` column.
167
+ For other (non-mapped) date fields, or mapped datetime fields for
168
+ which a date widget is preferred, use
169
+ :meth:`~wuttaweb.forms.base.Form.set_widget()`.
170
+
171
+ This is a subclass of
172
+ :class:`deform:deform.widget.DateInputWidget` and uses these
173
+ Deform templates:
174
+
175
+ * ``dateinput``
176
+ """
177
+
178
+ def __init__(self, request, *args, **kwargs):
179
+ super().__init__(*args, **kwargs)
180
+ self.request = request
181
+ self.config = self.request.wutta_config
182
+ self.app = self.config.get_app()
183
+
184
+ def serialize(self, field, cstruct, **kw):
185
+ """ """
186
+ readonly = kw.get('readonly', self.readonly)
187
+ if readonly and cstruct:
188
+ dt = datetime.datetime.fromisoformat(cstruct)
189
+ return self.app.render_date(dt)
190
+
191
+ return super().serialize(field, cstruct, **kw)
192
+
193
+
156
194
  class WuttaDateTimeWidget(DateTimeInputWidget):
157
195
  """
158
196
  Custom widget for :class:`python:datetime.datetime` fields.
@@ -2284,6 +2284,16 @@ class GridAction:
2284
2284
 
2285
2285
  Optional ``target`` attribute for the ``<a>`` tag.
2286
2286
 
2287
+ .. attribute:: click_handler
2288
+
2289
+ Optional JS click handler for the action. This value will be
2290
+ rendered as-is within the final grid template, hence the JS
2291
+ string must be callable code. Note that ``props.row`` will be
2292
+ available in the calling context, so a couple of examples:
2293
+
2294
+ * ``deleteThisThing(props.row)``
2295
+ * ``$emit('do-something', props.row)``
2296
+
2287
2297
  .. attribute:: icon
2288
2298
 
2289
2299
  Name of icon to be shown for the action link.
@@ -2302,6 +2312,7 @@ class GridAction:
2302
2312
  label=None,
2303
2313
  url=None,
2304
2314
  target=None,
2315
+ click_handler=None,
2305
2316
  icon=None,
2306
2317
  link_class=None,
2307
2318
  ):
@@ -2311,6 +2322,7 @@ class GridAction:
2311
2322
  self.key = key
2312
2323
  self.url = url
2313
2324
  self.target = target
2325
+ self.click_handler = click_handler
2314
2326
  self.label = label or self.app.make_title(key)
2315
2327
  self.icon = icon or key
2316
2328
  self.link_class = link_class or ''
@@ -183,6 +183,9 @@
183
183
  % if action.target:
184
184
  target="${action.target}"
185
185
  % endif
186
+ % if action.click_handler:
187
+ @click.prevent="${action.click_handler}"
188
+ % endif
186
189
  class="${action.link_class}">
187
190
  ${action.render_icon_and_label()}
188
191
  </a>
@@ -8,10 +8,14 @@
8
8
 
9
9
  <%def name="page_content()">
10
10
  % if grid is not Undefined:
11
- ${grid.render_vue_tag()}
11
+ ${self.render_grid_tag()}
12
12
  % endif
13
13
  </%def>
14
14
 
15
+ <%def name="render_grid_tag()">
16
+ ${grid.render_vue_tag()}
17
+ </%def>
18
+
15
19
  <%def name="render_vue_templates()">
16
20
  ${parent.render_vue_templates()}
17
21
  ${self.render_vue_template_grid()}
@@ -3,6 +3,8 @@
3
3
  from unittest import TestCase
4
4
  from unittest.mock import MagicMock, patch
5
5
 
6
+ import sqlalchemy as sa
7
+
6
8
  import colander
7
9
  import deform
8
10
  from pyramid import testing
@@ -188,6 +190,18 @@ class TestForm(TestCase):
188
190
  self.assertIn('created', form.widgets)
189
191
  self.assertIsInstance(form.widgets['created'], MyWidget)
190
192
 
193
+ # mock up a table with all relevant column types
194
+ class Whatever(model.Base):
195
+ __tablename__ = 'whatever'
196
+ id = sa.Column(sa.Integer(), primary_key=True)
197
+ date = sa.Column(sa.Date())
198
+ date_time = sa.Column(sa.DateTime())
199
+
200
+ # widget set for all known types
201
+ form = self.make_form(model_class=Whatever)
202
+ self.assertIsInstance(form.widgets['date'], widgets.WuttaDateWidget)
203
+ self.assertIsInstance(form.widgets['date_time'], widgets.WuttaDateTimeWidget)
204
+
191
205
  def test_set_grid(self):
192
206
  form = self.make_form(fields=['foo', 'bar'])
193
207
  self.assertNotIn('foo', form.widgets)
@@ -87,6 +87,46 @@ class TestObjectRefWidget(WebTestCase):
87
87
  self.assertNotIn('url', values)
88
88
 
89
89
 
90
+ class TestWuttaDateWidget(WebTestCase):
91
+
92
+ def make_field(self, node, **kwargs):
93
+ # TODO: not sure why default renderer is in use even though
94
+ # pyramid_deform was included in setup? but this works..
95
+ kwargs.setdefault('renderer', deform.Form.default_renderer)
96
+ return deform.Field(node, **kwargs)
97
+
98
+ def make_widget(self, **kwargs):
99
+ return mod.WuttaDateWidget(self.request, **kwargs)
100
+
101
+ def test_serialize(self):
102
+ node = colander.SchemaNode(colander.Date())
103
+ field = self.make_field(node)
104
+
105
+ # first try normal date
106
+ widget = self.make_widget()
107
+ dt = datetime.date(2025, 1, 15)
108
+
109
+ # editable widget has normal picker html
110
+ result = widget.serialize(field, str(dt))
111
+ self.assertIn('<wutta-datepicker', result)
112
+
113
+ # readonly is rendered per app convention
114
+ result = widget.serialize(field, str(dt), readonly=True)
115
+ self.assertEqual(result, '2025-01-15')
116
+
117
+ # now try again with datetime
118
+ widget = self.make_widget()
119
+ dt = datetime.datetime(2025, 1, 15, 8, 35)
120
+
121
+ # editable widget has normal picker html
122
+ result = widget.serialize(field, str(dt))
123
+ self.assertIn('<wutta-datepicker', result)
124
+
125
+ # readonly is rendered per app convention
126
+ result = widget.serialize(field, str(dt), readonly=True)
127
+ self.assertEqual(result, '2025-01-15')
128
+
129
+
90
130
  class TestWuttaDateTimeWidget(WebTestCase):
91
131
 
92
132
  def make_field(self, node, **kwargs):
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