WuttaWeb 0.19.1__tar.gz → 0.19.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 (202) hide show
  1. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/CHANGELOG.md +10 -0
  2. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/PKG-INFO +1 -2
  3. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/pyproject.toml +1 -2
  4. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/forms/schema.py +16 -4
  5. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/forms/widgets.py +5 -36
  6. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/grids/base.py +23 -11
  7. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/base.mako +1 -1
  8. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/master.py +3 -0
  9. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/forms/test_schema.py +30 -6
  10. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/forms/test_widgets.py +0 -30
  11. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_master.py +32 -0
  12. wuttaweb-0.19.1/tests/views/__init__.py +0 -0
  13. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/.gitignore +0 -0
  14. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/COPYING.txt +0 -0
  15. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/README.md +0 -0
  16. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/Makefile +0 -0
  17. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/_static/.keepme +0 -0
  18. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.app.rst +0 -0
  19. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.auth.rst +0 -0
  20. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.cli.rst +0 -0
  21. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.cli.webapp.rst +0 -0
  22. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.conf.rst +0 -0
  23. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.db.continuum.rst +0 -0
  24. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.db.rst +0 -0
  25. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.db.sess.rst +0 -0
  26. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.emails.rst +0 -0
  27. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.forms.base.rst +0 -0
  28. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.forms.rst +0 -0
  29. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.forms.schema.rst +0 -0
  30. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.forms.widgets.rst +0 -0
  31. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.grids.base.rst +0 -0
  32. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.grids.filters.rst +0 -0
  33. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.grids.rst +0 -0
  34. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.handler.rst +0 -0
  35. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.helpers.rst +0 -0
  36. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.menus.rst +0 -0
  37. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.progress.rst +0 -0
  38. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.rst +0 -0
  39. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.static.rst +0 -0
  40. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.subscribers.rst +0 -0
  41. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.util.rst +0 -0
  42. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.auth.rst +0 -0
  43. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.base.rst +0 -0
  44. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.batch.rst +0 -0
  45. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.common.rst +0 -0
  46. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.email.rst +0 -0
  47. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.essential.rst +0 -0
  48. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.master.rst +0 -0
  49. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.people.rst +0 -0
  50. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.progress.rst +0 -0
  51. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.roles.rst +0 -0
  52. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.rst +0 -0
  53. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.settings.rst +0 -0
  54. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.upgrades.rst +0 -0
  55. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/api/wuttaweb.views.users.rst +0 -0
  56. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/conf.py +0 -0
  57. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/glossary.rst +0 -0
  58. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/index.rst +0 -0
  59. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/make.bat +0 -0
  60. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/narr/cli/builtin.rst +0 -0
  61. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/narr/cli/index.rst +0 -0
  62. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/narr/templates/base.rst +0 -0
  63. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/narr/templates/index.rst +0 -0
  64. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/narr/templates/lookup.rst +0 -0
  65. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/docs/narr/templates/overview.rst +0 -0
  66. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/__init__.py +0 -0
  67. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/_version.py +0 -0
  68. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/app.py +0 -0
  69. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/auth.py +0 -0
  70. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/cli/__init__.py +0 -0
  71. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/cli/webapp.py +0 -0
  72. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/conf.py +0 -0
  73. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/db/__init__.py +0 -0
  74. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/db/continuum.py +0 -0
  75. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/db/sess.py +0 -0
  76. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
  77. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
  78. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/emails.py +0 -0
  79. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/forms/__init__.py +0 -0
  80. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/forms/base.py +0 -0
  81. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/grids/__init__.py +0 -0
  82. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/grids/filters.py +0 -0
  83. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/handler.py +0 -0
  84. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/helpers.py +0 -0
  85. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/menus.py +0 -0
  86. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/progress.py +0 -0
  87. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/static/__init__.py +0 -0
  88. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/static/img/favicon.ico +0 -0
  89. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/static/img/logo.png +0 -0
  90. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/static/img/testing.png +0 -0
  91. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/subscribers.py +0 -0
  92. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
  93. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/appinfo/index.mako +0 -0
  94. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/auth/change_password.mako +0 -0
  95. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/auth/login.mako +0 -0
  96. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/base_meta.mako +0 -0
  97. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/batch/view.mako +0 -0
  98. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/configure.mako +0 -0
  99. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
  100. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
  101. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
  102. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
  103. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
  104. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
  105. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/password.pt +0 -0
  106. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/permissions.pt +0 -0
  107. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
  108. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
  109. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
  110. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
  111. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
  112. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
  113. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
  114. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/select.pt +0 -0
  115. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/textarea.pt +0 -0
  116. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/deform/textinput.pt +0 -0
  117. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/email/settings/view.mako +0 -0
  118. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/forbidden.mako +0 -0
  119. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/form.mako +0 -0
  120. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
  121. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/grids/table_element.mako +0 -0
  122. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/grids/vue_template.mako +0 -0
  123. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/home.mako +0 -0
  124. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/master/configure.mako +0 -0
  125. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/master/create.mako +0 -0
  126. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/master/delete.mako +0 -0
  127. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/master/edit.mako +0 -0
  128. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/master/form.mako +0 -0
  129. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/master/index.mako +0 -0
  130. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/master/view.mako +0 -0
  131. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/notfound.mako +0 -0
  132. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/page.mako +0 -0
  133. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/people/view_profile.mako +0 -0
  134. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/progress.mako +0 -0
  135. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/setup.mako +0 -0
  136. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/upgrade.mako +0 -0
  137. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
  138. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/upgrades/view.mako +0 -0
  139. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/templates/wutta-components.mako +0 -0
  140. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/testing.py +0 -0
  141. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/util.py +0 -0
  142. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/__init__.py +0 -0
  143. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/auth.py +0 -0
  144. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/base.py +0 -0
  145. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/batch.py +0 -0
  146. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/common.py +0 -0
  147. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/email.py +0 -0
  148. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/essential.py +0 -0
  149. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/people.py +0 -0
  150. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/progress.py +0 -0
  151. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/roles.py +0 -0
  152. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/settings.py +0 -0
  153. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/upgrades.py +0 -0
  154. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/src/wuttaweb/views/users.py +0 -0
  155. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tasks.py +0 -0
  156. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/__init__.py +0 -0
  157. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/cli/__init__.py +0 -0
  158. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/cli/test_webapp.py +0 -0
  159. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/db/__init__.py +0 -0
  160. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/db/test_continuum.py +0 -0
  161. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/forms/test_base.py +0 -0
  162. {wuttaweb-0.19.1/tests/forms → wuttaweb-0.19.2/tests/grids}/__init__.py +0 -0
  163. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/grids/test_base.py +0 -0
  164. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/grids/test_filters.py +0 -0
  165. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
  166. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
  167. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/bb_oruga.js +0 -0
  168. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/bb_oruga_bulma.css +0 -0
  169. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/bb_oruga_bulma.js +0 -0
  170. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/bb_vue.js +0 -0
  171. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/bb_vue_fontawesome.js +0 -0
  172. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/buefy.css +0 -0
  173. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/buefy.js +0 -0
  174. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/fontawesome.js +0 -0
  175. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/vue.js +0 -0
  176. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/libcache/vue_resource.js +0 -0
  177. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_app.py +0 -0
  178. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_auth.py +0 -0
  179. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_emails.py +0 -0
  180. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_handler.py +0 -0
  181. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_helpers.py +0 -0
  182. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_menus.py +0 -0
  183. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_progress.py +0 -0
  184. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_static.py +0 -0
  185. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_subscribers.py +0 -0
  186. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/test_util.py +0 -0
  187. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/util.py +0 -0
  188. {wuttaweb-0.19.1/tests/grids → wuttaweb-0.19.2/tests/views}/__init__.py +0 -0
  189. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test___init__.py +0 -0
  190. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_auth.py +0 -0
  191. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_base.py +0 -0
  192. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_batch.py +0 -0
  193. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_common.py +0 -0
  194. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_email.py +0 -0
  195. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_essential.py +0 -0
  196. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_people.py +0 -0
  197. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_progress.py +0 -0
  198. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_roles.py +0 -0
  199. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_settings.py +0 -0
  200. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_upgrades.py +0 -0
  201. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tests/views/test_users.py +0 -0
  202. {wuttaweb-0.19.1 → wuttaweb-0.19.2}/tox.ini +0 -0
@@ -5,6 +5,16 @@ 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.19.2 (2025-01-07)
9
+
10
+ ### Fix
11
+
12
+ - always use prop key for default grid filters
13
+ - avoid `request.current_route_url()` for user menu
14
+ - add `scale` kwarg for `WuttaMoney` schema type, widget
15
+ - make WuttaQuantity serialize w/ app handler, remove custom widget
16
+ - bugfix for bool simple settings with default value
17
+
8
18
  ## v0.19.1 (2025-01-06)
9
19
 
10
20
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: WuttaWeb
3
- Version: 0.19.1
3
+ Version: 0.19.2
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
@@ -37,7 +37,6 @@ Requires-Dist: pyramid-fanstatic
37
37
  Requires-Dist: pyramid-mako
38
38
  Requires-Dist: pyramid-tm
39
39
  Requires-Dist: pyramid>=2
40
- Requires-Dist: sqlalchemy-utils
41
40
  Requires-Dist: waitress
42
41
  Requires-Dist: webhelpers2
43
42
  Requires-Dist: wuttjamaican[db]>=0.19.2
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "WuttaWeb"
9
- version = "0.19.1"
9
+ version = "0.19.2"
10
10
  description = "Web App for Wutta Framework"
11
11
  readme = "README.md"
12
12
  authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
@@ -42,7 +42,6 @@ dependencies = [
42
42
  "pyramid_fanstatic",
43
43
  "pyramid_mako",
44
44
  "pyramid_tm",
45
- "SQLAlchemy-Utils",
46
45
  "waitress",
47
46
  "WebHelpers2",
48
47
  "WuttJamaican[db]>=0.19.2",
@@ -164,9 +164,13 @@ class WuttaMoney(colander.Money):
164
164
  by default.
165
165
 
166
166
  :param request: Current :term:`request` object.
167
+
168
+ :param scale: If this kwarg is specified, it will be passed along
169
+ to the widget constructor.
167
170
  """
168
171
 
169
172
  def __init__(self, request, *args, **kwargs):
173
+ self.scale = kwargs.pop('scale', None)
170
174
  super().__init__(*args, **kwargs)
171
175
  self.request = request
172
176
  self.config = self.request.wutta_config
@@ -174,6 +178,8 @@ class WuttaMoney(colander.Money):
174
178
 
175
179
  def widget_maker(self, **kwargs):
176
180
  """ """
181
+ if self.scale:
182
+ kwargs.setdefault('scale', self.scale)
177
183
  return widgets.WuttaMoneyInputWidget(self.request, **kwargs)
178
184
 
179
185
 
@@ -181,8 +187,9 @@ class WuttaQuantity(colander.Decimal):
181
187
  """
182
188
  Custom schema type for "quantity" fields.
183
189
 
184
- This is a subclass of :class:`colander:colander.Decimal` but uses
185
- :class:`~wuttaweb.forms.widgets.WuttaQuantityWidget` by default.
190
+ This is a subclass of :class:`colander:colander.Decimal` but will
191
+ serialize values via
192
+ :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_quantity()`.
186
193
 
187
194
  :param request: Current :term:`request` object.
188
195
  """
@@ -193,9 +200,14 @@ class WuttaQuantity(colander.Decimal):
193
200
  self.config = self.request.wutta_config
194
201
  self.app = self.config.get_app()
195
202
 
196
- def widget_maker(self, **kwargs):
203
+ def serialize(self, node, appstruct):
197
204
  """ """
198
- return widgets.WuttaQuantityWidget(self.request, **kwargs)
205
+ if appstruct in (colander.null, None):
206
+ return colander.null
207
+
208
+ # nb. we render as quantity here to avoid values like 12.0000,
209
+ # so we just show value like 12 instead
210
+ return self.app.render_quantity(appstruct)
199
211
 
200
212
 
201
213
  class WuttaSet(colander.Set):
@@ -206,45 +206,13 @@ class WuttaMoneyInputWidget(MoneyInputWidget):
206
206
  * ``moneyinput``
207
207
 
208
208
  :param request: Current :term:`request` object.
209
- """
210
-
211
- def __init__(self, request, *args, **kwargs):
212
- super().__init__(*args, **kwargs)
213
- self.request = request
214
- self.config = self.request.wutta_config
215
- self.app = self.config.get_app()
216
-
217
- def serialize(self, field, cstruct, **kw):
218
- """ """
219
- readonly = kw.get('readonly', self.readonly)
220
- if readonly:
221
- if cstruct in (colander.null, None):
222
- return HTML.tag('span')
223
- cstruct = decimal.Decimal(cstruct)
224
- return HTML.tag('span', c=[self.app.render_currency(cstruct)])
225
-
226
- return super().serialize(field, cstruct, **kw)
227
-
228
-
229
- class WuttaQuantityWidget(TextInputWidget):
230
- """
231
- Custom widget for "quantity" fields. This is used by default for
232
- :class:`~wuttaweb.forms.schema.WuttaQuantity` type nodes.
233
-
234
- The main purpose of this widget is to leverage
235
- :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_quantity()`
236
- for the readonly display.
237
209
 
238
- This is a subclass of
239
- :class:`deform:deform.widget.TextInputWidget` and uses these
240
- Deform templates:
241
-
242
- * ``textinput``
243
-
244
- :param request: Current :term:`request` object.
210
+ :param scale: If this kwarg is specified, it will be passed along
211
+ to ``render_currency()`` call.
245
212
  """
246
213
 
247
214
  def __init__(self, request, *args, **kwargs):
215
+ self.scale = kwargs.pop('scale', 2)
248
216
  super().__init__(*args, **kwargs)
249
217
  self.request = request
250
218
  self.config = self.request.wutta_config
@@ -257,7 +225,8 @@ class WuttaQuantityWidget(TextInputWidget):
257
225
  if cstruct in (colander.null, None):
258
226
  return HTML.tag('span')
259
227
  cstruct = decimal.Decimal(cstruct)
260
- return HTML.tag('span', c=[self.app.render_quantity(cstruct)])
228
+ text = self.app.render_currency(cstruct, scale=self.scale)
229
+ return HTML.tag('span', c=[text])
261
230
 
262
231
  return super().serialize(field, cstruct, **kw)
263
232
 
@@ -32,7 +32,6 @@ from collections import namedtuple, OrderedDict
32
32
 
33
33
  import sqlalchemy as sa
34
34
  from sqlalchemy import orm
35
- from sqlalchemy_utils import get_columns
36
35
 
37
36
  import paginate
38
37
  from paginate_sqlalchemy import SqlalchemyOrmPage
@@ -1147,16 +1146,29 @@ class Grid:
1147
1146
  filters = filters or {}
1148
1147
 
1149
1148
  if self.model_class:
1150
- # nb. i first tried self.get_model_columns() but my notes
1151
- # say that was too aggressive in many cases. then i tried
1152
- # using the *subset* of self.columns, just the ones which
1153
- # corresponded to a property on the model class. and now
1154
- # i am using sa-utils to give the "true" column list..
1155
- for col in get_columns(self.model_class):
1156
- if col.key in filters:
1157
- continue
1158
- prop = getattr(self.model_class, col.key)
1159
- filters[prop.key] = self.make_filter(prop)
1149
+
1150
+ # nb. i have found this confusing for some reason. some
1151
+ # things i've tried so far include:
1152
+ #
1153
+ # i first tried self.get_model_columns() but my notes say
1154
+ # that was too aggressive in many cases.
1155
+ #
1156
+ # then i tried using the *subset* of self.columns, just
1157
+ # the ones which correspond to a property on the model
1158
+ # class. but sometimes that skips filters we need.
1159
+ #
1160
+ # then i tried get_columns() from sa-utils to give the
1161
+ # "true" column list, but that fails when the underlying
1162
+ # column has different name than the prop/attr key.
1163
+ #
1164
+ # so now, we are looking directly at the sa mapper, for
1165
+ # all column attrs and then using the prop key.
1166
+
1167
+ inspector = sa.inspect(self.model_class)
1168
+ for prop in inspector.column_attrs:
1169
+ if prop.key not in filters:
1170
+ attr = getattr(self.model_class, prop.key)
1171
+ filters[prop.key] = self.make_filter(attr)
1160
1172
 
1161
1173
  return filters
1162
1174
 
@@ -659,7 +659,7 @@
659
659
  % if request.is_root:
660
660
  ${h.form(url('stop_root'), ref='stopBeingRootForm')}
661
661
  ${h.csrf_token(request)}
662
- <input type="hidden" name="referrer" value="${request.current_route_url()}" />
662
+ <input type="hidden" name="referrer" value="${request.url}" />
663
663
  <a @click="stopBeingRoot()"
664
664
  class="navbar-item has-background-danger has-text-white">
665
665
  Stop being root
@@ -1329,6 +1329,9 @@ class MasterView(View):
1329
1329
 
1330
1330
  if name in data:
1331
1331
  value = data[name]
1332
+ elif simple.get('type') is bool:
1333
+ # nb. bool false will be *missing* from data
1334
+ value = False
1332
1335
  else:
1333
1336
  value = simple.get('default')
1334
1337
 
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8; -*-
2
2
 
3
3
  import datetime
4
+ import decimal
4
5
  from unittest import TestCase
5
6
  from unittest.mock import patch
6
7
 
@@ -15,7 +16,7 @@ from wuttaweb.forms import widgets
15
16
  from wuttaweb.testing import DataTestCase, WebTestCase
16
17
 
17
18
 
18
- class TestWutaDateTime(TestCase):
19
+ class TestWuttaDateTime(TestCase):
19
20
 
20
21
  def test_deserialize(self):
21
22
  typ = mod.WuttaDateTime()
@@ -84,18 +85,41 @@ class TestWuttaMoney(WebTestCase):
84
85
 
85
86
  def test_widget_maker(self):
86
87
  enum = self.app.enum
88
+
89
+ # default scale
87
90
  typ = mod.WuttaMoney(self.request)
88
91
  widget = typ.widget_maker()
89
92
  self.assertIsInstance(widget, widgets.WuttaMoneyInputWidget)
93
+ self.assertEqual(widget.scale, 2)
94
+
95
+ # custom scale
96
+ typ = mod.WuttaMoney(self.request, scale=4)
97
+ widget = typ.widget_maker()
98
+ self.assertIsInstance(widget, widgets.WuttaMoneyInputWidget)
99
+ self.assertEqual(widget.scale, 4)
90
100
 
91
101
 
92
102
  class TestWuttaQuantity(WebTestCase):
93
103
 
94
- def test_widget_maker(self):
95
- enum = self.app.enum
96
- typ = mod.WuttaQuantity(self.request)
97
- widget = typ.widget_maker()
98
- self.assertIsInstance(widget, widgets.WuttaQuantityWidget)
104
+ def test_serialize(self):
105
+ node = colander.SchemaNode(mod.WuttaQuantity(self.request))
106
+ typ = node.typ
107
+
108
+ # null
109
+ result = typ.serialize(node, colander.null)
110
+ self.assertIs(result, colander.null)
111
+ result = typ.serialize(node, None)
112
+ self.assertIs(result, colander.null)
113
+
114
+ # quantity
115
+ result = typ.serialize(node, 42)
116
+ self.assertEqual(result, '42')
117
+ result = typ.serialize(node, 42.00)
118
+ self.assertEqual(result, '42')
119
+ result = typ.serialize(node, decimal.Decimal('42.00'))
120
+ self.assertEqual(result, '42')
121
+ result = typ.serialize(node, 42.13)
122
+ self.assertEqual(result, '42.13')
99
123
 
100
124
 
101
125
  class TestObjectRef(DataTestCase):
@@ -143,36 +143,6 @@ class TestWuttaMoneyInputWidget(WebTestCase):
143
143
  self.assertEqual(result, '<span></span>')
144
144
 
145
145
 
146
- class TestWuttaQuantityWidget(WebTestCase):
147
-
148
- def make_field(self, node, **kwargs):
149
- # TODO: not sure why default renderer is in use even though
150
- # pyramid_deform was included in setup? but this works..
151
- kwargs.setdefault('renderer', deform.Form.default_renderer)
152
- return deform.Field(node, **kwargs)
153
-
154
- def make_widget(self, **kwargs):
155
- return mod.WuttaQuantityWidget(self.request, **kwargs)
156
-
157
- def test_serialize(self):
158
- node = colander.SchemaNode(schema.WuttaQuantity(self.request))
159
- field = self.make_field(node)
160
- widget = self.make_widget()
161
- amount = decimal.Decimal('42.00')
162
-
163
- # editable widget has normal text input
164
- result = widget.serialize(field, str(amount))
165
- self.assertIn('<b-input', result)
166
-
167
- # readonly is rendered per app convention
168
- result = widget.serialize(field, str(amount), readonly=True)
169
- self.assertEqual(result, '<span>42</span>')
170
-
171
- # readonly w/ null value
172
- result = widget.serialize(field, None, readonly=True)
173
- self.assertEqual(result, '<span></span>')
174
-
175
-
176
146
  class TestFileDownloadWidget(WebTestCase):
177
147
 
178
148
  def make_field(self, node, **kwargs):
@@ -1565,6 +1565,38 @@ class TestMasterView(WebTestCase):
1565
1565
  count = self.session.query(model.Setting).count()
1566
1566
  self.assertEqual(count, 0)
1567
1567
 
1568
+ def test_configure_gather_settings(self):
1569
+ view = self.make_view()
1570
+
1571
+ simple_settings = [
1572
+ {'name': 'wutta.app_title'},
1573
+ {'name': 'wutta.foo'},
1574
+ {'name': 'wutta.flag', 'type': bool, 'default': True},
1575
+ {'name': 'wutta.number', 'type': int, 'default': 42},
1576
+ {'name': 'wutta.value1', 'save_if_empty': True},
1577
+ {'name': 'wutta.value2', 'save_if_empty': False},
1578
+ {'name': 'wutta.value3', 'save_if_empty': False, 'default': 'baz'},
1579
+ ]
1580
+
1581
+ data = {
1582
+ 'wutta.app_title': 'Poser',
1583
+ 'wutta.foo': 'bar',
1584
+ 'wutta.number': 44,
1585
+ 'wutta.value1': None,
1586
+ }
1587
+
1588
+ with patch.object(view, 'configure_get_simple_settings', return_value=simple_settings):
1589
+ settings = view.configure_gather_settings(data)
1590
+ self.assertEqual(len(settings), 6)
1591
+ self.assertEqual(settings, [
1592
+ {'name': 'wutta.app_title', 'value': 'Poser'},
1593
+ {'name': 'wutta.foo', 'value': 'bar'},
1594
+ {'name': 'wutta.flag', 'value': 'false'},
1595
+ {'name': 'wutta.number', 'value': '44'},
1596
+ {'name': 'wutta.value1', 'value': ''},
1597
+ {'name': 'wutta.value3', 'value': 'baz'},
1598
+ ])
1599
+
1568
1600
  ##############################
1569
1601
  # row methods
1570
1602
  ##############################
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes