Jelajahi Sumber

Run pyupgrade with `--py38-plus`

zerolab 1 tahun lalu
induk
melakukan
ac10b36c7b
100 mengubah file dengan 192 tambahan dan 255 penghapusan
  1. 1 2
      docs/conf.py
  2. 2 3
      scripts/get-translator-credits.py
  3. 1 3
      wagtail/admin/compare.py
  4. 1 1
      wagtail/admin/forms/account.py
  5. 1 1
      wagtail/admin/forms/collections.py
  6. 1 3
      wagtail/admin/forms/models.py
  7. 0 1
      wagtail/admin/migrations/0001_create_admin_access_permissions.py
  8. 2 2
      wagtail/admin/panels/base.py
  9. 2 2
      wagtail/admin/panels/field_panel.py
  10. 1 1
      wagtail/admin/panels/group.py
  11. 2 2
      wagtail/admin/rich_text/converters/editor_html.py
  12. 1 1
      wagtail/admin/rich_text/converters/html_to_contentstate.py
  13. 1 1
      wagtail/admin/templatetags/wagtailadmin_tags.py
  14. 2 4
      wagtail/admin/tests/benches.py
  15. 2 4
      wagtail/admin/tests/pages/test_bulk_actions/test_bulk_delete.py
  16. 3 5
      wagtail/admin/tests/pages/test_bulk_actions/test_bulk_move.py
  17. 1 3
      wagtail/admin/tests/pages/test_bulk_actions/test_bulk_publish.py
  18. 1 3
      wagtail/admin/tests/pages/test_bulk_actions/test_bulk_unpublish.py
  19. 1 1
      wagtail/admin/tests/pages/test_edit_page.py
  20. 1 1
      wagtail/admin/tests/pages/test_move_page.py
  21. 3 3
      wagtail/admin/tests/pages/test_preview.py
  22. 26 26
      wagtail/admin/tests/test_filters.py
  23. 1 3
      wagtail/admin/tests/test_site_summary.py
  24. 3 3
      wagtail/admin/tests/test_templatetags.py
  25. 6 6
      wagtail/admin/tests/test_workflows.py
  26. 0 2
      wagtail/admin/tests/tests.py
  27. 3 4
      wagtail/admin/ui/tables/__init__.py
  28. 1 1
      wagtail/admin/viewsets/__init__.py
  29. 1 1
      wagtail/admin/wagtail_hooks.py
  30. 1 1
      wagtail/admin/widgets/button.py
  31. 1 1
      wagtail/admin/widgets/chooser.py
  32. 1 1
      wagtail/admin/widgets/workflows.py
  33. 1 1
      wagtail/api/conf.py
  34. 1 1
      wagtail/api/v2/router.py
  35. 2 2
      wagtail/api/v2/tests/test_documents.py
  36. 2 2
      wagtail/api/v2/tests/test_images.py
  37. 2 2
      wagtail/api/v2/tests/test_pages.py
  38. 3 3
      wagtail/bin/wagtail.py
  39. 5 7
      wagtail/blocks/base.py
  40. 1 1
      wagtail/blocks/field_block.py
  41. 1 1
      wagtail/blocks/list_block.py
  42. 7 7
      wagtail/blocks/migrations/operations.py
  43. 2 2
      wagtail/blocks/migrations/utils.py
  44. 3 4
      wagtail/blocks/stream_block.py
  45. 6 3
      wagtail/blocks/struct_block.py
  46. 1 1
      wagtail/contrib/forms/forms.py
  47. 0 1
      wagtail/contrib/forms/migrations/0001_initial.py
  48. 0 1
      wagtail/contrib/forms/migrations/0002_add_verbose_names.py
  49. 0 1
      wagtail/contrib/forms/migrations/0003_capitalizeverbose.py
  50. 0 1
      wagtail/contrib/forms/migrations/0004_add_verbose_name_plural.py
  51. 1 1
      wagtail/contrib/forms/models.py
  52. 0 1
      wagtail/contrib/forms/tests/test_forms.py
  53. 0 1
      wagtail/contrib/forms/tests/test_models.py
  54. 6 7
      wagtail/contrib/forms/tests/test_views.py
  55. 0 1
      wagtail/contrib/forms/tests/utils.py
  56. 2 2
      wagtail/contrib/frontend_cache/backends.py
  57. 1 1
      wagtail/contrib/frontend_cache/tests.py
  58. 1 1
      wagtail/contrib/frontend_cache/utils.py
  59. 1 1
      wagtail/contrib/modeladmin/helpers/permission.py
  60. 5 5
      wagtail/contrib/modeladmin/helpers/url.py
  61. 2 2
      wagtail/contrib/modeladmin/mixins.py
  62. 3 3
      wagtail/contrib/modeladmin/options.py
  63. 5 13
      wagtail/contrib/modeladmin/tests/test_page_modeladmin.py
  64. 1 1
      wagtail/contrib/redirects/forms.py
  65. 8 8
      wagtail/contrib/redirects/management/commands/import_redirects.py
  66. 0 1
      wagtail/contrib/redirects/migrations/0001_initial.py
  67. 0 1
      wagtail/contrib/redirects/migrations/0002_add_verbose_names.py
  68. 0 1
      wagtail/contrib/redirects/migrations/0003_make_site_field_editable.py
  69. 0 1
      wagtail/contrib/redirects/migrations/0004_set_unique_on_path_and_site.py
  70. 0 1
      wagtail/contrib/redirects/migrations/0005_capitalizeverbose.py
  71. 12 12
      wagtail/contrib/redirects/tests/test_import_admin_views.py
  72. 5 7
      wagtail/contrib/redirects/tests/test_import_command.py
  73. 1 1
      wagtail/contrib/redirects/tests/test_import_utils.py
  74. 0 1
      wagtail/contrib/redirects/tests/test_redirects.py
  75. 1 1
      wagtail/contrib/redirects/utils.py
  76. 0 1
      wagtail/contrib/search_promotions/migrations/0002_capitalizeverbose.py
  77. 1 1
      wagtail/contrib/search_promotions/models.py
  78. 3 3
      wagtail/contrib/search_promotions/tests.py
  79. 1 1
      wagtail/contrib/settings/context_processors.py
  80. 1 1
      wagtail/contrib/settings/models.py
  81. 1 3
      wagtail/contrib/settings/permissions.py
  82. 1 1
      wagtail/contrib/settings/registry.py
  83. 1 1
      wagtail/contrib/settings/tests/generic/test_admin.py
  84. 1 1
      wagtail/contrib/settings/tests/site_specific/test_admin.py
  85. 3 3
      wagtail/contrib/settings/tests/site_specific/test_forms.py
  86. 2 2
      wagtail/contrib/settings/tests/site_specific/test_model.py
  87. 1 1
      wagtail/contrib/settings/views.py
  88. 1 1
      wagtail/contrib/simple_translation/forms.py
  89. 1 1
      wagtail/contrib/table_block/templatetags/table_block_tags.py
  90. 6 10
      wagtail/coreutils.py
  91. 0 1
      wagtail/documents/migrations/0001_initial.py
  92. 0 1
      wagtail/documents/migrations/0002_initial_data.py
  93. 0 1
      wagtail/documents/migrations/0003_add_verbose_names.py
  94. 0 1
      wagtail/documents/migrations/0004_capitalizeverbose.py
  95. 0 1
      wagtail/documents/migrations/0005_alter_uploaded_by_user_on_delete_action.py
  96. 0 1
      wagtail/documents/migrations/0005_document_collection.py
  97. 0 1
      wagtail/documents/migrations/0006_copy_document_permissions_to_collections.py
  98. 0 1
      wagtail/documents/migrations/0007_merge.py
  99. 1 1
      wagtail/documents/tests/test_admin_views.py
  100. 1 3
      wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py

+ 1 - 2
docs/conf.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # Wagtail documentation build configuration file, created by
 # sphinx-quickstart on Tue Jan 14 17:38:55 2014.
@@ -85,7 +84,7 @@ copyright = f"{datetime.now().year}, Torchbox and contributors"
 # built documents.
 
 # The short X.Y version.
-version = "{}.{}".format(VERSION[0], VERSION[1])
+version = f"{VERSION[0]}.{VERSION[1]}"
 # The full version, including alpha/beta/rc tags.
 release = __version__
 

+ 2 - 3
scripts/get-translator-credits.py

@@ -1,7 +1,6 @@
 import re
 import subprocess
 from collections import defaultdict
-from io import open
 
 from babel import Locale
 
@@ -20,7 +19,7 @@ for file_listing_line in file_listing.stdout:
         continue
 
     # read author list from each file
-    with open(filename, "rt") as f:
+    with open(filename) as f:
         has_found_translators_heading = False
         for line in f:
             line = line.strip()
@@ -60,7 +59,7 @@ language_names = [
 language_names.sort()
 
 for (language_name, locale) in language_names:
-    print(("%s - %s" % (language_name, locale)))  # noqa: T201
+    print(f"{language_name} - {locale}")  # noqa: T201
     print("-----")  # noqa: T201
     for author in sorted(authors_by_locale[locale]):
         print(author.replace("@", "."))  # noqa: T201

+ 1 - 3
wagtail/admin/compare.py

@@ -294,9 +294,7 @@ class BaseSequenceBlockComparison(BlockComparison):
                 block_rendered = comparison.htmlvalue(comparison.val_a)
 
             classes = " ".join(classes)
-            comparisons_html.append(
-                '<div class="{0}">{1}</div>'.format(classes, block_rendered)
-            )
+            comparisons_html.append(f'<div class="{classes}">{block_rendered}</div>')
 
         return mark_safe("\n".join(comparisons_html))
 

+ 1 - 1
wagtail/admin/forms/account.py

@@ -125,7 +125,7 @@ class AvatarPreferencesForm(forms.ModelForm):
             # will clear the now-updated field on self.instance too
             try:
                 self._original_avatar.storage.delete(self._original_avatar.name)
-            except IOError:
+            except OSError:
                 # failure to delete the old avatar shouldn't prevent us from continuing
                 warnings.warn(
                     "Failed to delete old avatar file: %s" % self._original_avatar.name

+ 1 - 1
wagtail/admin/forms/collections.py

@@ -339,7 +339,7 @@ def collection_member_permission_formset_factory(
         )
 
     GroupCollectionMemberPermissionFormSet = type(
-        str("GroupCollectionMemberPermissionFormSet"),
+        "GroupCollectionMemberPermissionFormSet",
         (BaseGroupCollectionMemberPermissionFormSet,),
         {
             "permission_types": permission_types,

+ 1 - 3
wagtail/admin/forms/models.py

@@ -121,9 +121,7 @@ class WagtailAdminModelFormMetaclass(PermissionedFormMetaclass, ClusterFormMetac
             if "formfield_callback" not in attrs or attrs["formfield_callback"] is None:
                 attrs["formfield_callback"] = formfield_for_dbfield
 
-            new_class = super(WagtailAdminModelFormMetaclass, cls).__new__(
-                cls, name, bases, attrs
-            )
+            new_class = super().__new__(cls, name, bases, attrs)
             return new_class
 
     @classmethod

+ 0 - 1
wagtail/admin/migrations/0001_create_admin_access_permissions.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations
 
 

+ 2 - 2
wagtail/admin/panels/base.py

@@ -175,7 +175,7 @@ class Panel:
         pass
 
     def __repr__(self):
-        return "<%s with model=%s>" % (
+        return "<{} with model={}>".format(
             self.__class__.__name__,
             self.model,
         )
@@ -317,7 +317,7 @@ class Panel:
             return mark_safe(self.render_html() + self.render_missing_fields())
 
         def __repr__(self):
-            return "<%s with model=%s instance=%s request=%s form=%s>" % (
+            return "<{} with model={} instance={} request={} form={}>".format(
                 self.__class__.__name__,
                 self.panel.model,
                 self.instance,

+ 2 - 2
wagtail/admin/panels/field_panel.py

@@ -122,7 +122,7 @@ class FieldPanel(Panel):
         return super().format_value_for_display(value)
 
     def __repr__(self):
-        return "<%s '%s' with model=%s>" % (
+        return "<{} '{}' with model={}>".format(
             self.__class__.__name__,
             self.field_name,
             self.model,
@@ -362,7 +362,7 @@ class FieldPanel(Panel):
             return []
 
         def __repr__(self):
-            return "<%s '%s' with model=%s instance=%s request=%s form=%s>" % (
+            return "<{} '{}' with model={} instance={} request={} form={}>".format(
                 self.__class__.__name__,
                 self.field_name,
                 self.panel.model,

+ 1 - 1
wagtail/admin/panels/group.py

@@ -102,7 +102,7 @@ class PanelGroup(Panel):
                     instance=self.instance,
                     request=self.request,
                     form=self.form,
-                    prefix=("%s-child-%s" % (self.prefix, identifier)),
+                    prefix=(f"{self.prefix}-child-{identifier}"),
                 )
                 for child, identifier in zip(
                     self.panel.children, self.panel.child_identifiers

+ 2 - 2
wagtail/admin/rich_text/converters/editor_html.py

@@ -110,7 +110,7 @@ class DbWhitelister(Whitelister):
             if tag.name == "div":
                 tag.name = "p"
 
-            super(DbWhitelister, self).clean_tag_node(doc, tag)
+            super().clean_tag_node(doc, tag)
 
 
 class EditorHTMLConverter:
@@ -176,6 +176,6 @@ class PageLinkHandler:
             if parent_page:
                 attrs += 'data-parent-id="%d" ' % parent_page.id
 
-            return '<a %shref="%s">' % (attrs, escape(page.localized.specific.url))
+            return f'<a {attrs}href="{escape(page.localized.specific.url)}">'
         except Page.DoesNotExist:
             return "<a>"

+ 1 - 1
wagtail/admin/rich_text/converters/html_to_contentstate.py

@@ -388,7 +388,7 @@ class HtmlToContentStateHandler(HTMLParser):
         if not self.open_elements:
             return  # avoid a pop from an empty list if we have an extra end tag
         expected_name, element_handler = self.open_elements.pop()
-        assert name == expected_name, "Unmatched tags: expected %s, got %s" % (
+        assert name == expected_name, "Unmatched tags: expected {}, got {}".format(
             expected_name,
             name,
         )

+ 1 - 1
wagtail/admin/templatetags/wagtailadmin_tags.py

@@ -970,7 +970,7 @@ def component(context, obj, fallback_render_method=False):
     if fallback_render_method and not has_render_html_method and hasattr(obj, "render"):
         return obj.render()
     elif not has_render_html_method:
-        raise ValueError("Cannot render %r as a component" % (obj,))
+        raise ValueError(f"Cannot render {obj!r} as a component")
 
     return obj.render_html(context)
 

+ 2 - 4
wagtail/admin/tests/benches.py

@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
 from django.test import TestCase
 from django.urls import reverse
 from django.utils import timezone
@@ -33,7 +31,7 @@ class BenchPageExplorerWith50LargePages(Benchmark, WagtailTestUtils, TestCase):
         for i in range(50):
             self.root_page.add_child(
                 instance=StreamPage(
-                    title="Page {}".format(i + 1),
+                    title=f"Page {i + 1}",
                     slug=str(i + 1),
                     body=body,
                 )
@@ -71,7 +69,7 @@ class BenchPageExplorerWithCustomURLPages(Benchmark, WagtailTestUtils, TestCase)
         for i in range(50):
             self.root_page.add_child(
                 instance=SingleEventPage(
-                    title="Event {}".format(i + 1),
+                    title=f"Event {i + 1}",
                     slug=str(i + 1),
                     date_from=timezone.now(),
                     audience="public",

+ 2 - 4
wagtail/admin/tests/pages/test_bulk_actions/test_bulk_delete.py

@@ -130,12 +130,10 @@ class TestBulkDelete(WagtailTestUtils, TestCase):
         )
 
         for child_page in self.pages_to_be_deleted:
-            self.assertInHTML(
-                "<li>{page_title}</li>".format(page_title=child_page.title), html
-            )
+            self.assertInHTML(f"<li>{child_page.title}</li>", html)
 
         self.assertTagInHTML(
-            """<form action="{}" method="POST"></form>""".format(self.url),
+            f"""<form action="{self.url}" method="POST"></form>""",
             html,
             count=0,
         )

+ 3 - 5
wagtail/admin/tests/pages/test_bulk_actions/test_bulk_move.py

@@ -126,12 +126,10 @@ class TestBulkMove(WagtailTestUtils, TestCase):
         self.assertInHTML("<p>You don't have permission to move these pages</p>", html)
 
         for child_page in self.pages_to_be_moved:
-            self.assertInHTML(
-                "<li>{page_title}</li>".format(page_title=child_page.title), html
-            )
+            self.assertInHTML(f"<li>{child_page.title}</li>", html)
 
         self.assertTagInHTML(
-            """<form action="{}" method="POST"></form>""".format(self.url),
+            f"""<form action="{self.url}" method="POST"></form>""",
             html,
             count=0,
         )
@@ -170,7 +168,7 @@ class TestBulkMove(WagtailTestUtils, TestCase):
         html = response.content.decode()
 
         self.assertInHTML(
-            "<p>The following pages cannot be moved to {}</p>".format(page.title), html
+            f"<p>The following pages cannot be moved to {page.title}</p>", html
         )
 
         for child_page in self.pages_to_be_moved:

+ 1 - 3
wagtail/admin/tests/pages/test_bulk_actions/test_bulk_publish.py

@@ -130,9 +130,7 @@ class TestBulkPublish(WagtailTestUtils, TestCase):
         )
 
         for child_page in self.pages_to_be_published:
-            self.assertInHTML(
-                "<li>{page_title}</li>".format(page_title=child_page.title), html
-            )
+            self.assertInHTML(f"<li>{child_page.title}</li>", html)
 
     def test_publish_view_post(self):
         """

+ 1 - 3
wagtail/admin/tests/pages/test_bulk_actions/test_bulk_unpublish.py

@@ -105,9 +105,7 @@ class TestBulkUnpublish(WagtailTestUtils, TestCase):
         )
 
         for child_page in self.pages_to_be_unpublished:
-            self.assertInHTML(
-                "<li>{page_title}</li>".format(page_title=child_page.title), html
-            )
+            self.assertInHTML(f"<li>{child_page.title}</li>", html)
 
     def test_unpublish_view_post(self):
         """

+ 1 - 1
wagtail/admin/tests/pages/test_edit_page.py

@@ -2281,7 +2281,7 @@ class TestIssue2492(WagtailTestUtils, TestCase):
 
         # The "View Live" button should have the custom URL.
         for message in response.context["messages"]:
-            self.assertIn('"{}"'.format(new_url), message.message)
+            self.assertIn(f'"{new_url}"', message.message)
             break
 
 

+ 1 - 1
wagtail/admin/tests/pages/test_move_page.py

@@ -124,7 +124,7 @@ class TestPageMove(WagtailTestUtils, TestCase):
         self.assertEqual(len(messages), 1)
         self.assertEqual(messages[0].level, message_constants.ERROR)
         # Slug should be in error message.
-        self.assertIn("{}".format(self.test_page_b.slug), messages[0].message)
+        self.assertIn(f"{self.test_page_b.slug}", messages[0].message)
 
     def test_move_triggers_signals(self):
         # Connect a mock signal handler to pre_page_move and post_page_move signals

+ 3 - 3
wagtail/admin/tests/pages/test_preview.py

@@ -240,7 +240,7 @@ class TestPreview(WagtailTestUtils, TestCase):
         )
 
         # Check the user can refresh the preview
-        preview_session_key = "wagtail-preview-{}".format(self.event_page.id)
+        preview_session_key = f"wagtail-preview-{self.event_page.id}"
         self.assertIn(preview_session_key, self.client.session)
 
         response = self.client.get(preview_url)
@@ -274,7 +274,7 @@ class TestPreview(WagtailTestUtils, TestCase):
         )
 
         # Check the user can still see the preview with the last valid data
-        preview_session_key = "wagtail-preview-{}".format(self.event_page.id)
+        preview_session_key = f"wagtail-preview-{self.event_page.id}"
         self.assertIn(preview_session_key, self.client.session)
 
         response = self.client.get(preview_url)
@@ -355,7 +355,7 @@ class TestPreview(WagtailTestUtils, TestCase):
         )
 
     def test_preview_on_edit_clear_preview_data(self):
-        preview_session_key = "wagtail-preview-{}".format(self.event_page.id)
+        preview_session_key = f"wagtail-preview-{self.event_page.id}"
 
         # Set a fake preview session data for the page
         self.client.session[preview_session_key] = "test data"

+ 26 - 26
wagtail/admin/tests/test_filters.py

@@ -54,20 +54,20 @@ class TestFilteredModelChoiceField(WagtailTestUtils, TestCase):
         expected_html = """
             <select name="users" data-widget="filtered-select" data-filter-field="id_group" required id="id_users">
                 <option value="" selected>---------</option>
-                <option value="%(david)s" data-filter-value="%(musicians)s,%(actors)s">%(david_username)s</option>
-                <option value="%(kevin)s" data-filter-value="%(actors)s">%(kevin_username)s</option>
-                <option value="%(morten)s" data-filter-value="%(musicians)s">%(morten_username)s</option>
+                <option value="{david}" data-filter-value="{musicians},{actors}">{david_username}</option>
+                <option value="{kevin}" data-filter-value="{actors}">{kevin_username}</option>
+                <option value="{morten}" data-filter-value="{musicians}">{morten_username}</option>
             </select>
-        """ % {
-            "david": self.david.pk,
-            "kevin": self.kevin.pk,
-            "morten": self.morten.pk,
-            "musicians": self.musicians.pk,
-            "actors": self.actors.pk,
-            "david_username": self.david.get_username(),
-            "kevin_username": self.kevin.get_username(),
-            "morten_username": self.morten.get_username(),
-        }
+        """.format(
+            david=self.david.pk,
+            kevin=self.kevin.pk,
+            morten=self.morten.pk,
+            musicians=self.musicians.pk,
+            actors=self.actors.pk,
+            david_username=self.david.get_username(),
+            kevin_username=self.kevin.get_username(),
+            morten_username=self.morten.get_username(),
+        )
         self.assertHTMLEqual(html, expected_html)
 
     def test_with_callable(self):
@@ -83,18 +83,18 @@ class TestFilteredModelChoiceField(WagtailTestUtils, TestCase):
         expected_html = """
             <select name="users" data-widget="filtered-select" data-filter-field="id_group" required id="id_users">
                 <option value="" selected>---------</option>
-                <option value="%(david)s" data-filter-value="%(musicians)s,%(actors)s">%(david_username)s</option>
-                <option value="%(kevin)s" data-filter-value="%(actors)s">%(kevin_username)s</option>
-                <option value="%(morten)s" data-filter-value="%(musicians)s">%(morten_username)s</option>
+                <option value="{david}" data-filter-value="{musicians},{actors}">{david_username}</option>
+                <option value="{kevin}" data-filter-value="{actors}">{kevin_username}</option>
+                <option value="{morten}" data-filter-value="{musicians}">{morten_username}</option>
             </select>
-        """ % {
-            "david": self.david.pk,
-            "kevin": self.kevin.pk,
-            "morten": self.morten.pk,
-            "musicians": self.musicians.pk,
-            "actors": self.actors.pk,
-            "david_username": self.david.get_username(),
-            "kevin_username": self.kevin.get_username(),
-            "morten_username": self.morten.get_username(),
-        }
+        """.format(
+            david=self.david.pk,
+            kevin=self.kevin.pk,
+            morten=self.morten.pk,
+            musicians=self.musicians.pk,
+            actors=self.actors.pk,
+            david_username=self.david.get_username(),
+            kevin_username=self.kevin.get_username(),
+            morten_username=self.morten.get_username(),
+        )
         self.assertHTMLEqual(html, expected_html)

+ 1 - 3
wagtail/admin/tests/test_site_summary.py

@@ -57,9 +57,7 @@ class TestPagesSummary(WagtailTestUtils, TestCase):
         self.assertSummaryContainsLinkToPage(self.wagtail_root.pk)
 
     def test_summary_includes_page_count_without_wagtail_root(self):
-        self.assertSummaryContains(
-            "<span>{}</span> Pages".format(Page.objects.count() - 1)
-        )
+        self.assertSummaryContains(f"<span>{Page.objects.count() - 1}</span> Pages")
 
     def test_summary_shows_zero_pages_if_none_exist_except_wagtail_root(self):
         Page.objects.exclude(pk=self.wagtail_root.pk).delete()

+ 3 - 3
wagtail/admin/tests/test_templatetags.py

@@ -142,17 +142,17 @@ class TestTimesinceTags(TestCase):
 
         # Check prefix output
         timesince = timesince_last_update(dt, show_time_prefix=True)
-        self.assertEqual(timesince, "at {}".format(formatted_time))
+        self.assertEqual(timesince, f"at {formatted_time}")
 
         # Check user output
         timesince = timesince_last_update(dt, user_display_name="Gary")
-        self.assertEqual(timesince, "{} by Gary".format(formatted_time))
+        self.assertEqual(timesince, f"{formatted_time} by Gary")
 
         # Check user and prefix output
         timesince = timesince_last_update(
             dt, show_time_prefix=True, user_display_name="Gary"
         )
-        self.assertEqual(timesince, "at {} by Gary".format(formatted_time))
+        self.assertEqual(timesince, f"at {formatted_time} by Gary")
 
     def test_timesince_last_update_before_today_shows_timeago(self):
         dt = timezone.now() - timedelta(weeks=1, days=2)

+ 6 - 6
wagtail/admin/tests/test_workflows.py

@@ -1188,7 +1188,7 @@ class TestSubmitPageToWorkflow(BasePageWorkflowTests):
         # Should show the moderation status
         self.assertRegex(
             response.content.decode("utf-8"),
-            r"Sent to[\s|\n]+{}".format(self.object.current_workflow_task.name),
+            rf"Sent to[\s|\n]+{self.object.current_workflow_task.name}",
         )
         self.assertContains(response, "In Moderation")
         self.assertNotContains(response, "Draft")
@@ -3413,13 +3413,13 @@ class TestPageWorkflowStatus(BasePageWorkflowTests):
         response = self.client.get(self.get_url("edit"))
         self.assertRegex(
             response.content.decode("utf-8"),
-            r"Sent to[\s|\n]+{}".format(self.task_1.name),
+            rf"Sent to[\s|\n]+{self.task_1.name}",
         )
 
         response = self.workflow_action("approve")
         self.assertRegex(
             response.content.decode("utf-8"),
-            r"Sent to[\s|\n]+{}".format(self.task_2.name),
+            rf"Sent to[\s|\n]+{self.task_2.name}",
         )
 
         response = self.workflow_action("reject")
@@ -3430,7 +3430,7 @@ class TestPageWorkflowStatus(BasePageWorkflowTests):
         response = self.client.get(self.get_url("edit"))
         self.assertRegex(
             response.content.decode("utf-8"),
-            r"Sent to[\s|\n]+{}".format(self.task_2.name),
+            rf"Sent to[\s|\n]+{self.task_2.name}",
         )
 
         response = self.workflow_action("approve")
@@ -3448,14 +3448,14 @@ class TestPageWorkflowStatus(BasePageWorkflowTests):
         response = self.workflow_action("approve")
         self.assertRegex(
             response.content.decode("utf-8"),
-            r"Sent to[\s|\n]+{}".format(self.task_2.name),
+            rf"Sent to[\s|\n]+{self.task_2.name}",
         )
         self.workflow_action("reject")
         self.post("restart-workflow")
         response = self.client.get(self.get_url("edit"))
         self.assertRegex(
             response.content.decode("utf-8"),
-            r"Sent to[\s|\n]+{}".format(self.task_1.name),
+            rf"Sent to[\s|\n]+{self.task_1.name}",
         )
 
     def test_workflow_status_modal_task_comments(self):

+ 0 - 2
wagtail/admin/tests/tests.py

@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 import json
 import unittest
 

+ 3 - 4
wagtail/admin/ui/tables/__init__.py

@@ -129,7 +129,7 @@ class BaseColumn(metaclass=MediaDefiningClass):
         return Column.Cell(self, instance)
 
     def __repr__(self):
-        return "<%s.%s: %s>" % (
+        return "<{}.{}: {}>".format(
             self.__class__.__module__,
             self.__class__.__qualname__,
             self.name,
@@ -209,7 +209,7 @@ class TitleColumn(Column):
             return self._get_label_id_func(instance)
         elif self.label_prefix:
             id = multigetattr(instance, self.id_accessor)
-            return "%s-%s" % (self.label_prefix, id)
+            return f"{self.label_prefix}-{id}"
 
 
 class StatusFlagColumn(Column):
@@ -433,8 +433,7 @@ class Table(Component):
             return self.columns[key].get_cell(self.instance)
 
         def __iter__(self):
-            for name in self.columns:
-                yield name
+            yield from self.columns
 
         def __repr__(self):
             return repr([col.get_cell(self.instance) for col in self.columns.values()])

+ 1 - 1
wagtail/admin/viewsets/__init__.py

@@ -30,7 +30,7 @@ class ViewSetRegistry:
             if vs_urlpatterns:
                 urlpatterns.append(
                     re_path(
-                        r"^{}/".format(viewset.url_prefix),
+                        rf"^{viewset.url_prefix}/",
                         include((vs_urlpatterns, viewset.name), namespace=viewset.name),
                     )
                 )

+ 1 - 1
wagtail/admin/wagtail_hooks.py

@@ -1164,7 +1164,7 @@ def register_icons(icons):
         "wagtail.svg",
         "warning.svg",
     ]:
-        icons.append("wagtailadmin/icons/{}".format(icon))
+        icons.append(f"wagtailadmin/icons/{icon}")
     return icons
 
 

+ 1 - 1
wagtail/admin/widgets/button.py

@@ -35,7 +35,7 @@ class Button:
         return self.render()
 
     def __repr__(self):
-        return "<Button: {}>".format(self.label)
+        return f"<Button: {self.label}>"
 
     def __lt__(self, other):
         if not isinstance(other, Button):

+ 1 - 1
wagtail/admin/widgets/chooser.py

@@ -164,7 +164,7 @@ class BaseChooser(widgets.Input):
         widget_html = self.render_html(name, value_data, attrs)
 
         js = self.render_js_init(id_, name, value_data)
-        out = "{0}<script>{1}</script>".format(widget_html, js)
+        out = f"{widget_html}<script>{js}</script>"
         return mark_safe(out)
 
     @property

+ 1 - 1
wagtail/admin/widgets/workflows.py

@@ -18,7 +18,7 @@ class AdminTaskChooser(BaseChooser):
     classname = "task-chooser"
 
     def render_js_init(self, id_, name, value_data):
-        return "createTaskChooser({0});".format(json.dumps(id_))
+        return f"createTaskChooser({json.dumps(id_)});"
 
     @property
     def media(self):

+ 1 - 1
wagtail/api/conf.py

@@ -7,4 +7,4 @@ class APIField:
         return hash(self.name)
 
     def __repr__(self):
-        return "<APIField {}>".format(self.name)
+        return f"<APIField {self.name}>"

+ 1 - 1
wagtail/api/v2/router.py

@@ -74,7 +74,7 @@ class WagtailAPIRouter:
 
         for name, class_ in self._endpoints.items():
             pattern = re_path(
-                r"^{}/".format(name),
+                rf"^{name}/",
                 include((class_.get_urlpatterns(), name), namespace=name),
             )
             urlpatterns.append(pattern)

+ 2 - 2
wagtail/api/v2/tests/test_documents.py

@@ -596,12 +596,12 @@ class TestDocumentCacheInvalidation(TestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestDocumentCacheInvalidation, cls).setUpClass()
+        super().setUpClass()
         signal_handlers.register_signal_handlers()
 
     @classmethod
     def tearDownClass(cls):
-        super(TestDocumentCacheInvalidation, cls).tearDownClass()
+        super().tearDownClass()
         signal_handlers.unregister_signal_handlers()
 
     def test_resave_document_purges(self, purge):

+ 2 - 2
wagtail/api/v2/tests/test_images.py

@@ -588,12 +588,12 @@ class TestImageCacheInvalidation(TestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestImageCacheInvalidation, cls).setUpClass()
+        super().setUpClass()
         signal_handlers.register_signal_handlers()
 
     @classmethod
     def tearDownClass(cls):
-        super(TestImageCacheInvalidation, cls).tearDownClass()
+        super().tearDownClass()
         signal_handlers.unregister_signal_handlers()
 
     def test_resave_image_purges(self, purge):

+ 2 - 2
wagtail/api/v2/tests/test_pages.py

@@ -1781,12 +1781,12 @@ class TestPageCacheInvalidation(TestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(TestPageCacheInvalidation, cls).setUpClass()
+        super().setUpClass()
         signal_handlers.register_signal_handlers()
 
     @classmethod
     def tearDownClass(cls):
-        super(TestPageCacheInvalidation, cls).tearDownClass()
+        super().tearDownClass()
         signal_handlers.unregister_signal_handlers()
 
     def test_republish_page_purges(self, purge):

+ 3 - 3
wagtail/bin/wagtail.py

@@ -33,7 +33,7 @@ class Command:
             prog = None
         else:
             # hack the prog name as reported to ArgumentParser to include the command
-            prog = "%s %s" % (prog_name(), command_name)
+            prog = f"{prog_name()} {command_name}"
 
         parser = ArgumentParser(
             description=getattr(self, "description", None), add_help=False, prog=prog
@@ -392,7 +392,7 @@ class Version(Command):
 
         version = wagtail.get_version(wagtail.VERSION)
 
-        print("You are using Wagtail %(version)s" % {"version": version})  # noqa: T201
+        print(f"You are using Wagtail {version}")  # noqa: T201
 
 
 COMMANDS = {
@@ -412,7 +412,7 @@ def help_index():
     )
     print("Available subcommands:\n")  # NOQA: T201
     for name, cmd in sorted(COMMANDS.items()):
-        print("    %s%s" % (name.ljust(20), cmd.description))  # NOQA: T201
+        print(f"    {name.ljust(20)}{cmd.description}")  # NOQA: T201
 
 
 def unknown_command(command):

+ 5 - 7
wagtail/blocks/base.py

@@ -37,7 +37,7 @@ class BaseBlock(type):
     def __new__(mcs, name, bases, attrs):
         meta_class = attrs.pop("Meta", None)
 
-        cls = super(BaseBlock, mcs).__new__(mcs, name, bases, attrs)
+        cls = super().__new__(mcs, name, bases, attrs)
 
         # Get all the Meta classes from all the bases
         meta_class_bases = [meta_class] + [
@@ -70,7 +70,7 @@ class Block(metaclass=BaseBlock):
     def __new__(cls, *args, **kwargs):
         # adapted from django.utils.deconstruct.deconstructible; capture the arguments
         # so that we can return them in the 'deconstruct' method
-        obj = super(Block, cls).__new__(cls)
+        obj = super().__new__(cls)
         obj._constructor_args = (args, kwargs)
         return obj
 
@@ -357,7 +357,7 @@ class Block(metaclass=BaseBlock):
         try:
             path = module.DECONSTRUCT_ALIASES[self.__class__]
         except (AttributeError, KeyError):
-            path = "%s.%s" % (module_name, name)
+            path = f"{module_name}.{name}"
 
         return (
             path,
@@ -450,7 +450,7 @@ class BoundBlock:
         return self.block.render(self.value)
 
     def __repr__(self):
-        return "<block %s: %r>" % (
+        return "<block {}: {!r}>".format(
             self.block.name or type(self.block).__name__,
             self.value,
         )
@@ -474,9 +474,7 @@ class DeclarativeSubBlocksMetaclass(BaseBlock):
         current_blocks.sort(key=lambda x: x[1].creation_counter)
         attrs["declared_blocks"] = collections.OrderedDict(current_blocks)
 
-        new_class = super(DeclarativeSubBlocksMetaclass, mcs).__new__(
-            mcs, name, bases, attrs
-        )
+        new_class = super().__new__(mcs, name, bases, attrs)
 
         # Walk through the MRO, collecting all inherited sub-blocks, to make
         # the combined `base_blocks`.

+ 1 - 1
wagtail/blocks/field_block.py

@@ -918,7 +918,7 @@ class PageChooserBlock(ChooserBlock):
 
             for target_model in self.target_models:
                 opts = target_model._meta
-                target_models.append("{}.{}".format(opts.app_label, opts.object_name))
+                target_models.append(f"{opts.app_label}.{opts.object_name}")
 
             kwargs.pop("target_model", None)
             kwargs["page_type"] = target_models

+ 1 - 1
wagtail/blocks/list_block.py

@@ -134,7 +134,7 @@ class ListValue(MutableSequence):
         )
 
     def __repr__(self):
-        return "<ListValue: %r>" % ([bb.value for bb in self.bound_blocks],)
+        return f"<ListValue: {[bb.value for bb in self.bound_blocks]!r}>"
 
 
 class ListBlock(Block):

+ 7 - 7
wagtail/blocks/migrations/operations.py

@@ -46,7 +46,7 @@ class RenameStreamChildrenOperation(BaseBlockOperation):
 
     @property
     def operation_name_fragment(self):
-        return "rename_{}_to_{}".format(self.old_name, self.new_name)
+        return f"rename_{self.old_name}_to_{self.new_name}"
 
 
 @deconstructible
@@ -78,7 +78,7 @@ class RenameStructChildrenOperation(BaseBlockOperation):
 
     @property
     def operation_name_fragment(self):
-        return "rename_{}_to_{}".format(self.old_name, self.new_name)
+        return f"rename_{self.old_name}_to_{self.new_name}"
 
 
 @deconstructible
@@ -106,7 +106,7 @@ class RemoveStreamChildrenOperation(BaseBlockOperation):
 
     @property
     def operation_name_fragment(self):
-        return "remove_{}".format(self.name)
+        return f"remove_{self.name}"
 
 
 @deconstructible
@@ -134,7 +134,7 @@ class RemoveStructChildrenOperation(BaseBlockOperation):
 
     @property
     def operation_name_fragment(self):
-        return "remove_{}".format(self.name)
+        return f"remove_{self.name}"
 
 
 class StreamChildrenToListBlockOperation(BaseBlockOperation):
@@ -179,7 +179,7 @@ class StreamChildrenToListBlockOperation(BaseBlockOperation):
 
     @property
     def operation_name_fragment(self):
-        return "{}_to_list_block_{}".format(self.block_name, self.list_block_name)
+        return f"{self.block_name}_to_list_block_{self.list_block_name}"
 
 
 class StreamChildrenToStreamBlockOperation(BaseBlockOperation):
@@ -308,7 +308,7 @@ class StreamChildrenToStructBlockOperation(BaseBlockOperation):
 
     @property
     def operation_name_fragment(self):
-        return "{}_to_struct_block_{}".format(self.block_name, self.struct_block_name)
+        return f"{self.block_name}_to_struct_block_{self.struct_block_name}"
 
 
 class ListChildrenToStructBlockOperation(BaseBlockOperation):
@@ -329,4 +329,4 @@ class ListChildrenToStructBlockOperation(BaseBlockOperation):
 
     @property
     def operation_name_fragment(self):
-        return "list_block_items_to_{}".format(self.block_name)
+        return f"list_block_items_to_{self.block_name}"

+ 2 - 2
wagtail/blocks/migrations/utils.py

@@ -92,7 +92,7 @@ def map_block_value(block_value, block_def, block_path, operation, **kwargs):
         )
 
     else:
-        raise ValueError("Unexpected Structural Block: {}".format(block_value))
+        raise ValueError(f"Unexpected Structural Block: {block_value}")
 
 
 def map_stream_block_value(stream_block_value, block_def, block_path, **kwargs):
@@ -165,7 +165,7 @@ def map_struct_block_value(struct_block_value, block_def, block_path, **kwargs):
             try:
                 child_block_def = block_def.child_blocks[key]
             except KeyError:
-                raise InvalidBlockDefError("No current block def named {}".format(key))
+                raise InvalidBlockDefError(f"No current block def named {key}")
             altered_child_value = map_block_value(
                 child_value,
                 block_def=child_block_def,

+ 3 - 4
wagtail/blocks/stream_block.py

@@ -429,7 +429,7 @@ class StreamValue(MutableSequence):
 
         def __init__(self, *args, **kwargs):
             self.id = kwargs.pop("id")
-            super(StreamValue.StreamChild, self).__init__(*args, **kwargs)
+            super().__init__(*args, **kwargs)
 
         @property
         def block_type(self):
@@ -534,8 +534,7 @@ class StreamValue(MutableSequence):
             return result
 
         def __iter__(self):
-            for block_name in self.block_names:
-                yield block_name
+            yield from self.block_names
 
         def __len__(self):
             return len(self.block_names)
@@ -710,7 +709,7 @@ class StreamValue(MutableSequence):
         return len(self._bound_blocks)
 
     def __repr__(self):
-        return "<%s %r>" % (type(self).__name__, list(self))
+        return f"<{type(self).__name__} {list(self)!r}>"
 
     def render_as_block(self, context=None):
         return self.stream_block.render(self, context=context)

+ 6 - 3
wagtail/blocks/struct_block.py

@@ -139,14 +139,17 @@ class BaseStructBlock(Block):
     def value_from_datadict(self, data, files, prefix):
         return self._to_struct_value(
             [
-                (name, block.value_from_datadict(data, files, "%s-%s" % (prefix, name)))
+                (
+                    name,
+                    block.value_from_datadict(data, files, f"{prefix}-{name}"),
+                )
                 for name, block in self.child_blocks.items()
             ]
         )
 
     def value_omitted_from_data(self, data, files, prefix):
         return all(
-            block.value_omitted_from_data(data, files, "%s-%s" % (prefix, name))
+            block.value_omitted_from_data(data, files, f"{prefix}-{name}")
             for name, block in self.child_blocks.items()
         )
 
@@ -318,7 +321,7 @@ class BaseStructBlock(Block):
                     (
                         name,
                         PlaceholderBoundBlock(
-                            block, value.get(name), prefix="%s-%s" % (prefix, name)
+                            block, value.get(name), prefix=f"{prefix}-{name}"
                         ),
                     )
                     for name, block in self.child_blocks.items()

+ 1 - 1
wagtail/contrib/forms/forms.py

@@ -157,7 +157,7 @@ class FormBuilder:
         return options
 
     def get_form_class(self):
-        return type(str("WagtailForm"), (BaseForm,), self.formfields)
+        return type("WagtailForm", (BaseForm,), self.formfields)
 
 
 class SelectDateForm(django.forms.Form):

+ 0 - 1
wagtail/contrib/forms/migrations/0001_initial.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 0 - 1
wagtail/contrib/forms/migrations/0002_add_verbose_names.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 0 - 1
wagtail/contrib/forms/migrations/0003_capitalizeverbose.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 0 - 1
wagtail/contrib/forms/migrations/0004_add_verbose_name_plural.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations
 
 

+ 1 - 1
wagtail/contrib/forms/models.py

@@ -369,7 +369,7 @@ class EmailFormMixin(models.Model):
             elif isinstance(value, datetime.date):
                 value = date_format(value, settings.SHORT_DATE_FORMAT)
 
-            content.append("{}: {}".format(field.label, value))
+            content.append(f"{field.label}: {value}")
 
         return "\n".join(content)
 

+ 0 - 1
wagtail/contrib/forms/tests/test_forms.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django import forms
 from django.test import TestCase
 

+ 0 - 1
wagtail/contrib/forms/tests/test_models.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 import unittest
 
 from django import VERSION as DJANGO_VERSION

+ 6 - 7
wagtail/contrib/forms/tests/test_views.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 import datetime
 from io import BytesIO
 
@@ -68,7 +67,7 @@ class TestFormResponsesPanel(TestCase):
         result = self.panel.render_html()
 
         url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,))
-        link = '<a href="{}">1</a>'.format(url)
+        link = f'<a href="{url}">1</a>'
 
         self.assertIn(link, result)
 
@@ -117,7 +116,7 @@ class TestFormResponsesPanelWithCustomSubmissionClass(WagtailTestUtils, TestCase
         result = self.panel.render_html()
 
         url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,))
-        link = '<a href="{}">1</a>'.format(url)
+        link = f'<a href="{url}">1</a>'
 
         self.assertIn(link, result)
 
@@ -1190,7 +1189,7 @@ class TestDeleteFormSubmission(WagtailTestUtils, TestCase):
     def test_delete_submission_show_confirmation(self):
         response = self.client.get(
             reverse("wagtailforms:delete_submissions", args=(self.form_page.id,))
-            + "?selected-submissions={}".format(FormSubmission.objects.first().id)
+            + f"?selected-submissions={FormSubmission.objects.first().id}"
         )
         # Check show confirm page when HTTP method is GET
         self.assertTemplateUsed(response, "wagtailforms/confirm_delete.html")
@@ -1201,7 +1200,7 @@ class TestDeleteFormSubmission(WagtailTestUtils, TestCase):
     def test_delete_submission_with_permissions(self):
         response = self.client.post(
             reverse("wagtailforms:delete_submissions", args=(self.form_page.id,))
-            + "?selected-submissions={}".format(FormSubmission.objects.first().id)
+            + f"?selected-submissions={FormSubmission.objects.first().id}"
         )
 
         # Check that the submission is gone
@@ -1233,7 +1232,7 @@ class TestDeleteFormSubmission(WagtailTestUtils, TestCase):
 
         response = self.client.post(
             reverse("wagtailforms:delete_submissions", args=(self.form_page.id,))
-            + "?selected-submissions={}".format(FormSubmission.objects.first().id)
+            + f"?selected-submissions={FormSubmission.objects.first().id}"
         )
 
         # Check that the user received a permission denied response
@@ -1252,7 +1251,7 @@ class TestDeleteFormSubmission(WagtailTestUtils, TestCase):
         ):
             response = self.client.post(
                 reverse("wagtailforms:delete_submissions", args=(self.form_page.id,))
-                + "?selected-submissions={}".format(FormSubmission.objects.first().id)
+                + f"?selected-submissions={FormSubmission.objects.first().id}"
             )
 
         # An user can't delete a from submission with the hook

+ 0 - 1
wagtail/contrib/forms/tests/utils.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from wagtail.models import Page
 from wagtail.test.testapp.models import (
     FormField,

+ 2 - 2
wagtail/contrib/frontend_cache/backends.py

@@ -107,7 +107,7 @@ class CloudflareBackend(BaseBackend):
     def _purge_urls(self, urls):
         try:
             purge_url = (
-                "https://api.cloudflare.com/client/v4/zones/{0}/purge_cache".format(
+                "https://api.cloudflare.com/client/v4/zones/{}/purge_cache".format(
                     self.cloudflare_zoneid
                 )
             )
@@ -115,7 +115,7 @@ class CloudflareBackend(BaseBackend):
             headers = {"Content-Type": "application/json"}
 
             if self.cloudflare_token:
-                headers["Authorization"] = "Bearer {}".format(self.cloudflare_token)
+                headers["Authorization"] = f"Bearer {self.cloudflare_token}"
             else:
                 headers["X-Auth-Email"] = self.cloudflare_email
                 headers["X-Auth-Key"] = self.cloudflare_api_key

+ 1 - 1
wagtail/contrib/frontend_cache/tests.py

@@ -481,7 +481,7 @@ class TestCloudflareCachePurgingFunctions(TestCase):
 
     def test_cloudflare_purge_batch_chunked(self):
         batch = PurgeBatch()
-        urls = ["https://localhost/foo{}".format(i) for i in range(1, 65)]
+        urls = [f"https://localhost/foo{i}" for i in range(1, 65)]
         batch.add_urls(urls)
         batch.purge()
 

+ 1 - 1
wagtail/contrib/frontend_cache/utils.py

@@ -50,7 +50,7 @@ def get_backends(backend_settings=None, backends=None):
             backend_cls = import_string(backend)
         except ImportError as e:
             raise InvalidFrontendCacheBackendError(
-                "Could not find backend '%s': %s" % (backend, e)
+                f"Could not find backend '{backend}': {e}"
             )
 
         backend_objects[backend_name] = backend_cls(backend_config)

+ 1 - 1
wagtail/contrib/modeladmin/helpers/permission.py

@@ -47,7 +47,7 @@ class PermissionHelper:
         Django user's built-in `has_perm` method.
         """
 
-        return user.has_perm("%s.%s" % (self.opts.app_label, perm_codename))
+        return user.has_perm(f"{self.opts.app_label}.{perm_codename}")
 
     def user_has_any_permissions(self, user):
         """

+ 5 - 5
wagtail/contrib/modeladmin/helpers/url.py

@@ -14,15 +14,15 @@ class AdminURLHelper:
     def _get_base_url_path(self, base_url_path):
         if base_url_path:
             return base_url_path.strip().strip("/")
-        return r"%s/%s" % (self.opts.app_label, self.opts.model_name)
+        return rf"{self.opts.app_label}/{self.opts.model_name}"
 
     def _get_action_url_pattern(self, action):
         if action == "index":
             return r"^%s/$" % (self.base_url_path)
-        return r"^%s/%s/$" % (self.base_url_path, action)
+        return rf"^{self.base_url_path}/{action}/$"
 
     def _get_object_specific_action_url_pattern(self, action):
-        return r"^%s/%s/(?P<instance_pk>[-\w]+)/$" % (
+        return r"^{}/{}/(?P<instance_pk>[-\w]+)/$".format(
             self.base_url_path,
             action,
         )
@@ -33,7 +33,7 @@ class AdminURLHelper:
         return self._get_object_specific_action_url_pattern(action)
 
     def get_action_url_name(self, action):
-        return "%s_modeladmin_%s" % (
+        return "{}_modeladmin_{}".format(
             self.base_url_path.replace("/", "_"),
             action,
         )
@@ -71,5 +71,5 @@ class PageAdminURLHelper(AdminURLHelper):
         if action in ("add", "edit", "delete", "unpublish", "copy", "history"):
             url_name = "wagtailadmin_pages:%s" % action
             target_url = reverse(url_name, args=args, kwargs=kwargs)
-            return "%s?next=%s" % (target_url, quote(self.index_url))
+            return f"{target_url}?next={quote(self.index_url)}"
         return super().get_action_url(action, *args, **kwargs)

+ 2 - 2
wagtail/contrib/modeladmin/mixins.py

@@ -46,7 +46,7 @@ class ThumbnailMixin:
         }
         if not image:
             if self.thumb_default:
-                return mark_safe("<img{}>".format(flatatt(img_attrs)))
+                return mark_safe(f"<img{flatatt(img_attrs)}>")
             return ""
 
         # try to get a rendition of the image to use
@@ -55,4 +55,4 @@ class ThumbnailMixin:
         spec = self.thumb_image_filter_spec
         rendition = get_rendition_or_not_found(image, spec)
         img_attrs.update({"src": rendition.url})
-        return mark_safe("<img{}>".format(flatatt(img_attrs)))
+        return mark_safe(f"<img{flatatt(img_attrs)}>")

+ 3 - 3
wagtail/contrib/modeladmin/options.py

@@ -507,9 +507,9 @@ class ModelAdmin(WagtailRegisterable):
         app_label = self.opts.app_label.lower()
         model_name = self.opts.model_name.lower()
         return [
-            "modeladmin/%s/%s/%s.html" % (app_label, model_name, action),
-            "modeladmin/%s/%s.html" % (app_label, action),
-            "modeladmin/%s.html" % (action,),
+            f"modeladmin/{app_label}/{model_name}/{action}.html",
+            f"modeladmin/{app_label}/{action}.html",
+            f"modeladmin/{action}.html",
         ]
 
     def get_index_template(self):

+ 5 - 13
wagtail/contrib/modeladmin/tests/test_page_modeladmin.py

@@ -149,9 +149,7 @@ class TestCreateView(WagtailTestUtils, TestCase):
 
         expected_path = "/admin/pages/add/tests/businesschild/%d/" % business_index.pk
         expected_next_path = "/admin/tests/businesschild/"
-        self.assertRedirects(
-            response, "%s?next=%s" % (expected_path, expected_next_path)
-        )
+        self.assertRedirects(response, f"{expected_path}?next={expected_next_path}")
 
 
 class TestInspectView(WagtailTestUtils, TestCase):
@@ -249,9 +247,7 @@ class TestEditView(WagtailTestUtils, TestCase):
 
         expected_path = "/admin/pages/4/edit/"
         expected_next_path = "/admin/tests/eventpage/"
-        self.assertRedirects(
-            response, "%s?next=%s" % (expected_path, expected_next_path)
-        )
+        self.assertRedirects(response, f"{expected_path}?next={expected_next_path}")
 
     def test_non_existent(self):
         response = self.get(100)
@@ -261,7 +257,7 @@ class TestEditView(WagtailTestUtils, TestCase):
     def test_using_core_page(self):
         # The core page is slightly different to other pages, so exclude it
         root_page = Page.objects.get(depth=1)
-        response = self.client.get("/admin/wagtailcore/page/{}/".format(root_page.id))
+        response = self.client.get(f"/admin/wagtailcore/page/{root_page.id}/")
         self.assertEqual(response.status_code, 404)
 
 
@@ -279,9 +275,7 @@ class TestDeleteView(WagtailTestUtils, TestCase):
 
         expected_path = "/admin/pages/4/delete/"
         expected_next_path = "/admin/tests/eventpage/"
-        self.assertRedirects(
-            response, "%s?next=%s" % (expected_path, expected_next_path)
-        )
+        self.assertRedirects(response, f"{expected_path}?next={expected_next_path}")
 
 
 class TestChooseParentView(WagtailTestUtils, TestCase):
@@ -310,9 +304,7 @@ class TestChooseParentView(WagtailTestUtils, TestCase):
 
         expected_path = "/admin/pages/add/tests/eventpage/2/"
         expected_next_path = "/admin/tests/eventpage/"
-        self.assertRedirects(
-            response, "%s?next=%s" % (expected_path, expected_next_path)
-        )
+        self.assertRedirects(response, f"{expected_path}?next={expected_next_path}")
 
     def test_back_to_listing(self):
         response = self.client.post("/admin/tests/eventpage/choose_parent/")

+ 1 - 1
wagtail/contrib/redirects/forms.py

@@ -58,7 +58,7 @@ class ImportForm(forms.Form):
     def __init__(self, allowed_extensions, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
-        accept = ",".join([".{}".format(x) for x in allowed_extensions])
+        accept = ",".join([f".{x}" for x in allowed_extensions])
         self.fields["import_file"].widget = forms.FileInput(attrs={"accept": accept})
 
         uppercased_extensions = [x.upper() for x in allowed_extensions]

+ 8 - 8
wagtail/contrib/redirects/management/commands/import_redirects.py

@@ -95,10 +95,10 @@ class Command(BaseCommand):
             site = Site.objects.get(id=site_id)
 
         if not os.path.exists(src):
-            raise Exception("Missing file '{0}'".format(src))
+            raise Exception(f"Missing file '{src}'")
 
         if not os.path.getsize(src) > 0:
-            raise Exception("File '{0}' is empty".format(src))
+            raise Exception(f"File '{src}' is empty")
 
         _, extension = os.path.splitext(src)
         extension = extension.lstrip(".")
@@ -108,7 +108,7 @@ class Command(BaseCommand):
 
         import_format_cls = get_format_cls_by_extension(format_)
         if import_format_cls is None:
-            raise Exception("Invalid format '{0}'".format(extension))
+            raise Exception(f"Invalid format '{extension}'")
         input_format = import_format_cls()
 
         if extension in ["xls", "xlsx"]:
@@ -126,7 +126,7 @@ class Command(BaseCommand):
             self.stdout.write("--------------")
 
             if site:
-                self.stdout.write("Using site: {0}".format(site.hostname))
+                self.stdout.write(f"Using site: {site.hostname}")
 
             self.stdout.write("Importing redirects:")
 
@@ -193,10 +193,10 @@ class Command(BaseCommand):
                 successes += 1
 
         self.stdout.write("\n")
-        self.stdout.write("Found: {}".format(total))
-        self.stdout.write("Created: {}".format(successes))
-        self.stdout.write("Skipped : {}".format(skipped))
-        self.stdout.write("Errors: {}".format(len(errors)))
+        self.stdout.write(f"Found: {total}")
+        self.stdout.write(f"Created: {successes}")
+        self.stdout.write(f"Skipped : {skipped}")
+        self.stdout.write(f"Errors: {len(errors)}")
 
 
 def get_input(msg):  # pragma: no cover

+ 0 - 1
wagtail/contrib/redirects/migrations/0001_initial.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 0 - 1
wagtail/contrib/redirects/migrations/0002_add_verbose_names.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 0 - 1
wagtail/contrib/redirects/migrations/0003_make_site_field_editable.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 0 - 1
wagtail/contrib/redirects/migrations/0004_set_unique_on_path_and_site.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 0 - 1
wagtail/contrib/redirects/migrations/0005_capitalizeverbose.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 12 - 12
wagtail/contrib/redirects/tests/test_import_admin_views.py

@@ -49,7 +49,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
         self.assertIn("import_file", response.context["form"].errors)
 
     def test_non_valid_format_returns_error(self):
-        f = "{}/files/example.yaml".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.yaml"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -67,7 +67,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             )
 
     def test_valid_csv_triggers_confirm_view(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -86,7 +86,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             self.assertEqual(len(response.context["dataset"]), 3)
 
     def test_import_step(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -115,7 +115,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             self.assertEqual(Redirect.objects.all().count(), 2)
 
     def test_import_step_with_offset_columns(self):
-        f = "{}/files/example_offset_columns.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example_offset_columns.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -144,7 +144,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             self.assertEqual(Redirect.objects.all().count(), 2)
 
     def test_permanent_setting(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -173,7 +173,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             self.assertFalse(Redirect.objects.first().is_permanent)
 
     def test_site_setting(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
         (_, filename) = os.path.split(f)
 
         default_site = Site.objects.first()
@@ -210,7 +210,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             self.assertEqual(Redirect.objects.first().site, new_site)
 
     def test_import_xlsx(self):
-        f = "{}/files/example.xlsx".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.xlsx"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -240,7 +240,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             self.assertEqual(Redirect.objects.all().count(), 3)
 
     def test_unicode_error_when_importing(self):
-        f = "{}/files/example_faulty.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example_faulty.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -261,7 +261,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
         self.assertEqual(response.status_code, 405)
 
     def test_error_in_data_renders_confirm_view_on_import(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -285,7 +285,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
             self.assertTemplateUsed(response, "wagtailredirects/confirm_import.html")
 
     def test_import_tsv(self):
-        f = "{}/files/example.tsv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.tsv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -317,7 +317,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
 
     @override_settings(WAGTAIL_REDIRECTS_FILE_STORAGE="cache")
     def test_import_xlsx_with_cache_store_engine(self):
-        f = "{}/files/example.xlsx".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.xlsx"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:
@@ -348,7 +348,7 @@ class TestImportAdminViews(WagtailTestUtils, TestCase):
 
     @override_settings(WAGTAIL_REDIRECTS_FILE_STORAGE="cache")
     def test_process_validation_works_when_using_plaintext_files_and_cache(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:

+ 5 - 7
wagtail/contrib/redirects/tests/test_import_command.py

@@ -25,7 +25,7 @@ class TestImportCommand(TestCase):
             call_command("import_redirects", src="random", stdout=out)
 
     def test_invalid_extension_raises_error(self):
-        f = "{}/files/example.yaml".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.yaml"
 
         with self.assertRaisesMessage(Exception, "Invalid format 'yaml'"):
             out = StringIO()
@@ -34,9 +34,7 @@ class TestImportCommand(TestCase):
     def test_empty_file_raises_error(self):
         empty_file = tempfile.NamedTemporaryFile()
 
-        with self.assertRaisesMessage(
-            Exception, "File '{}' is empty".format(empty_file.name)
-        ):
+        with self.assertRaisesMessage(Exception, f"File '{empty_file.name}' is empty"):
             out = StringIO()
             call_command("import_redirects", src=empty_file.name, stdout=out)
 
@@ -53,14 +51,14 @@ class TestImportCommand(TestCase):
         self.assertEqual(Redirect.objects.count(), 0)
 
     def test_format_gets_picked_up_from_file_extension(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
 
         out = StringIO()
         call_command("import_redirects", src=f, stdout=out)
         self.assertEqual(Redirect.objects.count(), 2)
 
     def test_binary_formats_are_supported(self):
-        f = "{}/files/example.xlsx".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.xlsx"
 
         out = StringIO()
         call_command("import_redirects", src=f, stdout=out)
@@ -209,7 +207,7 @@ class TestImportCommand(TestCase):
         out = StringIO()
         call_command(
             "import_redirects",
-            "--src={}".format(invalid_file.name),
+            f"--src={invalid_file.name}",
             "--from=1",
             "--to=3",
             "--format=csv",

+ 1 - 1
wagtail/contrib/redirects/tests/test_import_utils.py

@@ -15,7 +15,7 @@ TEST_ROOT = os.path.abspath(os.path.dirname(__file__))
 
 class TestImportUtils(TestCase):
     def test_writing_file_with_format(self):
-        f = "{}/files/example.csv".format(TEST_ROOT)
+        f = f"{TEST_ROOT}/files/example.csv"
         (_, filename) = os.path.split(f)
 
         with open(f, "rb") as infile:

+ 0 - 1
wagtail/contrib/redirects/tests/test_redirects.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.test import TestCase, override_settings
 from django.urls import reverse
 

+ 1 - 1
wagtail/contrib/redirects/utils.py

@@ -8,7 +8,7 @@ def write_to_file_storage(import_file, input_format):
     FileStorage = get_file_storage()
     file_storage = FileStorage()
 
-    data = bytes()
+    data = b""
     for chunk in import_file.chunks():
         data += chunk
 

+ 0 - 1
wagtail/contrib/search_promotions/migrations/0002_capitalizeverbose.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 

+ 1 - 1
wagtail/contrib/search_promotions/models.py

@@ -110,7 +110,7 @@ class SearchPromotion(models.Model):
         )
 
     def __str__(self):
-        return "%s - %s" % (self.query.query_string, self.page.title)
+        return f"{self.query.query_string} - {self.page.title}"
 
     class Meta:
         ordering = ("sort_order",)

+ 3 - 3
wagtail/contrib/search_promotions/tests.py

@@ -493,21 +493,21 @@ class TestGarbageCollectManagementCommand(TestCase):
         # should be deleted by the search_garbage_collect command.
         query_ids_to_be_deleted = []
         for i in range(10):
-            q = Query.get("Hello {}".format(i))
+            q = Query.get(f"Hello {i}")
             q.add_hit(date=old_hit_date)
             query_ids_to_be_deleted.append(q.id)
 
         # Add 10 hits that are less than one week old. These ones should not be deleted.
         recent_query_ids = []
         for i in range(10):
-            q = Query.get("World {}".format(i))
+            q = Query.get(f"World {i}")
             q.add_hit(date=recent_hit_date)
             recent_query_ids.append(q.id)
 
         # Add 10 queries that are promoted. These ones should not be deleted.
         promoted_query_ids = []
         for i in range(10):
-            q = Query.get("Foo bar {}".format(i))
+            q = Query.get(f"Foo bar {i}")
             q.add_hit(date=old_hit_date)
             SearchPromotion.objects.create(
                 query=q, page_id=1, sort_order=0, description="Test"

+ 1 - 1
wagtail/contrib/settings/context_processors.py

@@ -37,7 +37,7 @@ class SettingModuleProxy(dict):
         return value
 
     def __str__(self):
-        return "SettingModuleProxy({0})".format(self.app_label)
+        return f"SettingModuleProxy({self.app_label})"
 
     def get_setting(self, model_name):
         """

+ 1 - 1
wagtail/contrib/settings/models.py

@@ -51,7 +51,7 @@ class AbstractSetting(models.Model):
         Returns the name of the attribute that should be used to store
         a reference to the fetched/created object on a request.
         """
-        return "_{}.{}".format(cls._meta.app_label, cls._meta.model_name).lower()
+        return f"_{cls._meta.app_label}.{cls._meta.model_name}".lower()
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)

+ 1 - 3
wagtail/contrib/settings/permissions.py

@@ -1,5 +1,3 @@
 def user_can_edit_setting_type(user, model):
     """Check if a user has permission to edit this setting type"""
-    return user.has_perm(
-        "{}.change_{}".format(model._meta.app_label, model._meta.model_name)
-    )
+    return user.has_perm(f"{model._meta.app_label}.change_{model._meta.model_name}")

+ 1 - 1
wagtail/contrib/settings/registry.py

@@ -90,7 +90,7 @@ class Registry(list):
         def permissions_hook():
             return Permission.objects.filter(
                 content_type__app_label=model._meta.app_label,
-                codename="change_{}".format(model._meta.model_name),
+                codename=f"change_{model._meta.model_name}",
             )
 
         # Register an admin URL finder

+ 1 - 1
wagtail/contrib/settings/tests/generic/test_admin.py

@@ -160,7 +160,7 @@ class TestGenericSettingEditView(BaseTestGenericSettingView):
         self.assertRedirects(
             response,
             status_code=302,
-            expected_url="%s%s/" % (url, TestGenericSetting.objects.first().pk),
+            expected_url=f"{url}{TestGenericSetting.objects.first().pk}/",
         )
 
 

+ 1 - 1
wagtail/contrib/settings/tests/site_specific/test_admin.py

@@ -161,7 +161,7 @@ class TestSiteSettingEditView(BaseTestSiteSettingView):
 
         response = self.client.get(url)
         self.assertRedirects(
-            response, status_code=302, expected_url="%s%s/" % (url, default_site.pk)
+            response, status_code=302, expected_url=f"{url}{default_site.pk}/"
         )
 
     def test_get_redirect_to_relevant_instance_invalid(self):

+ 3 - 3
wagtail/contrib/settings/tests/site_specific/test_forms.py

@@ -18,13 +18,13 @@ class TestSiteSwitchFromSiteOrdering(TestCase):
         site_3 = Site.objects.create(hostname="alfa.com", root_page=self.root_page)
         form = SiteSwitchForm(site_1, TestSiteSetting)
         expected_choices = [
-            ("/admin/settings/tests/testsitesetting/{}/".format(site_3.id), "alfa.com"),
+            (f"/admin/settings/tests/testsitesetting/{site_3.id}/", "alfa.com"),
             (
-                "/admin/settings/tests/testsitesetting/{}/".format(site_2.id),
+                f"/admin/settings/tests/testsitesetting/{site_2.id}/",
                 "bravo.com [default]",
             ),
             (
-                "/admin/settings/tests/testsitesetting/{}/".format(site_1.id),
+                f"/admin/settings/tests/testsitesetting/{site_1.id}/",
                 "charly.com",
             ),
         ]

+ 2 - 2
wagtail/contrib/settings/tests/site_specific/test_model.py

@@ -64,7 +64,7 @@ class SettingModelTestCase(SiteSettingsTestMixin, TestCase):
             pickled = pickle.dumps(obj, -1)
         except Exception as e:  # noqa: BLE001
             raise AssertionError(
-                "An error occured when attempting to pickle %r: %s" % (obj, e)
+                f"An error occured when attempting to pickle {obj!r}: {e}"
             )
 
         # Now unpickle the pickled ImportantPages
@@ -72,7 +72,7 @@ class SettingModelTestCase(SiteSettingsTestMixin, TestCase):
             unpickled = pickle.loads(pickled)
         except Exception as e:  # noqa: BLE001
             raise AssertionError(
-                "An error occured when attempting to unpickle %r: %s" % (obj, e)
+                f"An error occured when attempting to unpickle {obj!r}: {e}"
             )
 
         # Using 'page_url' should create a new InvokeViaAttributeShortcut

+ 1 - 1
wagtail/contrib/settings/views.py

@@ -35,7 +35,7 @@ def get_model_from_url_params(app_name, model_name):
     return model
 
 
-@lru_cache()
+@lru_cache
 def get_setting_edit_handler(model):
     if hasattr(model, "edit_handler"):
         edit_handler = model.edit_handler

+ 1 - 1
wagtail/contrib/simple_translation/forms.py

@@ -108,7 +108,7 @@ class SubmitTranslationForm(forms.Form):
                     len(disabled_locales),
                 )
                 help_text += "<br>"
-                help_text += '<a href="{}">'.format(url)
+                help_text += f'<a href="{url}">'
                 help_text += ngettext(
                     "Translate the parent page.",
                     "Translate the parent pages.",

+ 1 - 1
wagtail/contrib/table_block/templatetags/table_block_tags.py

@@ -13,5 +13,5 @@ def cell_classname(context, row_index, col_index, table_header=None):
         index = (row_index, col_index)
         cell_class = classnames.get(index)
         if cell_class:
-            return mark_safe('class="{}"'.format(cell_class))
+            return mark_safe(f'class="{cell_class}"')
     return ""

+ 6 - 10
wagtail/coreutils.py

@@ -74,7 +74,7 @@ def resolve_model_string(model_string, default_app=None):
                 model_name = model_string
             else:
                 raise ValueError(
-                    "Can not resolve {0!r} into a model. Model names "
+                    "Can not resolve {!r} into a model. Model names "
                     "should be in the form app_label.model_name".format(model_string),
                     model_string,
                 )
@@ -85,9 +85,7 @@ def resolve_model_string(model_string, default_app=None):
         return model_string
 
     else:
-        raise ValueError(
-            "Can not resolve {0!r} into a model".format(model_string), model_string
-        )
+        raise ValueError(f"Can not resolve {model_string!r} into a model", model_string)
 
 
 SCRIPT_RE = re.compile(r"<(-*)/script>")
@@ -249,7 +247,7 @@ def find_available_slug(parent, requested_slug, ignore_page_id=None):
     return slug
 
 
-@functools.lru_cache()
+@functools.lru_cache
 def get_content_languages():
     """
     Cache of settings.WAGTAIL_CONTENT_LANGUAGES in a dictionary for easy lookups by key.
@@ -328,7 +326,7 @@ def get_supported_content_language_variant(lang_code, strict=False):
     raise LookupError(lang_code)
 
 
-@functools.lru_cache()
+@functools.lru_cache
 def get_locales_display_names() -> dict:
     """
     Cache of the locale id -> locale display name mapping
@@ -385,14 +383,12 @@ def multigetattr(item, accessor):
                     TypeError,  # unsubscriptable object
                 ):
                     raise AttributeError(
-                        "Failed lookup for key [%s] in %r" % (bit, current)
+                        f"Failed lookup for key [{bit}] in {current!r}"
                     )
 
         if callable(current):
             if getattr(current, "alters_data", False):
-                raise SuspiciousOperation(
-                    "Cannot call %r from multigetattr" % (current,)
-                )
+                raise SuspiciousOperation(f"Cannot call {current!r} from multigetattr")
 
             # if calling without arguments is invalid, let the exception bubble up
             current = current()

+ 0 - 1
wagtail/documents/migrations/0001_initial.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 import taggit.managers
 from django.conf import settings
 from django.db import migrations, models

+ 0 - 1
wagtail/documents/migrations/0002_initial_data.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations
 
 

+ 0 - 1
wagtail/documents/migrations/0003_add_verbose_names.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.conf import settings
 from django.db import migrations, models
 

+ 0 - 1
wagtail/documents/migrations/0004_capitalizeverbose.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 import taggit.managers
 from django.conf import settings
 from django.db import migrations, models

+ 0 - 1
wagtail/documents/migrations/0005_alter_uploaded_by_user_on_delete_action.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # Generated by Django 1.9 on 2015-12-22 16:09
 import django.db.models.deletion
 from django.conf import settings

+ 0 - 1
wagtail/documents/migrations/0005_document_collection.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations, models
 
 import wagtail.models

+ 0 - 1
wagtail/documents/migrations/0006_copy_document_permissions_to_collections.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 from django.db import migrations
 
 

+ 0 - 1
wagtail/documents/migrations/0007_merge.py

@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # Generated by Django 1.9.1 on 2016-01-28 14:46
 from django.db import migrations
 

+ 1 - 1
wagtail/documents/tests/test_admin_views.py

@@ -149,7 +149,7 @@ class TestDocumentIndexView(WagtailTestUtils, TestCase):
 
         edit_url = reverse("wagtaildocs:edit", args=(doc.id,))
         next_url = quote(response._request.get_full_path())
-        self.assertContains(response, "%s?next=%s" % (edit_url, next_url))
+        self.assertContains(response, f"{edit_url}?next={next_url}")
 
     def test_search_form_rendered(self):
         response = self.get()

+ 1 - 3
wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py

@@ -52,9 +52,7 @@ class TestBulkAddTags(WagtailTestUtils, TestCase):
         )
 
         for document in self.documents:
-            self.assertInHTML(
-                "<li>{document_title}</li>".format(document_title=document.title), html
-            )
+            self.assertInHTML(f"<li>{document.title}</li>", html)
 
         self.client.post(self.url, self.post_data)
 

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini