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.
Files changed (345) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_page.py +1 -1
  3. wagtail/actions/create_alias.py +1 -1
  4. wagtail/actions/delete_page.py +1 -1
  5. wagtail/actions/publish_page_revision.py +1 -1
  6. wagtail/actions/publish_revision.py +1 -1
  7. wagtail/actions/revert_to_page_revision.py +1 -1
  8. wagtail/actions/unpublish.py +1 -1
  9. wagtail/actions/unpublish_page.py +1 -1
  10. wagtail/admin/auth.py +3 -1
  11. wagtail/admin/checks.py +2 -2
  12. wagtail/admin/filters.py +28 -1
  13. wagtail/admin/forms/collections.py +1 -1
  14. wagtail/admin/forms/comments.py +1 -1
  15. wagtail/admin/forms/models.py +1 -1
  16. wagtail/admin/forms/pages.py +1 -1
  17. wagtail/admin/forms/tags.py +1 -1
  18. wagtail/admin/locale/cs/LC_MESSAGES/django.mo +0 -0
  19. wagtail/admin/locale/cs/LC_MESSAGES/django.po +25 -1
  20. wagtail/admin/locale/en/LC_MESSAGES/django.po +278 -192
  21. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +29 -15
  22. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  23. wagtail/admin/locale/it/LC_MESSAGES/django.po +3 -2
  24. wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
  25. wagtail/admin/locale/nl/LC_MESSAGES/django.po +57 -3
  26. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.mo +0 -0
  27. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.po +8 -2
  28. wagtail/admin/locale/ru/LC_MESSAGES/django.mo +0 -0
  29. wagtail/admin/locale/ru/LC_MESSAGES/django.po +58 -1
  30. wagtail/admin/locale/tr/LC_MESSAGES/django.mo +0 -0
  31. wagtail/admin/locale/tr/LC_MESSAGES/django.po +3 -2
  32. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  33. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +2 -2
  40. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  42. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/icons.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  48. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  49. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  51. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  52. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  53. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  54. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  55. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  56. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +2 -2
  57. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-modal.js +1 -1
  58. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-transition.js +1 -1
  59. wagtail/admin/static/wagtailadmin/js/vendor/jquery-3.6.0.min.js +1 -1
  60. wagtail/admin/static/wagtailadmin/js/vendor/jquery-ui-1.13.2.min.js +1 -1
  61. wagtail/admin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js +1 -1
  62. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload-process.js +1 -1
  63. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload.js +1 -1
  64. wagtail/admin/static/wagtailadmin/js/vendor/jquery.iframe-transport.js +1 -1
  65. wagtail/admin/static/wagtailadmin/js/vendor/tag-it.js +1 -1
  66. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  67. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +1 -1
  68. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  69. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  70. wagtail/admin/templates/wagtailadmin/account/account.html +2 -0
  71. wagtail/admin/templates/wagtailadmin/base.html +14 -0
  72. wagtail/admin/templates/wagtailadmin/generic/chooser/chooser.html +2 -1
  73. wagtail/admin/templates/wagtailadmin/generic/chooser/creation_form.html +2 -1
  74. wagtail/admin/templates/wagtailadmin/generic/form.html +3 -1
  75. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  76. wagtail/admin/templates/wagtailadmin/panels/object_list.html +1 -1
  77. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +3 -2
  78. wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  80. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +19 -0
  81. wagtail/admin/templates/wagtailadmin/shared/panel.html +1 -1
  82. wagtail/admin/templates/wagtailadmin/shared/set_privacy.html +15 -0
  83. wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +28 -1
  84. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +2 -2
  85. wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_header.html → tables/ordering_header.html} +2 -2
  86. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +1 -1
  87. wagtail/admin/templates/wagtailadmin/userbar/base.html +6 -3
  88. wagtail/admin/templates/wagtailadmin/userbar/item_admin.html +2 -2
  89. wagtail/admin/templates/wagtailadmin/userbar/item_page_add.html +2 -2
  90. wagtail/admin/templates/wagtailadmin/userbar/item_page_edit.html +2 -2
  91. wagtail/admin/templates/wagtailadmin/userbar/item_page_explore.html +2 -2
  92. wagtail/admin/templates/wagtailadmin/widgets/{daterange_input.html → range_input.html} +1 -1
  93. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/chooser.html +4 -2
  94. wagtail/admin/templatetags/wagtailadmin_tags.py +56 -22
  95. wagtail/admin/tests/api/test_pages.py +7 -7
  96. wagtail/admin/tests/api/test_renderer_classes.py +16 -0
  97. wagtail/admin/tests/pages/test_create_page.py +34 -2
  98. wagtail/admin/tests/pages/test_edit_page.py +128 -14
  99. wagtail/admin/tests/pages/test_explorer_view.py +34 -7
  100. wagtail/admin/tests/pages/test_reorder_page.py +11 -0
  101. wagtail/admin/tests/test_collections_views.py +12 -0
  102. wagtail/admin/tests/test_edit_handlers.py +3 -3
  103. wagtail/admin/tests/test_filters.py +2 -2
  104. wagtail/admin/tests/test_keyboard_shortcuts.py +52 -2
  105. wagtail/admin/tests/test_menu.py +0 -2
  106. wagtail/admin/tests/test_privacy.py +16 -16
  107. wagtail/admin/tests/test_templatetags.py +137 -0
  108. wagtail/admin/tests/test_userbar.py +75 -35
  109. wagtail/admin/tests/test_views_generic.py +34 -0
  110. wagtail/admin/tests/test_workflows.py +34 -0
  111. wagtail/admin/tests/viewsets/test_model_viewset.py +322 -0
  112. wagtail/admin/ui/tables/orderable.py +73 -0
  113. wagtail/admin/ui/tables/pages.py +3 -13
  114. wagtail/admin/userbar.py +6 -1
  115. wagtail/admin/views/collection_privacy.py +6 -2
  116. wagtail/admin/views/generic/__init__.py +1 -0
  117. wagtail/admin/views/generic/mixins.py +20 -2
  118. wagtail/admin/views/generic/models.py +67 -1
  119. wagtail/admin/views/generic/ordering.py +79 -0
  120. wagtail/admin/views/home.py +3 -3
  121. wagtail/admin/views/page_privacy.py +5 -2
  122. wagtail/admin/views/pages/create.py +1 -1
  123. wagtail/admin/views/pages/edit.py +2 -2
  124. wagtail/admin/views/pages/listing.py +7 -42
  125. wagtail/admin/views/pages/move.py +1 -1
  126. wagtail/admin/views/pages/ordering.py +1 -1
  127. wagtail/admin/viewsets/base.py +1 -1
  128. wagtail/admin/viewsets/model.py +49 -1
  129. wagtail/admin/wagtail_hooks.py +2 -1
  130. wagtail/admin/widgets/slug.py +10 -10
  131. wagtail/api/v2/serializers.py +1 -1
  132. wagtail/api/v2/tests/test_renderer_classes.py +32 -0
  133. wagtail/apps.py +2 -0
  134. wagtail/bin/wagtail.py +1 -1
  135. wagtail/blocks/struct_block.py +2 -1
  136. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +14 -14
  137. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.mo +0 -0
  138. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.po +19 -2
  139. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.mo +0 -0
  140. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +18 -1
  141. wagtail/contrib/frontend_cache/tests.py +4 -2
  142. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +4 -4
  143. wagtail/contrib/redirects/tests/test_tmp_storages.py +20 -0
  144. wagtail/contrib/redirects/tmp_storages.py +1 -1
  145. wagtail/contrib/redirects/views.py +3 -3
  146. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +3 -3
  147. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.mo +0 -0
  148. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +43 -3
  149. wagtail/contrib/search_promotions/static/wagtailsearchpromotions/js/query-chooser-modal.js +1 -1
  150. wagtail/contrib/search_promotions/views/settings.py +2 -2
  151. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.mo +0 -0
  152. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.po +6 -1
  153. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +1 -1
  154. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.mo +0 -0
  155. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.po +6 -2
  156. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.mo +0 -0
  157. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +6 -1
  158. wagtail/contrib/settings/tests/site_specific/test_admin.py +40 -6
  159. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  160. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  161. wagtail/contrib/styleguide/templates/wagtailstyleguide/base.html +5 -5
  162. wagtail/contrib/table_block/blocks.py +1 -0
  163. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +5 -1
  164. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  165. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  166. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  167. wagtail/coreutils.py +5 -5
  168. wagtail/documents/forms.py +18 -1
  169. wagtail/documents/locale/en/LC_MESSAGES/django.po +10 -10
  170. wagtail/documents/locale/nl/LC_MESSAGES/django.mo +0 -0
  171. wagtail/documents/locale/nl/LC_MESSAGES/django.po +9 -0
  172. wagtail/documents/locale/ru/LC_MESSAGES/django.mo +0 -0
  173. wagtail/documents/locale/ru/LC_MESSAGES/django.po +9 -0
  174. wagtail/documents/models.py +1 -1
  175. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  176. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  177. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  178. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  179. wagtail/documents/templates/wagtaildocs/documents/add.html +0 -34
  180. wagtail/documents/tests/test_admin_views.py +132 -26
  181. wagtail/documents/tests/test_collection_privacy.py +18 -4
  182. wagtail/documents/tests/test_form_overrides.py +1 -1
  183. wagtail/documents/tests/test_search.py +21 -8
  184. wagtail/documents/views/documents.py +1 -1
  185. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  186. wagtail/embeds/static/wagtailembeds/js/embed-chooser-modal.js +1 -1
  187. wagtail/images/forms.py +16 -1
  188. wagtail/images/locale/cs/LC_MESSAGES/django.mo +0 -0
  189. wagtail/images/locale/cs/LC_MESSAGES/django.po +12 -1
  190. wagtail/images/locale/en/LC_MESSAGES/django.po +57 -46
  191. wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
  192. wagtail/images/locale/nl/LC_MESSAGES/django.po +37 -14
  193. wagtail/images/locale/ru/LC_MESSAGES/django.mo +0 -0
  194. wagtail/images/locale/ru/LC_MESSAGES/django.po +20 -1
  195. wagtail/images/models.py +1 -1
  196. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  197. wagtail/images/static/wagtailimages/js/focal-point-chooser.js +1 -1
  198. wagtail/images/static/wagtailimages/js/image-block.js +1 -1
  199. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  200. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  201. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  202. wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
  203. wagtail/images/static/wagtailimages/js/vendor/jquery.Jcrop.min.js +1 -1
  204. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
  205. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-validate.js +1 -1
  206. wagtail/images/static/wagtailimages/js/vendor/load-image.min.js +1 -1
  207. wagtail/images/templates/wagtailimages/chooser/chooser.html +22 -13
  208. wagtail/images/templates/wagtailimages/chooser/image_preview_column_cell.html +10 -0
  209. wagtail/images/templates/wagtailimages/chooser/results.html +24 -20
  210. wagtail/images/templates/wagtailimages/chooser/title_column_cell.html +15 -0
  211. wagtail/images/templates/wagtailimages/images/add.html +0 -34
  212. wagtail/images/templates/wagtailimages/images/index.html +3 -3
  213. wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
  214. wagtail/images/templates/wagtailimages/images/layout_toggle_button.html +8 -7
  215. wagtail/images/templatetags/wagtailimages_tags.py +2 -2
  216. wagtail/images/tests/test_admin_views.py +87 -0
  217. wagtail/images/tests/test_form_overrides.py +1 -1
  218. wagtail/images/tests/test_models.py +48 -9
  219. wagtail/images/views/chooser.py +66 -2
  220. wagtail/locale/en/LC_MESSAGES/django.po +55 -55
  221. wagtail/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  222. wagtail/locale/is_IS/LC_MESSAGES/django.po +3 -3
  223. wagtail/locale/nl/LC_MESSAGES/django.mo +0 -0
  224. wagtail/locale/nl/LC_MESSAGES/django.po +11 -2
  225. wagtail/locale/ru/LC_MESSAGES/django.mo +0 -0
  226. wagtail/locale/ru/LC_MESSAGES/django.po +11 -1
  227. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  228. wagtail/locales/locale/nl/LC_MESSAGES/django.mo +0 -0
  229. wagtail/locales/locale/nl/LC_MESSAGES/django.po +12 -1
  230. wagtail/locales/locale/ru/LC_MESSAGES/django.mo +0 -0
  231. wagtail/locales/locale/ru/LC_MESSAGES/django.po +10 -1
  232. wagtail/locales/views.py +2 -2
  233. wagtail/models/orderable.py +10 -0
  234. wagtail/models/pages.py +9 -11
  235. wagtail/models/sites.py +1 -1
  236. wagtail/models/workflows.py +8 -5
  237. wagtail/project_template/home/tests.py +6 -7
  238. wagtail/project_template/project_name/settings/base.py +9 -9
  239. wagtail/project_template/requirements.txt +1 -1
  240. wagtail/query.py +7 -2
  241. wagtail/rich_text/rewriters.py +1 -1
  242. wagtail/search/apps.py +4 -49
  243. wagtail/search/backends/__init__.py +1 -113
  244. wagtail/search/backends/base.py +1 -547
  245. wagtail/search/backends/database/__init__.py +1 -50
  246. wagtail/search/backends/database/fallback.py +1 -253
  247. wagtail/search/backends/database/mysql/mysql.py +1 -700
  248. wagtail/search/backends/database/mysql/query.py +1 -258
  249. wagtail/search/backends/database/postgres/postgres.py +1 -749
  250. wagtail/search/backends/database/postgres/query.py +1 -83
  251. wagtail/search/backends/database/postgres/weights.py +1 -63
  252. wagtail/search/backends/database/sqlite/query.py +1 -294
  253. wagtail/search/backends/database/sqlite/sqlite.py +1 -719
  254. wagtail/search/backends/database/sqlite/utils.py +1 -35
  255. wagtail/search/backends/deprecation.py +45 -0
  256. wagtail/search/backends/elasticsearch7.py +18 -1260
  257. wagtail/search/backends/elasticsearch8.py +21 -96
  258. wagtail/search/backends/elasticsearch9.py +35 -0
  259. wagtail/search/backends/opensearch2.py +35 -0
  260. wagtail/search/backends/opensearch3.py +35 -0
  261. wagtail/search/index.py +1 -358
  262. wagtail/search/locale/en/LC_MESSAGES/django.po +2 -10
  263. wagtail/search/management/commands/update_index.py +1 -205
  264. wagtail/search/management/commands/wagtail_update_index.py +1 -4
  265. wagtail/search/models.py +32 -158
  266. wagtail/search/query.py +1 -114
  267. wagtail/search/queryset.py +1 -43
  268. wagtail/search/signal_handlers.py +1 -24
  269. wagtail/search/tasks.py +1 -10
  270. wagtail/search/tests/test_elasticsearch.py +22 -0
  271. wagtail/search/utils.py +1 -206
  272. wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
  273. wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -3
  274. wagtail/snippets/locale/ru/LC_MESSAGES/django.mo +0 -0
  275. wagtail/snippets/locale/ru/LC_MESSAGES/django.po +8 -1
  276. wagtail/snippets/locale/tr/LC_MESSAGES/django.mo +0 -0
  277. wagtail/snippets/locale/tr/LC_MESSAGES/django.po +8 -1
  278. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  279. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  280. wagtail/snippets/tests/test_preview.py +5 -6
  281. wagtail/snippets/tests/test_reordering.py +319 -0
  282. wagtail/snippets/tests/test_snippets.py +65 -12
  283. wagtail/snippets/views/snippets.py +16 -0
  284. wagtail/test/numberformat.py +30 -0
  285. wagtail/test/settings.py +35 -12
  286. wagtail/test/testapp/fields.py +12 -0
  287. wagtail/test/testapp/migrations/0056_commentablejsonpage.py +50 -0
  288. wagtail/test/testapp/migrations/0057_featurecompletetoy_sort_order.py +23 -0
  289. wagtail/test/testapp/migrations/0058_customlocktask.py +31 -0
  290. wagtail/test/testapp/models.py +27 -0
  291. wagtail/test/testapp/urls.py +1 -0
  292. wagtail/test/testapp/views.py +18 -2
  293. wagtail/test/utils/page_tests.py +17 -17
  294. wagtail/test/utils/template_tests.py +4 -6
  295. wagtail/test/utils/wagtail_tests.py +1 -2
  296. wagtail/tests/test_blocks.py +15 -0
  297. wagtail/tests/test_page_model.py +15 -0
  298. wagtail/{search/tests → tests}/test_page_search.py +29 -2
  299. wagtail/tests/test_search_fields.py +69 -0
  300. wagtail/tests/test_tests.py +62 -6
  301. wagtail/tests/test_workflow.py +25 -1
  302. wagtail/users/locale/cs/LC_MESSAGES/django.mo +0 -0
  303. wagtail/users/locale/cs/LC_MESSAGES/django.po +3 -0
  304. wagtail/users/locale/en/LC_MESSAGES/django.po +2 -2
  305. wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
  306. wagtail/users/locale/nl/LC_MESSAGES/django.po +6 -3
  307. wagtail/users/locale/ru/LC_MESSAGES/django.mo +0 -0
  308. wagtail/users/locale/ru/LC_MESSAGES/django.po +5 -1
  309. wagtail/users/locale/tr/LC_MESSAGES/django.mo +0 -0
  310. wagtail/users/locale/tr/LC_MESSAGES/django.po +78 -4
  311. wagtail/users/templates/wagtailusers/users/create.html +2 -0
  312. wagtail/users/templates/wagtailusers/users/edit.html +2 -0
  313. wagtail/users/tests/test_admin_views.py +4 -0
  314. wagtail/users/views/users.py +1 -1
  315. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/METADATA +7 -6
  316. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/RECORD +322 -328
  317. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +0 -13
  318. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +0 -13
  319. wagtail/search/tests/__init__.py +0 -0
  320. wagtail/search/tests/elasticsearch_common_tests.py +0 -251
  321. wagtail/search/tests/test_backends.py +0 -1215
  322. wagtail/search/tests/test_db_backend.py +0 -62
  323. wagtail/search/tests/test_elasticsearch7_backend.py +0 -1452
  324. wagtail/search/tests/test_elasticsearch8_backend.py +0 -15
  325. wagtail/search/tests/test_index_functions.py +0 -256
  326. wagtail/search/tests/test_indexed_class.py +0 -157
  327. wagtail/search/tests/test_mysql_backend.py +0 -192
  328. wagtail/search/tests/test_postgres_backend.py +0 -210
  329. wagtail/search/tests/test_queries.py +0 -332
  330. wagtail/search/tests/test_related_fields.py +0 -102
  331. wagtail/search/tests/test_sqlite_backend.py +0 -52
  332. wagtail/test/search/__init__.py +0 -0
  333. wagtail/test/search/apps.py +0 -9
  334. wagtail/test/search/fixtures/search.json +0 -545
  335. wagtail/test/search/migrations/0001_initial.py +0 -146
  336. wagtail/test/search/migrations/0002_bookunindexed.py +0 -43
  337. wagtail/test/search/migrations/0003_book_summary.py +0 -18
  338. wagtail/test/search/migrations/__init__.py +0 -0
  339. wagtail/test/search/models.py +0 -137
  340. /wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_cell.html → tables/ordering_cell.html} +0 -0
  341. /wagtail/{search/checks.py → checks.py} +0 -0
  342. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/WHEEL +0 -0
  343. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/entry_points.txt +0 -0
  344. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/licenses/LICENSE +0 -0
  345. {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()