WuttaWeb 0.17.2__tar.gz → 0.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/CHANGELOG.md +7 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/PKG-INFO +4 -2
- wuttaweb-0.18.0/docs/api/wuttaweb.cli.rst +6 -0
- wuttaweb-0.18.0/docs/api/wuttaweb.cli.webapp.rst +6 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/conf.py +1 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/index.rst +3 -0
- wuttaweb-0.18.0/docs/narr/cli/builtin.rst +28 -0
- wuttaweb-0.18.0/docs/narr/cli/index.rst +14 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/pyproject.toml +7 -6
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/app.py +99 -24
- wuttaweb-0.18.0/src/wuttaweb/cli/__init__.py +28 -0
- wuttaweb-0.18.0/src/wuttaweb/cli/webapp.py +88 -0
- wuttaweb-0.18.0/tests/cli/test_webapp.py +104 -0
- wuttaweb-0.18.0/tests/test_app.py +131 -0
- wuttaweb-0.18.0/tests/views/__init__.py +0 -0
- wuttaweb-0.17.2/tests/test_app.py +0 -61
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/.gitignore +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/COPYING.txt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/README.md +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/Makefile +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/_static/.keepme +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.app.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.auth.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.conf.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.db.continuum.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.db.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.db.sess.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.forms.base.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.forms.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.forms.schema.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.forms.widgets.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.grids.base.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.grids.filters.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.grids.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.handler.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.helpers.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.menus.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.progress.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.static.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.subscribers.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.util.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.auth.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.base.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.batch.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.common.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.essential.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.master.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.people.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.progress.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.roles.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.settings.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.upgrades.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/api/wuttaweb.views.users.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/glossary.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/make.bat +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/narr/templates/base.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/narr/templates/index.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/narr/templates/lookup.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/docs/narr/templates/overview.rst +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/_version.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/auth.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/conf.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/db/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/db/continuum.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/db/sess.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/email/templates/feedback.html.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/email/templates/feedback.txt.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/forms/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/forms/base.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/forms/schema.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/forms/widgets.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/grids/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/grids/base.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/grids/filters.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/handler.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/helpers.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/menus.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/progress.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/static/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/static/img/favicon.ico +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/static/img/logo.png +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/static/img/testing.png +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/subscribers.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/appinfo/index.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/auth/change_password.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/auth/login.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/base.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/base_meta.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/batch/view.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/configure.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/password.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/permissions.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/select.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/textarea.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/deform/textinput.pt +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/forbidden.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/form.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/grids/table_element.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/grids/vue_template.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/home.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/master/configure.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/master/create.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/master/delete.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/master/edit.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/master/form.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/master/index.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/master/view.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/notfound.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/page.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/people/view_profile.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/progress.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/setup.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/upgrade.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/upgrades/view.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/templates/wutta-components.mako +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/util.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/auth.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/base.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/batch.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/common.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/essential.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/master.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/people.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/progress.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/roles.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/settings.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/upgrades.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/src/wuttaweb/views/users.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tasks.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/__init__.py +0 -0
- {wuttaweb-0.17.2/tests/db → wuttaweb-0.18.0/tests/cli}/__init__.py +0 -0
- {wuttaweb-0.17.2/tests/forms → wuttaweb-0.18.0/tests/db}/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/db/test_continuum.py +0 -0
- {wuttaweb-0.17.2/tests/grids → wuttaweb-0.18.0/tests/forms}/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/forms/test_base.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/forms/test_schema.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/forms/test_widgets.py +0 -0
- {wuttaweb-0.17.2/tests/views → wuttaweb-0.18.0/tests/grids}/__init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/grids/test_base.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/grids/test_filters.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/bb_oruga.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/bb_oruga_bulma.css +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/bb_oruga_bulma.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/bb_vue.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/bb_vue_fontawesome.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/buefy.css +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/buefy.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/fontawesome.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/vue.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/libcache/vue_resource.js +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_auth.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_handler.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_helpers.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_menus.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_progress.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_static.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_subscribers.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/test_util.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/util.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test___init__.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_auth.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_base.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_batch.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_common.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_master.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_people.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_progress.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_roles.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_settings.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_upgrades.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/tests/views/test_users.py +0 -0
- {wuttaweb-0.17.2 → wuttaweb-0.18.0}/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.18.0 (2024-12-18)
|
|
9
|
+
|
|
10
|
+
### Feat
|
|
11
|
+
|
|
12
|
+
- add basic support for running in ASGI context
|
|
13
|
+
- add support for running via uvicorn; `wutta webapp` command
|
|
14
|
+
|
|
8
15
|
## v0.17.2 (2024-12-17)
|
|
9
16
|
|
|
10
17
|
### Fix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: WuttaWeb
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.0
|
|
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
|
|
@@ -25,6 +25,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
25
25
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
26
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
27
|
Requires-Python: >=3.8
|
|
28
|
+
Requires-Dist: asgiref
|
|
28
29
|
Requires-Dist: colanderalchemy
|
|
29
30
|
Requires-Dist: humanize
|
|
30
31
|
Requires-Dist: markdown
|
|
@@ -38,13 +39,14 @@ Requires-Dist: pyramid-tm
|
|
|
38
39
|
Requires-Dist: pyramid>=2
|
|
39
40
|
Requires-Dist: waitress
|
|
40
41
|
Requires-Dist: webhelpers2
|
|
41
|
-
Requires-Dist: wuttjamaican[db]>=0.18.
|
|
42
|
+
Requires-Dist: wuttjamaican[db]>=0.18.1
|
|
42
43
|
Requires-Dist: zope-sqlalchemy>=1.5
|
|
43
44
|
Provides-Extra: continuum
|
|
44
45
|
Requires-Dist: wutta-continuum; extra == 'continuum'
|
|
45
46
|
Provides-Extra: docs
|
|
46
47
|
Requires-Dist: furo; extra == 'docs'
|
|
47
48
|
Requires-Dist: sphinx; extra == 'docs'
|
|
49
|
+
Requires-Dist: sphinxcontrib-programoutput; extra == 'docs'
|
|
48
50
|
Provides-Extra: tests
|
|
49
51
|
Requires-Dist: pytest-cov; extra == 'tests'
|
|
50
52
|
Requires-Dist: tox; extra == 'tests'
|
|
@@ -19,6 +19,7 @@ the narrative docs are pretty scant. That will eventually change.
|
|
|
19
19
|
:caption: Documentation:
|
|
20
20
|
|
|
21
21
|
glossary
|
|
22
|
+
narr/cli/index
|
|
22
23
|
narr/templates/index
|
|
23
24
|
|
|
24
25
|
.. toctree::
|
|
@@ -28,6 +29,8 @@ the narrative docs are pretty scant. That will eventually change.
|
|
|
28
29
|
api/wuttaweb
|
|
29
30
|
api/wuttaweb.app
|
|
30
31
|
api/wuttaweb.auth
|
|
32
|
+
api/wuttaweb.cli
|
|
33
|
+
api/wuttaweb.cli.webapp
|
|
31
34
|
api/wuttaweb.conf
|
|
32
35
|
api/wuttaweb.db
|
|
33
36
|
api/wuttaweb.db.continuum
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
===================
|
|
3
|
+
Built-in Commands
|
|
4
|
+
===================
|
|
5
|
+
|
|
6
|
+
Below are the :term:`subcommands <subcommand>` which come with
|
|
7
|
+
WuttaWeb.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
.. _wutta-webapp:
|
|
11
|
+
|
|
12
|
+
``wutta webapp``
|
|
13
|
+
----------------
|
|
14
|
+
|
|
15
|
+
Run the web app, according to config file(s).
|
|
16
|
+
|
|
17
|
+
This command is a convenience only; under the hood it can run `uvicorn
|
|
18
|
+
<https://www.uvicorn.org/#uvicornrun>`_ but by default will run
|
|
19
|
+
whatever :ref:`pserve <pyramid:pserve_script>` is setup to do (which
|
|
20
|
+
usually is `waitress
|
|
21
|
+
<https://docs.pylonsproject.org/projects/waitress/en/latest/index.html>`_).
|
|
22
|
+
|
|
23
|
+
Ultimately it's all up to config, so run different web apps with
|
|
24
|
+
different config files.
|
|
25
|
+
|
|
26
|
+
Defined in: :mod:`wuttaweb.cli.webapp`
|
|
27
|
+
|
|
28
|
+
.. program-output:: wutta webapp --help
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "WuttaWeb"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.18.0"
|
|
10
10
|
description = "Web App for Wutta Framework"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
|
|
@@ -30,6 +30,7 @@ classifiers = [
|
|
|
30
30
|
]
|
|
31
31
|
requires-python = ">= 3.8"
|
|
32
32
|
dependencies = [
|
|
33
|
+
"asgiref",
|
|
33
34
|
"ColanderAlchemy",
|
|
34
35
|
"humanize",
|
|
35
36
|
"markdown",
|
|
@@ -43,32 +44,32 @@ dependencies = [
|
|
|
43
44
|
"pyramid_tm",
|
|
44
45
|
"waitress",
|
|
45
46
|
"WebHelpers2",
|
|
46
|
-
"WuttJamaican[db]>=0.18.
|
|
47
|
+
"WuttJamaican[db]>=0.18.1",
|
|
47
48
|
"zope.sqlalchemy>=1.5",
|
|
48
49
|
]
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
[project.optional-dependencies]
|
|
52
53
|
continuum = ["Wutta-Continuum"]
|
|
53
|
-
docs = ["Sphinx", "furo"]
|
|
54
|
+
docs = ["Sphinx", "furo", "sphinxcontrib-programoutput"]
|
|
54
55
|
tests = ["pytest-cov", "tox"]
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
[project.entry-points."fanstatic.libraries"]
|
|
58
59
|
wuttaweb_img = "wuttaweb.static:img"
|
|
59
60
|
|
|
60
|
-
|
|
61
61
|
[project.entry-points."paste.app_factory"]
|
|
62
62
|
main = "wuttaweb.app:main"
|
|
63
63
|
|
|
64
|
-
|
|
65
64
|
[project.entry-points."wutta.app.providers"]
|
|
66
65
|
wuttaweb = "wuttaweb.app:WebAppProvider"
|
|
67
66
|
|
|
68
|
-
|
|
69
67
|
[project.entry-points."wutta.config.extensions"]
|
|
70
68
|
wuttaweb = "wuttaweb.conf:WuttaWebConfigExtension"
|
|
71
69
|
|
|
70
|
+
[project.entry-points."wutta.typer_imports"]
|
|
71
|
+
wuttaweb = "wuttaweb.cli"
|
|
72
|
+
|
|
72
73
|
|
|
73
74
|
[project.urls]
|
|
74
75
|
Homepage = "https://wuttaproject.org/"
|
|
@@ -24,17 +24,22 @@
|
|
|
24
24
|
Application
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
+
import logging
|
|
27
28
|
import os
|
|
28
29
|
|
|
29
30
|
from wuttjamaican.app import AppProvider
|
|
30
31
|
from wuttjamaican.conf import make_config
|
|
31
32
|
|
|
33
|
+
from asgiref.wsgi import WsgiToAsgi
|
|
32
34
|
from pyramid.config import Configurator
|
|
33
35
|
|
|
34
36
|
import wuttaweb.db
|
|
35
37
|
from wuttaweb.auth import WuttaSecurityPolicy
|
|
36
38
|
|
|
37
39
|
|
|
40
|
+
log = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
38
43
|
class WebAppProvider(AppProvider):
|
|
39
44
|
"""
|
|
40
45
|
The :term:`app provider` for WuttaWeb. This adds some methods to
|
|
@@ -87,17 +92,20 @@ def make_wutta_config(settings, config_maker=None, **kwargs):
|
|
|
87
92
|
|
|
88
93
|
If this config file path cannot be discovered, an error is raised.
|
|
89
94
|
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
wutta_config = settings.get('wutta_config')
|
|
96
|
+
if not wutta_config:
|
|
97
|
+
|
|
98
|
+
# validate config file path
|
|
99
|
+
path = settings.get('wutta.config')
|
|
100
|
+
if not path or not os.path.exists(path):
|
|
101
|
+
raise ValueError("Please set 'wutta.config' in [app:main] "
|
|
102
|
+
"section of config to the path of your "
|
|
103
|
+
"config file. Lame, but necessary.")
|
|
104
|
+
|
|
105
|
+
# make config, add to settings
|
|
106
|
+
config_maker = config_maker or make_config
|
|
107
|
+
wutta_config = config_maker(path, **kwargs)
|
|
108
|
+
settings['wutta_config'] = wutta_config
|
|
101
109
|
|
|
102
110
|
# configure database sessions
|
|
103
111
|
if hasattr(wutta_config, 'appdb_engine'):
|
|
@@ -148,19 +156,18 @@ def make_pyramid_config(settings):
|
|
|
148
156
|
|
|
149
157
|
def main(global_config, **settings):
|
|
150
158
|
"""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
instead.
|
|
159
|
+
Make and return the WSGI application, per given settings.
|
|
160
|
+
|
|
161
|
+
This function is designed to be called via Paste, hence it does
|
|
162
|
+
require params and therefore can't be used directly as app factory
|
|
163
|
+
for general WSGI servers. For the latter see
|
|
164
|
+
:func:`make_wsgi_app()` instead.
|
|
165
|
+
|
|
166
|
+
And this *particular* function is not even that useful, it only
|
|
167
|
+
constructs an app with minimal views built-in to WuttaWeb. Most
|
|
168
|
+
apps will define their own ``main()`` function (e.g. as
|
|
169
|
+
``poser.web.app:main``), similar to this one but with additional
|
|
170
|
+
views and other config.
|
|
164
171
|
"""
|
|
165
172
|
wutta_config = make_wutta_config(settings)
|
|
166
173
|
pyramid_config = make_pyramid_config(settings)
|
|
@@ -170,3 +177,71 @@ def main(global_config, **settings):
|
|
|
170
177
|
pyramid_config.include('wuttaweb.views')
|
|
171
178
|
|
|
172
179
|
return pyramid_config.make_wsgi_app()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def make_wsgi_app(main_app=None, config=None):
|
|
183
|
+
"""
|
|
184
|
+
Make and return a WSGI app, using the given Paste app factory.
|
|
185
|
+
|
|
186
|
+
See also :func:`make_asgi_app()` for the ASGI equivalent.
|
|
187
|
+
|
|
188
|
+
This function could be used directly for general WSGI servers
|
|
189
|
+
(e.g. uvicorn), ***if*** you just want the built-in :func:`main()`
|
|
190
|
+
app factory.
|
|
191
|
+
|
|
192
|
+
But most likely you do not, in which case you must define your own
|
|
193
|
+
function and call this one with your preferred app factory::
|
|
194
|
+
|
|
195
|
+
from wuttaweb.app import make_wsgi_app
|
|
196
|
+
|
|
197
|
+
def my_main(global_config, **settings):
|
|
198
|
+
# TODO: build your app
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
def make_my_wsgi_app():
|
|
202
|
+
return make_wsgi_app(my_main)
|
|
203
|
+
|
|
204
|
+
So ``make_my_wsgi_app()`` could then be used as-is for general
|
|
205
|
+
WSGI servers. However, note that this approach will require
|
|
206
|
+
setting the ``WUTTA_CONFIG_FILES`` environment variable, unless
|
|
207
|
+
running via :ref:`wutta-webapp`.
|
|
208
|
+
|
|
209
|
+
:param main_app: Either a Paste-compatible app factory, or
|
|
210
|
+
:term:`spec` for one. If not specified, the built-in
|
|
211
|
+
:func:`main()` is assumed.
|
|
212
|
+
|
|
213
|
+
:param config: Optional :term:`config object`. If not specified,
|
|
214
|
+
one is created based on ``WUTTA_CONFIG_FILES`` environment
|
|
215
|
+
variable.
|
|
216
|
+
"""
|
|
217
|
+
if not config:
|
|
218
|
+
config = make_config()
|
|
219
|
+
app = config.get_app()
|
|
220
|
+
|
|
221
|
+
# extract pyramid settings
|
|
222
|
+
settings = config.get_dict('app:main')
|
|
223
|
+
|
|
224
|
+
# keep same config object
|
|
225
|
+
settings['wutta_config'] = config
|
|
226
|
+
|
|
227
|
+
# determine the app factory
|
|
228
|
+
if isinstance(main_app, str):
|
|
229
|
+
make_wsgi_app = app.load_object(main_app)
|
|
230
|
+
elif callable(main_app):
|
|
231
|
+
make_wsgi_app = main_app
|
|
232
|
+
else:
|
|
233
|
+
raise ValueError("main_app must be spec or callable")
|
|
234
|
+
|
|
235
|
+
# construct a pyramid app "per usual"
|
|
236
|
+
return make_wsgi_app({}, **settings)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def make_asgi_app(main_app=None, config=None):
|
|
240
|
+
"""
|
|
241
|
+
Make and return a ASGI app, using the given Paste app factory.
|
|
242
|
+
|
|
243
|
+
This works the same as :func:`make_wsgi_app()` and should be
|
|
244
|
+
called in the same way etc.
|
|
245
|
+
"""
|
|
246
|
+
wsgi_app = make_wsgi_app(main_app, config=config)
|
|
247
|
+
return WsgiToAsgi(wsgi_app)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- coding: utf-8; -*-
|
|
2
|
+
################################################################################
|
|
3
|
+
#
|
|
4
|
+
# wuttaweb -- Web App for Wutta Framework
|
|
5
|
+
# Copyright © 2024 Lance Edgar
|
|
6
|
+
#
|
|
7
|
+
# This file is part of Wutta Framework.
|
|
8
|
+
#
|
|
9
|
+
# Wutta Framework is free software: you can redistribute it and/or modify it
|
|
10
|
+
# under the terms of the GNU General Public License as published by the Free
|
|
11
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
|
12
|
+
# later version.
|
|
13
|
+
#
|
|
14
|
+
# Wutta Framework is distributed in the hope that it will be useful, but
|
|
15
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
17
|
+
# more details.
|
|
18
|
+
#
|
|
19
|
+
# You should have received a copy of the GNU General Public License along with
|
|
20
|
+
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
|
|
21
|
+
#
|
|
22
|
+
################################################################################
|
|
23
|
+
"""
|
|
24
|
+
WuttaWeb - ``wutta`` subcommands
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# nb. must bring in all modules for discovery to work
|
|
28
|
+
from . import webapp
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# -*- coding: utf-8; -*-
|
|
2
|
+
################################################################################
|
|
3
|
+
#
|
|
4
|
+
# wuttaweb -- Web App for Wutta Framework
|
|
5
|
+
# Copyright © 2024 Lance Edgar
|
|
6
|
+
#
|
|
7
|
+
# This file is part of Wutta Framework.
|
|
8
|
+
#
|
|
9
|
+
# Wutta Framework is free software: you can redistribute it and/or modify it
|
|
10
|
+
# under the terms of the GNU General Public License as published by the Free
|
|
11
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
|
12
|
+
# later version.
|
|
13
|
+
#
|
|
14
|
+
# Wutta Framework is distributed in the hope that it will be useful, but
|
|
15
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
17
|
+
# more details.
|
|
18
|
+
#
|
|
19
|
+
# You should have received a copy of the GNU General Public License along with
|
|
20
|
+
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
|
|
21
|
+
#
|
|
22
|
+
################################################################################
|
|
23
|
+
"""
|
|
24
|
+
See also: :ref:`wutta-webapp`
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
import sys
|
|
29
|
+
from typing_extensions import Annotated
|
|
30
|
+
|
|
31
|
+
import typer
|
|
32
|
+
from pyramid.scripts import pserve
|
|
33
|
+
|
|
34
|
+
from wuttjamaican.cli import wutta_typer
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@wutta_typer.command()
|
|
38
|
+
def webapp(
|
|
39
|
+
ctx: typer.Context,
|
|
40
|
+
auto_reload: Annotated[
|
|
41
|
+
bool,
|
|
42
|
+
typer.Option('--reload', '-r',
|
|
43
|
+
help="Auto-reload web app when files change.")] = False,
|
|
44
|
+
):
|
|
45
|
+
"""
|
|
46
|
+
Run the configured web app
|
|
47
|
+
"""
|
|
48
|
+
config = ctx.parent.wutta_config
|
|
49
|
+
|
|
50
|
+
# we'll need config file(s) to specify for web app
|
|
51
|
+
if not config.files_read:
|
|
52
|
+
sys.stderr.write("no config files found!\n")
|
|
53
|
+
sys.exit(1)
|
|
54
|
+
|
|
55
|
+
runner = config.get(f'{config.appname}.web.app.runner', default='pserve')
|
|
56
|
+
if runner == 'pserve':
|
|
57
|
+
|
|
58
|
+
# run pserve
|
|
59
|
+
argv = ['pserve', f'file+ini:{config.files_read[0]}']
|
|
60
|
+
if ctx.params['auto_reload']:
|
|
61
|
+
argv.append('--reload')
|
|
62
|
+
pserve.main(argv=argv)
|
|
63
|
+
|
|
64
|
+
elif runner == 'uvicorn':
|
|
65
|
+
|
|
66
|
+
import uvicorn
|
|
67
|
+
|
|
68
|
+
# need service details from config
|
|
69
|
+
spec = config.require(f'{config.appname}.web.app.spec')
|
|
70
|
+
kw = {
|
|
71
|
+
'host': config.get(f'{config.appname}.web.app.host', default='127.0.0.1'),
|
|
72
|
+
'port': config.get_int(f'{config.appname}.web.app.port', default=8000),
|
|
73
|
+
'reload': ctx.params['auto_reload'],
|
|
74
|
+
'reload_dirs': config.get_list(f'{config.appname}.web.app.reload_dirs'),
|
|
75
|
+
'factory': config.get_bool(f'{config.appname}.web.app.factory', default=False),
|
|
76
|
+
'interface': config.get(f'{config.appname}.web.app.interface', default='auto'),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# also must inject our config files to env, since there is no
|
|
80
|
+
# other way to specify when running via uvicorn
|
|
81
|
+
os.environ['WUTTA_CONFIG_FILES'] = os.pathsep.join(config.files_read)
|
|
82
|
+
|
|
83
|
+
# run uvicorn
|
|
84
|
+
uvicorn.run(spec, **kw)
|
|
85
|
+
|
|
86
|
+
else:
|
|
87
|
+
sys.stderr.write(f"unknown web app runner: {runner}\n")
|
|
88
|
+
sys.exit(2)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# -*- coding: utf-8; -*-
|
|
2
|
+
|
|
3
|
+
from unittest.mock import MagicMock, patch
|
|
4
|
+
|
|
5
|
+
from wuttjamaican.testing import ConfigTestCase
|
|
6
|
+
|
|
7
|
+
from wuttaweb.cli import webapp as mod
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestWebapp(ConfigTestCase):
|
|
11
|
+
|
|
12
|
+
def make_context(self, **kwargs):
|
|
13
|
+
params = {'auto_reload': False}
|
|
14
|
+
params.update(kwargs.get('params', {}))
|
|
15
|
+
ctx = MagicMock(params=params)
|
|
16
|
+
ctx.parent.wutta_config = self.config
|
|
17
|
+
return ctx
|
|
18
|
+
|
|
19
|
+
def test_missing_config_file(self):
|
|
20
|
+
# nb. our default config has no files, so can test w/ that
|
|
21
|
+
ctx = self.make_context()
|
|
22
|
+
with patch.object(mod, 'sys') as sys:
|
|
23
|
+
sys.exit.side_effect = RuntimeError
|
|
24
|
+
self.assertRaises(RuntimeError, mod.webapp, ctx)
|
|
25
|
+
sys.stderr.write.assert_called_once_with("no config files found!\n")
|
|
26
|
+
sys.exit.assert_called_once_with(1)
|
|
27
|
+
|
|
28
|
+
def test_invalid_runner(self):
|
|
29
|
+
|
|
30
|
+
# make new config from file, with bad setting
|
|
31
|
+
path = self.write_file('my.conf', """
|
|
32
|
+
[wutta.web]
|
|
33
|
+
app.runner = bogus
|
|
34
|
+
""")
|
|
35
|
+
self.config = self.make_config(files=[path])
|
|
36
|
+
|
|
37
|
+
ctx = self.make_context()
|
|
38
|
+
with patch.object(mod, 'sys') as sys:
|
|
39
|
+
sys.exit.side_effect = RuntimeError
|
|
40
|
+
self.assertRaises(RuntimeError, mod.webapp, ctx)
|
|
41
|
+
sys.stderr.write.assert_called_once_with("unknown web app runner: bogus\n")
|
|
42
|
+
sys.exit.assert_called_once_with(2)
|
|
43
|
+
|
|
44
|
+
def test_pserve(self):
|
|
45
|
+
|
|
46
|
+
path = self.write_file('my.conf', """
|
|
47
|
+
[wutta.web]
|
|
48
|
+
app.runner = pserve
|
|
49
|
+
""")
|
|
50
|
+
self.config = self.make_config(files=[path])
|
|
51
|
+
|
|
52
|
+
# normal
|
|
53
|
+
with patch.object(mod, 'pserve') as pserve:
|
|
54
|
+
ctx = self.make_context()
|
|
55
|
+
mod.webapp(ctx)
|
|
56
|
+
pserve.main.assert_called_once_with(argv=['pserve', f'file+ini:{path}'])
|
|
57
|
+
|
|
58
|
+
# with reload
|
|
59
|
+
with patch.object(mod, 'pserve') as pserve:
|
|
60
|
+
ctx = self.make_context(params={'auto_reload': True})
|
|
61
|
+
mod.webapp(ctx)
|
|
62
|
+
pserve.main.assert_called_once_with(argv=['pserve', f'file+ini:{path}', '--reload'])
|
|
63
|
+
|
|
64
|
+
def test_uvicorn(self):
|
|
65
|
+
|
|
66
|
+
path = self.write_file('my.conf', """
|
|
67
|
+
[wutta.web]
|
|
68
|
+
app.runner = uvicorn
|
|
69
|
+
app.spec = wuttaweb.app:make_wsgi_app
|
|
70
|
+
""")
|
|
71
|
+
self.config = self.make_config(files=[path])
|
|
72
|
+
|
|
73
|
+
orig_import = __import__
|
|
74
|
+
uvicorn = MagicMock()
|
|
75
|
+
|
|
76
|
+
def mock_import(name, *args, **kwargs):
|
|
77
|
+
if name == 'uvicorn':
|
|
78
|
+
return uvicorn
|
|
79
|
+
return orig_import(name, *args, **kwargs)
|
|
80
|
+
|
|
81
|
+
# normal
|
|
82
|
+
with patch('builtins.__import__', side_effect=mock_import):
|
|
83
|
+
ctx = self.make_context()
|
|
84
|
+
mod.webapp(ctx)
|
|
85
|
+
uvicorn.run.assert_called_once_with('wuttaweb.app:make_wsgi_app',
|
|
86
|
+
host='127.0.0.1',
|
|
87
|
+
port=8000,
|
|
88
|
+
reload=False,
|
|
89
|
+
reload_dirs=None,
|
|
90
|
+
factory=False,
|
|
91
|
+
interface='auto')
|
|
92
|
+
|
|
93
|
+
# with reload
|
|
94
|
+
uvicorn.run.reset_mock()
|
|
95
|
+
with patch('builtins.__import__', side_effect=mock_import):
|
|
96
|
+
ctx = self.make_context(params={'auto_reload': True})
|
|
97
|
+
mod.webapp(ctx)
|
|
98
|
+
uvicorn.run.assert_called_once_with('wuttaweb.app:make_wsgi_app',
|
|
99
|
+
host='127.0.0.1',
|
|
100
|
+
port=8000,
|
|
101
|
+
reload=True,
|
|
102
|
+
reload_dirs=None,
|
|
103
|
+
factory=False,
|
|
104
|
+
interface='auto')
|