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,210 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
from django.db import connection
|
|
4
|
-
from django.test import TestCase
|
|
5
|
-
from django.test.utils import override_settings
|
|
6
|
-
|
|
7
|
-
from wagtail.search.query import Phrase
|
|
8
|
-
from wagtail.search.tests.test_backends import BackendTests
|
|
9
|
-
from wagtail.test.search import models
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@unittest.skipUnless(
|
|
13
|
-
connection.vendor == "postgresql", "The current database is not PostgreSQL"
|
|
14
|
-
)
|
|
15
|
-
@override_settings(
|
|
16
|
-
WAGTAILSEARCH_BACKENDS={
|
|
17
|
-
"default": {
|
|
18
|
-
"BACKEND": "wagtail.search.backends.database.postgres.postgres",
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
)
|
|
22
|
-
class TestPostgresSearchBackend(BackendTests, TestCase):
|
|
23
|
-
backend_path = "wagtail.search.backends.database.postgres.postgres"
|
|
24
|
-
|
|
25
|
-
def test_weights(self):
|
|
26
|
-
from ..backends.database.postgres.weights import (
|
|
27
|
-
BOOSTS_WEIGHTS,
|
|
28
|
-
WEIGHTS_VALUES,
|
|
29
|
-
determine_boosts_weights,
|
|
30
|
-
get_weight,
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
self.assertListEqual(
|
|
34
|
-
BOOSTS_WEIGHTS, [(10, "A"), (2, "B"), (0.5, "C"), (0.25, "D")]
|
|
35
|
-
)
|
|
36
|
-
self.assertListEqual(WEIGHTS_VALUES, [0.025, 0.05, 0.2, 1.0])
|
|
37
|
-
|
|
38
|
-
self.assertEqual(get_weight(15), "A")
|
|
39
|
-
self.assertEqual(get_weight(10), "A")
|
|
40
|
-
self.assertEqual(get_weight(9.9), "B")
|
|
41
|
-
self.assertEqual(get_weight(2), "B")
|
|
42
|
-
self.assertEqual(get_weight(1.9), "C")
|
|
43
|
-
self.assertEqual(get_weight(0), "D")
|
|
44
|
-
self.assertEqual(get_weight(-1), "D")
|
|
45
|
-
|
|
46
|
-
self.assertListEqual(
|
|
47
|
-
determine_boosts_weights([1]), [(1, "A"), (0, "B"), (0, "C"), (0, "D")]
|
|
48
|
-
)
|
|
49
|
-
self.assertListEqual(
|
|
50
|
-
determine_boosts_weights([-1]), [(-1, "A"), (-1, "B"), (-1, "C"), (-1, "D")]
|
|
51
|
-
)
|
|
52
|
-
self.assertListEqual(
|
|
53
|
-
determine_boosts_weights([-1, 1, 2]),
|
|
54
|
-
[(2, "A"), (1, "B"), (-1, "C"), (-1, "D")],
|
|
55
|
-
)
|
|
56
|
-
self.assertListEqual(
|
|
57
|
-
determine_boosts_weights([0, 1, 2, 3]),
|
|
58
|
-
[(3, "A"), (2, "B"), (1, "C"), (0, "D")],
|
|
59
|
-
)
|
|
60
|
-
self.assertListEqual(
|
|
61
|
-
determine_boosts_weights([0, 0.25, 0.75, 1, 1.5]),
|
|
62
|
-
[(1.5, "A"), (1, "B"), (0.5, "C"), (0, "D")],
|
|
63
|
-
)
|
|
64
|
-
self.assertListEqual(
|
|
65
|
-
determine_boosts_weights([0, 1, 2, 3, 4, 5, 6]),
|
|
66
|
-
[(6, "A"), (4, "B"), (2, "C"), (0, "D")],
|
|
67
|
-
)
|
|
68
|
-
self.assertListEqual(
|
|
69
|
-
determine_boosts_weights([-2, -1, 0, 1, 2, 3, 4]),
|
|
70
|
-
[(4, "A"), (2, "B"), (0, "C"), (-2, "D")],
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
def test_search_tsquery_chars(self):
|
|
74
|
-
"""
|
|
75
|
-
Checks that tsquery characters are correctly escaped
|
|
76
|
-
and do not generate a PostgreSQL syntax error.
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
# Simple quote should be escaped inside each tsquery term.
|
|
80
|
-
results = self.backend.search("L'amour piqué par une abeille", models.Book)
|
|
81
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
82
|
-
results = self.backend.search("'starting quote", models.Book)
|
|
83
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
84
|
-
results = self.backend.search("ending quote'", models.Book)
|
|
85
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
86
|
-
results = self.backend.search("double quo''te", models.Book)
|
|
87
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
88
|
-
results = self.backend.search("triple quo'''te", models.Book)
|
|
89
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
90
|
-
|
|
91
|
-
# Now suffixes.
|
|
92
|
-
results = self.backend.search("Something:B", models.Book)
|
|
93
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
94
|
-
results = self.backend.search("Something:*", models.Book)
|
|
95
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
96
|
-
results = self.backend.search("Something:A*BCD", models.Book)
|
|
97
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
98
|
-
|
|
99
|
-
# Now the AND operator.
|
|
100
|
-
results = self.backend.search("first & second", models.Book)
|
|
101
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
102
|
-
|
|
103
|
-
# Now the OR operator.
|
|
104
|
-
results = self.backend.search("first | second", models.Book)
|
|
105
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
106
|
-
|
|
107
|
-
# Now the NOT operator.
|
|
108
|
-
results = self.backend.search("first & !second", models.Book)
|
|
109
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
110
|
-
|
|
111
|
-
# Now the phrase operator.
|
|
112
|
-
results = self.backend.search("first <-> second", models.Book)
|
|
113
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
114
|
-
|
|
115
|
-
def test_autocomplete_tsquery_chars(self):
|
|
116
|
-
"""
|
|
117
|
-
Checks that tsquery characters are correctly escaped
|
|
118
|
-
and do not generate a PostgreSQL syntax error.
|
|
119
|
-
"""
|
|
120
|
-
|
|
121
|
-
# Simple quote should be escaped inside each tsquery term.
|
|
122
|
-
results = self.backend.autocomplete(
|
|
123
|
-
"L'amour piqué par une abeille", models.Book
|
|
124
|
-
)
|
|
125
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
126
|
-
results = self.backend.autocomplete("'starting quote", models.Book)
|
|
127
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
128
|
-
results = self.backend.autocomplete("ending quote'", models.Book)
|
|
129
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
130
|
-
results = self.backend.autocomplete("double quo''te", models.Book)
|
|
131
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
132
|
-
results = self.backend.autocomplete("triple quo'''te", models.Book)
|
|
133
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
134
|
-
|
|
135
|
-
# Backslashes should be escaped inside each tsquery term.
|
|
136
|
-
results = self.backend.autocomplete("backslash\\", models.Book)
|
|
137
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
138
|
-
|
|
139
|
-
# Now suffixes.
|
|
140
|
-
results = self.backend.autocomplete("Something:B", models.Book)
|
|
141
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
142
|
-
results = self.backend.autocomplete("Something:*", models.Book)
|
|
143
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
144
|
-
results = self.backend.autocomplete("Something:A*BCD", models.Book)
|
|
145
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
146
|
-
|
|
147
|
-
# Now the AND operator.
|
|
148
|
-
results = self.backend.autocomplete("first & second", models.Book)
|
|
149
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
150
|
-
|
|
151
|
-
# Now the OR operator.
|
|
152
|
-
results = self.backend.autocomplete("first | second", models.Book)
|
|
153
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
154
|
-
|
|
155
|
-
# Now the NOT operator.
|
|
156
|
-
results = self.backend.autocomplete("first & !second", models.Book)
|
|
157
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
158
|
-
|
|
159
|
-
# Now the phrase operator.
|
|
160
|
-
results = self.backend.autocomplete("first <-> second", models.Book)
|
|
161
|
-
self.assertUnsortedListEqual([r.title for r in results], [])
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
@unittest.skipUnless(
|
|
165
|
-
connection.vendor == "postgresql", "The current database is not PostgreSQL"
|
|
166
|
-
)
|
|
167
|
-
@override_settings(
|
|
168
|
-
WAGTAILSEARCH_BACKENDS={
|
|
169
|
-
"default": {
|
|
170
|
-
"BACKEND": "wagtail.search.backends.database.postgres.postgres",
|
|
171
|
-
"SEARCH_CONFIG": "dutch",
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
)
|
|
175
|
-
class TestPostgresLanguageTextSearch(TestCase):
|
|
176
|
-
backend_path = "wagtail.search.backends.database.postgres.postgres"
|
|
177
|
-
|
|
178
|
-
def setUp(self):
|
|
179
|
-
# get search backend by backend_path
|
|
180
|
-
BackendTests.setUp(self)
|
|
181
|
-
|
|
182
|
-
book = models.Book.objects.create(
|
|
183
|
-
title="Nu is beter dan nooit",
|
|
184
|
-
publication_date="1999-05-01",
|
|
185
|
-
number_of_pages=333,
|
|
186
|
-
)
|
|
187
|
-
self.backend.add(book)
|
|
188
|
-
self.book = book
|
|
189
|
-
|
|
190
|
-
def test_search_language_plain_text(self):
|
|
191
|
-
results = self.backend.search("Nu is beter dan nooit", models.Book)
|
|
192
|
-
self.assertEqual(list(results), [self.book])
|
|
193
|
-
|
|
194
|
-
results = self.backend.search("is beter", models.Book)
|
|
195
|
-
self.assertEqual(list(results), [self.book])
|
|
196
|
-
|
|
197
|
-
# search deals even with variations
|
|
198
|
-
results = self.backend.search("zijn beter", models.Book)
|
|
199
|
-
self.assertEqual(list(results), [self.book])
|
|
200
|
-
|
|
201
|
-
# search deals even when there are minor typos
|
|
202
|
-
results = self.backend.search("zij beter dan", models.Book)
|
|
203
|
-
self.assertEqual(list(results), [self.book])
|
|
204
|
-
|
|
205
|
-
def test_search_language_phrase_text(self):
|
|
206
|
-
results = self.backend.search(Phrase("Nu is beter"), models.Book)
|
|
207
|
-
self.assertEqual(list(results), [self.book])
|
|
208
|
-
|
|
209
|
-
results = self.backend.search(Phrase("Nu zijn beter"), models.Book)
|
|
210
|
-
self.assertEqual(list(results), [self.book])
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
from django.test import SimpleTestCase, TestCase
|
|
2
|
-
|
|
3
|
-
from wagtail.search.query import And, Or, Phrase, PlainText
|
|
4
|
-
from wagtail.search.utils import (
|
|
5
|
-
balanced_reduce,
|
|
6
|
-
normalise_query_string,
|
|
7
|
-
parse_query_string,
|
|
8
|
-
separate_filters_from_query,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class TestQueryStringNormalisation(TestCase):
|
|
13
|
-
def test_truncation(self):
|
|
14
|
-
test_querystring = "a" * 1000
|
|
15
|
-
result = normalise_query_string(test_querystring)
|
|
16
|
-
self.assertEqual(len(result), 255)
|
|
17
|
-
|
|
18
|
-
def test_no_truncation(self):
|
|
19
|
-
test_querystring = "a" * 10
|
|
20
|
-
result = normalise_query_string(test_querystring)
|
|
21
|
-
self.assertEqual(len(result), 10)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class TestSeparateFiltersFromQuery(SimpleTestCase):
|
|
25
|
-
def test_only_query(self):
|
|
26
|
-
filters, query = separate_filters_from_query("hello world")
|
|
27
|
-
|
|
28
|
-
self.assertDictEqual(filters.dict(), {})
|
|
29
|
-
self.assertEqual(query, "hello world")
|
|
30
|
-
|
|
31
|
-
def test_filter(self):
|
|
32
|
-
filters, query = separate_filters_from_query("author:foo")
|
|
33
|
-
|
|
34
|
-
self.assertDictEqual(filters.dict(), {"author": "foo"})
|
|
35
|
-
self.assertEqual(query, "")
|
|
36
|
-
|
|
37
|
-
def test_filter_with_quotation_mark(self):
|
|
38
|
-
filters, query = separate_filters_from_query('author:"foo bar"')
|
|
39
|
-
|
|
40
|
-
self.assertDictEqual(filters.dict(), {"author": "foo bar"})
|
|
41
|
-
self.assertEqual(query, "")
|
|
42
|
-
|
|
43
|
-
def test_filter_and_query(self):
|
|
44
|
-
filters, query = separate_filters_from_query("author:foo hello world")
|
|
45
|
-
|
|
46
|
-
self.assertDictEqual(filters.dict(), {"author": "foo"})
|
|
47
|
-
self.assertEqual(query, "hello world")
|
|
48
|
-
|
|
49
|
-
def test_filter_with_quotation_mark_and_query(self):
|
|
50
|
-
filters, query = separate_filters_from_query('author:"foo bar" hello world')
|
|
51
|
-
|
|
52
|
-
self.assertDictEqual(filters.dict(), {"author": "foo bar"})
|
|
53
|
-
self.assertEqual(query, "hello world")
|
|
54
|
-
|
|
55
|
-
def test_filter_with_unclosed_quotation_mark_and_query(self):
|
|
56
|
-
filters, query = separate_filters_from_query('author:"foo bar hello world')
|
|
57
|
-
|
|
58
|
-
self.assertDictEqual(filters.dict(), {})
|
|
59
|
-
self.assertEqual(query, 'author:"foo bar hello world')
|
|
60
|
-
|
|
61
|
-
def test_two_filters_and_query(self):
|
|
62
|
-
filters, query = separate_filters_from_query(
|
|
63
|
-
'author:"foo bar" hello world bar:beer'
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
self.assertDictEqual(filters.dict(), {"author": "foo bar", "bar": "beer"})
|
|
67
|
-
self.assertEqual(query, "hello world")
|
|
68
|
-
|
|
69
|
-
def test_two_filters_with_quotation_marks_and_query(self):
|
|
70
|
-
filters, query = separate_filters_from_query(
|
|
71
|
-
'author:"foo bar" hello world bar:"two beers"'
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
self.assertDictEqual(filters.dict(), {"author": "foo bar", "bar": "two beers"})
|
|
75
|
-
self.assertEqual(query, "hello world")
|
|
76
|
-
|
|
77
|
-
filters, query = separate_filters_from_query(
|
|
78
|
-
"author:'foo bar' hello world bar:'two beers'"
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
self.assertDictEqual(filters.dict(), {"author": "foo bar", "bar": "two beers"})
|
|
82
|
-
self.assertEqual(query, "hello world")
|
|
83
|
-
|
|
84
|
-
def test_return_list_of_multiple_instances_for_same_filter_key(self):
|
|
85
|
-
filters, query = separate_filters_from_query(
|
|
86
|
-
'foo:test1 hello world foo:test2 foo:"test3" foo2:test4'
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
self.assertDictEqual(filters.dict(), {"foo": "test3", "foo2": "test4"})
|
|
90
|
-
self.assertListEqual(filters.getlist("foo"), ["test1", "test2", "test3"])
|
|
91
|
-
self.assertEqual(query, "hello world")
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class TestParseQueryString(SimpleTestCase):
|
|
95
|
-
def test_simple_query(self):
|
|
96
|
-
filters, query = parse_query_string("hello world")
|
|
97
|
-
|
|
98
|
-
self.assertDictEqual(filters.dict(), {})
|
|
99
|
-
self.assertEqual(repr(query), repr(PlainText("hello world")))
|
|
100
|
-
|
|
101
|
-
def test_with_phrase(self):
|
|
102
|
-
filters, query = parse_query_string('"hello world"')
|
|
103
|
-
|
|
104
|
-
self.assertDictEqual(filters.dict(), {})
|
|
105
|
-
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
|
106
|
-
|
|
107
|
-
filters, query = parse_query_string("'hello world'")
|
|
108
|
-
|
|
109
|
-
self.assertDictEqual(filters.dict(), {})
|
|
110
|
-
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
|
111
|
-
|
|
112
|
-
def test_with_simple_and_phrase(self):
|
|
113
|
-
filters, query = parse_query_string('this is simple "hello world"')
|
|
114
|
-
|
|
115
|
-
self.assertDictEqual(filters.dict(), {})
|
|
116
|
-
self.assertEqual(
|
|
117
|
-
repr(query), repr(And([PlainText("this is simple"), Phrase("hello world")]))
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
filters, query = parse_query_string("this is simple 'hello world'")
|
|
121
|
-
|
|
122
|
-
self.assertDictEqual(filters.dict(), {})
|
|
123
|
-
self.assertEqual(
|
|
124
|
-
repr(query), repr(And([PlainText("this is simple"), Phrase("hello world")]))
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
def test_operator(self):
|
|
128
|
-
filters, query = parse_query_string(
|
|
129
|
-
'this is simple "hello world"', operator="or"
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
self.assertDictEqual(filters.dict(), {})
|
|
133
|
-
self.assertEqual(
|
|
134
|
-
repr(query),
|
|
135
|
-
repr(
|
|
136
|
-
Or([PlainText("this is simple", operator="or"), Phrase("hello world")])
|
|
137
|
-
),
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
filters, query = parse_query_string(
|
|
141
|
-
"this is simple 'hello world'", operator="or"
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
self.assertDictEqual(filters.dict(), {})
|
|
145
|
-
self.assertEqual(
|
|
146
|
-
repr(query),
|
|
147
|
-
repr(
|
|
148
|
-
Or([PlainText("this is simple", operator="or"), Phrase("hello world")])
|
|
149
|
-
),
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
def test_with_phrase_unclosed(self):
|
|
153
|
-
filters, query = parse_query_string('"hello world')
|
|
154
|
-
|
|
155
|
-
self.assertDictEqual(filters.dict(), {})
|
|
156
|
-
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
|
157
|
-
|
|
158
|
-
filters, query = parse_query_string("'hello world")
|
|
159
|
-
|
|
160
|
-
self.assertDictEqual(filters.dict(), {})
|
|
161
|
-
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
|
162
|
-
|
|
163
|
-
def test_phrase_with_filter(self):
|
|
164
|
-
filters, query = parse_query_string('"hello world" author:"foo bar" bar:beer')
|
|
165
|
-
|
|
166
|
-
self.assertDictEqual(filters.dict(), {"author": "foo bar", "bar": "beer"})
|
|
167
|
-
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
|
168
|
-
|
|
169
|
-
filters, query = parse_query_string("'hello world' author:'foo bar' bar:beer")
|
|
170
|
-
|
|
171
|
-
self.assertDictEqual(filters.dict(), {"author": "foo bar", "bar": "beer"})
|
|
172
|
-
self.assertEqual(repr(query), repr(Phrase("hello world")))
|
|
173
|
-
|
|
174
|
-
def test_long_queries(self):
|
|
175
|
-
filters, query = parse_query_string("0" * 60_000)
|
|
176
|
-
self.assertEqual(filters.dict(), {})
|
|
177
|
-
self.assertEqual(repr(query), repr(PlainText("0" * 60_000)))
|
|
178
|
-
|
|
179
|
-
filters, _ = parse_query_string(f'{"a" * 60_000}:"foo bar"')
|
|
180
|
-
self.assertEqual(filters.dict(), {"a" * 60_000: "foo bar"})
|
|
181
|
-
|
|
182
|
-
def test_long_filter_value(self):
|
|
183
|
-
filters, _ = parse_query_string(f"foo:ba{'r' * 60_000}")
|
|
184
|
-
self.assertEqual(filters.dict(), {"foo": f"ba{'r' * 60_000}"})
|
|
185
|
-
|
|
186
|
-
def test_joined_filters(self):
|
|
187
|
-
filters, query = parse_query_string("foo:bar:baz")
|
|
188
|
-
self.assertEqual(filters.dict(), {"foo": "bar"})
|
|
189
|
-
self.assertEqual(repr(query), repr(PlainText(":baz")))
|
|
190
|
-
|
|
191
|
-
filters, query = parse_query_string("foo:'bar':baz")
|
|
192
|
-
self.assertEqual(filters.dict(), {"foo": "bar"})
|
|
193
|
-
self.assertEqual(repr(query), repr(PlainText(":baz")))
|
|
194
|
-
|
|
195
|
-
filters, query = parse_query_string("foo:'bar:baz'")
|
|
196
|
-
self.assertEqual(filters.dict(), {"foo": "bar:baz"})
|
|
197
|
-
|
|
198
|
-
def test_multiple_phrases(self):
|
|
199
|
-
filters, query = parse_query_string('"hello world" "hi earth"')
|
|
200
|
-
|
|
201
|
-
self.assertEqual(
|
|
202
|
-
repr(query), repr(And([Phrase("hello world"), Phrase("hi earth")]))
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
filters, query = parse_query_string("'hello world' 'hi earth'")
|
|
206
|
-
|
|
207
|
-
self.assertEqual(
|
|
208
|
-
repr(query), repr(And([Phrase("hello world"), Phrase("hi earth")]))
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
def test_mixed_phrases_with_filters(self):
|
|
212
|
-
filters, query = parse_query_string(
|
|
213
|
-
""""lord of the rings" army_1:"elves" army_2:'humans'"""
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
self.assertDictEqual(filters.dict(), {"army_1": "elves", "army_2": "humans"})
|
|
217
|
-
self.assertEqual(
|
|
218
|
-
repr(query),
|
|
219
|
-
repr(Phrase("lord of the rings")),
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
class TestBalancedReduce(SimpleTestCase):
|
|
224
|
-
# For simple values, this should behave exactly the same as Pythons reduce()
|
|
225
|
-
# So I've copied its tests: https://github.com/python/cpython/blob/21cdb711e3b1975398c54141e519ead02670610e/Lib/test/test_functools.py#L771
|
|
226
|
-
|
|
227
|
-
def test_reduce(self):
|
|
228
|
-
class Squares:
|
|
229
|
-
def __init__(self, max):
|
|
230
|
-
self.max = max
|
|
231
|
-
self.sofar = []
|
|
232
|
-
|
|
233
|
-
def __len__(self):
|
|
234
|
-
return len(self.sofar)
|
|
235
|
-
|
|
236
|
-
def __getitem__(self, i):
|
|
237
|
-
if not 0 <= i < self.max:
|
|
238
|
-
raise IndexError
|
|
239
|
-
n = len(self.sofar)
|
|
240
|
-
while n <= i:
|
|
241
|
-
self.sofar.append(n * n)
|
|
242
|
-
n += 1
|
|
243
|
-
return self.sofar[i]
|
|
244
|
-
|
|
245
|
-
def add(x, y):
|
|
246
|
-
return x + y
|
|
247
|
-
|
|
248
|
-
self.assertEqual(balanced_reduce(add, ["a", "b", "c"], ""), "abc")
|
|
249
|
-
self.assertEqual(
|
|
250
|
-
balanced_reduce(add, [["a", "c"], [], ["d", "w"]], []), ["a", "c", "d", "w"]
|
|
251
|
-
)
|
|
252
|
-
self.assertEqual(balanced_reduce(lambda x, y: x * y, range(2, 8), 1), 5040)
|
|
253
|
-
self.assertEqual(
|
|
254
|
-
balanced_reduce(lambda x, y: x * y, range(2, 21), 1), 2432902008176640000
|
|
255
|
-
)
|
|
256
|
-
self.assertEqual(balanced_reduce(add, Squares(10)), 285)
|
|
257
|
-
self.assertEqual(balanced_reduce(add, Squares(10), 0), 285)
|
|
258
|
-
self.assertEqual(balanced_reduce(add, Squares(0), 0), 0)
|
|
259
|
-
self.assertRaises(TypeError, balanced_reduce)
|
|
260
|
-
self.assertRaises(TypeError, balanced_reduce, 42, 42)
|
|
261
|
-
self.assertRaises(TypeError, balanced_reduce, 42, 42, 42)
|
|
262
|
-
self.assertEqual(
|
|
263
|
-
balanced_reduce(42, "1"), "1"
|
|
264
|
-
) # func is never called with one item
|
|
265
|
-
self.assertEqual(
|
|
266
|
-
balanced_reduce(42, "", "1"), "1"
|
|
267
|
-
) # func is never called with one item
|
|
268
|
-
self.assertRaises(TypeError, balanced_reduce, 42, (42, 42))
|
|
269
|
-
self.assertRaises(
|
|
270
|
-
TypeError, balanced_reduce, add, []
|
|
271
|
-
) # arg 2 must not be empty sequence with no initial value
|
|
272
|
-
self.assertRaises(TypeError, balanced_reduce, add, "")
|
|
273
|
-
self.assertRaises(TypeError, balanced_reduce, add, ())
|
|
274
|
-
self.assertRaises(TypeError, balanced_reduce, add, object())
|
|
275
|
-
|
|
276
|
-
class TestFailingIter:
|
|
277
|
-
def __iter__(self):
|
|
278
|
-
raise RuntimeError
|
|
279
|
-
|
|
280
|
-
self.assertRaises(RuntimeError, balanced_reduce, add, TestFailingIter())
|
|
281
|
-
|
|
282
|
-
self.assertIsNone(balanced_reduce(add, [], None))
|
|
283
|
-
self.assertEqual(balanced_reduce(add, [], 42), 42)
|
|
284
|
-
|
|
285
|
-
class BadSeq:
|
|
286
|
-
def __getitem__(self, index):
|
|
287
|
-
raise ValueError
|
|
288
|
-
|
|
289
|
-
self.assertRaises(ValueError, balanced_reduce, 42, BadSeq())
|
|
290
|
-
|
|
291
|
-
# Test reduce()'s use of iterators.
|
|
292
|
-
def test_iterator_usage(self):
|
|
293
|
-
class SequenceClass:
|
|
294
|
-
def __init__(self, n):
|
|
295
|
-
self.n = n
|
|
296
|
-
|
|
297
|
-
def __getitem__(self, i):
|
|
298
|
-
if 0 <= i < self.n:
|
|
299
|
-
return i
|
|
300
|
-
else:
|
|
301
|
-
raise IndexError
|
|
302
|
-
|
|
303
|
-
from operator import add
|
|
304
|
-
|
|
305
|
-
self.assertEqual(balanced_reduce(add, SequenceClass(5)), 10)
|
|
306
|
-
self.assertEqual(balanced_reduce(add, SequenceClass(5), 42), 52)
|
|
307
|
-
self.assertRaises(TypeError, balanced_reduce, add, SequenceClass(0))
|
|
308
|
-
self.assertEqual(balanced_reduce(add, SequenceClass(0), 42), 42)
|
|
309
|
-
self.assertEqual(balanced_reduce(add, SequenceClass(1)), 0)
|
|
310
|
-
self.assertEqual(balanced_reduce(add, SequenceClass(1), 42), 42)
|
|
311
|
-
|
|
312
|
-
d = {"one": 1, "two": 2, "three": 3}
|
|
313
|
-
self.assertEqual(balanced_reduce(add, d), "".join(d.keys()))
|
|
314
|
-
|
|
315
|
-
# This test is specific to balanced_reduce
|
|
316
|
-
def test_is_balanced(self):
|
|
317
|
-
# Tests that balanced_reduce returns the object as a balanced tree
|
|
318
|
-
class CombinedNode:
|
|
319
|
-
def __init__(self, a, b):
|
|
320
|
-
self.a = a
|
|
321
|
-
self.b = b
|
|
322
|
-
|
|
323
|
-
def __repr__(self):
|
|
324
|
-
return f"({self.a} {self.b})"
|
|
325
|
-
|
|
326
|
-
self.assertEqual(
|
|
327
|
-
repr(
|
|
328
|
-
balanced_reduce(CombinedNode, ["A", "B", "C", "D", "E", "F", "G", "H"])
|
|
329
|
-
),
|
|
330
|
-
"(((A B) (C D)) ((E F) (G H)))",
|
|
331
|
-
# Note: functools.reduce will return '(((((((A B) C) D) E) F) G) H)'
|
|
332
|
-
)
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
from django.test import TestCase
|
|
2
|
-
|
|
3
|
-
from wagtail.search import index
|
|
4
|
-
from wagtail.test.search.models import Book, Novel
|
|
5
|
-
from wagtail.test.testapp.models import Advert, ManyToManyBlogPage
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TestSelectOnQuerySet(TestCase):
|
|
9
|
-
def test_select_on_queryset_with_foreign_key(self):
|
|
10
|
-
fields = index.RelatedFields(
|
|
11
|
-
"protagonist",
|
|
12
|
-
[
|
|
13
|
-
index.SearchField("name"),
|
|
14
|
-
],
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
queryset = fields.select_on_queryset(Novel.objects.all())
|
|
18
|
-
|
|
19
|
-
# ForeignKey should be select_related
|
|
20
|
-
self.assertFalse(queryset._prefetch_related_lookups)
|
|
21
|
-
self.assertIn("protagonist", queryset.query.select_related)
|
|
22
|
-
|
|
23
|
-
def test_select_on_queryset_with_one_to_one(self):
|
|
24
|
-
fields = index.RelatedFields(
|
|
25
|
-
"book_ptr",
|
|
26
|
-
[
|
|
27
|
-
index.SearchField("title"),
|
|
28
|
-
],
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
queryset = fields.select_on_queryset(Novel.objects.all())
|
|
32
|
-
|
|
33
|
-
# OneToOneField should be select_related
|
|
34
|
-
self.assertFalse(queryset._prefetch_related_lookups)
|
|
35
|
-
self.assertIn("book_ptr", queryset.query.select_related)
|
|
36
|
-
|
|
37
|
-
def test_select_on_queryset_with_many_to_many(self):
|
|
38
|
-
fields = index.RelatedFields(
|
|
39
|
-
"adverts",
|
|
40
|
-
[
|
|
41
|
-
index.SearchField("title"),
|
|
42
|
-
],
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
queryset = fields.select_on_queryset(ManyToManyBlogPage.objects.all())
|
|
46
|
-
|
|
47
|
-
# ManyToManyField should be prefetch_related
|
|
48
|
-
self.assertIn("adverts", queryset._prefetch_related_lookups)
|
|
49
|
-
self.assertFalse(queryset.query.select_related)
|
|
50
|
-
|
|
51
|
-
def test_select_on_queryset_with_reverse_foreign_key(self):
|
|
52
|
-
fields = index.RelatedFields(
|
|
53
|
-
"categories", [index.RelatedFields("category", [index.SearchField("name")])]
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
queryset = fields.select_on_queryset(ManyToManyBlogPage.objects.all())
|
|
57
|
-
|
|
58
|
-
# reverse ForeignKey should be prefetch_related
|
|
59
|
-
self.assertIn("categories", queryset._prefetch_related_lookups)
|
|
60
|
-
self.assertFalse(queryset.query.select_related)
|
|
61
|
-
|
|
62
|
-
def test_select_on_queryset_with_reverse_one_to_one(self):
|
|
63
|
-
fields = index.RelatedFields(
|
|
64
|
-
"novel",
|
|
65
|
-
[
|
|
66
|
-
index.SearchField("subtitle"),
|
|
67
|
-
],
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
queryset = fields.select_on_queryset(Book.objects.all())
|
|
71
|
-
|
|
72
|
-
# reverse OneToOneField should be select_related
|
|
73
|
-
self.assertFalse(queryset._prefetch_related_lookups)
|
|
74
|
-
self.assertIn("novel", queryset.query.select_related)
|
|
75
|
-
|
|
76
|
-
def test_select_on_queryset_with_reverse_many_to_many(self):
|
|
77
|
-
fields = index.RelatedFields(
|
|
78
|
-
"manytomanyblogpage",
|
|
79
|
-
[
|
|
80
|
-
index.SearchField("title"),
|
|
81
|
-
],
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
queryset = fields.select_on_queryset(Advert.objects.all())
|
|
85
|
-
|
|
86
|
-
# reverse ManyToManyField should be prefetch_related
|
|
87
|
-
self.assertIn("manytomanyblogpage", queryset._prefetch_related_lookups)
|
|
88
|
-
self.assertFalse(queryset.query.select_related)
|
|
89
|
-
|
|
90
|
-
def test_select_on_queryset_with_taggable_manager(self):
|
|
91
|
-
fields = index.RelatedFields(
|
|
92
|
-
"tags",
|
|
93
|
-
[
|
|
94
|
-
index.SearchField("name"),
|
|
95
|
-
],
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
queryset = fields.select_on_queryset(Novel.objects.all())
|
|
99
|
-
|
|
100
|
-
# Tags should be prefetch_related
|
|
101
|
-
self.assertIn("tags", queryset._prefetch_related_lookups)
|
|
102
|
-
self.assertFalse(queryset.query.select_related)
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import sqlite3
|
|
2
|
-
import unittest
|
|
3
|
-
from unittest import skip
|
|
4
|
-
|
|
5
|
-
from django.db import connection
|
|
6
|
-
from django.test.testcases import TestCase
|
|
7
|
-
from django.test.utils import override_settings
|
|
8
|
-
|
|
9
|
-
from wagtail.search.backends.database.sqlite.utils import fts5_available
|
|
10
|
-
from wagtail.search.tests.test_backends import BackendTests
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@unittest.skipUnless(
|
|
14
|
-
connection.vendor == "sqlite", "The current database is not SQLite"
|
|
15
|
-
)
|
|
16
|
-
@unittest.skipIf(
|
|
17
|
-
sqlite3.sqlite_version_info < (3, 19, 0), "This SQLite version is not supported"
|
|
18
|
-
)
|
|
19
|
-
@unittest.skipUnless(fts5_available(), "The SQLite fts5 extension is not available")
|
|
20
|
-
@override_settings(
|
|
21
|
-
WAGTAILSEARCH_BACKENDS={
|
|
22
|
-
"default": {
|
|
23
|
-
"BACKEND": "wagtail.search.backends.database.sqlite.sqlite",
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
)
|
|
27
|
-
class TestSQLiteSearchBackend(BackendTests, TestCase):
|
|
28
|
-
backend_path = "wagtail.search.backends.database.sqlite.sqlite"
|
|
29
|
-
|
|
30
|
-
@skip("The SQLite backend doesn't support boosting.")
|
|
31
|
-
def test_search_boosting_on_related_fields(self):
|
|
32
|
-
return super().test_search_boosting_on_related_fields()
|
|
33
|
-
|
|
34
|
-
@skip("The SQLite backend doesn't support boosting.")
|
|
35
|
-
def test_boost(self):
|
|
36
|
-
return super().test_boost()
|
|
37
|
-
|
|
38
|
-
@skip("The SQLite backend doesn't score annotations.")
|
|
39
|
-
def test_annotate_score(self):
|
|
40
|
-
return super().test_annotate_score()
|
|
41
|
-
|
|
42
|
-
@skip("The SQLite backend doesn't score annotations.")
|
|
43
|
-
def test_annotate_score_with_slice(self):
|
|
44
|
-
return super().test_annotate_score_with_slice()
|
|
45
|
-
|
|
46
|
-
@skip("The SQLite backend doesn't support searching on specified fields.")
|
|
47
|
-
def test_autocomplete_with_fields_arg(self):
|
|
48
|
-
return super().test_autocomplete_with_fields_arg()
|
|
49
|
-
|
|
50
|
-
@skip("The SQLite backend doesn't guarantee correct ranking of results.")
|
|
51
|
-
def test_ranking(self):
|
|
52
|
-
return super().test_ranking()
|