WuttaWeb 0.20.3__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.
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/CHANGELOG.md +7 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/PKG-INFO +1 -1
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/pyproject.toml +1 -1
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/forms/base.py +10 -6
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/forms/schema.py +16 -3
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/forms/widgets.py +39 -1
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/forms/test_base.py +14 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/forms/test_widgets.py +40 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/.gitignore +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/COPYING.txt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/README.md +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/Makefile +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/_static/.keepme +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.app.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.auth.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.cli.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.cli.webapp.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.conf.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.db.continuum.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.db.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.db.sess.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.emails.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.base.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.schema.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.forms.widgets.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.grids.base.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.grids.filters.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.grids.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.handler.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.helpers.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.menus.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.progress.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.static.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.subscribers.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.util.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.auth.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.base.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.batch.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.common.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.email.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.essential.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.master.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.people.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.progress.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.reports.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.roles.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.settings.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.upgrades.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/api/wuttaweb.views.users.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/conf.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/glossary.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/index.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/make.bat +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/narr/cli/builtin.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/narr/cli/index.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/narr/templates/base.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/narr/templates/index.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/narr/templates/lookup.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/docs/narr/templates/overview.rst +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/_version.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/app.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/auth.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/cli/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/cli/webapp.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/conf.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/db/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/db/continuum.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/db/sess.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/emails.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/forms/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/grids/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/grids/base.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/grids/filters.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/handler.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/helpers.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/menus.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/progress.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/static/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/static/img/favicon.ico +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/static/img/logo.png +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/static/img/testing.png +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/subscribers.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/appinfo/index.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/auth/change_password.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/auth/login.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/base.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/base_meta.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/batch/view.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/configure.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/password.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/permissions.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/select.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/textarea.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/deform/textinput.pt +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/email/settings/view.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/forbidden.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/form.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/grids/table_element.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/grids/vue_template.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/home.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/configure.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/create.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/delete.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/edit.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/form.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/index.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/master/view.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/notfound.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/page.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/people/view_profile.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/progress.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/reports/view.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/setup.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/upgrade.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/upgrades/view.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/templates/wutta-components.mako +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/testing.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/util.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/auth.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/base.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/batch.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/common.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/email.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/essential.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/master.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/people.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/progress.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/reports.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/roles.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/settings.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/upgrades.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/src/wuttaweb/views/users.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tasks.py +0 -0
- {wuttaweb-0.20.3/tests/views → wuttaweb-0.20.4/tests}/__init__.py +0 -0
- {wuttaweb-0.20.3/tests/grids → wuttaweb-0.20.4/tests/cli}/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/cli/test_webapp.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/db/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/db/test_continuum.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/forms/test_schema.py +0 -0
- {wuttaweb-0.20.3/tests/cli → wuttaweb-0.20.4/tests/grids}/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/grids/test_base.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/grids/test_filters.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/bb_oruga.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/bb_oruga_bulma.css +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/bb_oruga_bulma.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/bb_vue.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/bb_vue_fontawesome.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/buefy.css +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/buefy.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/fontawesome.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/vue.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/libcache/vue_resource.js +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_app.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_auth.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_emails.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_handler.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_helpers.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_menus.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_progress.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_static.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_subscribers.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/test_util.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/util.py +0 -0
- {wuttaweb-0.20.3/tests → wuttaweb-0.20.4/tests/views}/__init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test___init__.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_auth.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_base.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_batch.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_common.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_email.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_essential.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_master.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_people.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_progress.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_reports.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_roles.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_settings.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_upgrades.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tests/views/test_users.py +0 -0
- {wuttaweb-0.20.3 → wuttaweb-0.20.4}/tox.ini +0 -0
|
@@ -5,6 +5,13 @@ 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
|
+
|
|
8
15
|
## v0.20.3 (2025-01-14)
|
|
9
16
|
|
|
10
17
|
### Fix
|
|
@@ -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
|
-
|
|
550
|
-
:
|
|
551
|
-
|
|
552
|
-
:class
|
|
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.
|
|
569
|
-
|
|
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
|
|
338
|
-
return appstruct
|
|
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
|
|
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.
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|