WuttaWeb 0.20.1__tar.gz → 0.20.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 (205) hide show
  1. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/CHANGELOG.md +9 -0
  2. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/PKG-INFO +1 -1
  3. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/pyproject.toml +1 -1
  4. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/grids/base.py +33 -5
  5. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/base.mako +1 -1
  6. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/grids/vue_template.mako +3 -0
  7. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/master.py +31 -10
  8. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/grids/test_base.py +27 -1
  9. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_master.py +23 -0
  10. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/.gitignore +0 -0
  11. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/COPYING.txt +0 -0
  12. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/README.md +0 -0
  13. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/Makefile +0 -0
  14. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/_static/.keepme +0 -0
  15. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.app.rst +0 -0
  16. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.auth.rst +0 -0
  17. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.cli.rst +0 -0
  18. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.cli.webapp.rst +0 -0
  19. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.conf.rst +0 -0
  20. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.db.continuum.rst +0 -0
  21. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.db.rst +0 -0
  22. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.db.sess.rst +0 -0
  23. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.emails.rst +0 -0
  24. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.forms.base.rst +0 -0
  25. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.forms.rst +0 -0
  26. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.forms.schema.rst +0 -0
  27. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.forms.widgets.rst +0 -0
  28. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.grids.base.rst +0 -0
  29. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.grids.filters.rst +0 -0
  30. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.grids.rst +0 -0
  31. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.handler.rst +0 -0
  32. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.helpers.rst +0 -0
  33. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.menus.rst +0 -0
  34. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.progress.rst +0 -0
  35. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.rst +0 -0
  36. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.static.rst +0 -0
  37. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.subscribers.rst +0 -0
  38. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.util.rst +0 -0
  39. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.auth.rst +0 -0
  40. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.base.rst +0 -0
  41. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.batch.rst +0 -0
  42. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.common.rst +0 -0
  43. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.email.rst +0 -0
  44. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.essential.rst +0 -0
  45. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.master.rst +0 -0
  46. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.people.rst +0 -0
  47. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.progress.rst +0 -0
  48. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.reports.rst +0 -0
  49. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.roles.rst +0 -0
  50. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.rst +0 -0
  51. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.settings.rst +0 -0
  52. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.upgrades.rst +0 -0
  53. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/api/wuttaweb.views.users.rst +0 -0
  54. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/conf.py +0 -0
  55. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/glossary.rst +0 -0
  56. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/index.rst +0 -0
  57. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/make.bat +0 -0
  58. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/narr/cli/builtin.rst +0 -0
  59. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/narr/cli/index.rst +0 -0
  60. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/narr/templates/base.rst +0 -0
  61. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/narr/templates/index.rst +0 -0
  62. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/narr/templates/lookup.rst +0 -0
  63. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/docs/narr/templates/overview.rst +0 -0
  64. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/__init__.py +0 -0
  65. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/_version.py +0 -0
  66. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/app.py +0 -0
  67. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/auth.py +0 -0
  68. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/cli/__init__.py +0 -0
  69. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/cli/webapp.py +0 -0
  70. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/conf.py +0 -0
  71. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/db/__init__.py +0 -0
  72. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/db/continuum.py +0 -0
  73. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/db/sess.py +0 -0
  74. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
  75. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
  76. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/emails.py +0 -0
  77. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/forms/__init__.py +0 -0
  78. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/forms/base.py +0 -0
  79. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/forms/schema.py +0 -0
  80. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/forms/widgets.py +0 -0
  81. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/grids/__init__.py +0 -0
  82. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/grids/filters.py +0 -0
  83. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/handler.py +0 -0
  84. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/helpers.py +0 -0
  85. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/menus.py +0 -0
  86. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/progress.py +0 -0
  87. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/static/__init__.py +0 -0
  88. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/static/img/favicon.ico +0 -0
  89. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/static/img/logo.png +0 -0
  90. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/static/img/testing.png +0 -0
  91. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/subscribers.py +0 -0
  92. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
  93. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/appinfo/index.mako +0 -0
  94. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/auth/change_password.mako +0 -0
  95. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/auth/login.mako +0 -0
  96. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/base_meta.mako +0 -0
  97. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/batch/view.mako +0 -0
  98. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/configure.mako +0 -0
  99. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
  100. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
  101. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
  102. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
  103. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
  104. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
  105. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/password.pt +0 -0
  106. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/permissions.pt +0 -0
  107. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
  108. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
  109. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
  110. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
  111. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
  112. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
  113. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
  114. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/select.pt +0 -0
  115. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/textarea.pt +0 -0
  116. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/deform/textinput.pt +0 -0
  117. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/email/settings/view.mako +0 -0
  118. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/forbidden.mako +0 -0
  119. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/form.mako +0 -0
  120. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
  121. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/grids/table_element.mako +0 -0
  122. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/home.mako +0 -0
  123. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/master/configure.mako +0 -0
  124. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/master/create.mako +0 -0
  125. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/master/delete.mako +0 -0
  126. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/master/edit.mako +0 -0
  127. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/master/form.mako +0 -0
  128. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/master/index.mako +0 -0
  129. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/master/view.mako +0 -0
  130. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/notfound.mako +0 -0
  131. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/page.mako +0 -0
  132. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/people/view_profile.mako +0 -0
  133. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/progress.mako +0 -0
  134. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/reports/view.mako +0 -0
  135. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/setup.mako +0 -0
  136. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/upgrade.mako +0 -0
  137. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
  138. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/upgrades/view.mako +0 -0
  139. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/templates/wutta-components.mako +0 -0
  140. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/testing.py +0 -0
  141. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/util.py +0 -0
  142. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/__init__.py +0 -0
  143. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/auth.py +0 -0
  144. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/base.py +0 -0
  145. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/batch.py +0 -0
  146. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/common.py +0 -0
  147. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/email.py +0 -0
  148. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/essential.py +0 -0
  149. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/people.py +0 -0
  150. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/progress.py +0 -0
  151. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/reports.py +0 -0
  152. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/roles.py +0 -0
  153. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/settings.py +0 -0
  154. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/upgrades.py +0 -0
  155. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/src/wuttaweb/views/users.py +0 -0
  156. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tasks.py +0 -0
  157. {wuttaweb-0.20.1/tests/views → wuttaweb-0.20.2/tests}/__init__.py +0 -0
  158. {wuttaweb-0.20.1/tests/grids → wuttaweb-0.20.2/tests/cli}/__init__.py +0 -0
  159. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/cli/test_webapp.py +0 -0
  160. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/db/__init__.py +0 -0
  161. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/db/test_continuum.py +0 -0
  162. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/forms/test_base.py +0 -0
  163. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/forms/test_schema.py +0 -0
  164. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/forms/test_widgets.py +0 -0
  165. {wuttaweb-0.20.1/tests/cli → wuttaweb-0.20.2/tests/grids}/__init__.py +0 -0
  166. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/grids/test_filters.py +0 -0
  167. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
  168. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
  169. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/bb_oruga.js +0 -0
  170. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/bb_oruga_bulma.css +0 -0
  171. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/bb_oruga_bulma.js +0 -0
  172. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/bb_vue.js +0 -0
  173. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/bb_vue_fontawesome.js +0 -0
  174. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/buefy.css +0 -0
  175. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/buefy.js +0 -0
  176. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/fontawesome.js +0 -0
  177. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/vue.js +0 -0
  178. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/libcache/vue_resource.js +0 -0
  179. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_app.py +0 -0
  180. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_auth.py +0 -0
  181. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_emails.py +0 -0
  182. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_handler.py +0 -0
  183. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_helpers.py +0 -0
  184. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_menus.py +0 -0
  185. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_progress.py +0 -0
  186. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_static.py +0 -0
  187. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_subscribers.py +0 -0
  188. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/test_util.py +0 -0
  189. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/util.py +0 -0
  190. {wuttaweb-0.20.1/tests → wuttaweb-0.20.2/tests/views}/__init__.py +0 -0
  191. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test___init__.py +0 -0
  192. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_auth.py +0 -0
  193. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_base.py +0 -0
  194. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_batch.py +0 -0
  195. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_common.py +0 -0
  196. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_email.py +0 -0
  197. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_essential.py +0 -0
  198. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_people.py +0 -0
  199. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_progress.py +0 -0
  200. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_reports.py +0 -0
  201. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_roles.py +0 -0
  202. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_settings.py +0 -0
  203. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_upgrades.py +0 -0
  204. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tests/views/test_users.py +0 -0
  205. {wuttaweb-0.20.1 → wuttaweb-0.20.2}/tox.ini +0 -0
@@ -5,6 +5,15 @@ 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.2 (2025-01-14)
9
+
10
+ ### Fix
11
+
12
+ - improve support for composite `model_key` in MasterView
13
+ - let content header text be a bit longer
14
+ - add optional `target` attr for GridAction
15
+ - add `render_date()` method for grids
16
+
8
17
  ## v0.20.1 (2025-01-13)
9
18
 
10
19
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: WuttaWeb
3
- Version: 0.20.1
3
+ Version: 0.20.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
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "WuttaWeb"
9
- version = "0.20.1"
9
+ version = "0.20.2"
10
10
  description = "Web App for Wutta Framework"
11
11
  readme = "README.md"
12
12
  authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
@@ -602,6 +602,7 @@ class Grid:
602
602
  * ``'batch_id'`` -> :meth:`render_batch_id()`
603
603
  * ``'boolean'`` -> :meth:`render_boolean()`
604
604
  * ``'currency'`` -> :meth:`render_currency()`
605
+ * ``'date'`` -> :meth:`render_date()`
605
606
  * ``'datetime'`` -> :meth:`render_datetime()`
606
607
  * ``'quantity'`` -> :meth:`render_quantity()`
607
608
 
@@ -611,6 +612,7 @@ class Grid:
611
612
  'batch_id': self.render_batch_id,
612
613
  'boolean': self.render_boolean,
613
614
  'currency': self.render_currency,
615
+ 'date': self.render_date,
614
616
  'datetime': self.render_datetime,
615
617
  'quantity': self.render_quantity,
616
618
  }
@@ -631,11 +633,13 @@ class Grid:
631
633
  data type implies a default renderer. This is only possible
632
634
  if :attr:`model_class` is set to a SQLAlchemy mapped class.
633
635
 
634
- This only looks for a couple of data types, and configures as
636
+ This only looks for a few data types, and configures as
635
637
  follows:
636
638
 
637
639
  * :class:`sqlalchemy:sqlalchemy.types.Boolean` ->
638
640
  :meth:`render_boolean()`
641
+ * :class:`sqlalchemy:sqlalchemy.types.Date` ->
642
+ :meth:`render_date()`
639
643
  * :class:`sqlalchemy:sqlalchemy.types.DateTime` ->
640
644
  :meth:`render_datetime()`
641
645
  """
@@ -651,7 +655,9 @@ class Grid:
651
655
  prop = getattr(attr, 'prop', None)
652
656
  if prop and isinstance(prop, orm.ColumnProperty):
653
657
  column = prop.columns[0]
654
- if isinstance(column.type, sa.DateTime):
658
+ if isinstance(column.type, sa.Date):
659
+ self.set_renderer(key, self.render_date)
660
+ elif isinstance(column.type, sa.DateTime):
655
661
  self.set_renderer(key, self.render_datetime)
656
662
  elif isinstance(column.type, sa.Boolean):
657
663
  self.set_renderer(key, self.render_boolean)
@@ -1820,7 +1826,7 @@ class Grid:
1820
1826
  This may be used automatically per
1821
1827
  :meth:`set_default_renderers()` or you can use it explicitly::
1822
1828
 
1823
- grid.set_renderer('foo', grid.render_boolean)
1829
+ grid.set_renderer('foo', 'boolean')
1824
1830
  """
1825
1831
  return self.app.render_boolean(value)
1826
1832
 
@@ -1839,6 +1845,22 @@ class Grid:
1839
1845
  """
1840
1846
  return self.app.render_currency(value, **kwargs)
1841
1847
 
1848
+ def render_date(self, obj, key, value):
1849
+ """
1850
+ Column renderer for :class:`python:datetime.date` values.
1851
+
1852
+ This calls
1853
+ :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_date()`
1854
+ for the return value.
1855
+
1856
+ This may be used automatically per
1857
+ :meth:`set_default_renderers()` or you can use it explicitly::
1858
+
1859
+ grid.set_renderer('foo', 'date')
1860
+ """
1861
+ dt = getattr(obj, key)
1862
+ return self.app.render_date(dt)
1863
+
1842
1864
  def render_datetime(self, obj, key, value):
1843
1865
  """
1844
1866
  Column renderer for :class:`python:datetime.datetime` values.
@@ -1850,7 +1872,7 @@ class Grid:
1850
1872
  This may be used automatically per
1851
1873
  :meth:`set_default_renderers()` or you can use it explicitly::
1852
1874
 
1853
- grid.set_renderer('foo', grid.render_datetime)
1875
+ grid.set_renderer('foo', 'datetime')
1854
1876
  """
1855
1877
  dt = getattr(obj, key)
1856
1878
  return self.app.render_datetime(dt)
@@ -1865,7 +1887,7 @@ class Grid:
1865
1887
 
1866
1888
  This is not used automatically but you can use it explicitly::
1867
1889
 
1868
- grid.set_renderer('foo', grid.render_quantity)
1890
+ grid.set_renderer('foo', 'quantity')
1869
1891
  """
1870
1892
  return self.app.render_quantity(value)
1871
1893
 
@@ -2258,6 +2280,10 @@ class GridAction:
2258
2280
 
2259
2281
  See also :meth:`get_url()`.
2260
2282
 
2283
+ .. attribute:: target
2284
+
2285
+ Optional ``target`` attribute for the ``<a>`` tag.
2286
+
2261
2287
  .. attribute:: icon
2262
2288
 
2263
2289
  Name of icon to be shown for the action link.
@@ -2275,6 +2301,7 @@ class GridAction:
2275
2301
  key,
2276
2302
  label=None,
2277
2303
  url=None,
2304
+ target=None,
2278
2305
  icon=None,
2279
2306
  link_class=None,
2280
2307
  ):
@@ -2283,6 +2310,7 @@ class GridAction:
2283
2310
  self.app = self.config.get_app()
2284
2311
  self.key = key
2285
2312
  self.url = url
2313
+ self.target = target
2286
2314
  self.label = label or self.app.make_title(key)
2287
2315
  self.icon = icon or key
2288
2316
  self.link_class = link_class or ''
@@ -155,7 +155,7 @@
155
155
  }
156
156
 
157
157
  #content-title h1 {
158
- max-width: 80%;
158
+ max-width: 85%;
159
159
  overflow: hidden;
160
160
  padding-left: 0.5rem;
161
161
  text-overflow: ellipsis;
@@ -180,6 +180,9 @@
180
180
  % for action in grid.actions:
181
181
  <a v-if="props.row._action_url_${action.key}"
182
182
  :href="props.row._action_url_${action.key}"
183
+ % if action.target:
184
+ target="${action.target}"
185
+ % endif
183
186
  class="${action.link_class}">
184
187
  ${action.render_icon_and_label()}
185
188
  </a>
@@ -2176,6 +2176,28 @@ class MasterView(View):
2176
2176
  """
2177
2177
  return str(instance) or "(no title)"
2178
2178
 
2179
+ def get_action_route_kwargs(self, obj):
2180
+ """
2181
+ Get a dict of route kwargs for the given object.
2182
+
2183
+ This is called from :meth:`get_action_url()` and must return
2184
+ kwargs suitable for use with ``request.route_url()``.
2185
+
2186
+ In practice this should return a dict which has keys for each
2187
+ field from :meth:`get_model_key()` and values which come from
2188
+ the object.
2189
+
2190
+ :param obj: Model instance object.
2191
+
2192
+ :returns: The dict of route kwargs for the object.
2193
+ """
2194
+ try:
2195
+ return dict([(key, obj[key])
2196
+ for key in self.get_model_key()])
2197
+ except TypeError:
2198
+ return dict([(key, getattr(obj, key))
2199
+ for key in self.get_model_key()])
2200
+
2179
2201
  def get_action_url(self, action, obj, **kwargs):
2180
2202
  """
2181
2203
  Generate an "action" URL for the given model instance.
@@ -2183,22 +2205,21 @@ class MasterView(View):
2183
2205
  This is a shortcut which generates a route name based on
2184
2206
  :meth:`get_route_prefix()` and the ``action`` param.
2185
2207
 
2186
- It returns the URL based on generated route name and object's
2187
- model key values.
2208
+ It calls :meth:`get_action_route_kwargs()` and then passes
2209
+ those along with route name to ``request.route_url()``, and
2210
+ returns the result.
2188
2211
 
2189
2212
  :param action: String name for the action, which corresponds
2190
2213
  to part of some named route, e.g. ``'view'`` or ``'edit'``.
2191
2214
 
2192
2215
  :param obj: Model instance object.
2216
+
2217
+ :param \**kwargs: Additional kwargs to be passed to
2218
+ ``request.route_url()``, if needed.
2193
2219
  """
2194
- route_prefix = self.get_route_prefix()
2195
- try:
2196
- kw = dict([(key, obj[key])
2197
- for key in self.get_model_key()])
2198
- except TypeError:
2199
- kw = dict([(key, getattr(obj, key))
2200
- for key in self.get_model_key()])
2220
+ kw = self.get_action_route_kwargs(obj)
2201
2221
  kw.update(kwargs)
2222
+ route_prefix = self.get_route_prefix()
2202
2223
  return self.request.route_url(f'{route_prefix}.{action}', **kw)
2203
2224
 
2204
2225
  def get_action_url_view(self, obj, i):
@@ -2729,7 +2750,7 @@ class MasterView(View):
2729
2750
  inspector = sa.inspect(model_class)
2730
2751
  keys = [col.name for col in inspector.primary_key]
2731
2752
  return tuple([prop.key for prop in inspector.column_attrs
2732
- if [col.name for col in prop.columns] == keys])
2753
+ if all([col.name in keys for col in prop.columns])])
2733
2754
 
2734
2755
  raise AttributeError(f"you must define model_key for view class: {cls}")
2735
2756
 
@@ -213,7 +213,7 @@ class TestGrid(WebTestCase):
213
213
  obj = MagicMock(foo=42.00)
214
214
  self.assertEqual(grid.renderers['foo'](obj, 'foo', 42.00), '42')
215
215
 
216
- def test_set_default_renderer(self):
216
+ def test_set_default_renderers(self):
217
217
  model = self.app.model
218
218
 
219
219
  # no defaults for "plain" schema
@@ -249,6 +249,18 @@ class TestGrid(WebTestCase):
249
249
  self.assertIn('executing', grid.renderers)
250
250
  self.assertIs(grid.renderers['executing'], myrender)
251
251
 
252
+ # nb. as of writing we have no Date columns in default schema,
253
+ # so must invent one to test that type
254
+ class SomeFoolery(model.Base):
255
+ __tablename__ = 'somefoolery'
256
+ id = sa.Column(sa.Integer(), primary_key=True)
257
+ created = sa.Column(sa.Date())
258
+
259
+ # renderer set for date mapped field
260
+ grid = self.make_grid(model_class=SomeFoolery)
261
+ self.assertIn('created', grid.renderers)
262
+ self.assertIsNot(grid.renderers['created'], myrender)
263
+
252
264
  def test_linked_columns(self):
253
265
  grid = self.make_grid(columns=['foo', 'bar'])
254
266
  self.assertEqual(grid.linked_columns, [])
@@ -1415,6 +1427,20 @@ class TestGrid(WebTestCase):
1415
1427
  # zero is *not* empty string (with this renderer)
1416
1428
  self.assertEqual(grid.render_quantity(obj, 'foo', 0), "0")
1417
1429
 
1430
+ def test_render_date(self):
1431
+ grid = self.make_grid(columns=['foo', 'bar'])
1432
+
1433
+ # null
1434
+ obj = MagicMock(dt=None)
1435
+ result = grid.render_date(obj, 'dt', None)
1436
+ self.assertIsNone(result)
1437
+
1438
+ # typical
1439
+ dt = datetime.date(2025, 1, 13)
1440
+ obj = MagicMock(dt=dt)
1441
+ result = grid.render_date(obj, 'dt', str(dt))
1442
+ self.assertEqual(result, '2025-01-13')
1443
+
1418
1444
  def test_render_datetime(self):
1419
1445
  grid = self.make_grid(columns=['foo', 'bar'])
1420
1446
 
@@ -750,6 +750,29 @@ class TestMasterView(WebTestCase):
750
750
  self.request.matchdict = {'name': 'blarg'}
751
751
  self.assertRaises(HTTPNotFound, view.get_instance, session=self.session)
752
752
 
753
+ def test_get_action_route_kwargs(self):
754
+ model = self.app.model
755
+ with patch.object(mod.MasterView, 'model_class', new=model.Setting, create=True):
756
+ view = self.make_view()
757
+
758
+ # dict object
759
+ setting = {'name': 'foo', 'value': 'bar'}
760
+ kw = view.get_action_route_kwargs(setting)
761
+ self.assertEqual(kw, {'name': 'foo'})
762
+
763
+ # mapped object
764
+ setting = model.Setting(name='foo', value='bar')
765
+ kw = view.get_action_route_kwargs(setting)
766
+ self.assertEqual(kw, {'name': 'foo'})
767
+
768
+ # non-standard object
769
+ class MySetting:
770
+ def __init__(self, **kw):
771
+ self.__dict__.update(kw)
772
+ setting = MySetting(name='foo', value='bar')
773
+ kw = view.get_action_route_kwargs(setting)
774
+ self.assertEqual(kw, {'name': 'foo'})
775
+
753
776
  def test_get_action_url_for_dict(self):
754
777
  model = self.app.model
755
778
  setting = {'name': 'foo', 'value': 'bar'}
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