wagtail 7.1.1__py3-none-any.whl → 7.2rc1__py3-none-any.whl
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.
- wagtail/__init__.py +1 -1
- wagtail/actions/copy_page.py +1 -1
- wagtail/actions/create_alias.py +1 -1
- wagtail/actions/delete_page.py +1 -1
- wagtail/actions/publish_page_revision.py +1 -1
- wagtail/actions/publish_revision.py +1 -1
- wagtail/actions/revert_to_page_revision.py +1 -1
- wagtail/actions/unpublish.py +1 -1
- wagtail/actions/unpublish_page.py +1 -1
- wagtail/admin/auth.py +3 -1
- wagtail/admin/checks.py +2 -2
- wagtail/admin/filters.py +28 -1
- wagtail/admin/forms/collections.py +1 -1
- wagtail/admin/forms/comments.py +1 -1
- wagtail/admin/forms/models.py +1 -1
- wagtail/admin/forms/pages.py +1 -1
- wagtail/admin/forms/tags.py +1 -1
- wagtail/admin/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/cs/LC_MESSAGES/django.po +25 -1
- wagtail/admin/locale/en/LC_MESSAGES/django.po +278 -192
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +29 -15
- wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/it/LC_MESSAGES/django.po +3 -2
- wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/nl/LC_MESSAGES/django.po +57 -3
- wagtail/admin/locale/nl/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/nl/LC_MESSAGES/djangojs.po +8 -2
- wagtail/admin/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/ru/LC_MESSAGES/django.po +58 -1
- wagtail/admin/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/tr/LC_MESSAGES/django.po +3 -2
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
- wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +2 -2
- wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
- wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
- wagtail/admin/static/wagtailadmin/js/icons.js +1 -1
- wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
- wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +2 -2
- wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-transition.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery-3.6.0.min.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery-ui-1.13.2.min.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload-process.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.iframe-transport.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/tag-it.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +1 -1
- wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
- wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
- wagtail/admin/templates/wagtailadmin/account/account.html +2 -0
- wagtail/admin/templates/wagtailadmin/base.html +14 -0
- wagtail/admin/templates/wagtailadmin/generic/chooser/chooser.html +2 -1
- wagtail/admin/templates/wagtailadmin/generic/chooser/creation_form.html +2 -1
- wagtail/admin/templates/wagtailadmin/generic/form.html +3 -1
- wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
- wagtail/admin/templates/wagtailadmin/panels/object_list.html +1 -1
- wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +3 -2
- wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +19 -0
- wagtail/admin/templates/wagtailadmin/shared/panel.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/set_privacy.html +15 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +28 -1
- wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +2 -2
- wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_header.html → tables/ordering_header.html} +2 -2
- wagtail/admin/templates/wagtailadmin/tables/title_cell.html +1 -1
- wagtail/admin/templates/wagtailadmin/userbar/base.html +6 -3
- wagtail/admin/templates/wagtailadmin/userbar/item_admin.html +2 -2
- wagtail/admin/templates/wagtailadmin/userbar/item_page_add.html +2 -2
- wagtail/admin/templates/wagtailadmin/userbar/item_page_edit.html +2 -2
- wagtail/admin/templates/wagtailadmin/userbar/item_page_explore.html +2 -2
- wagtail/admin/templates/wagtailadmin/widgets/{daterange_input.html → range_input.html} +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/task_chooser/chooser.html +4 -2
- wagtail/admin/templatetags/wagtailadmin_tags.py +56 -22
- wagtail/admin/tests/api/test_pages.py +7 -7
- wagtail/admin/tests/api/test_renderer_classes.py +16 -0
- wagtail/admin/tests/pages/test_create_page.py +34 -2
- wagtail/admin/tests/pages/test_edit_page.py +128 -14
- wagtail/admin/tests/pages/test_explorer_view.py +34 -7
- wagtail/admin/tests/pages/test_reorder_page.py +11 -0
- wagtail/admin/tests/test_collections_views.py +12 -0
- wagtail/admin/tests/test_edit_handlers.py +3 -3
- wagtail/admin/tests/test_filters.py +2 -2
- wagtail/admin/tests/test_keyboard_shortcuts.py +52 -2
- wagtail/admin/tests/test_menu.py +0 -2
- wagtail/admin/tests/test_privacy.py +16 -16
- wagtail/admin/tests/test_templatetags.py +137 -0
- wagtail/admin/tests/test_userbar.py +75 -35
- wagtail/admin/tests/test_views_generic.py +34 -0
- wagtail/admin/tests/test_workflows.py +34 -0
- wagtail/admin/tests/viewsets/test_model_viewset.py +322 -0
- wagtail/admin/ui/tables/orderable.py +73 -0
- wagtail/admin/ui/tables/pages.py +3 -13
- wagtail/admin/userbar.py +6 -1
- wagtail/admin/views/collection_privacy.py +6 -2
- wagtail/admin/views/generic/__init__.py +1 -0
- wagtail/admin/views/generic/mixins.py +20 -2
- wagtail/admin/views/generic/models.py +67 -1
- wagtail/admin/views/generic/ordering.py +79 -0
- wagtail/admin/views/home.py +3 -3
- wagtail/admin/views/page_privacy.py +5 -2
- wagtail/admin/views/pages/create.py +1 -1
- wagtail/admin/views/pages/edit.py +2 -2
- wagtail/admin/views/pages/listing.py +7 -42
- wagtail/admin/views/pages/move.py +1 -1
- wagtail/admin/views/pages/ordering.py +1 -1
- wagtail/admin/viewsets/base.py +1 -1
- wagtail/admin/viewsets/model.py +49 -1
- wagtail/admin/wagtail_hooks.py +2 -1
- wagtail/admin/widgets/slug.py +10 -10
- wagtail/api/v2/serializers.py +1 -1
- wagtail/api/v2/tests/test_renderer_classes.py +32 -0
- wagtail/apps.py +2 -0
- wagtail/bin/wagtail.py +1 -1
- wagtail/blocks/struct_block.py +2 -1
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +14 -14
- wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.po +19 -2
- wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +18 -1
- wagtail/contrib/frontend_cache/tests.py +4 -2
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +4 -4
- wagtail/contrib/redirects/tests/test_tmp_storages.py +20 -0
- wagtail/contrib/redirects/tmp_storages.py +1 -1
- wagtail/contrib/redirects/views.py +3 -3
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +43 -3
- wagtail/contrib/search_promotions/static/wagtailsearchpromotions/js/query-chooser-modal.js +1 -1
- wagtail/contrib/search_promotions/views/settings.py +2 -2
- wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.po +6 -1
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.po +6 -2
- wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +6 -1
- wagtail/contrib/settings/tests/site_specific/test_admin.py +40 -6
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/styleguide/templates/wagtailstyleguide/base.html +5 -5
- wagtail/contrib/table_block/blocks.py +1 -0
- wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +5 -1
- wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
- wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
- wagtail/coreutils.py +5 -5
- wagtail/documents/forms.py +18 -1
- wagtail/documents/locale/en/LC_MESSAGES/django.po +10 -10
- wagtail/documents/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/nl/LC_MESSAGES/django.po +9 -0
- wagtail/documents/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/ru/LC_MESSAGES/django.po +9 -0
- wagtail/documents/models.py +1 -1
- wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
- wagtail/documents/templates/wagtaildocs/documents/add.html +0 -34
- wagtail/documents/tests/test_admin_views.py +132 -26
- wagtail/documents/tests/test_collection_privacy.py +18 -4
- wagtail/documents/tests/test_form_overrides.py +1 -1
- wagtail/documents/tests/test_search.py +21 -8
- wagtail/documents/views/documents.py +1 -1
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/embeds/static/wagtailembeds/js/embed-chooser-modal.js +1 -1
- wagtail/images/forms.py +16 -1
- wagtail/images/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/cs/LC_MESSAGES/django.po +12 -1
- wagtail/images/locale/en/LC_MESSAGES/django.po +57 -46
- wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/nl/LC_MESSAGES/django.po +37 -14
- wagtail/images/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/ru/LC_MESSAGES/django.po +20 -1
- wagtail/images/models.py +1 -1
- wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
- wagtail/images/static/wagtailimages/js/focal-point-chooser.js +1 -1
- wagtail/images/static/wagtailimages/js/image-block.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
- wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.Jcrop.min.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-validate.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/load-image.min.js +1 -1
- wagtail/images/templates/wagtailimages/chooser/chooser.html +22 -13
- wagtail/images/templates/wagtailimages/chooser/image_preview_column_cell.html +10 -0
- wagtail/images/templates/wagtailimages/chooser/results.html +24 -20
- wagtail/images/templates/wagtailimages/chooser/title_column_cell.html +15 -0
- wagtail/images/templates/wagtailimages/images/add.html +0 -34
- wagtail/images/templates/wagtailimages/images/index.html +3 -3
- wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
- wagtail/images/templates/wagtailimages/images/layout_toggle_button.html +8 -7
- wagtail/images/templatetags/wagtailimages_tags.py +2 -2
- wagtail/images/tests/test_admin_views.py +87 -0
- wagtail/images/tests/test_form_overrides.py +1 -1
- wagtail/images/tests/test_models.py +48 -9
- wagtail/images/views/chooser.py +66 -2
- wagtail/locale/en/LC_MESSAGES/django.po +55 -55
- wagtail/locale/is_IS/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/is_IS/LC_MESSAGES/django.po +3 -3
- wagtail/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/nl/LC_MESSAGES/django.po +11 -2
- wagtail/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/ru/LC_MESSAGES/django.po +11 -1
- wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/locales/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/nl/LC_MESSAGES/django.po +12 -1
- wagtail/locales/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/ru/LC_MESSAGES/django.po +10 -1
- wagtail/locales/views.py +2 -2
- wagtail/models/orderable.py +10 -0
- wagtail/models/pages.py +9 -11
- wagtail/models/sites.py +1 -1
- wagtail/models/workflows.py +8 -5
- wagtail/project_template/home/tests.py +6 -7
- wagtail/project_template/project_name/settings/base.py +9 -9
- wagtail/project_template/requirements.txt +1 -1
- wagtail/query.py +7 -2
- wagtail/rich_text/rewriters.py +1 -1
- wagtail/search/apps.py +4 -49
- wagtail/search/backends/__init__.py +1 -113
- wagtail/search/backends/base.py +1 -547
- wagtail/search/backends/database/__init__.py +1 -50
- wagtail/search/backends/database/fallback.py +1 -253
- wagtail/search/backends/database/mysql/mysql.py +1 -700
- wagtail/search/backends/database/mysql/query.py +1 -258
- wagtail/search/backends/database/postgres/postgres.py +1 -749
- wagtail/search/backends/database/postgres/query.py +1 -83
- wagtail/search/backends/database/postgres/weights.py +1 -63
- wagtail/search/backends/database/sqlite/query.py +1 -294
- wagtail/search/backends/database/sqlite/sqlite.py +1 -719
- wagtail/search/backends/database/sqlite/utils.py +1 -35
- wagtail/search/backends/deprecation.py +45 -0
- wagtail/search/backends/elasticsearch7.py +18 -1260
- wagtail/search/backends/elasticsearch8.py +21 -96
- wagtail/search/backends/elasticsearch9.py +35 -0
- wagtail/search/backends/opensearch2.py +35 -0
- wagtail/search/backends/opensearch3.py +35 -0
- wagtail/search/index.py +1 -358
- wagtail/search/locale/en/LC_MESSAGES/django.po +2 -10
- wagtail/search/management/commands/update_index.py +1 -205
- wagtail/search/management/commands/wagtail_update_index.py +1 -4
- wagtail/search/models.py +32 -158
- wagtail/search/query.py +1 -114
- wagtail/search/queryset.py +1 -43
- wagtail/search/signal_handlers.py +1 -24
- wagtail/search/tasks.py +1 -10
- wagtail/search/tests/test_elasticsearch.py +22 -0
- wagtail/search/utils.py +1 -206
- wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/snippets/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/snippets/locale/ru/LC_MESSAGES/django.po +8 -1
- wagtail/snippets/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/snippets/locale/tr/LC_MESSAGES/django.po +8 -1
- wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
- wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
- wagtail/snippets/tests/test_preview.py +5 -6
- wagtail/snippets/tests/test_reordering.py +319 -0
- wagtail/snippets/tests/test_snippets.py +65 -12
- wagtail/snippets/views/snippets.py +16 -0
- wagtail/test/numberformat.py +30 -0
- wagtail/test/settings.py +35 -12
- wagtail/test/testapp/fields.py +12 -0
- wagtail/test/testapp/migrations/0056_commentablejsonpage.py +50 -0
- wagtail/test/testapp/migrations/0057_featurecompletetoy_sort_order.py +23 -0
- wagtail/test/testapp/migrations/0058_customlocktask.py +31 -0
- wagtail/test/testapp/models.py +27 -0
- wagtail/test/testapp/urls.py +1 -0
- wagtail/test/testapp/views.py +18 -2
- wagtail/test/utils/page_tests.py +17 -17
- wagtail/test/utils/template_tests.py +4 -6
- wagtail/test/utils/wagtail_tests.py +1 -2
- wagtail/tests/test_blocks.py +15 -0
- wagtail/tests/test_page_model.py +15 -0
- wagtail/{search/tests → tests}/test_page_search.py +29 -2
- wagtail/tests/test_search_fields.py +69 -0
- wagtail/tests/test_tests.py +62 -6
- wagtail/tests/test_workflow.py +25 -1
- wagtail/users/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/cs/LC_MESSAGES/django.po +3 -0
- wagtail/users/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/nl/LC_MESSAGES/django.po +6 -3
- wagtail/users/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/ru/LC_MESSAGES/django.po +5 -1
- wagtail/users/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/tr/LC_MESSAGES/django.po +78 -4
- wagtail/users/templates/wagtailusers/users/create.html +2 -0
- wagtail/users/templates/wagtailusers/users/edit.html +2 -0
- wagtail/users/tests/test_admin_views.py +4 -0
- wagtail/users/views/users.py +1 -1
- {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/METADATA +7 -6
- {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/RECORD +322 -328
- wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +0 -13
- wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +0 -13
- wagtail/search/tests/__init__.py +0 -0
- wagtail/search/tests/elasticsearch_common_tests.py +0 -251
- wagtail/search/tests/test_backends.py +0 -1215
- wagtail/search/tests/test_db_backend.py +0 -62
- wagtail/search/tests/test_elasticsearch7_backend.py +0 -1452
- wagtail/search/tests/test_elasticsearch8_backend.py +0 -15
- wagtail/search/tests/test_index_functions.py +0 -256
- wagtail/search/tests/test_indexed_class.py +0 -157
- wagtail/search/tests/test_mysql_backend.py +0 -192
- wagtail/search/tests/test_postgres_backend.py +0 -210
- wagtail/search/tests/test_queries.py +0 -332
- wagtail/search/tests/test_related_fields.py +0 -102
- wagtail/search/tests/test_sqlite_backend.py +0 -52
- wagtail/test/search/__init__.py +0 -0
- wagtail/test/search/apps.py +0 -9
- wagtail/test/search/fixtures/search.json +0 -545
- wagtail/test/search/migrations/0001_initial.py +0 -146
- wagtail/test/search/migrations/0002_bookunindexed.py +0 -43
- wagtail/test/search/migrations/0003_book_summary.py +0 -18
- wagtail/test/search/migrations/__init__.py +0 -0
- wagtail/test/search/models.py +0 -137
- /wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_cell.html → tables/ordering_cell.html} +0 -0
- /wagtail/{search/checks.py → checks.py} +0 -0
- {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/WHEEL +0 -0
- {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/licenses/LICENSE +0 -0
- {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/top_level.txt +0 -0
|
@@ -1,83 +1 @@
|
|
|
1
|
-
from
|
|
2
|
-
from django.db.models.expressions import Expression, Value
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class LexemeCombinable(Expression):
|
|
6
|
-
BITAND = "&"
|
|
7
|
-
BITOR = "|"
|
|
8
|
-
|
|
9
|
-
def _combine(self, other, connector, reversed, node=None):
|
|
10
|
-
if not isinstance(other, LexemeCombinable):
|
|
11
|
-
raise TypeError(
|
|
12
|
-
f"Lexeme can only be combined with other Lexemes, got {type(other)}."
|
|
13
|
-
)
|
|
14
|
-
if reversed:
|
|
15
|
-
return CombinedLexeme(other, connector, self)
|
|
16
|
-
return CombinedLexeme(self, connector, other)
|
|
17
|
-
|
|
18
|
-
# On Combinable, these are not implemented to reduce confusion with Q. In
|
|
19
|
-
# this case we are actually (ab)using them to do logical combination so
|
|
20
|
-
# it's consistent with other usage in Django.
|
|
21
|
-
def bitand(self, other):
|
|
22
|
-
return self._combine(other, self.BITAND, False)
|
|
23
|
-
|
|
24
|
-
def bitor(self, other):
|
|
25
|
-
return self._combine(other, self.BITOR, False)
|
|
26
|
-
|
|
27
|
-
def __or__(self, other):
|
|
28
|
-
return self._combine(other, self.BITOR, False)
|
|
29
|
-
|
|
30
|
-
def __and__(self, other):
|
|
31
|
-
return self._combine(other, self.BITAND, False)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class Lexeme(LexemeCombinable, Value):
|
|
35
|
-
_output_field = SearchQueryField()
|
|
36
|
-
|
|
37
|
-
def __init__(
|
|
38
|
-
self, value, output_field=None, *, invert=False, prefix=False, weight=None
|
|
39
|
-
):
|
|
40
|
-
self.prefix = prefix
|
|
41
|
-
self.invert = invert
|
|
42
|
-
self.weight = weight
|
|
43
|
-
super().__init__(value, output_field=output_field)
|
|
44
|
-
|
|
45
|
-
def as_sql(self, compiler, connection):
|
|
46
|
-
param = "'%s'" % self.value.replace("'", "''").replace("\\", "\\\\")
|
|
47
|
-
|
|
48
|
-
template = "%s"
|
|
49
|
-
|
|
50
|
-
label = ""
|
|
51
|
-
if self.prefix:
|
|
52
|
-
label += "*"
|
|
53
|
-
if self.weight:
|
|
54
|
-
label += self.weight
|
|
55
|
-
|
|
56
|
-
if label:
|
|
57
|
-
param = f"{param}:{label}"
|
|
58
|
-
if self.invert:
|
|
59
|
-
param = f"!{param}"
|
|
60
|
-
|
|
61
|
-
return template, [param]
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class CombinedLexeme(LexemeCombinable):
|
|
65
|
-
_output_field = SearchQueryField()
|
|
66
|
-
|
|
67
|
-
def __init__(self, lhs, connector, rhs, output_field=None):
|
|
68
|
-
super().__init__(output_field=output_field)
|
|
69
|
-
self.connector = connector
|
|
70
|
-
self.lhs = lhs
|
|
71
|
-
self.rhs = rhs
|
|
72
|
-
|
|
73
|
-
def as_sql(self, compiler, connection):
|
|
74
|
-
value_params = []
|
|
75
|
-
lsql, params = compiler.compile(self.lhs)
|
|
76
|
-
value_params.extend(params)
|
|
77
|
-
|
|
78
|
-
rsql, params = compiler.compile(self.rhs)
|
|
79
|
-
value_params.extend(params)
|
|
80
|
-
|
|
81
|
-
combined_sql = f"({lsql} {self.connector} {rsql})"
|
|
82
|
-
combined_value = combined_sql % tuple(value_params)
|
|
83
|
-
return "%s", [combined_value]
|
|
1
|
+
from wagtailmodelsearch.backends.database.postgres.query import * # noqa: F403
|
|
@@ -1,63 +1 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from django.apps import apps
|
|
4
|
-
|
|
5
|
-
from wagtail.search.index import Indexed
|
|
6
|
-
from wagtail.search.utils import get_search_fields
|
|
7
|
-
|
|
8
|
-
# This file contains the implementation of weights for PostgreSQL tsvectors. Only PostgreSQL has support for them, so that's why we define them here.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
WEIGHTS = "ABCD"
|
|
12
|
-
WEIGHTS_COUNT = len(WEIGHTS)
|
|
13
|
-
# These are filled when apps are ready.
|
|
14
|
-
BOOSTS_WEIGHTS = []
|
|
15
|
-
WEIGHTS_VALUES = []
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def get_boosts():
|
|
19
|
-
boosts = set()
|
|
20
|
-
for model in apps.get_models():
|
|
21
|
-
if issubclass(model, Indexed):
|
|
22
|
-
for search_field in get_search_fields(model.get_search_fields()):
|
|
23
|
-
boost = search_field.boost
|
|
24
|
-
if boost is not None:
|
|
25
|
-
boosts.add(boost)
|
|
26
|
-
return boosts
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def determine_boosts_weights(boosts=()):
|
|
30
|
-
if not boosts:
|
|
31
|
-
boosts = get_boosts()
|
|
32
|
-
boosts = sorted(boosts, reverse=True)
|
|
33
|
-
min_boost = boosts[-1]
|
|
34
|
-
if len(boosts) <= WEIGHTS_COUNT:
|
|
35
|
-
return list(zip_longest(boosts, WEIGHTS, fillvalue=min(min_boost, 0)))
|
|
36
|
-
max_boost = boosts[0]
|
|
37
|
-
boost_step = (max_boost - min_boost) / (WEIGHTS_COUNT - 1)
|
|
38
|
-
return [(max_boost - (i * boost_step), weight) for i, weight in enumerate(WEIGHTS)]
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def set_weights():
|
|
42
|
-
BOOSTS_WEIGHTS.extend(determine_boosts_weights())
|
|
43
|
-
weights = [w for w, c in BOOSTS_WEIGHTS]
|
|
44
|
-
min_weight = min(weights)
|
|
45
|
-
if min_weight <= 0:
|
|
46
|
-
if min_weight == 0:
|
|
47
|
-
min_weight = -0.1
|
|
48
|
-
weights = [w - min_weight for w in weights]
|
|
49
|
-
max_weight = max(weights)
|
|
50
|
-
WEIGHTS_VALUES.extend([w / max_weight for w in reversed(weights)])
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def get_weight(boost):
|
|
54
|
-
if boost is None:
|
|
55
|
-
return WEIGHTS[-1]
|
|
56
|
-
for max_boost, weight in BOOSTS_WEIGHTS:
|
|
57
|
-
if boost >= max_boost:
|
|
58
|
-
return weight
|
|
59
|
-
return weight
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def get_sql_weights():
|
|
63
|
-
return "{" + ",".join(map(str, WEIGHTS_VALUES)) + "}"
|
|
1
|
+
from wagtailmodelsearch.backends.database.postgres.weights import * # noqa: F403
|
|
@@ -1,294 +1 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
4
|
-
from django.db.models.expressions import CombinedExpression, Expression, Func, Value
|
|
5
|
-
from django.db.models.fields import BooleanField, Field, FloatField
|
|
6
|
-
from django.db.models.sql.compiler import SQLCompiler
|
|
7
|
-
|
|
8
|
-
from wagtail.search.query import And, MatchAll, Not, Or, Phrase, PlainText, SearchQuery
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class BM25(Func):
|
|
12
|
-
function = "bm25"
|
|
13
|
-
output_field = FloatField()
|
|
14
|
-
|
|
15
|
-
def __init__(self):
|
|
16
|
-
expressions = ()
|
|
17
|
-
super().__init__(*expressions)
|
|
18
|
-
|
|
19
|
-
def as_sql(
|
|
20
|
-
self,
|
|
21
|
-
compiler: SQLCompiler,
|
|
22
|
-
connection: BaseDatabaseWrapper,
|
|
23
|
-
function=None,
|
|
24
|
-
template=None,
|
|
25
|
-
):
|
|
26
|
-
sql, params = "bm25(wagtailsearch_indexentry_fts)", []
|
|
27
|
-
return sql, params
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class LexemeCombinable(Expression):
|
|
31
|
-
BITAND = "AND"
|
|
32
|
-
BITOR = "OR"
|
|
33
|
-
|
|
34
|
-
def _combine(self, other, connector, reversed, node=None):
|
|
35
|
-
if not isinstance(other, LexemeCombinable):
|
|
36
|
-
raise TypeError(
|
|
37
|
-
f"Lexeme can only be combined with other Lexemes, got {type(other)}."
|
|
38
|
-
)
|
|
39
|
-
if reversed:
|
|
40
|
-
return CombinedLexeme(other, connector, self)
|
|
41
|
-
return CombinedLexeme(self, connector, other)
|
|
42
|
-
|
|
43
|
-
# On Combinable, these are not implemented to reduce confusion with Q. In
|
|
44
|
-
# this case we are actually (ab)using them to do logical combination so
|
|
45
|
-
# it's consistent with other usage in Django.
|
|
46
|
-
def bitand(self, other):
|
|
47
|
-
return self._combine(other, self.BITAND, False)
|
|
48
|
-
|
|
49
|
-
def bitor(self, other):
|
|
50
|
-
return self._combine(other, self.BITOR, False)
|
|
51
|
-
|
|
52
|
-
def __or__(self, other):
|
|
53
|
-
return self._combine(other, self.BITOR, False)
|
|
54
|
-
|
|
55
|
-
def __and__(self, other):
|
|
56
|
-
return self._combine(other, self.BITAND, False)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class SearchQueryField(Field):
|
|
60
|
-
def db_type(self, connection):
|
|
61
|
-
return None
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class Lexeme(LexemeCombinable, Value):
|
|
65
|
-
_output_field = SearchQueryField()
|
|
66
|
-
|
|
67
|
-
def __init__(self, value, output_field=None, *, prefix=False, weight=None):
|
|
68
|
-
self.prefix = prefix
|
|
69
|
-
self.weight = weight
|
|
70
|
-
super().__init__(value, output_field=output_field)
|
|
71
|
-
|
|
72
|
-
def as_sql(self, compiler, connection):
|
|
73
|
-
param = self.value.replace("'", "''").replace("\\", "\\\\")
|
|
74
|
-
|
|
75
|
-
if self.prefix:
|
|
76
|
-
template = '"%s"*'
|
|
77
|
-
else:
|
|
78
|
-
template = '"%s"'
|
|
79
|
-
|
|
80
|
-
return template, [param]
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class CombinedLexeme(LexemeCombinable):
|
|
84
|
-
_output_field = SearchQueryField()
|
|
85
|
-
|
|
86
|
-
def __init__(self, lhs, connector, rhs, output_field=None):
|
|
87
|
-
super().__init__(output_field=output_field)
|
|
88
|
-
self.connector = connector
|
|
89
|
-
self.lhs = lhs
|
|
90
|
-
self.rhs = rhs
|
|
91
|
-
|
|
92
|
-
def as_sql(self, compiler, connection):
|
|
93
|
-
value_params = []
|
|
94
|
-
lsql, params = compiler.compile(self.lhs)
|
|
95
|
-
value_params.extend(params)
|
|
96
|
-
|
|
97
|
-
rsql, params = compiler.compile(self.rhs)
|
|
98
|
-
value_params.extend(params)
|
|
99
|
-
|
|
100
|
-
combined_sql = f"{lsql} {self.connector} {rsql}"
|
|
101
|
-
combined_value = combined_sql % tuple(value_params)
|
|
102
|
-
return "%s", [combined_value]
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
class SearchQueryCombinable:
|
|
106
|
-
BITAND = "AND"
|
|
107
|
-
BITOR = "OR"
|
|
108
|
-
|
|
109
|
-
def _combine(self, other, connector: str, reversed: bool = False):
|
|
110
|
-
if not isinstance(other, SearchQueryCombinable):
|
|
111
|
-
raise TypeError(
|
|
112
|
-
"SearchQuery can only be combined with other SearchQuery "
|
|
113
|
-
"instances, got %s." % type(other).__name__
|
|
114
|
-
)
|
|
115
|
-
if reversed:
|
|
116
|
-
return CombinedSearchQueryExpression(other, connector, self)
|
|
117
|
-
return CombinedSearchQueryExpression(self, connector, other)
|
|
118
|
-
|
|
119
|
-
# On Combinable, these are not implemented to reduce confusion with Q. In
|
|
120
|
-
# this case we are actually (ab)using them to do logical combination so
|
|
121
|
-
# it's consistent with other usage in Django.
|
|
122
|
-
def __or__(self, other):
|
|
123
|
-
return self._combine(other, self.BITOR, False)
|
|
124
|
-
|
|
125
|
-
def __ror__(self, other):
|
|
126
|
-
return self._combine(other, self.BITOR, True)
|
|
127
|
-
|
|
128
|
-
def __and__(self, other):
|
|
129
|
-
return self._combine(other, self.BITAND, False)
|
|
130
|
-
|
|
131
|
-
def __rand__(self, other):
|
|
132
|
-
return self._combine(other, self.BITAND, True)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
class SearchQueryExpression(SearchQueryCombinable, Expression):
|
|
136
|
-
def __init__(self, value: LexemeCombinable, using=None, **extra):
|
|
137
|
-
super().__init__(output_field=SearchQueryField())
|
|
138
|
-
self.using = using
|
|
139
|
-
self.extra = extra
|
|
140
|
-
if isinstance(value, str): # If the value is a string, we assume it's a phrase
|
|
141
|
-
self.value = Value(
|
|
142
|
-
'"%s"' % value
|
|
143
|
-
) # We wrap it in quotes to make sure it's parsed as a phrase
|
|
144
|
-
else: # Otherwise, we assume it's a lexeme
|
|
145
|
-
self.value = value
|
|
146
|
-
|
|
147
|
-
def as_sql(
|
|
148
|
-
self,
|
|
149
|
-
compiler: SQLCompiler,
|
|
150
|
-
connection: BaseDatabaseWrapper,
|
|
151
|
-
**extra_context: Any,
|
|
152
|
-
) -> tuple[str, list[Any]]:
|
|
153
|
-
sql, params = compiler.compile(self.value)
|
|
154
|
-
return (sql, params)
|
|
155
|
-
|
|
156
|
-
def __repr__(self) -> str:
|
|
157
|
-
return self.value.__repr__()
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
class CombinedSearchQueryExpression(SearchQueryCombinable, CombinedExpression):
|
|
161
|
-
def __init__(self, lhs, connector, rhs, output_field=None):
|
|
162
|
-
super().__init__(lhs, connector, rhs, output_field)
|
|
163
|
-
|
|
164
|
-
def __str__(self):
|
|
165
|
-
return "(%s)" % super().__str__()
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
class MatchExpression(Expression):
|
|
169
|
-
filterable = True
|
|
170
|
-
template = (
|
|
171
|
-
"wagtailsearch_indexentry_fts MATCH %s" # TODO: Can the table name be inferred?
|
|
172
|
-
)
|
|
173
|
-
output_field = BooleanField()
|
|
174
|
-
|
|
175
|
-
def __init__(self, columns: list[str], query: SearchQueryCombinable) -> None:
|
|
176
|
-
super().__init__(output_field=self.output_field)
|
|
177
|
-
self.columns = columns
|
|
178
|
-
self.query = query
|
|
179
|
-
|
|
180
|
-
def as_sql(self, compiler, connection):
|
|
181
|
-
joined_columns = " ".join(
|
|
182
|
-
self.columns
|
|
183
|
-
) # The format of the columns is 'column1 column2'
|
|
184
|
-
compiled_query = compiler.compile(self.query) # Compile the query to a string
|
|
185
|
-
formatted_query = compiled_query[0] % tuple(
|
|
186
|
-
compiled_query[1]
|
|
187
|
-
) # Substitute the params in the query
|
|
188
|
-
params = [
|
|
189
|
-
"{{{column}}} : ({query})".format(
|
|
190
|
-
column=joined_columns, query=formatted_query
|
|
191
|
-
)
|
|
192
|
-
] # Build the full MATCH search query. It will be a parameter to the template, so no SQL injections are possible here.
|
|
193
|
-
return (self.template, params)
|
|
194
|
-
|
|
195
|
-
def __repr__(self):
|
|
196
|
-
return f"<MatchExpression: {self.columns!r} = {self.query!r}>"
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
class AndNot(SearchQuery):
|
|
200
|
-
"""
|
|
201
|
-
This is a binary search query, where there are two subqueries, and the search is done by searching the first, and excluding the second subquery.
|
|
202
|
-
For example, AndNot(X, Y) would be equivalent to doing And(X, Not(Y)), where X is the first subquery, and Y is the second subquery (the negated one).
|
|
203
|
-
This is done because the SQLite FTS5 module doesn't support the unary NOT operator.
|
|
204
|
-
"""
|
|
205
|
-
|
|
206
|
-
def __init__(self, subquery_a: SearchQuery, subquery_b: SearchQuery):
|
|
207
|
-
self.subquery_a = subquery_a
|
|
208
|
-
self.subquery_b = subquery_b
|
|
209
|
-
|
|
210
|
-
def __repr__(self):
|
|
211
|
-
return f"<{repr(self.subquery_a)} AndNot {repr(self.subquery_b)}>"
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def normalize(search_query: SearchQuery) -> tuple[SearchQuery]:
|
|
215
|
-
"""
|
|
216
|
-
Turns this query into a normalized version.
|
|
217
|
-
For example, And(Not(PlainText("Arepa")), PlainText("Crepe")) would be turned into AndNot(PlainText("Crepe"), PlainText("Arepa")): "Crepe AND NOT Arepa".
|
|
218
|
-
This is done because we need to get the NOT operator to the front of the query, so it can be used in the search, because the SQLite FTS5 module doesn't support the unary NOT operator. This means that, in order to support the NOT operator, we need to match against the non-negated version of the query, and then return everything that is not in the results of the non-negated query.
|
|
219
|
-
"""
|
|
220
|
-
if isinstance(search_query, Phrase):
|
|
221
|
-
return search_query # We can't normalize a Phrase.
|
|
222
|
-
if isinstance(search_query, PlainText):
|
|
223
|
-
return search_query # We can't normalize a PlainText.
|
|
224
|
-
if isinstance(search_query, And):
|
|
225
|
-
normalized_subqueries: list[SearchQuery] = [
|
|
226
|
-
normalize(subquery) for subquery in search_query.subqueries
|
|
227
|
-
] # This builds a list of normalized subqueries.
|
|
228
|
-
|
|
229
|
-
not_negated_subqueries = [
|
|
230
|
-
subquery
|
|
231
|
-
for subquery in normalized_subqueries
|
|
232
|
-
if not isinstance(subquery, Not)
|
|
233
|
-
] # All the non-negated subqueries.
|
|
234
|
-
not_negated_subqueries = [
|
|
235
|
-
subquery
|
|
236
|
-
for subquery in not_negated_subqueries
|
|
237
|
-
if not isinstance(subquery, MatchAll)
|
|
238
|
-
] # We can ignore all MatchAll SearchQueries here, because they are redundant.
|
|
239
|
-
negated_subqueries = [
|
|
240
|
-
subquery.subquery
|
|
241
|
-
for subquery in normalized_subqueries
|
|
242
|
-
if isinstance(subquery, Not)
|
|
243
|
-
]
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
negated_subqueries == []
|
|
247
|
-
): # If there are no negated subqueries, return an And(), now without the redundant MatchAll subqueries.
|
|
248
|
-
return And(not_negated_subqueries)
|
|
249
|
-
|
|
250
|
-
for subquery in (
|
|
251
|
-
negated_subqueries
|
|
252
|
-
): # If there's a negated MatchAll subquery, then nothing will get matched.
|
|
253
|
-
if isinstance(subquery, MatchAll):
|
|
254
|
-
return Not(MatchAll())
|
|
255
|
-
|
|
256
|
-
return AndNot(And(not_negated_subqueries), Or(negated_subqueries))
|
|
257
|
-
if isinstance(search_query, Or):
|
|
258
|
-
normalized_subqueries: list[SearchQuery] = [
|
|
259
|
-
normalize(subquery) for subquery in search_query.subqueries
|
|
260
|
-
] # This builds a list of (subquery, negated) tuples.
|
|
261
|
-
|
|
262
|
-
negated_subqueries = [
|
|
263
|
-
subquery.subquery
|
|
264
|
-
for subquery in normalized_subqueries
|
|
265
|
-
if isinstance(subquery, Not)
|
|
266
|
-
]
|
|
267
|
-
if (
|
|
268
|
-
negated_subqueries == []
|
|
269
|
-
): # If there are no negated subqueries, return an Or().
|
|
270
|
-
return Or(normalized_subqueries)
|
|
271
|
-
|
|
272
|
-
for subquery in (
|
|
273
|
-
negated_subqueries
|
|
274
|
-
): # If there's a MatchAll subquery, then anything will get matched.
|
|
275
|
-
if isinstance(subquery, MatchAll):
|
|
276
|
-
return MatchAll()
|
|
277
|
-
|
|
278
|
-
not_negated_subqueries = [
|
|
279
|
-
subquery
|
|
280
|
-
for subquery in normalized_subqueries
|
|
281
|
-
if not isinstance(subquery, Not)
|
|
282
|
-
] # All the non-negated subqueries.
|
|
283
|
-
not_negated_subqueries = [
|
|
284
|
-
subquery
|
|
285
|
-
for subquery in not_negated_subqueries
|
|
286
|
-
if not isinstance(subquery, MatchAll)
|
|
287
|
-
] # We can ignore all MatchAll SearchQueries here, because they are redundant.
|
|
288
|
-
|
|
289
|
-
return AndNot(MatchAll(), And(negated_subqueries))
|
|
290
|
-
if isinstance(search_query, Not):
|
|
291
|
-
normalized = normalize(search_query.subquery)
|
|
292
|
-
return Not(normalized) # Normalize the subquery, then invert it.
|
|
293
|
-
if isinstance(search_query, MatchAll):
|
|
294
|
-
return search_query # We can't normalize a MatchAll.
|
|
1
|
+
from wagtailmodelsearch.backends.database.sqlite.query import * # noqa: F403
|