From 690d0a740e8f87a655f99117b1555b933774718c Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Wed, 28 Jun 2023 16:34:09 +0100 Subject: [PATCH 01/11] Purge revisions of non-page models in purge_revisions command --- .../management/commands/purge_revisions.py | 6 +- wagtail/tests/test_management_commands.py | 77 +++++++++---------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/wagtail/management/commands/purge_revisions.py b/wagtail/management/commands/purge_revisions.py index 495b074d077e..275ead915788 100644 --- a/wagtail/management/commands/purge_revisions.py +++ b/wagtail/management/commands/purge_revisions.py @@ -13,7 +13,7 @@ class Command(BaseCommand): - help = "Delete page revisions which are not the latest revision for a page, published or scheduled to be published, or in moderation" + help = "Delete revisions which are not the latest revision, published or scheduled to be published, or in moderation" def add_arguments(self, parser): parser.add_argument( @@ -39,7 +39,7 @@ def handle(self, *args, **options): def purge_revisions(days=None): # exclude revisions which have been submitted for moderation in the old system - purgeable_revisions = Revision.page_revisions.exclude( + purgeable_revisions = Revision.objects.exclude( submitted_for_moderation=True ).exclude( # and exclude revisions with an approved_go_live_at date @@ -61,7 +61,7 @@ def purge_revisions(days=None): deleted_revisions_count = 0 for revision in purgeable_revisions.iterator(): - # don't delete the latest revision for any page + # don't delete the latest revision if not revision.is_latest_revision(): revision.delete() deleted_revisions_count += 1 diff --git a/wagtail/tests/test_management_commands.py b/wagtail/tests/test_management_commands.py index 9415770bc043..12952bcf5fde 100644 --- a/wagtail/tests/test_management_commands.py +++ b/wagtail/tests/test_management_commands.py @@ -608,10 +608,11 @@ def test_future_expired_will_not_be_unpublished(self): self.assertFalse(self.snippet.expired) -class TestPurgeRevisionsCommand(TestCase): - fixtures = ["test.json"] - +class TestPurgeRevisionsCommandForPages(TestCase): def setUp(self): + self.object = self.get_object() + + def get_object(self): # Find root page self.root_page = Page.objects.get(id=2) self.page = SimplePage( @@ -622,6 +623,7 @@ def setUp(self): ) self.root_page.add_child(instance=self.page) self.page.refresh_from_db() + return self.page def run_command(self, days=None): if days: @@ -632,32 +634,25 @@ def run_command(self, days=None): return management.call_command("purge_revisions", stdout=StringIO()) def test_latest_revision_not_purged(self): - - revision_1 = self.page.save_revision() - - revision_2 = self.page.save_revision() + revision_1 = self.object.save_revision() + revision_2 = self.object.save_revision() self.run_command() # revision 1 should be deleted, revision 2 should not be - self.assertNotIn( - revision_1, Revision.page_revisions.filter(object_id=self.page.id) - ) - self.assertIn( - revision_2, Revision.page_revisions.filter(object_id=self.page.id) - ) + self.assertFalse(Revision.objects.filter(id=revision_1.id).exists()) + self.assertTrue(Revision.objects.filter(id=revision_2.id).exists()) def test_revisions_in_moderation_not_purged(self): + revision = self.object.save_revision(submitted_for_moderation=True) - self.page.save_revision(submitted_for_moderation=True) + # Save a new revision to ensure that the moderated revision + # is not the latest one + self.object.save_revision() self.run_command() - self.assertTrue( - Revision.page_revisions.filter( - object_id=self.page.id, submitted_for_moderation=True - ).exists() - ) + self.assertTrue(Revision.objects.filter(id=revision.id).exists()) try: from wagtail.models import Task, Workflow, WorkflowTask @@ -667,46 +662,43 @@ def test_revisions_in_moderation_not_purged(self): user = get_user_model().objects.first() WorkflowTask.objects.create(workflow=workflow, task=task_1, sort_order=1) - snippet = FullFeaturedSnippet.objects.create(text="Initial", live=False) - page_revision = self.page.save_revision() - snippet_revision = snippet.save_revision() - workflow.start(self.page, user) - workflow.start(snippet, user) + revision = self.object.save_revision() + workflow.start(self.object, user) + + # Save a new revision to ensure that the revision in the workflow + # is not the latest one + self.object.save_revision() + self.run_command() # even though they're no longer the latest revisions, the old revisions # should stay as they are attached to an in progress workflow - self.assertTrue(Revision.objects.filter(id=page_revision.id).exists()) - self.assertTrue(Revision.objects.filter(id=snippet_revision.id).exists()) + self.assertTrue(Revision.objects.filter(id=revision.id).exists()) except ImportError: pass def test_revisions_with_approve_go_live_not_purged(self): - - approved_revision = self.page.save_revision( + revision = self.object.save_revision( approved_go_live_at=timezone.now() + timedelta(days=1) ) - self.page.save_revision() + # Save a new revision to ensure that the approved revision + # is not the latest one + self.object.save_revision() self.run_command() - self.assertIn( - approved_revision, Revision.page_revisions.filter(object_id=self.page.id) - ) + self.assertTrue(Revision.objects.filter(id=revision.id).exists()) def test_purge_revisions_with_date_cutoff(self): + old_revision = self.object.save_revision() - old_revision = self.page.save_revision() - - self.page.save_revision() + self.object.save_revision() self.run_command(days=30) # revision should not be deleted, as it is younger than 30 days - self.assertIn( - old_revision, Revision.page_revisions.filter(object_id=self.page.id) - ) + self.assertTrue(Revision.objects.filter(id=old_revision.id).exists()) old_revision.created_at = timezone.now() - timedelta(days=31) old_revision.save() @@ -714,9 +706,12 @@ def test_purge_revisions_with_date_cutoff(self): self.run_command(days=30) # revision is now older than 30 days, so should be deleted - self.assertNotIn( - old_revision, Revision.page_revisions.filter(object_id=self.page.id) - ) + self.assertFalse(Revision.objects.filter(id=old_revision.id).exists()) + + +class TestPurgeRevisionsCommandForSnippets(TestPurgeRevisionsCommandForPages): + def get_object(self): + return FullFeaturedSnippet.objects.create(text="Hello world!") class TestPurgeEmbedsCommand(TestCase): From 2a888bcb30c02fa09d15b32ccf60fae8b13dda4c Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Wed, 28 Jun 2023 16:42:47 +0100 Subject: [PATCH 02/11] Replace workflow support check with WAGTAIL_WORKFLOW_ENABLED setting check The workflow models can always be imported via wagtail.models even if workflow is disabled. Instead of checking the import with try/except, we should check the setting instead. --- .../management/commands/purge_revisions.py | 12 ++--- wagtail/tests/test_management_commands.py | 49 +++++++++++-------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/wagtail/management/commands/purge_revisions.py b/wagtail/management/commands/purge_revisions.py index 275ead915788..7008fc159296 100644 --- a/wagtail/management/commands/purge_revisions.py +++ b/wagtail/management/commands/purge_revisions.py @@ -1,15 +1,9 @@ +from django.conf import settings from django.core.management.base import BaseCommand from django.db.models import Q from django.utils import timezone -from wagtail.models import Revision - -try: - from wagtail.models import WorkflowState - - workflow_support = True -except ImportError: - workflow_support = False +from wagtail.models import Revision, WorkflowState class Command(BaseCommand): @@ -46,7 +40,7 @@ def purge_revisions(days=None): approved_go_live_at__isnull=False ) - if workflow_support: + if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True): purgeable_revisions = purgeable_revisions.exclude( # and exclude revisions linked to an in progress or needs changes workflow state Q(task_states__workflow_state__status=WorkflowState.STATUS_IN_PROGRESS) diff --git a/wagtail/tests/test_management_commands.py b/wagtail/tests/test_management_commands.py index 12952bcf5fde..e2a1c904c4f2 100644 --- a/wagtail/tests/test_management_commands.py +++ b/wagtail/tests/test_management_commands.py @@ -6,11 +6,19 @@ from django.contrib.auth.models import Group from django.core import management from django.db import models -from django.test import TestCase +from django.test import TestCase, override_settings from django.utils import timezone from wagtail.embeds.models import Embed -from wagtail.models import Collection, Page, PageLogEntry, Revision +from wagtail.models import ( + Collection, + Page, + PageLogEntry, + Revision, + Task, + Workflow, + WorkflowTask, +) from wagtail.signals import page_published, page_unpublished, published, unpublished from wagtail.test.testapp.models import ( DraftStateModel, @@ -643,7 +651,7 @@ def test_latest_revision_not_purged(self): self.assertFalse(Revision.objects.filter(id=revision_1.id).exists()) self.assertTrue(Revision.objects.filter(id=revision_2.id).exists()) - def test_revisions_in_moderation_not_purged(self): + def test_revisions_in_moderation_or_workflow_not_purged(self): revision = self.object.save_revision(submitted_for_moderation=True) # Save a new revision to ensure that the moderated revision @@ -654,28 +662,29 @@ def test_revisions_in_moderation_not_purged(self): self.assertTrue(Revision.objects.filter(id=revision.id).exists()) - try: - from wagtail.models import Task, Workflow, WorkflowTask + workflow = Workflow.objects.create(name="test_workflow") + task_1 = Task.objects.create(name="test_task_1") + user = get_user_model().objects.first() + WorkflowTask.objects.create(workflow=workflow, task=task_1, sort_order=1) - workflow = Workflow.objects.create(name="test_workflow") - task_1 = Task.objects.create(name="test_task_1") - user = get_user_model().objects.first() - WorkflowTask.objects.create(workflow=workflow, task=task_1, sort_order=1) + revision = self.object.save_revision() + workflow.start(self.object, user) + + # Save a new revision to ensure that the revision in the workflow + # is not the latest one + self.object.save_revision() - revision = self.object.save_revision() - workflow.start(self.object, user) + self.run_command() - # Save a new revision to ensure that the revision in the workflow - # is not the latest one - self.object.save_revision() + # even though they're no longer the latest revisions, the old revisions + # should stay as they are attached to an in progress workflow + self.assertTrue(Revision.objects.filter(id=revision.id).exists()) + # If workflow is disabled at some point after that, the revision should + # be deleted + with override_settings(WAGTAIL_WORKFLOW_ENABLED=False): self.run_command() - - # even though they're no longer the latest revisions, the old revisions - # should stay as they are attached to an in progress workflow - self.assertTrue(Revision.objects.filter(id=revision.id).exists()) - except ImportError: - pass + self.assertFalse(Revision.objects.filter(id=revision.id).exists()) def test_revisions_with_approve_go_live_not_purged(self): revision = self.object.save_revision( From 8074ed4bbc087813a922a52d65cedc523f99e721 Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Thu, 29 Jun 2023 11:34:00 +0100 Subject: [PATCH 03/11] Add not_page_revisions method to RevisionQuerySet and RevisionsManager Also simplify RevisionsManager definition using Manager.from_queryset() --- wagtail/models/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/wagtail/models/__init__.py b/wagtail/models/__init__.py index edf7bfd2d70c..eb4fd133d876 100644 --- a/wagtail/models/__init__.py +++ b/wagtail/models/__init__.py @@ -2656,8 +2656,14 @@ class Meta: class RevisionQuerySet(models.QuerySet): + def page_revisions_q(self): + return Q(base_content_type=get_default_page_content_type()) + def page_revisions(self): - return self.filter(base_content_type=get_default_page_content_type()) + return self.filter(self.page_revisions_q()) + + def not_page_revisions(self): + return self.exclude(self.page_revisions_q()) def submitted(self): return self.filter(submitted_for_moderation=True) @@ -2671,12 +2677,7 @@ def for_instance(self, instance): ) -class RevisionsManager(models.Manager): - def get_queryset(self): - return RevisionQuerySet(self.model, using=self._db) - - def for_instance(self, instance): - return self.get_queryset().for_instance(instance) +RevisionsManager = models.Manager.from_queryset(RevisionQuerySet) class PageRevisionsManager(RevisionsManager): From 12583d9c483687ebb8fcb86bfd4e1fba492bcd75 Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Thu, 29 Jun 2023 11:39:06 +0100 Subject: [PATCH 04/11] Allow purging revisions of only page/non-page models --- docs/reference/management_commands.md | 12 +++- .../management/commands/purge_revisions.py | 28 ++++++-- wagtail/tests/test_management_commands.py | 65 ++++++++++++++----- 3 files changed, 82 insertions(+), 23 deletions(-) diff --git a/docs/reference/management_commands.md b/docs/reference/management_commands.md index bc739c5a743a..cd419760d570 100644 --- a/docs/reference/management_commands.md +++ b/docs/reference/management_commands.md @@ -45,13 +45,19 @@ Options: ## purge_revisions ```sh -manage.py purge_revisions [--days=] +manage.py purge_revisions [--days=] [--pages] [--non-pages] ``` -This command deletes old page revisions which are not in moderation, live, approved to go live, or the latest -revision for a page. If the `days` argument is supplied, only revisions older than the specified number of +This command deletes old revisions which are not in moderation, live, approved to go live, or the latest +revision. If the `days` argument is supplied, only revisions older than the specified number of days will be deleted. +If the `pages` argument is supplied, only revisions of page models will be deleted. If the `non-pages` argument is supplied, only revisions of non-page models will be deleted. If both or neither arguments are supplied, revisions of all models will be deleted. + +```{versionadded} 5.1 +Support for deleting revisions of non-page models is added. +``` + (purge_embeds)= ## purge_embeds diff --git a/wagtail/management/commands/purge_revisions.py b/wagtail/management/commands/purge_revisions.py index 7008fc159296..c862a1018dd4 100644 --- a/wagtail/management/commands/purge_revisions.py +++ b/wagtail/management/commands/purge_revisions.py @@ -15,11 +15,23 @@ def add_arguments(self, parser): type=int, help="Only delete revisions older than this number of days", ) + parser.add_argument( + "--pages", + action="store_true", + help="Only delete revisions of page models", + ) + parser.add_argument( + "--non-pages", + action="store_true", + help="Only delete revisions of non-page models", + ) def handle(self, *args, **options): days = options.get("days") + pages = options.get("pages") + non_pages = options.get("non_pages") - revisions_deleted = purge_revisions(days=days) + revisions_deleted = purge_revisions(days=days, pages=pages, non_pages=non_pages) if revisions_deleted: self.stdout.write( @@ -31,11 +43,17 @@ def handle(self, *args, **options): self.stdout.write("No revisions deleted") -def purge_revisions(days=None): +def purge_revisions(days=None, pages=True, non_pages=True): + if pages == non_pages: + # If both are True or both are False, purge revisions of pages and non-pages + objects = Revision.objects.all() + elif pages: + objects = Revision.objects.page_revisions() + elif non_pages: + objects = Revision.objects.not_page_revisions() + # exclude revisions which have been submitted for moderation in the old system - purgeable_revisions = Revision.objects.exclude( - submitted_for_moderation=True - ).exclude( + purgeable_revisions = objects.exclude(submitted_for_moderation=True).exclude( # and exclude revisions with an approved_go_live_at date approved_go_live_at__isnull=False ) diff --git a/wagtail/tests/test_management_commands.py b/wagtail/tests/test_management_commands.py index e2a1c904c4f2..e75dd91c0e8c 100644 --- a/wagtail/tests/test_management_commands.py +++ b/wagtail/tests/test_management_commands.py @@ -617,6 +617,8 @@ def test_future_expired_will_not_be_unpublished(self): class TestPurgeRevisionsCommandForPages(TestCase): + base_options = {} + def setUp(self): self.object = self.get_object() @@ -633,13 +635,16 @@ def get_object(self): self.page.refresh_from_db() return self.page - def run_command(self, days=None): - if days: - days_input = "--days=" + str(days) - return management.call_command( - "purge_revisions", days_input, stdout=StringIO() - ) - return management.call_command("purge_revisions", stdout=StringIO()) + def assertRevisionNotExists(self, revision): + self.assertFalse(Revision.objects.filter(id=revision.id).exists()) + + def assertRevisionExists(self, revision): + self.assertTrue(Revision.objects.filter(id=revision.id).exists()) + + def run_command(self, **options): + return management.call_command( + "purge_revisions", **{**self.base_options, **options}, stdout=StringIO() + ) def test_latest_revision_not_purged(self): revision_1 = self.object.save_revision() @@ -648,8 +653,8 @@ def test_latest_revision_not_purged(self): self.run_command() # revision 1 should be deleted, revision 2 should not be - self.assertFalse(Revision.objects.filter(id=revision_1.id).exists()) - self.assertTrue(Revision.objects.filter(id=revision_2.id).exists()) + self.assertRevisionNotExists(revision_1) + self.assertRevisionExists(revision_2) def test_revisions_in_moderation_or_workflow_not_purged(self): revision = self.object.save_revision(submitted_for_moderation=True) @@ -660,7 +665,7 @@ def test_revisions_in_moderation_or_workflow_not_purged(self): self.run_command() - self.assertTrue(Revision.objects.filter(id=revision.id).exists()) + self.assertRevisionExists(revision) workflow = Workflow.objects.create(name="test_workflow") task_1 = Task.objects.create(name="test_task_1") @@ -678,13 +683,13 @@ def test_revisions_in_moderation_or_workflow_not_purged(self): # even though they're no longer the latest revisions, the old revisions # should stay as they are attached to an in progress workflow - self.assertTrue(Revision.objects.filter(id=revision.id).exists()) + self.assertRevisionExists(revision) # If workflow is disabled at some point after that, the revision should # be deleted with override_settings(WAGTAIL_WORKFLOW_ENABLED=False): self.run_command() - self.assertFalse(Revision.objects.filter(id=revision.id).exists()) + self.assertRevisionNotExists(revision) def test_revisions_with_approve_go_live_not_purged(self): revision = self.object.save_revision( @@ -697,7 +702,7 @@ def test_revisions_with_approve_go_live_not_purged(self): self.run_command() - self.assertTrue(Revision.objects.filter(id=revision.id).exists()) + self.assertRevisionExists(revision) def test_purge_revisions_with_date_cutoff(self): old_revision = self.object.save_revision() @@ -707,7 +712,7 @@ def test_purge_revisions_with_date_cutoff(self): self.run_command(days=30) # revision should not be deleted, as it is younger than 30 days - self.assertTrue(Revision.objects.filter(id=old_revision.id).exists()) + self.assertRevisionExists(old_revision) old_revision.created_at = timezone.now() - timedelta(days=31) old_revision.save() @@ -715,7 +720,7 @@ def test_purge_revisions_with_date_cutoff(self): self.run_command(days=30) # revision is now older than 30 days, so should be deleted - self.assertFalse(Revision.objects.filter(id=old_revision.id).exists()) + self.assertRevisionNotExists(old_revision) class TestPurgeRevisionsCommandForSnippets(TestPurgeRevisionsCommandForPages): @@ -723,6 +728,36 @@ def get_object(self): return FullFeaturedSnippet.objects.create(text="Hello world!") +class TestPurgeRevisionsCommandForPagesWithPagesOnly(TestPurgeRevisionsCommandForPages): + base_options = {"pages": True} + + +class TestPurgeRevisionsCommandForPagesWithNonPagesOnly( + TestPurgeRevisionsCommandForPages +): + base_options = {"non_pages": True} + + def assertRevisionNotExists(self, revision): + # Page revisions won't be purged if only non_pages is specified + return self.assertRevisionExists(revision) + + +class TestPurgeRevisionsCommandForSnippetsWithNonPagesOnly( + TestPurgeRevisionsCommandForSnippets +): + base_options = {"non_pages": True} + + +class TestPurgeRevisionsCommandForSnippetsWithPagesOnly( + TestPurgeRevisionsCommandForSnippets +): + base_options = {"pages": True} + + def assertRevisionNotExists(self, revision): + # Snippet revisions won't be purged if only pages is specified + return self.assertRevisionExists(revision) + + class TestPurgeEmbedsCommand(TestCase): fixtures = ["test.json"] From 3d0282573d0d23f9eabe2fb6427e58b01f79ffe0 Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Fri, 14 Jul 2023 10:20:45 +0100 Subject: [PATCH 05/11] Release notes for #10619 --- CHANGELOG.txt | 1 + docs/releases/5.1.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 2f803c26a44d..6b590ffdbe20 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -23,6 +23,7 @@ Changelog * Add support for `--template` option to `wagtail start` (Thibaud Colas) * Change to always cache renditions (Jake Howard) * Update link/document rich text tooltips for consistency with the inline toolbar (Albina Starykova) + * Purge revisions of non-page models in `purge_revisions` command (Sage Abdullah) * Fix: Prevent choosers from failing when initial value is an unrecognised ID, e.g. when moving a page from a location where `parent_page_types` would disallow it (Dan Braghis) * Fix: Move comment notifications toggle to the comments side panel (Sage Abdullah) * Fix: Remove comment button on InlinePanel fields (Sage Abdullah) diff --git a/docs/releases/5.1.md b/docs/releases/5.1.md index a99c652b97c1..e039444c1e82 100644 --- a/docs/releases/5.1.md +++ b/docs/releases/5.1.md @@ -62,6 +62,7 @@ As part of tackling Wagtail’s technical debt and improving [CSP compatibility] * Add support for adding [HTML `attrs`](panels_attrs) on `FieldPanel`, `FieldRowPanel`, `MultiFieldPanel`, and others (Aman Pandey, Antoni Martyniuk, LB (Ben) Johnston) * Change to always cache renditions (Jake Howard) * Update link/document rich text tooltips for consistency with the inline toolbar (Albina Starykova) + * Purge revisions of non-page models in `purge_revisions` command (Sage Abdullah) ### Bug fixes @@ -315,7 +316,7 @@ Note: The `data-w-tag-options-value` is a JSON object serialised into string. Dj ### Image Renditions are now cached by default Wagtail will try to use the cache called "renditions". If no such cache exists, it will fall back to using the default cache. -You can [configure the "renditions" cache](custom_image_renditions_cache) to use a different cache backend or to provide +You can [configure the "renditions" cache](custom_image_renditions_cache) to use a different cache backend or to provide additional configuration parameters. ### Tooltips now rely on new data attributes From adde8b66f670684a1335b1b6274ccd63e8b8de91 Mon Sep 17 00:00:00 2001 From: zerolab Date: Thu, 13 Jul 2023 20:02:20 +0100 Subject: [PATCH 06/11] Drop support for Python 3.7 --- .github/workflows/test.yml | 12 ++++++------ .pre-commit-config.yaml | 2 +- README.md | 4 ++-- docs/getting_started/tutorial.md | 4 ++-- docs/releases/upgrading.md | 4 ++-- ruff.toml | 2 ++ setup.py | 3 +-- tox.ini | 3 +-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5ed39a14a031..22ed4b310190 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ concurrency: # - test runs with USE_EMAIL_USER_MODEL=yes and DISABLE_TIMEZONE=yes # Current configuration: -# - django 3.2, python 3.7, postgres +# - django 3.2, python 3.8, postgres # - django 3.2, python 3.8, mysql # - django 4.1, python 3.9, sqlite # - django 4.2, python 3.10, mysql @@ -28,8 +28,8 @@ concurrency: # - django 4.2, python 3.11, postgres, DISABLE_TIMEZONE=yes # - django stable/4.2.x, python 3.10, postgres (allow failures) # - django main, python 3.10, postgres (allow failures) -# - elasticsearch 5, django 3.2, python 3.7, sqlite -# - elasticsearch 6, django 3.2, python 3.7, postgres +# - elasticsearch 5, django 3.2, python 3.8, sqlite +# - elasticsearch 6, django 3.2, python 3.8, postgres # - elasticsearch 7, django 4.1, python 3.8, postgres # - elasticsearch 7, django 4.2, python 3.9, sqlite, USE_EMAIL_USER_MODEL=yes @@ -73,7 +73,7 @@ jobs: strategy: matrix: include: - - python: '3.7' + - python: '3.8' django: 'Django>=3.2,<3.3' experimental: false - python: '3.11' @@ -191,7 +191,7 @@ jobs: strategy: matrix: include: - - python: '3.7' + - python: '3.8' django: 'Django>=3.2,<3.3' steps: - name: Configure sysctl limits @@ -285,7 +285,7 @@ jobs: strategy: matrix: include: - - python: '3.7' + - python: '3.8' django: 'Django>=3.2,<3.3' services: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 73f9fc886d4d..162209d1d3ea 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: hooks: - id: black language_version: python3 - args: ['--target-version', 'py37'] + args: ['--target-version', 'py38'] - repo: https://github.com/astral-sh/ruff-pre-commit rev: 'v0.0.272' diff --git a/README.md b/README.md index 6bb0a3de75bb..994853046053 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,10 @@ _(If you are reading this on GitHub, the details here may not be indicative of t Wagtail supports: - Django 3.2.x, 4.1.x and 4.2.x -- Python 3.7, 3.8, 3.9, 3.10 and 3.11 +- Python 3.8, 3.9, 3.10 and 3.11 - PostgreSQL, MySQL and SQLite (with JSON1) as database backends -[Previous versions of Wagtail](https://docs.wagtail.org/en/stable/releases/upgrading.html#compatible-django-python-versions) additionally supported Python 2.7 and earlier Django versions. +[Previous versions of Wagtail](https://docs.wagtail.org/en/stable/releases/upgrading.html#compatible-django-python-versions) additionally supported Python 2.7, 3.7 and earlier Django versions. --- diff --git a/docs/getting_started/tutorial.md b/docs/getting_started/tutorial.md index adffd6839731..3db0ac2dd230 100644 --- a/docs/getting_started/tutorial.md +++ b/docs/getting_started/tutorial.md @@ -12,7 +12,7 @@ If you want to add Wagtail to an existing Django project instead, see [](integra ### Install dependencies -Wagtail supports Python 3.7, 3.8, 3.9, 3.10, and 3.11. +Wagtail supports Python 3.8, 3.9, 3.10, and 3.11. To check if you have an appropriate version of Python 3, run the following command: @@ -24,7 +24,7 @@ python3 --version py --version ``` -If none of the preceding commands return a version number, or return a version lower than 3.7, then [install Python 3](https://www.python.org/downloads/). +If none of the preceding commands return a version number, or return a version lower than 3.8, then [install Python 3](https://www.python.org/downloads/). (virtual_environment_creation)= diff --git a/docs/releases/upgrading.md b/docs/releases/upgrading.md index e008e3a2454c..f2cad1db1f63 100644 --- a/docs/releases/upgrading.md +++ b/docs/releases/upgrading.md @@ -58,8 +58,8 @@ New feature releases frequently add support for newer versions of Django and Pyt The compatible versions of Django and Python for each Wagtail release are: | Wagtail release | Compatible Django versions | Compatible Python versions | -| --------------- | -------------------------- | -------------------------- | -| 5.1 | 3.2, 4.1, 4.2 | 3.7, 3.8, 3.9, 3.10, 3.11 | +| --------------- | -------------------------- |----------------------------| +| 5.1 | 3.2, 4.1, 4.2 | 3.8, 3.9, 3.10, 3.11 | | 5.0 | 3.2, 4.1, 4.2 | 3.7, 3.8, 3.9, 3.10, 3.11 | | 4.2 | 3.2, 4.0, 4.1 | 3.7, 3.8, 3.9, 3.10, 3.11 | | 4.1 LTS | 3.2, 4.0, 4.1 | 3.7, 3.8, 3.9, 3.10, 3.11 | diff --git a/ruff.toml b/ruff.toml index 017656615174..8232b75ec238 100644 --- a/ruff.toml +++ b/ruff.toml @@ -9,6 +9,8 @@ ignore = ["D100","D101","D102","D103","D105","N806","E501"] exclude = ["wagtail/project_template/*","node_modules","venv",".venv","migrations"] line-length = 88 +target-version = "py38" # minimum target version + # E: pycodestyle errors # F: Pyflakes # I: isort diff --git a/setup.py b/setup.py index 3370734ae0d7..0c56bcb756b0 100755 --- a/setup.py +++ b/setup.py @@ -106,7 +106,6 @@ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -118,7 +117,7 @@ "Framework :: Wagtail", "Topic :: Internet :: WWW/HTTP :: Site Management", ], - python_requires=">=3.7", + python_requires=">=3.8", install_requires=install_requires, extras_require={"testing": testing_extras, "docs": documentation_extras}, entry_points=""" diff --git a/tox.ini b/tox.ini index 7dc8a61314d8..622ca6209adf 100644 --- a/tox.ini +++ b/tox.ini @@ -2,7 +2,7 @@ skipsdist = True usedevelop = True -envlist = py{37,38,39,310,311}-dj{32,41,42,42stable,main}-{sqlite,postgres,mysql,mssql}-{elasticsearch7,elasticsearch6,elasticsearch5,noelasticsearch}-{customuser,emailuser}-{tz,notz}, +envlist = py{38,39,310,311}-dj{32,41,42,42stable,main}-{sqlite,postgres,mysql,mssql}-{elasticsearch7,elasticsearch6,elasticsearch5,noelasticsearch}-{customuser,emailuser}-{tz,notz}, [testenv] install_command = pip install -e ".[testing]" -U {opts} {packages} @@ -13,7 +13,6 @@ commands = noelasticsearch: coverage run runtests.py {posargs} basepython = - py37: python3.7 py38: python3.8 py39: python3.9 py310: python3.10 From ac10b36c7bd7812c1f8e2e5e80b0e8f580c89817 Mon Sep 17 00:00:00 2001 From: zerolab Date: Thu, 13 Jul 2023 20:08:24 +0100 Subject: [PATCH 07/11] Run pyupgrade with `--py38-plus` --- docs/conf.py | 3 +- scripts/get-translator-credits.py | 5 +- wagtail/admin/compare.py | 4 +- wagtail/admin/forms/account.py | 2 +- wagtail/admin/forms/collections.py | 2 +- wagtail/admin/forms/models.py | 4 +- .../0001_create_admin_access_permissions.py | 1 - wagtail/admin/panels/base.py | 4 +- wagtail/admin/panels/field_panel.py | 4 +- wagtail/admin/panels/group.py | 2 +- .../admin/rich_text/converters/editor_html.py | 4 +- .../converters/html_to_contentstate.py | 2 +- .../admin/templatetags/wagtailadmin_tags.py | 2 +- wagtail/admin/tests/benches.py | 6 +-- .../test_bulk_actions/test_bulk_delete.py | 6 +-- .../pages/test_bulk_actions/test_bulk_move.py | 8 ++- .../test_bulk_actions/test_bulk_publish.py | 4 +- .../test_bulk_actions/test_bulk_unpublish.py | 4 +- wagtail/admin/tests/pages/test_edit_page.py | 2 +- wagtail/admin/tests/pages/test_move_page.py | 2 +- wagtail/admin/tests/pages/test_preview.py | 6 +-- wagtail/admin/tests/test_filters.py | 52 +++++++++---------- wagtail/admin/tests/test_site_summary.py | 4 +- wagtail/admin/tests/test_templatetags.py | 6 +-- wagtail/admin/tests/test_workflows.py | 12 ++--- wagtail/admin/tests/tests.py | 2 - wagtail/admin/ui/tables/__init__.py | 7 ++- wagtail/admin/viewsets/__init__.py | 2 +- wagtail/admin/wagtail_hooks.py | 2 +- wagtail/admin/widgets/button.py | 2 +- wagtail/admin/widgets/chooser.py | 2 +- wagtail/admin/widgets/workflows.py | 2 +- wagtail/api/conf.py | 2 +- wagtail/api/v2/router.py | 2 +- wagtail/api/v2/tests/test_documents.py | 4 +- wagtail/api/v2/tests/test_images.py | 4 +- wagtail/api/v2/tests/test_pages.py | 4 +- wagtail/bin/wagtail.py | 6 +-- wagtail/blocks/base.py | 12 ++--- wagtail/blocks/field_block.py | 2 +- wagtail/blocks/list_block.py | 2 +- wagtail/blocks/migrations/operations.py | 14 ++--- wagtail/blocks/migrations/utils.py | 4 +- wagtail/blocks/stream_block.py | 7 ++- wagtail/blocks/struct_block.py | 9 ++-- wagtail/contrib/forms/forms.py | 2 +- .../contrib/forms/migrations/0001_initial.py | 1 - .../migrations/0002_add_verbose_names.py | 1 - .../migrations/0003_capitalizeverbose.py | 1 - .../0004_add_verbose_name_plural.py | 1 - wagtail/contrib/forms/models.py | 2 +- wagtail/contrib/forms/tests/test_forms.py | 1 - wagtail/contrib/forms/tests/test_models.py | 1 - wagtail/contrib/forms/tests/test_views.py | 13 +++-- wagtail/contrib/forms/tests/utils.py | 1 - wagtail/contrib/frontend_cache/backends.py | 4 +- wagtail/contrib/frontend_cache/tests.py | 2 +- wagtail/contrib/frontend_cache/utils.py | 2 +- .../contrib/modeladmin/helpers/permission.py | 2 +- wagtail/contrib/modeladmin/helpers/url.py | 10 ++-- wagtail/contrib/modeladmin/mixins.py | 4 +- wagtail/contrib/modeladmin/options.py | 6 +-- .../modeladmin/tests/test_page_modeladmin.py | 18 ++----- wagtail/contrib/redirects/forms.py | 2 +- .../management/commands/import_redirects.py | 16 +++--- .../redirects/migrations/0001_initial.py | 1 - .../migrations/0002_add_verbose_names.py | 1 - .../0003_make_site_field_editable.py | 1 - .../0004_set_unique_on_path_and_site.py | 1 - .../migrations/0005_capitalizeverbose.py | 1 - .../tests/test_import_admin_views.py | 24 ++++----- .../redirects/tests/test_import_command.py | 12 ++--- .../redirects/tests/test_import_utils.py | 2 +- .../contrib/redirects/tests/test_redirects.py | 1 - wagtail/contrib/redirects/utils.py | 2 +- .../migrations/0002_capitalizeverbose.py | 1 - wagtail/contrib/search_promotions/models.py | 2 +- wagtail/contrib/search_promotions/tests.py | 6 +-- .../contrib/settings/context_processors.py | 2 +- wagtail/contrib/settings/models.py | 2 +- wagtail/contrib/settings/permissions.py | 4 +- wagtail/contrib/settings/registry.py | 2 +- .../settings/tests/generic/test_admin.py | 2 +- .../tests/site_specific/test_admin.py | 2 +- .../tests/site_specific/test_forms.py | 6 +-- .../tests/site_specific/test_model.py | 4 +- wagtail/contrib/settings/views.py | 2 +- wagtail/contrib/simple_translation/forms.py | 2 +- .../templatetags/table_block_tags.py | 2 +- wagtail/coreutils.py | 16 +++--- wagtail/documents/migrations/0001_initial.py | 1 - .../documents/migrations/0002_initial_data.py | 1 - .../migrations/0003_add_verbose_names.py | 1 - .../migrations/0004_capitalizeverbose.py | 1 - ...alter_uploaded_by_user_on_delete_action.py | 1 - .../migrations/0005_document_collection.py | 1 - ...opy_document_permissions_to_collections.py | 1 - wagtail/documents/migrations/0007_merge.py | 1 - wagtail/documents/tests/test_admin_views.py | 2 +- .../test_bulk_actions/test_bulk_add_tags.py | 4 +- .../test_bulk_add_to_collection.py | 4 +- .../test_bulk_actions/test_bulk_delete.py | 4 +- .../tests/test_collection_privacy.py | 6 +-- wagtail/documents/tests/test_models.py | 2 +- wagtail/documents/tests/test_views.py | 4 +- wagtail/embeds/finders/instagram.py | 2 +- wagtail/embeds/finders/oembed.py | 2 +- wagtail/embeds/migrations/0001_initial.py | 1 - .../migrations/0002_add_verbose_names.py | 1 - .../migrations/0003_capitalizeverbose.py | 1 - wagtail/images/checks.py | 8 +-- wagtail/images/migrations/0001_initial.py | 1 - .../images/migrations/0002_initial_data.py | 1 - .../migrations/0003_fix_focal_point_fields.py | 1 - .../0004_make_focal_point_key_not_nullable.py | 1 - .../0005_make_filter_spec_unique.py | 1 - .../migrations/0006_add_verbose_names.py | 1 - .../images/migrations/0007_image_file_size.py | 1 - .../migrations/0008_image_created_at_index.py | 1 - .../migrations/0009_capitalizeverbose.py | 1 - .../0010_change_on_delete_behaviour.py | 1 - .../migrations/0011_image_collection.py | 1 - ...2_copy_image_permissions_to_collections.py | 1 - .../0013_make_rendition_upload_callable.py | 1 - .../migrations/0014_add_filter_spec_field.py | 1 - .../migrations/0015_fill_filter_spec_field.py | 1 - ...016_deprecate_rendition_filter_relation.py | 1 - .../0017_reduce_focal_point_key_max_length.py | 1 - .../0018_remove_rendition_filter.py | 1 - .../images/migrations/0019_delete_filter.py | 1 - wagtail/images/models.py | 8 +-- .../images/templatetags/wagtailimages_tags.py | 2 +- wagtail/images/tests/test_admin_views.py | 4 +- wagtail/images/tests/test_blocks.py | 3 +- .../test_bulk_actions/test_bulk_add_tags.py | 4 +- .../test_bulk_add_to_collection.py | 4 +- .../test_bulk_actions/test_bulk_delete.py | 4 +- wagtail/images/tests/test_image_operations.py | 4 +- wagtail/images/tests/test_jinja2.py | 2 +- wagtail/images/tests/test_models.py | 2 +- wagtail/images/tests/test_shortcuts.py | 1 - wagtail/images/tests/test_signal_handlers.py | 4 +- wagtail/images/utils.py | 2 +- wagtail/images/views/serve.py | 2 +- .../management/commands/publish_scheduled.py | 8 +-- wagtail/migrations/0001_initial.py | 1 - ...0016_change_page_url_path_to_text_field.py | 1 - wagtail/migrations/0002_initial_data.py | 1 - ...ess_constraint_on_group_page_permission.py | 1 - wagtail/migrations/0004_page_locked.py | 1 - ..._add_page_lock_permission_to_moderators.py | 1 - .../0006_add_lock_page_permission.py | 1 - .../0007_page_latest_revision_created_at.py | 1 - ...008_populate_latest_revision_created_at.py | 1 - ...to_now_add_from_pagerevision_created_at.py | 1 - ...010_change_page_owner_to_null_on_delete.py | 1 - .../0011_page_first_published_at.py | 1 - .../migrations/0012_extend_page_slug_field.py | 1 - .../0013_update_golive_expire_help_text.py | 1 - wagtail/migrations/0014_add_verbose_name.py | 1 - .../migrations/0015_add_more_verbose_names.py | 1 - ...0016_change_page_url_path_to_text_field.py | 1 - ...change_edit_page_permission_description.py | 1 - ...revision_submitted_for_moderation_index.py | 1 - .../migrations/0019_verbose_names_cleanup.py | 1 - ...20_add_index_on_page_first_published_at.py | 1 - wagtail/migrations/0021_capitalizeverbose.py | 1 - wagtail/migrations/0022_add_site_name.py | 1 - ...alter_page_revision_on_delete_behaviour.py | 1 - ...r_page_content_type_on_delete_behaviour.py | 1 - wagtail/migrations/0024_collection.py | 1 - .../0025_collection_initial_data.py | 1 - .../0026_group_collection_permission.py | 1 - .../0027_fix_collection_path_collation.py | 1 - wagtail/migrations/0028_merge.py | 1 - .../migrations/0029_unicode_slugfield_dj19.py | 1 - .../0030_index_on_pagerevision_created_at.py | 1 - .../0031_add_page_view_restriction_types.py | 1 - .../0032_add_bulk_delete_page_permission.py | 1 - .../0033_remove_golive_expiry_help_text.py | 1 - wagtail/migrations/0034_page_live_revision.py | 1 - .../migrations/0035_page_last_published_at.py | 1 - .../0036_populate_page_last_published_at.py | 1 - .../0037_set_page_owner_editable.py | 1 - .../0038_make_first_published_at_editable.py | 1 - .../0039_collectionviewrestriction.py | 1 - wagtail/migrations/0040_page_draft_title.py | 1 - .../migrations/0048_add_default_workflows.py | 1 - .../0066_collection_management_permissions.py | 1 - wagtail/models/__init__.py | 16 +++--- wagtail/models/i18n.py | 4 +- wagtail/models/sites.py | 2 +- wagtail/permission_policies/base.py | 2 +- .../home/migrations/0001_initial.py | 1 - .../home/migrations/0002_create_homepage.py | 1 - wagtail/search/backends/__init__.py | 8 +-- wagtail/search/backends/base.py | 2 +- .../search/backends/database/mysql/mysql.py | 6 +-- .../search/backends/database/mysql/query.py | 8 +-- .../backends/database/postgres/postgres.py | 2 +- .../backends/database/postgres/query.py | 6 +-- .../search/backends/database/sqlite/query.py | 6 +-- .../search/backends/database/sqlite/sqlite.py | 6 +-- wagtail/search/backends/elasticsearch5.py | 6 +-- wagtail/search/index.py | 4 +- wagtail/search/migrations/0001_initial.py | 1 - .../migrations/0002_add_verbose_names.py | 1 - .../migrations/0003_remove_editors_pick.py | 1 - wagtail/search/models.py | 2 +- wagtail/search/query.py | 10 ++-- .../tests/elasticsearch_common_tests.py | 6 +-- wagtail/search/tests/test_backends.py | 1 - .../tests/test_elasticsearch5_backend.py | 1 - .../tests/test_elasticsearch6_backend.py | 1 - .../tests/test_elasticsearch7_backend.py | 1 - wagtail/search/tests/test_indexed_class.py | 4 +- wagtail/search/tests/test_page_search.py | 2 - wagtail/search/tests/test_queries.py | 6 +-- wagtail/search/utils.py | 3 +- wagtail/snippets/permissions.py | 2 +- wagtail/snippets/tests/test_snippets.py | 2 +- wagtail/templatetags/wagtailcore_tags.py | 2 +- wagtail/test/benchmark.py | 2 - wagtail/test/customuser/fields.py | 4 +- .../customuser/migrations/0001_initial.py | 1 - .../migrations/0002_added_file_field.py | 1 - .../test/demosite/migrations/0001_initial.py | 1 - .../migrations/0002_capitalizeverbose.py | 1 - .../modeladmintest/migrations/0001_initial.py | 1 - .../modeladmintest/migrations/0002_token.py | 1 - .../migrations/0003_publisher.py | 1 - .../migrations/0004_venuepage.py | 1 - .../migrations/0005_book_cover_image.py | 1 - wagtail/test/modeladmintest/wagtail_hooks.py | 4 +- .../routablepage/migrations/0001_initial.py | 1 - .../0002_routablepagewithoutindexroutetest.py | 1 - .../test/search/migrations/0001_initial.py | 1 - wagtail/test/search/models.py | 2 +- .../test/snippets/migrations/0001_initial.py | 1 - .../migrations/0002_searchablesnippet.py | 1 - .../0003_fancysnippet_standardsnippet.py | 1 - .../migrations/0004_fileuploadsnippet.py | 1 - ...isectionrichtextsnippet_richtextsection.py | 1 - ...0006_standarsnippetwithcustomprimarykey.py | 2 - wagtail/test/testapp/forms.py | 2 +- wagtail/test/testapp/models.py | 10 ++-- wagtail/test/testapp/rich_text.py | 4 +- wagtail/test/urls_multilang.py | 2 - wagtail/test/utils/page_tests.py | 2 +- wagtail/test/utils/wagtail_tests.py | 3 +- wagtail/tests/test_audit_log.py | 4 +- wagtail/tests/test_blocks.py | 1 - wagtail/tests/test_migrations.py | 21 ++++---- wagtail/tests/test_page_model.py | 6 ++- wagtail/tests/test_page_permissions.py | 2 +- wagtail/tests/test_permission_policies.py | 4 +- wagtail/tests/test_streamfield.py | 3 +- wagtail/tests/test_utils.py | 1 - wagtail/users/migrations/0001_initial.py | 1 - .../0002_add_verbose_name_on_userprofile.py | 1 - .../migrations/0003_add_verbose_names.py | 1 - .../migrations/0004_capitalizeverbose.py | 1 - ...0005_make_related_name_wagtail_specific.py | 1 - .../0006_userprofile_prefered_language.py | 1 - wagtail/users/tests/test_admin_views.py | 15 +++--- .../test_bulk_actions/test_bulk_delete.py | 2 +- .../test_bulk_set_active_state.py | 2 +- wagtail/users/utils.py | 2 +- wagtail/users/views/users.py | 6 +-- wagtail/users/wagtail_hooks.py | 6 +-- wagtail/utils/apps.py | 2 +- wagtail/utils/setup.py | 7 ++- wagtail/utils/widgets.py | 2 +- 273 files changed, 335 insertions(+), 536 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 92c0260bc8c2..19ab04163d0c 100644 --- a/docs/conf.py +++ b/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 @@ # 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__ diff --git a/scripts/get-translator-credits.py b/scripts/get-translator-credits.py index 99d871003e2f..cb2012e39085 100644 --- a/scripts/get-translator-credits.py +++ b/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 @@ 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 @@ def get_language_name(locale_string): 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 diff --git a/wagtail/admin/compare.py b/wagtail/admin/compare.py index 6c70be23fb96..2b0d7f0b832f 100644 --- a/wagtail/admin/compare.py +++ b/wagtail/admin/compare.py @@ -294,9 +294,7 @@ def htmldiff(self): block_rendered = comparison.htmlvalue(comparison.val_a) classes = " ".join(classes) - comparisons_html.append( - '
{1}
'.format(classes, block_rendered) - ) + comparisons_html.append(f'
{block_rendered}
') return mark_safe("\n".join(comparisons_html)) diff --git a/wagtail/admin/forms/account.py b/wagtail/admin/forms/account.py index 273fbee3d723..16f794690b68 100644 --- a/wagtail/admin/forms/account.py +++ b/wagtail/admin/forms/account.py @@ -125,7 +125,7 @@ def save(self, commit=True): # 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 diff --git a/wagtail/admin/forms/collections.py b/wagtail/admin/forms/collections.py index 10f38e003010..40e12801503d 100644 --- a/wagtail/admin/forms/collections.py +++ b/wagtail/admin/forms/collections.py @@ -339,7 +339,7 @@ class CollectionMemberPermissionsForm(forms.Form): ) GroupCollectionMemberPermissionFormSet = type( - str("GroupCollectionMemberPermissionFormSet"), + "GroupCollectionMemberPermissionFormSet", (BaseGroupCollectionMemberPermissionFormSet,), { "permission_types": permission_types, diff --git a/wagtail/admin/forms/models.py b/wagtail/admin/forms/models.py index 04f44e2c7bb1..1af18434fc63 100644 --- a/wagtail/admin/forms/models.py +++ b/wagtail/admin/forms/models.py @@ -121,9 +121,7 @@ def __new__(cls, name, bases, attrs): 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 diff --git a/wagtail/admin/migrations/0001_create_admin_access_permissions.py b/wagtail/admin/migrations/0001_create_admin_access_permissions.py index 343761563c06..668ffc423d35 100644 --- a/wagtail/admin/migrations/0001_create_admin_access_permissions.py +++ b/wagtail/admin/migrations/0001_create_admin_access_permissions.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/admin/panels/base.py b/wagtail/admin/panels/base.py index 003b15d20f83..09c199d6843c 100644 --- a/wagtail/admin/panels/base.py +++ b/wagtail/admin/panels/base.py @@ -175,7 +175,7 @@ def on_model_bound(self): pass def __repr__(self): - return "<%s with model=%s>" % ( + return "<{} with model={}>".format( self.__class__.__name__, self.model, ) @@ -317,7 +317,7 @@ def render_form_content(self): 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, diff --git a/wagtail/admin/panels/field_panel.py b/wagtail/admin/panels/field_panel.py index 96fe0b78c35a..b60f8aa90a7c 100644 --- a/wagtail/admin/panels/field_panel.py +++ b/wagtail/admin/panels/field_panel.py @@ -122,7 +122,7 @@ def format_value_for_display(self, value): 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 @@ def get_comparison(self): 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, diff --git a/wagtail/admin/panels/group.py b/wagtail/admin/panels/group.py index 7dab3288ee1b..7a32c93889ed 100644 --- a/wagtail/admin/panels/group.py +++ b/wagtail/admin/panels/group.py @@ -102,7 +102,7 @@ def children(self): 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 diff --git a/wagtail/admin/rich_text/converters/editor_html.py b/wagtail/admin/rich_text/converters/editor_html.py index f69d135679bd..ca503027c5e1 100644 --- a/wagtail/admin/rich_text/converters/editor_html.py +++ b/wagtail/admin/rich_text/converters/editor_html.py @@ -110,7 +110,7 @@ def clean_tag_node(self, doc, tag): 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 @@ def expand_db_attributes(attrs): if parent_page: attrs += 'data-parent-id="%d" ' % parent_page.id - return '' % (attrs, escape(page.localized.specific.url)) + return f'' except Page.DoesNotExist: return "" diff --git a/wagtail/admin/rich_text/converters/html_to_contentstate.py b/wagtail/admin/rich_text/converters/html_to_contentstate.py index af5595196ecc..0a29443d4d45 100644 --- a/wagtail/admin/rich_text/converters/html_to_contentstate.py +++ b/wagtail/admin/rich_text/converters/html_to_contentstate.py @@ -388,7 +388,7 @@ def handle_endtag(self, name): 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, ) diff --git a/wagtail/admin/templatetags/wagtailadmin_tags.py b/wagtail/admin/templatetags/wagtailadmin_tags.py index 0b01986a3e55..e0320874b43b 100644 --- a/wagtail/admin/templatetags/wagtailadmin_tags.py +++ b/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) diff --git a/wagtail/admin/tests/benches.py b/wagtail/admin/tests/benches.py index 6c2a34b9891a..8443a6fd7638 100644 --- a/wagtail/admin/tests/benches.py +++ b/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 @@ def setUp(self): 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 @@ def setUp(self): 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", diff --git a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_delete.py b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_delete.py index 554ceef2e7c9..54c74a6af0f7 100644 --- a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_delete.py +++ b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_delete.py @@ -130,12 +130,10 @@ def test_page_delete_bad_permissions(self): ) for child_page in self.pages_to_be_deleted: - self.assertInHTML( - "
  • {page_title}
  • ".format(page_title=child_page.title), html - ) + self.assertInHTML(f"
  • {child_page.title}
  • ", html) self.assertTagInHTML( - """
    """.format(self.url), + f"""
    """, html, count=0, ) diff --git a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_move.py b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_move.py index 792ac2b9fcb9..b35db5920e21 100644 --- a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_move.py +++ b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_move.py @@ -126,12 +126,10 @@ def test_bulk_move_bad_permissions(self): self.assertInHTML("

    You don't have permission to move these pages

    ", html) for child_page in self.pages_to_be_moved: - self.assertInHTML( - "
  • {page_title}
  • ".format(page_title=child_page.title), html - ) + self.assertInHTML(f"
  • {child_page.title}
  • ", html) self.assertTagInHTML( - """
    """.format(self.url), + f"""
    """, html, count=0, ) @@ -170,7 +168,7 @@ def test_bulk_move_destination_not_allowed(self): html = response.content.decode() self.assertInHTML( - "

    The following pages cannot be moved to {}

    ".format(page.title), html + f"

    The following pages cannot be moved to {page.title}

    ", html ) for child_page in self.pages_to_be_moved: diff --git a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_publish.py b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_publish.py index 75c3be3843ad..86d2d019dcee 100644 --- a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_publish.py +++ b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_publish.py @@ -130,9 +130,7 @@ def test_publish_view_bad_permissions(self): ) for child_page in self.pages_to_be_published: - self.assertInHTML( - "
  • {page_title}
  • ".format(page_title=child_page.title), html - ) + self.assertInHTML(f"
  • {child_page.title}
  • ", html) def test_publish_view_post(self): """ diff --git a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_unpublish.py b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_unpublish.py index 4c4688fec830..a4f79c84f86b 100644 --- a/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_unpublish.py +++ b/wagtail/admin/tests/pages/test_bulk_actions/test_bulk_unpublish.py @@ -105,9 +105,7 @@ def test_unpublish_view_bad_permissions(self): ) for child_page in self.pages_to_be_unpublished: - self.assertInHTML( - "
  • {page_title}
  • ".format(page_title=child_page.title), html - ) + self.assertInHTML(f"
  • {child_page.title}
  • ", html) def test_unpublish_view_post(self): """ diff --git a/wagtail/admin/tests/pages/test_edit_page.py b/wagtail/admin/tests/pages/test_edit_page.py index 701dfc9ff695..453b3eec0f0e 100644 --- a/wagtail/admin/tests/pages/test_edit_page.py +++ b/wagtail/admin/tests/pages/test_edit_page.py @@ -2281,7 +2281,7 @@ def test_page_edit_post_publish_url(self): # 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 diff --git a/wagtail/admin/tests/pages/test_move_page.py b/wagtail/admin/tests/pages/test_move_page.py index 8d803dd86964..97c8767e993b 100644 --- a/wagtail/admin/tests/pages/test_move_page.py +++ b/wagtail/admin/tests/pages/test_move_page.py @@ -124,7 +124,7 @@ def test_page_move_confirm(self): 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 diff --git a/wagtail/admin/tests/pages/test_preview.py b/wagtail/admin/tests/pages/test_preview.py index 3676ac5c1e44..fc3da4114ee6 100644 --- a/wagtail/admin/tests/pages/test_preview.py +++ b/wagtail/admin/tests/pages/test_preview.py @@ -240,7 +240,7 @@ def test_preview_on_edit_with_m2m_field(self): ) # 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 @@ def test_preview_on_edit_with_valid_then_invalid_data(self): ) # 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 @@ def test_preview_on_create_clear_preview_data(self): ) 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" diff --git a/wagtail/admin/tests/test_filters.py b/wagtail/admin/tests/test_filters.py index bd6fcc309691..c98ca9835c49 100644 --- a/wagtail/admin/tests/test_filters.py +++ b/wagtail/admin/tests/test_filters.py @@ -54,20 +54,20 @@ class UserForm(forms.Form): expected_html = """ - """ % { - "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 UserForm(forms.Form): expected_html = """ - """ % { - "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) diff --git a/wagtail/admin/tests/test_site_summary.py b/wagtail/admin/tests/test_site_summary.py index a116a66e3e55..b77a2924ec97 100644 --- a/wagtail/admin/tests/test_site_summary.py +++ b/wagtail/admin/tests/test_site_summary.py @@ -57,9 +57,7 @@ def test_no_sites_summary_links_to_wagtail_root(self): self.assertSummaryContainsLinkToPage(self.wagtail_root.pk) def test_summary_includes_page_count_without_wagtail_root(self): - self.assertSummaryContains( - "{} Pages".format(Page.objects.count() - 1) - ) + self.assertSummaryContains(f"{Page.objects.count() - 1} Pages") def test_summary_shows_zero_pages_if_none_exist_except_wagtail_root(self): Page.objects.exclude(pk=self.wagtail_root.pk).delete() diff --git a/wagtail/admin/tests/test_templatetags.py b/wagtail/admin/tests/test_templatetags.py index 5e3207c464f8..6f94e130ac51 100644 --- a/wagtail/admin/tests/test_templatetags.py +++ b/wagtail/admin/tests/test_templatetags.py @@ -142,17 +142,17 @@ def test_timesince_last_update_today_shows_time(self): # 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) diff --git a/wagtail/admin/tests/test_workflows.py b/wagtail/admin/tests/test_workflows.py index 099fa0cab0dd..f6050119b09d 100644 --- a/wagtail/admin/tests/test_workflows.py +++ b/wagtail/admin/tests/test_workflows.py @@ -1188,7 +1188,7 @@ def test_submit_for_approval_changes_status_in_status_side_panel_meta(self): # 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 @@ def test_status_through_workflow_cycle(self): 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 @@ def test_status_through_workflow_cycle(self): 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 @@ def test_status_after_restart(self): 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): diff --git a/wagtail/admin/tests/tests.py b/wagtail/admin/tests/tests.py index 9a49e474f695..59084af2c7a9 100644 --- a/wagtail/admin/tests/tests.py +++ b/wagtail/admin/tests/tests.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import json import unittest diff --git a/wagtail/admin/ui/tables/__init__.py b/wagtail/admin/ui/tables/__init__.py index bc3cd52f07e8..d630df80d1c7 100644 --- a/wagtail/admin/ui/tables/__init__.py +++ b/wagtail/admin/ui/tables/__init__.py @@ -129,7 +129,7 @@ def get_cell(self, instance): 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 @@ def get_label_id(self, instance, parent_context): 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 @@ def __getitem__(self, key): 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()]) diff --git a/wagtail/admin/viewsets/__init__.py b/wagtail/admin/viewsets/__init__.py index a872de5c1350..105dfd4c96b1 100644 --- a/wagtail/admin/viewsets/__init__.py +++ b/wagtail/admin/viewsets/__init__.py @@ -30,7 +30,7 @@ def get_urlpatterns(self): if vs_urlpatterns: urlpatterns.append( re_path( - r"^{}/".format(viewset.url_prefix), + rf"^{viewset.url_prefix}/", include((vs_urlpatterns, viewset.name), namespace=viewset.name), ) ) diff --git a/wagtail/admin/wagtail_hooks.py b/wagtail/admin/wagtail_hooks.py index 0bd7d4d14e4d..7a2b2bd64aff 100644 --- a/wagtail/admin/wagtail_hooks.py +++ b/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 diff --git a/wagtail/admin/widgets/button.py b/wagtail/admin/widgets/button.py index c14c4b0edd88..5f904f192633 100644 --- a/wagtail/admin/widgets/button.py +++ b/wagtail/admin/widgets/button.py @@ -35,7 +35,7 @@ def __str__(self): return self.render() def __repr__(self): - return "".format(self.label) + return f"" def __lt__(self, other): if not isinstance(other, Button): diff --git a/wagtail/admin/widgets/chooser.py b/wagtail/admin/widgets/chooser.py index 6c8633b09137..784257ed3cc2 100644 --- a/wagtail/admin/widgets/chooser.py +++ b/wagtail/admin/widgets/chooser.py @@ -164,7 +164,7 @@ def render(self, name, value, attrs=None, renderer=None): widget_html = self.render_html(name, value_data, attrs) js = self.render_js_init(id_, name, value_data) - out = "{0}".format(widget_html, js) + out = f"{widget_html}" return mark_safe(out) @property diff --git a/wagtail/admin/widgets/workflows.py b/wagtail/admin/widgets/workflows.py index 73563e2ea241..66a0d8ea1bfe 100644 --- a/wagtail/admin/widgets/workflows.py +++ b/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): diff --git a/wagtail/api/conf.py b/wagtail/api/conf.py index 9cc798e46318..ff8463a5c0f2 100644 --- a/wagtail/api/conf.py +++ b/wagtail/api/conf.py @@ -7,4 +7,4 @@ def __hash__(self): return hash(self.name) def __repr__(self): - return "".format(self.name) + return f"" diff --git a/wagtail/api/v2/router.py b/wagtail/api/v2/router.py index 565611affaf8..4f84fd012f0c 100644 --- a/wagtail/api/v2/router.py +++ b/wagtail/api/v2/router.py @@ -74,7 +74,7 @@ def get_urlpatterns(self): 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) diff --git a/wagtail/api/v2/tests/test_documents.py b/wagtail/api/v2/tests/test_documents.py index 678b792586cf..722102568c51 100644 --- a/wagtail/api/v2/tests/test_documents.py +++ b/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): diff --git a/wagtail/api/v2/tests/test_images.py b/wagtail/api/v2/tests/test_images.py index e3939af3a2ab..2c4279bbab7b 100644 --- a/wagtail/api/v2/tests/test_images.py +++ b/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): diff --git a/wagtail/api/v2/tests/test_pages.py b/wagtail/api/v2/tests/test_pages.py index 6a7da49d0026..6b46bbfc678a 100644 --- a/wagtail/api/v2/tests/test_pages.py +++ b/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): diff --git a/wagtail/bin/wagtail.py b/wagtail/bin/wagtail.py index 55c7fb73e391..a0df1245f38a 100644 --- a/wagtail/bin/wagtail.py +++ b/wagtail/bin/wagtail.py @@ -33,7 +33,7 @@ def create_parser(self, command_name=None): 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 @@ def run(self): 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): diff --git a/wagtail/blocks/base.py b/wagtail/blocks/base.py index d5fb29f4cc21..c7c1f71917f6 100644 --- a/wagtail/blocks/base.py +++ b/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 Meta: 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 @@ def deconstruct(self): 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 @@ def __str__(self): return self.block.render(self.value) def __repr__(self): - return "" % ( + return "".format( self.block.name or type(self.block).__name__, self.value, ) @@ -474,9 +474,7 @@ def __new__(mcs, name, bases, attrs): 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`. diff --git a/wagtail/blocks/field_block.py b/wagtail/blocks/field_block.py index f3a212bfcc64..3c78e076caf9 100644 --- a/wagtail/blocks/field_block.py +++ b/wagtail/blocks/field_block.py @@ -918,7 +918,7 @@ def deconstruct(self): 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 diff --git a/wagtail/blocks/list_block.py b/wagtail/blocks/list_block.py index 2f5b092fe459..9f72df9e44f7 100644 --- a/wagtail/blocks/list_block.py +++ b/wagtail/blocks/list_block.py @@ -134,7 +134,7 @@ def insert(self, i, item): ) def __repr__(self): - return "" % ([bb.value for bb in self.bound_blocks],) + return f"" class ListBlock(Block): diff --git a/wagtail/blocks/migrations/operations.py b/wagtail/blocks/migrations/operations.py index f28dec2eb29d..0193f3ddad1d 100644 --- a/wagtail/blocks/migrations/operations.py +++ b/wagtail/blocks/migrations/operations.py @@ -46,7 +46,7 @@ def apply(self, block_value): @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 @@ def apply(self, block_value): @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 @@ def apply(self, block_value): @property def operation_name_fragment(self): - return "remove_{}".format(self.name) + return f"remove_{self.name}" @deconstructible @@ -134,7 +134,7 @@ def apply(self, block_value): @property def operation_name_fragment(self): - return "remove_{}".format(self.name) + return f"remove_{self.name}" class StreamChildrenToListBlockOperation(BaseBlockOperation): @@ -179,7 +179,7 @@ def map_temp_blocks_to_list_items(self): @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 @@ def apply(self, block_value): @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 @@ def apply(self, block_value): @property def operation_name_fragment(self): - return "list_block_items_to_{}".format(self.block_name) + return f"list_block_items_to_{self.block_name}" diff --git a/wagtail/blocks/migrations/utils.py b/wagtail/blocks/migrations/utils.py index 8b2086795aae..157cf27bded7 100644 --- a/wagtail/blocks/migrations/utils.py +++ b/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, diff --git a/wagtail/blocks/stream_block.py b/wagtail/blocks/stream_block.py index d8112d36be27..4ca08a2eb3fc 100644 --- a/wagtail/blocks/stream_block.py +++ b/wagtail/blocks/stream_block.py @@ -429,7 +429,7 @@ class StreamChild(BoundBlock): 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 @@ def __getitem__(self, block_name): 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 @@ def __len__(self): 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) diff --git a/wagtail/blocks/struct_block.py b/wagtail/blocks/struct_block.py index 1031eb43879a..fe0a208b8b02 100644 --- a/wagtail/blocks/struct_block.py +++ b/wagtail/blocks/struct_block.py @@ -139,14 +139,17 @@ def get_default(self): 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 @@ def get_form_context(self, value, prefix="", errors=None): ( 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() diff --git a/wagtail/contrib/forms/forms.py b/wagtail/contrib/forms/forms.py index f76b2911feee..7566fbce6baa 100644 --- a/wagtail/contrib/forms/forms.py +++ b/wagtail/contrib/forms/forms.py @@ -157,7 +157,7 @@ def get_field_options(self, field): 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): diff --git a/wagtail/contrib/forms/migrations/0001_initial.py b/wagtail/contrib/forms/migrations/0001_initial.py index c8fc5ae0fee7..8ca5217c31ac 100644 --- a/wagtail/contrib/forms/migrations/0001_initial.py +++ b/wagtail/contrib/forms/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/forms/migrations/0002_add_verbose_names.py b/wagtail/contrib/forms/migrations/0002_add_verbose_names.py index 0ab6707437bd..ee93027aa51b 100644 --- a/wagtail/contrib/forms/migrations/0002_add_verbose_names.py +++ b/wagtail/contrib/forms/migrations/0002_add_verbose_names.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/forms/migrations/0003_capitalizeverbose.py b/wagtail/contrib/forms/migrations/0003_capitalizeverbose.py index 172c07996c24..443b85acca5d 100644 --- a/wagtail/contrib/forms/migrations/0003_capitalizeverbose.py +++ b/wagtail/contrib/forms/migrations/0003_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/forms/migrations/0004_add_verbose_name_plural.py b/wagtail/contrib/forms/migrations/0004_add_verbose_name_plural.py index 585880d111e4..1a34a756162c 100644 --- a/wagtail/contrib/forms/migrations/0004_add_verbose_name_plural.py +++ b/wagtail/contrib/forms/migrations/0004_add_verbose_name_plural.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/contrib/forms/models.py b/wagtail/contrib/forms/models.py index bf907a3298c0..809d90570876 100644 --- a/wagtail/contrib/forms/models.py +++ b/wagtail/contrib/forms/models.py @@ -369,7 +369,7 @@ def render_email(self, form): 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) diff --git a/wagtail/contrib/forms/tests/test_forms.py b/wagtail/contrib/forms/tests/test_forms.py index 641e3b541360..6163d8354c61 100644 --- a/wagtail/contrib/forms/tests/test_forms.py +++ b/wagtail/contrib/forms/tests/test_forms.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django import forms from django.test import TestCase diff --git a/wagtail/contrib/forms/tests/test_models.py b/wagtail/contrib/forms/tests/test_models.py index beaa7f343dc9..05a309c6ef65 100644 --- a/wagtail/contrib/forms/tests/test_models.py +++ b/wagtail/contrib/forms/tests/test_models.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import unittest from django import VERSION as DJANGO_VERSION diff --git a/wagtail/contrib/forms/tests/test_views.py b/wagtail/contrib/forms/tests/test_views.py index 9c466146034e..634581dc30e4 100644 --- a/wagtail/contrib/forms/tests/test_views.py +++ b/wagtail/contrib/forms/tests/test_views.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import datetime from io import BytesIO @@ -68,7 +67,7 @@ def test_render_with_submissions(self): result = self.panel.render_html() url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,)) - link = '
    1'.format(url) + link = f'1' self.assertIn(link, result) @@ -117,7 +116,7 @@ def test_render_with_submissions(self): result = self.panel.render_html() url = reverse("wagtailforms:list_submissions", args=(self.form_page.id,)) - link = '1'.format(url) + link = f'1' self.assertIn(link, result) @@ -1190,7 +1189,7 @@ def setUp(self): 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 @@ def test_delete_submission_show_confirmation(self): 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 @@ def test_delete_submission_bad_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 user received a permission denied response @@ -1252,7 +1251,7 @@ def construct_forms_for_user(user, queryset): ): 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 diff --git a/wagtail/contrib/forms/tests/utils.py b/wagtail/contrib/forms/tests/utils.py index f78ab068a965..c10e665c15e8 100644 --- a/wagtail/contrib/forms/tests/utils.py +++ b/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, diff --git a/wagtail/contrib/frontend_cache/backends.py b/wagtail/contrib/frontend_cache/backends.py index f7087bd90b03..82eac40ab0e7 100644 --- a/wagtail/contrib/frontend_cache/backends.py +++ b/wagtail/contrib/frontend_cache/backends.py @@ -107,7 +107,7 @@ def __init__(self, params): 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 @@ def _purge_urls(self, urls): 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 diff --git a/wagtail/contrib/frontend_cache/tests.py b/wagtail/contrib/frontend_cache/tests.py index 91232a7d0368..033f95b68d7a 100644 --- a/wagtail/contrib/frontend_cache/tests.py +++ b/wagtail/contrib/frontend_cache/tests.py @@ -481,7 +481,7 @@ def setUp(self): 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() diff --git a/wagtail/contrib/frontend_cache/utils.py b/wagtail/contrib/frontend_cache/utils.py index 3599755030b5..82df8306fb11 100644 --- a/wagtail/contrib/frontend_cache/utils.py +++ b/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) diff --git a/wagtail/contrib/modeladmin/helpers/permission.py b/wagtail/contrib/modeladmin/helpers/permission.py index 46e21ccd9d73..e04d9dcee8cd 100644 --- a/wagtail/contrib/modeladmin/helpers/permission.py +++ b/wagtail/contrib/modeladmin/helpers/permission.py @@ -47,7 +47,7 @@ def user_has_specific_permission(self, user, perm_codename): 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): """ diff --git a/wagtail/contrib/modeladmin/helpers/url.py b/wagtail/contrib/modeladmin/helpers/url.py index 5bbb954ab47e..4cf240e3d387 100644 --- a/wagtail/contrib/modeladmin/helpers/url.py +++ b/wagtail/contrib/modeladmin/helpers/url.py @@ -14,15 +14,15 @@ def __init__(self, model, base_url_path=None): 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[-\w]+)/$" % ( + return r"^{}/{}/(?P[-\w]+)/$".format( self.base_url_path, action, ) @@ -33,7 +33,7 @@ def get_action_url_pattern(self, action): 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 @@ def get_action_url(self, action, *args, **kwargs): 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) diff --git a/wagtail/contrib/modeladmin/mixins.py b/wagtail/contrib/modeladmin/mixins.py index 706989b2737c..ba4258a85664 100644 --- a/wagtail/contrib/modeladmin/mixins.py +++ b/wagtail/contrib/modeladmin/mixins.py @@ -46,7 +46,7 @@ def admin_thumb(self, obj): } if not image: if self.thumb_default: - return mark_safe("".format(flatatt(img_attrs))) + return mark_safe(f"") return "" # try to get a rendition of the image to use @@ -55,4 +55,4 @@ def admin_thumb(self, obj): spec = self.thumb_image_filter_spec rendition = get_rendition_or_not_found(image, spec) img_attrs.update({"src": rendition.url}) - return mark_safe("".format(flatatt(img_attrs))) + return mark_safe(f"") diff --git a/wagtail/contrib/modeladmin/options.py b/wagtail/contrib/modeladmin/options.py index f8e21ac9a799..3eeabc35e3f8 100644 --- a/wagtail/contrib/modeladmin/options.py +++ b/wagtail/contrib/modeladmin/options.py @@ -507,9 +507,9 @@ def get_templates(self, action="index"): 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): diff --git a/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py b/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py index 791282b49d96..5c63959a7c59 100644 --- a/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py +++ b/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py @@ -149,9 +149,7 @@ def test_one_parent_exists(self): 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 @@ def test_simple(self): 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 @@ def test_non_existent(self): 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 @@ def test_simple(self): 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 @@ def test_post(self): 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/") diff --git a/wagtail/contrib/redirects/forms.py b/wagtail/contrib/redirects/forms.py index daeefb355ab0..f5a48672d81a 100644 --- a/wagtail/contrib/redirects/forms.py +++ b/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] diff --git a/wagtail/contrib/redirects/management/commands/import_redirects.py b/wagtail/contrib/redirects/management/commands/import_redirects.py index 491244514da4..698e76281ba7 100644 --- a/wagtail/contrib/redirects/management/commands/import_redirects.py +++ b/wagtail/contrib/redirects/management/commands/import_redirects.py @@ -95,10 +95,10 @@ def handle(self, *args, **options): 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 @@ def handle(self, *args, **options): 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 @@ def handle(self, *args, **options): 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 @@ def handle(self, *args, **options): 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 diff --git a/wagtail/contrib/redirects/migrations/0001_initial.py b/wagtail/contrib/redirects/migrations/0001_initial.py index c6ee4c984453..860fc39dcee1 100644 --- a/wagtail/contrib/redirects/migrations/0001_initial.py +++ b/wagtail/contrib/redirects/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/redirects/migrations/0002_add_verbose_names.py b/wagtail/contrib/redirects/migrations/0002_add_verbose_names.py index 81ec2f9c9bd9..7224c2a7e4a1 100644 --- a/wagtail/contrib/redirects/migrations/0002_add_verbose_names.py +++ b/wagtail/contrib/redirects/migrations/0002_add_verbose_names.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/redirects/migrations/0003_make_site_field_editable.py b/wagtail/contrib/redirects/migrations/0003_make_site_field_editable.py index 3974b4b3731b..6d99b6acad51 100644 --- a/wagtail/contrib/redirects/migrations/0003_make_site_field_editable.py +++ b/wagtail/contrib/redirects/migrations/0003_make_site_field_editable.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/redirects/migrations/0004_set_unique_on_path_and_site.py b/wagtail/contrib/redirects/migrations/0004_set_unique_on_path_and_site.py index 4231f66c7255..d54726688e65 100644 --- a/wagtail/contrib/redirects/migrations/0004_set_unique_on_path_and_site.py +++ b/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 diff --git a/wagtail/contrib/redirects/migrations/0005_capitalizeverbose.py b/wagtail/contrib/redirects/migrations/0005_capitalizeverbose.py index 248a6099b75b..a67f01558c95 100644 --- a/wagtail/contrib/redirects/migrations/0005_capitalizeverbose.py +++ b/wagtail/contrib/redirects/migrations/0005_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/redirects/tests/test_import_admin_views.py b/wagtail/contrib/redirects/tests/test_import_admin_views.py index 6ab2bac7f66d..d65c7424f651 100644 --- a/wagtail/contrib/redirects/tests/test_import_admin_views.py +++ b/wagtail/contrib/redirects/tests/test_import_admin_views.py @@ -49,7 +49,7 @@ def test_empty_import_file_returns_error(self): 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 @@ def test_non_valid_format_returns_error(self): ) 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 @@ def test_valid_csv_triggers_confirm_view(self): 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 @@ def test_import_step(self): 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 @@ def test_import_step_with_offset_columns(self): 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 @@ def test_permanent_setting(self): 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 @@ def test_site_setting(self): 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 @@ def test_import_xlsx(self): 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 @@ def test_not_valid_method_for_import_file(self): 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 @@ def test_error_in_data_renders_confirm_view_on_import(self): 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 @@ def test_import_tsv(self): @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 @@ def test_import_xlsx_with_cache_store_engine(self): @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: diff --git a/wagtail/contrib/redirects/tests/test_import_command.py b/wagtail/contrib/redirects/tests/test_import_command.py index e979b11ce12f..e437cf91feb2 100644 --- a/wagtail/contrib/redirects/tests/test_import_command.py +++ b/wagtail/contrib/redirects/tests/test_import_command.py @@ -25,7 +25,7 @@ def test_missing_file_raises_error(self): 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 @@ def test_invalid_extension_raises_error(self): 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 @@ def test_header_are_not_imported(self): 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 @@ def test_column_index_are_used(self): out = StringIO() call_command( "import_redirects", - "--src={}".format(invalid_file.name), + f"--src={invalid_file.name}", "--from=1", "--to=3", "--format=csv", diff --git a/wagtail/contrib/redirects/tests/test_import_utils.py b/wagtail/contrib/redirects/tests/test_import_utils.py index 288ff80a9d7e..90371601e461 100644 --- a/wagtail/contrib/redirects/tests/test_import_utils.py +++ b/wagtail/contrib/redirects/tests/test_import_utils.py @@ -15,7 +15,7 @@ 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: diff --git a/wagtail/contrib/redirects/tests/test_redirects.py b/wagtail/contrib/redirects/tests/test_redirects.py index 76bcaeee2a7b..4e868aeb4333 100644 --- a/wagtail/contrib/redirects/tests/test_redirects.py +++ b/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 diff --git a/wagtail/contrib/redirects/utils.py b/wagtail/contrib/redirects/utils.py index c006fcf8fa1d..7fafe2bc140c 100644 --- a/wagtail/contrib/redirects/utils.py +++ b/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 diff --git a/wagtail/contrib/search_promotions/migrations/0002_capitalizeverbose.py b/wagtail/contrib/search_promotions/migrations/0002_capitalizeverbose.py index 8ed818994b57..30f9032f6276 100644 --- a/wagtail/contrib/search_promotions/migrations/0002_capitalizeverbose.py +++ b/wagtail/contrib/search_promotions/migrations/0002_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/contrib/search_promotions/models.py b/wagtail/contrib/search_promotions/models.py index 5161a27c90a4..8f455efe8471 100644 --- a/wagtail/contrib/search_promotions/models.py +++ b/wagtail/contrib/search_promotions/models.py @@ -110,7 +110,7 @@ def __repr__(self): ) 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",) diff --git a/wagtail/contrib/search_promotions/tests.py b/wagtail/contrib/search_promotions/tests.py index b9c2b8727392..9ccccfbece2a 100644 --- a/wagtail/contrib/search_promotions/tests.py +++ b/wagtail/contrib/search_promotions/tests.py @@ -493,21 +493,21 @@ def test_garbage_collect_command(self): # 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" diff --git a/wagtail/contrib/settings/context_processors.py b/wagtail/contrib/settings/context_processors.py index 487439b85db0..83722d8a0373 100644 --- a/wagtail/contrib/settings/context_processors.py +++ b/wagtail/contrib/settings/context_processors.py @@ -37,7 +37,7 @@ def __missing__(self, model_name): return value def __str__(self): - return "SettingModuleProxy({0})".format(self.app_label) + return f"SettingModuleProxy({self.app_label})" def get_setting(self, model_name): """ diff --git a/wagtail/contrib/settings/models.py b/wagtail/contrib/settings/models.py index c02b03102b77..71ed4f2b932e 100644 --- a/wagtail/contrib/settings/models.py +++ b/wagtail/contrib/settings/models.py @@ -51,7 +51,7 @@ def get_cache_attr_name(cls): 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) diff --git a/wagtail/contrib/settings/permissions.py b/wagtail/contrib/settings/permissions.py index 5a2b654d7ab2..a5f3e613d163 100644 --- a/wagtail/contrib/settings/permissions.py +++ b/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}") diff --git a/wagtail/contrib/settings/registry.py b/wagtail/contrib/settings/registry.py index 87bd5e7c3e8d..565996daf1fa 100644 --- a/wagtail/contrib/settings/registry.py +++ b/wagtail/contrib/settings/registry.py @@ -90,7 +90,7 @@ def menu_hook(): 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 diff --git a/wagtail/contrib/settings/tests/generic/test_admin.py b/wagtail/contrib/settings/tests/generic/test_admin.py index 6cd340e15c98..09e90151f87c 100644 --- a/wagtail/contrib/settings/tests/generic/test_admin.py +++ b/wagtail/contrib/settings/tests/generic/test_admin.py @@ -160,7 +160,7 @@ def test_for_request(self): self.assertRedirects( response, status_code=302, - expected_url="%s%s/" % (url, TestGenericSetting.objects.first().pk), + expected_url=f"{url}{TestGenericSetting.objects.first().pk}/", ) diff --git a/wagtail/contrib/settings/tests/site_specific/test_admin.py b/wagtail/contrib/settings/tests/site_specific/test_admin.py index 4b71507b12b1..3729b568d7e4 100644 --- a/wagtail/contrib/settings/tests/site_specific/test_admin.py +++ b/wagtail/contrib/settings/tests/site_specific/test_admin.py @@ -161,7 +161,7 @@ def test_get_redirect_to_relevant_instance(self): 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): diff --git a/wagtail/contrib/settings/tests/site_specific/test_forms.py b/wagtail/contrib/settings/tests/site_specific/test_forms.py index a521add6b0a2..72cc7927b558 100644 --- a/wagtail/contrib/settings/tests/site_specific/test_forms.py +++ b/wagtail/contrib/settings/tests/site_specific/test_forms.py @@ -18,13 +18,13 @@ def test_site_order_by_hostname(self): 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", ), ] diff --git a/wagtail/contrib/settings/tests/site_specific/test_model.py b/wagtail/contrib/settings/tests/site_specific/test_model.py index 15da76246926..55ccc868e0e2 100644 --- a/wagtail/contrib/settings/tests/site_specific/test_model.py +++ b/wagtail/contrib/settings/tests/site_specific/test_model.py @@ -64,7 +64,7 @@ def test_importantpages_object_is_pickleable(self): 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 @@ def test_importantpages_object_is_pickleable(self): 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 diff --git a/wagtail/contrib/settings/views.py b/wagtail/contrib/settings/views.py index 390bf0bbae8c..8ab160a2b2e9 100644 --- a/wagtail/contrib/settings/views.py +++ b/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 diff --git a/wagtail/contrib/simple_translation/forms.py b/wagtail/contrib/simple_translation/forms.py index efcf3e28f9a3..e13e21ba8371 100644 --- a/wagtail/contrib/simple_translation/forms.py +++ b/wagtail/contrib/simple_translation/forms.py @@ -108,7 +108,7 @@ def __init__(self, instance, *args, **kwargs): len(disabled_locales), ) help_text += "
    " - help_text += ''.format(url) + help_text += f'' help_text += ngettext( "Translate the parent page.", "Translate the parent pages.", diff --git a/wagtail/contrib/table_block/templatetags/table_block_tags.py b/wagtail/contrib/table_block/templatetags/table_block_tags.py index 39d3a09f28b7..1feeebc5e96f 100644 --- a/wagtail/contrib/table_block/templatetags/table_block_tags.py +++ b/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 "" diff --git a/wagtail/coreutils.py b/wagtail/coreutils.py index e7fab73f3c4d..e2fb2364b164 100644 --- a/wagtail/coreutils.py +++ b/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() diff --git a/wagtail/documents/migrations/0001_initial.py b/wagtail/documents/migrations/0001_initial.py index bd5330cec67a..d18d55be03b0 100644 --- a/wagtail/documents/migrations/0001_initial.py +++ b/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 diff --git a/wagtail/documents/migrations/0002_initial_data.py b/wagtail/documents/migrations/0002_initial_data.py index 86bf2de9d1ea..35465ffd1d5f 100644 --- a/wagtail/documents/migrations/0002_initial_data.py +++ b/wagtail/documents/migrations/0002_initial_data.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/documents/migrations/0003_add_verbose_names.py b/wagtail/documents/migrations/0003_add_verbose_names.py index fa9b5ce59f44..0f9bbcde6854 100644 --- a/wagtail/documents/migrations/0003_add_verbose_names.py +++ b/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 diff --git a/wagtail/documents/migrations/0004_capitalizeverbose.py b/wagtail/documents/migrations/0004_capitalizeverbose.py index f802b2b8c939..689d08e44faa 100644 --- a/wagtail/documents/migrations/0004_capitalizeverbose.py +++ b/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 diff --git a/wagtail/documents/migrations/0005_alter_uploaded_by_user_on_delete_action.py b/wagtail/documents/migrations/0005_alter_uploaded_by_user_on_delete_action.py index c0f42531c4ea..2e9c1d031a53 100644 --- a/wagtail/documents/migrations/0005_alter_uploaded_by_user_on_delete_action.py +++ b/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 diff --git a/wagtail/documents/migrations/0005_document_collection.py b/wagtail/documents/migrations/0005_document_collection.py index 17c57495692b..09a821546ebe 100644 --- a/wagtail/documents/migrations/0005_document_collection.py +++ b/wagtail/documents/migrations/0005_document_collection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models import wagtail.models diff --git a/wagtail/documents/migrations/0006_copy_document_permissions_to_collections.py b/wagtail/documents/migrations/0006_copy_document_permissions_to_collections.py index 838272265f65..74aa082ba749 100644 --- a/wagtail/documents/migrations/0006_copy_document_permissions_to_collections.py +++ b/wagtail/documents/migrations/0006_copy_document_permissions_to_collections.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/documents/migrations/0007_merge.py b/wagtail/documents/migrations/0007_merge.py index 12c7011df91b..3f2ed0346001 100644 --- a/wagtail/documents/migrations/0007_merge.py +++ b/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 diff --git a/wagtail/documents/tests/test_admin_views.py b/wagtail/documents/tests/test_admin_views.py index d3f4db0df2c3..bbe715b4559b 100644 --- a/wagtail/documents/tests/test_admin_views.py +++ b/wagtail/documents/tests/test_admin_views.py @@ -149,7 +149,7 @@ def test_edit_document_link_contains_next_url(self): 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() diff --git a/wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py b/wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py index 84ff5df76b7c..548722c2d259 100644 --- a/wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py +++ b/wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py @@ -52,9 +52,7 @@ def test_add_tags_with_limited_permissions(self): ) for document in self.documents: - self.assertInHTML( - "
  • {document_title}
  • ".format(document_title=document.title), html - ) + self.assertInHTML(f"
  • {document.title}
  • ", html) self.client.post(self.url, self.post_data) diff --git a/wagtail/documents/tests/test_bulk_actions/test_bulk_add_to_collection.py b/wagtail/documents/tests/test_bulk_actions/test_bulk_add_to_collection.py index d10d1d785e50..b42ff6bc96ff 100644 --- a/wagtail/documents/tests/test_bulk_actions/test_bulk_add_to_collection.py +++ b/wagtail/documents/tests/test_bulk_actions/test_bulk_add_to_collection.py @@ -51,9 +51,7 @@ def test_add_to_collection_with_limited_permissions(self): ) for document in self.documents: - self.assertInHTML( - "
  • {document_title}
  • ".format(document_title=document.title), html - ) + self.assertInHTML(f"
  • {document.title}
  • ", html) self.client.post(self.url, self.post_data) diff --git a/wagtail/documents/tests/test_bulk_actions/test_bulk_delete.py b/wagtail/documents/tests/test_bulk_actions/test_bulk_delete.py index f07ba981c8dc..309bdf1b417d 100644 --- a/wagtail/documents/tests/test_bulk_actions/test_bulk_delete.py +++ b/wagtail/documents/tests/test_bulk_actions/test_bulk_delete.py @@ -48,9 +48,7 @@ def test_delete_with_limited_permissions(self): ) for document in self.documents: - self.assertInHTML( - "
  • {document_title}
  • ".format(document_title=document.title), html - ) + self.assertInHTML(f"
  • {document.title}
  • ", html) response = self.client.post(self.url) # User should be redirected back to the index diff --git a/wagtail/documents/tests/test_collection_privacy.py b/wagtail/documents/tests/test_collection_privacy.py index d3a792534874..3cb9a9b23657 100644 --- a/wagtail/documents/tests/test_collection_privacy.py +++ b/wagtail/documents/tests/test_collection_privacy.py @@ -108,12 +108,12 @@ def test_anonymous_user_must_authenticate(self): def test_group_restriction_with_anonymous_user(self): response, url = self.get_document(self.group_collection) - self.assertRedirects(response, "/_util/login/?next={}".format(url)) + self.assertRedirects(response, f"/_util/login/?next={url}") def test_group_restriction_with_unpermitted_user(self): self.login(username="eventmoderator", password="password") response, url = self.get_document(self.group_collection) - self.assertRedirects(response, "/_util/login/?next={}".format(url)) + self.assertRedirects(response, f"/_util/login/?next={url}") def test_group_restriction_with_permitted_user(self): self.login(username="eventeditor", password="password") @@ -127,7 +127,7 @@ def test_group_restriction_with_superuser(self): def test_login_restriction_with_anonymous_user(self): response, url = self.get_document(self.login_collection) - self.assertRedirects(response, "/_util/login/?next={}".format(url)) + self.assertRedirects(response, f"/_util/login/?next={url}") def test_login_restriction_with_logged_in_user(self): self.login(username="eventmoderator", password="password") diff --git a/wagtail/documents/tests/test_models.py b/wagtail/documents/tests/test_models.py index 92d8b77bc7a6..cd31489b1f29 100644 --- a/wagtail/documents/tests/test_models.py +++ b/wagtail/documents/tests/test_models.py @@ -256,7 +256,7 @@ def setUp(self): def test_document_model(self): cls = get_document_model() self.assertEqual( - "%s.%s" % (cls._meta.app_label, cls.__name__), "tests.CustomDocument" + f"{cls._meta.app_label}.{cls.__name__}", "tests.CustomDocument" ) diff --git a/wagtail/documents/tests/test_views.py b/wagtail/documents/tests/test_views.py index b3a690215d1c..3a1097fd71d1 100644 --- a/wagtail/documents/tests/test_views.py +++ b/wagtail/documents/tests/test_views.py @@ -49,13 +49,13 @@ def test_response_code(self): def test_content_disposition_header(self): self.assertEqual( self.get(self.document)["Content-Disposition"], - 'attachment; filename="{}"'.format(self.document.filename), + f'attachment; filename="{self.document.filename}"', ) def test_inline_content_disposition_header(self): self.assertEqual( self.get(self.pdf_document)["Content-Disposition"], - 'inline; filename="{}"'.format(self.pdf_document.filename), + f'inline; filename="{self.pdf_document.filename}"', ) @mock.patch("wagtail.documents.views.serve.hooks") diff --git a/wagtail/embeds/finders/instagram.py b/wagtail/embeds/finders/instagram.py index 458248d1bc22..ad541ee76647 100644 --- a/wagtail/embeds/finders/instagram.py +++ b/wagtail/embeds/finders/instagram.py @@ -66,7 +66,7 @@ def find_embed(self, url, max_width=None, max_height=None): # Convert photos into HTML if oembed["type"] == "photo": - html = '' % (oembed["url"],) + html = ''.format(oembed["url"]) else: html = oembed.get("html") diff --git a/wagtail/embeds/finders/oembed.py b/wagtail/embeds/finders/oembed.py index 96a857cbc79b..79fa699f7890 100644 --- a/wagtail/embeds/finders/oembed.py +++ b/wagtail/embeds/finders/oembed.py @@ -70,7 +70,7 @@ def find_embed(self, url, max_width=None, max_height=None): # Convert photos into HTML if oembed["type"] == "photo": - html = '' % (oembed["url"],) + html = ''.format(oembed["url"]) else: html = oembed.get("html") diff --git a/wagtail/embeds/migrations/0001_initial.py b/wagtail/embeds/migrations/0001_initial.py index f00fdf789f46..82c69e7caa15 100644 --- a/wagtail/embeds/migrations/0001_initial.py +++ b/wagtail/embeds/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/embeds/migrations/0002_add_verbose_names.py b/wagtail/embeds/migrations/0002_add_verbose_names.py index 1864bf4bbc2b..4af0cb70a5cf 100644 --- a/wagtail/embeds/migrations/0002_add_verbose_names.py +++ b/wagtail/embeds/migrations/0002_add_verbose_names.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/embeds/migrations/0003_capitalizeverbose.py b/wagtail/embeds/migrations/0003_capitalizeverbose.py index 71931a3459b8..7b687c034249 100644 --- a/wagtail/embeds/migrations/0003_capitalizeverbose.py +++ b/wagtail/embeds/migrations/0003_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/images/checks.py b/wagtail/images/checks.py index 7a3153026ead..92a374d6a674 100644 --- a/wagtail/images/checks.py +++ b/wagtail/images/checks.py @@ -5,7 +5,7 @@ from willow.image import Image -@lru_cache() +@lru_cache def has_jpeg_support(): wagtail_jpg = os.path.join(os.path.dirname(__file__), "check_files", "wagtail.jpg") succeeded = True @@ -13,13 +13,13 @@ def has_jpeg_support(): with open(wagtail_jpg, "rb") as f: try: Image.open(f) - except IOError: + except OSError: succeeded = False return succeeded -@lru_cache() +@lru_cache def has_png_support(): wagtail_png = os.path.join(os.path.dirname(__file__), "check_files", "wagtail.png") succeeded = True @@ -27,7 +27,7 @@ def has_png_support(): with open(wagtail_png, "rb") as f: try: Image.open(f) - except IOError: + except OSError: succeeded = False return succeeded diff --git a/wagtail/images/migrations/0001_initial.py b/wagtail/images/migrations/0001_initial.py index ab021f01b0a6..fecb8e7079a2 100644 --- a/wagtail/images/migrations/0001_initial.py +++ b/wagtail/images/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 diff --git a/wagtail/images/migrations/0002_initial_data.py b/wagtail/images/migrations/0002_initial_data.py index 3b48c335e693..f65cda13556c 100644 --- a/wagtail/images/migrations/0002_initial_data.py +++ b/wagtail/images/migrations/0002_initial_data.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/images/migrations/0003_fix_focal_point_fields.py b/wagtail/images/migrations/0003_fix_focal_point_fields.py index 0ef8d60cf075..6e1c42401ac4 100644 --- a/wagtail/images/migrations/0003_fix_focal_point_fields.py +++ b/wagtail/images/migrations/0003_fix_focal_point_fields.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/images/migrations/0004_make_focal_point_key_not_nullable.py b/wagtail/images/migrations/0004_make_focal_point_key_not_nullable.py index 2819d2920c26..22394d9cdfa2 100644 --- a/wagtail/images/migrations/0004_make_focal_point_key_not_nullable.py +++ b/wagtail/images/migrations/0004_make_focal_point_key_not_nullable.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/images/migrations/0005_make_filter_spec_unique.py b/wagtail/images/migrations/0005_make_filter_spec_unique.py index 7c70757c8dd9..df9cef4d8f6f 100644 --- a/wagtail/images/migrations/0005_make_filter_spec_unique.py +++ b/wagtail/images/migrations/0005_make_filter_spec_unique.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/images/migrations/0006_add_verbose_names.py b/wagtail/images/migrations/0006_add_verbose_names.py index aad2f7f7508b..eef2afe8cabe 100644 --- a/wagtail/images/migrations/0006_add_verbose_names.py +++ b/wagtail/images/migrations/0006_add_verbose_names.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.conf import settings from django.db import migrations, models diff --git a/wagtail/images/migrations/0007_image_file_size.py b/wagtail/images/migrations/0007_image_file_size.py index dad236029f65..2bc06f129a1a 100644 --- a/wagtail/images/migrations/0007_image_file_size.py +++ b/wagtail/images/migrations/0007_image_file_size.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/images/migrations/0008_image_created_at_index.py b/wagtail/images/migrations/0008_image_created_at_index.py index 423993e55a16..ab1bb7851a6e 100644 --- a/wagtail/images/migrations/0008_image_created_at_index.py +++ b/wagtail/images/migrations/0008_image_created_at_index.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/images/migrations/0009_capitalizeverbose.py b/wagtail/images/migrations/0009_capitalizeverbose.py index b847b53d1f6d..c83a5ca8e3c9 100644 --- a/wagtail/images/migrations/0009_capitalizeverbose.py +++ b/wagtail/images/migrations/0009_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import taggit.managers from django.conf import settings from django.db import migrations, models diff --git a/wagtail/images/migrations/0010_change_on_delete_behaviour.py b/wagtail/images/migrations/0010_change_on_delete_behaviour.py index 3ae33dcae3e1..36bb7090cefd 100644 --- a/wagtail/images/migrations/0010_change_on_delete_behaviour.py +++ b/wagtail/images/migrations/0010_change_on_delete_behaviour.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import django.db.models.deletion from django.conf import settings from django.db import migrations, models diff --git a/wagtail/images/migrations/0011_image_collection.py b/wagtail/images/migrations/0011_image_collection.py index 78668b259946..d39977fe72d2 100644 --- a/wagtail/images/migrations/0011_image_collection.py +++ b/wagtail/images/migrations/0011_image_collection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models import wagtail.models diff --git a/wagtail/images/migrations/0012_copy_image_permissions_to_collections.py b/wagtail/images/migrations/0012_copy_image_permissions_to_collections.py index faf18c7ee83f..cdf089de5be2 100644 --- a/wagtail/images/migrations/0012_copy_image_permissions_to_collections.py +++ b/wagtail/images/migrations/0012_copy_image_permissions_to_collections.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/images/migrations/0013_make_rendition_upload_callable.py b/wagtail/images/migrations/0013_make_rendition_upload_callable.py index 5fc269da45bc..9ce3040cf473 100644 --- a/wagtail/images/migrations/0013_make_rendition_upload_callable.py +++ b/wagtail/images/migrations/0013_make_rendition_upload_callable.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import models, migrations import wagtail.images.models diff --git a/wagtail/images/migrations/0014_add_filter_spec_field.py b/wagtail/images/migrations/0014_add_filter_spec_field.py index 069a33d0d44d..45219e3f0a63 100644 --- a/wagtail/images/migrations/0014_add_filter_spec_field.py +++ b/wagtail/images/migrations/0014_add_filter_spec_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10 on 2016-08-11 12:03 from django.db import migrations, models import django.db.models.deletion diff --git a/wagtail/images/migrations/0015_fill_filter_spec_field.py b/wagtail/images/migrations/0015_fill_filter_spec_field.py index 48b80241da08..bfcfdb7af35e 100644 --- a/wagtail/images/migrations/0015_fill_filter_spec_field.py +++ b/wagtail/images/migrations/0015_fill_filter_spec_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10 on 2016-08-11 13:25 from django.db import migrations diff --git a/wagtail/images/migrations/0016_deprecate_rendition_filter_relation.py b/wagtail/images/migrations/0016_deprecate_rendition_filter_relation.py index cb17398d102c..fa3ec02372e8 100644 --- a/wagtail/images/migrations/0016_deprecate_rendition_filter_relation.py +++ b/wagtail/images/migrations/0016_deprecate_rendition_filter_relation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.11 on 2016-11-11 17:04 from django.db import migrations, models diff --git a/wagtail/images/migrations/0017_reduce_focal_point_key_max_length.py b/wagtail/images/migrations/0017_reduce_focal_point_key_max_length.py index e01a65a5a5b6..e90089b1fe36 100644 --- a/wagtail/images/migrations/0017_reduce_focal_point_key_max_length.py +++ b/wagtail/images/migrations/0017_reduce_focal_point_key_max_length.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/images/migrations/0018_remove_rendition_filter.py b/wagtail/images/migrations/0018_remove_rendition_filter.py index 727abc61d5de..ffaa98c8109a 100644 --- a/wagtail/images/migrations/0018_remove_rendition_filter.py +++ b/wagtail/images/migrations/0018_remove_rendition_filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.4 on 2016-12-16 17:15 from django.db import migrations diff --git a/wagtail/images/migrations/0019_delete_filter.py b/wagtail/images/migrations/0019_delete_filter.py index 73c538980128..b919c43e464b 100644 --- a/wagtail/images/migrations/0019_delete_filter.py +++ b/wagtail/images/migrations/0019_delete_filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.5 on 2017-02-08 23:51 from django.db import migrations diff --git a/wagtail/images/models.py b/wagtail/images/models.py index 86d2988c2bb9..4c204afb0924 100644 --- a/wagtail/images/models.py +++ b/wagtail/images/models.py @@ -174,7 +174,7 @@ def open_file(self): image_file = storage.open(self.file.name, "rb") close_file = True - except IOError as e: + except OSError as e: # re-throw this as a SourceImageIOError so that calling code can distinguish # these from IOErrors elsewhere in the process raise SourceImageIOError(str(e)) @@ -1071,7 +1071,7 @@ def background_position_style(self): if focal_point: horz = int((focal_point.x * 100) // self.width) vert = int((focal_point.y * 100) // self.height) - return "background-position: {}% {}%;".format(horz, vert) + return f"background-position: {horz}% {vert}%;" else: return "background-position: 50% 50%;" @@ -1082,7 +1082,7 @@ def img_tag(self, extra_attributes={}): attrs.update(extra_attributes) - return mark_safe("".format(flatatt(attrs))) + return mark_safe(f"") def __html__(self): return self.img_tag() @@ -1094,7 +1094,7 @@ def get_upload_to(self, filename): @classmethod def check(cls, **kwargs): - errors = super(AbstractRendition, cls).check(**kwargs) + errors = super().check(**kwargs) if not cls._meta.abstract: if not any( set(constraint) == {"image", "filter_spec", "focal_point_key"} diff --git a/wagtail/images/templatetags/wagtailimages_tags.py b/wagtail/images/templatetags/wagtailimages_tags.py index f86f53d9891a..1610b90e416c 100644 --- a/wagtail/images/templatetags/wagtailimages_tags.py +++ b/wagtail/images/templatetags/wagtailimages_tags.py @@ -106,7 +106,7 @@ def __init__( self.filter_specs = filter_specs self.preserve_svg = preserve_svg - @lru_cache() + @lru_cache def get_filter(self, preserve_svg=False): if preserve_svg: return Filter(to_svg_safe_spec(self.filter_specs)) diff --git a/wagtail/images/tests/test_admin_views.py b/wagtail/images/tests/test_admin_views.py index 88e17c437f11..fe0cba25d251 100644 --- a/wagtail/images/tests/test_admin_views.py +++ b/wagtail/images/tests/test_admin_views.py @@ -34,7 +34,7 @@ from .utils import Image, get_test_image_file, get_test_image_file_svg # Get the chars that Django considers safe to leave unescaped in a URL -urlquote_safechars = RFC3986_SUBDELIMS + str("/~:@") +urlquote_safechars = RFC3986_SUBDELIMS + "/~:@" class TestImageIndexView(WagtailTestUtils, TestCase): @@ -221,7 +221,7 @@ def test_edit_image_link_contains_next_url(self): edit_url = reverse("wagtailimages:edit", args=(image.id,)) next_url = urllib.parse.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_tags(self): image_two_tags = Image.objects.create( diff --git a/wagtail/images/tests/test_blocks.py b/wagtail/images/tests/test_blocks.py index 4ff765b80a85..ec246ba8792a 100644 --- a/wagtail/images/tests/test_blocks.py +++ b/wagtail/images/tests/test_blocks.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -* import os import unittest.mock @@ -44,7 +43,7 @@ def get_image_filename(self, image, filterspec): Get the generated filename for a resized image """ name, ext = os.path.splitext(os.path.basename(image.file.name)) - return "{}images/{}.{}{}".format(settings.MEDIA_URL, name, filterspec, ext) + return f"{settings.MEDIA_URL}images/{name}.{filterspec}{ext}" def test_render(self): block = ImageChooserBlock() diff --git a/wagtail/images/tests/test_bulk_actions/test_bulk_add_tags.py b/wagtail/images/tests/test_bulk_actions/test_bulk_add_tags.py index 8d3cb040011c..23517468c16f 100644 --- a/wagtail/images/tests/test_bulk_actions/test_bulk_add_tags.py +++ b/wagtail/images/tests/test_bulk_actions/test_bulk_add_tags.py @@ -55,9 +55,7 @@ def test_add_tags_with_limited_permissions(self): ) for image in self.images: - self.assertInHTML( - "
  • {image_title}
  • ".format(image_title=image.title), html - ) + self.assertInHTML(f"
  • {image.title}
  • ", html) self.client.post(self.url, self.post_data) diff --git a/wagtail/images/tests/test_bulk_actions/test_bulk_add_to_collection.py b/wagtail/images/tests/test_bulk_actions/test_bulk_add_to_collection.py index ff6331d409da..6cf4a5e98efc 100644 --- a/wagtail/images/tests/test_bulk_actions/test_bulk_add_to_collection.py +++ b/wagtail/images/tests/test_bulk_actions/test_bulk_add_to_collection.py @@ -53,9 +53,7 @@ def test_add_to_collection_with_limited_permissions(self): ) for image in self.images: - self.assertInHTML( - "
  • {image_title}
  • ".format(image_title=image.title), html - ) + self.assertInHTML(f"
  • {image.title}
  • ", html) self.client.post(self.url, self.post_data) diff --git a/wagtail/images/tests/test_bulk_actions/test_bulk_delete.py b/wagtail/images/tests/test_bulk_actions/test_bulk_delete.py index 39f6b313753b..b94c2d4bbbf6 100644 --- a/wagtail/images/tests/test_bulk_actions/test_bulk_delete.py +++ b/wagtail/images/tests/test_bulk_actions/test_bulk_delete.py @@ -51,9 +51,7 @@ def test_delete_with_limited_permissions(self): ) for image in self.images: - self.assertInHTML( - "
  • {image_title}
  • ".format(image_title=image.title), html - ) + self.assertInHTML(f"
  • {image.title}
  • ", html) response = self.client.post(self.url) # User should be redirected back to the index diff --git a/wagtail/images/tests/test_image_operations.py b/wagtail/images/tests/test_image_operations.py index 7dc7f34fe448..fa102158345e 100644 --- a/wagtail/images/tests/test_image_operations.py +++ b/wagtail/images/tests/test_image_operations.py @@ -96,7 +96,9 @@ def test_filter_spec_error(self): ) test_filter_spec_error.__name__ = str( - "test_filter_%s_raises_%s" % (filter_spec, InvalidFilterSpecError.__name__) + "test_filter_{}_raises_{}".format( + filter_spec, InvalidFilterSpecError.__name__ + ) ) return test_filter_spec_error diff --git a/wagtail/images/tests/test_jinja2.py b/wagtail/images/tests/test_jinja2.py index 351a542c9fde..1cf851a083ea 100644 --- a/wagtail/images/tests/test_jinja2.py +++ b/wagtail/images/tests/test_jinja2.py @@ -60,7 +60,7 @@ def get_image_filename(self, image, filterspec): Get the generated filename for a resized image """ name, ext = os.path.splitext(os.path.basename(image.file.name)) - return "{}images/{}.{}{}".format(settings.MEDIA_URL, name, filterspec, ext) + return f"{settings.MEDIA_URL}images/{name}.{filterspec}{ext}" def test_image(self): self.assertHTMLEqual( diff --git a/wagtail/images/tests/test_models.py b/wagtail/images/tests/test_models.py index 5428e34a6589..e5b1f9204c20 100644 --- a/wagtail/images/tests/test_models.py +++ b/wagtail/images/tests/test_models.py @@ -482,7 +482,7 @@ def test_full_url(self): ren_img = self.image.get_rendition("original") full_url = ren_img.full_url img_name = ren_img.file.name.split("/")[1] - self.assertEqual(full_url, "http://testserver/media/images/{}".format(img_name)) + self.assertEqual(full_url, f"http://testserver/media/images/{img_name}") @override_settings( CACHES={ diff --git a/wagtail/images/tests/test_shortcuts.py b/wagtail/images/tests/test_shortcuts.py index 08f4a9520b54..b6284775921f 100644 --- a/wagtail/images/tests/test_shortcuts.py +++ b/wagtail/images/tests/test_shortcuts.py @@ -1,4 +1,3 @@ -# coding=utf-8 from django.test import TestCase from wagtail.images.shortcuts import get_rendition_or_not_found diff --git a/wagtail/images/tests/test_signal_handlers.py b/wagtail/images/tests/test_signal_handlers.py index 41d3f9e8db3d..17232d497663 100644 --- a/wagtail/images/tests/test_signal_handlers.py +++ b/wagtail/images/tests/test_signal_handlers.py @@ -79,9 +79,7 @@ def setUp(self): def test_image_model(self): cls = get_image_model() - self.assertEqual( - "%s.%s" % (cls._meta.app_label, cls.__name__), "tests.CustomImage" - ) + self.assertEqual(f"{cls._meta.app_label}.{cls.__name__}", "tests.CustomImage") @override_settings(WAGTAILIMAGES_FEATURE_DETECTION_ENABLED=True) diff --git a/wagtail/images/utils.py b/wagtail/images/utils.py index 7a3294710692..ea88fa55bcf7 100644 --- a/wagtail/images/utils.py +++ b/wagtail/images/utils.py @@ -88,7 +88,7 @@ def generate_signature(image_id, filter_spec, key=None): # Based on libthumbor hmac generation # https://github.com/thumbor/libthumbor/blob/b19dc58cf84787e08c8e397ab322e86268bb4345/libthumbor/crypto.py#L50 - url = "{}/{}/".format(image_id, filter_spec) + url = f"{image_id}/{filter_spec}/" return force_str( base64.urlsafe_b64encode(hmac.new(key, url.encode(), hashlib.sha1).digest()) ) diff --git a/wagtail/images/views/serve.py b/wagtail/images/views/serve.py index 6e3d3b8f3f87..d76e57ce6daf 100644 --- a/wagtail/images/views/serve.py +++ b/wagtail/images/views/serve.py @@ -36,7 +36,7 @@ def as_view(cls, **initkwargs): "ServeView action must be either 'serve' or 'redirect'" ) - return super(ServeView, cls).as_view(**initkwargs) + return super().as_view(**initkwargs) @method_decorator(cache_control(max_age=3600, public=True)) def get(self, request, signature, image_id, filter_spec, filename=None): diff --git a/wagtail/management/commands/publish_scheduled.py b/wagtail/management/commands/publish_scheduled.py index 9b43053e8c0d..195f82a8442b 100644 --- a/wagtail/management/commands/publish_scheduled.py +++ b/wagtail/management/commands/publish_scheduled.py @@ -58,7 +58,7 @@ def handle(self, *args, **options): if queryset.model is Page: for obj in queryset: self.stdout.write( - "{0}\t{1}\t{2}\t{3}".format( + "{}\t{}\t{}\t{}".format( obj.expire_at.strftime("%Y-%m-%d %H:%M"), obj.specific_class.__name__, obj.slug, @@ -68,7 +68,7 @@ def handle(self, *args, **options): else: for obj in queryset: self.stdout.write( - "{0}\t{1}\t{2}\t\t{3}".format( + "{}\t{}\t{}\t\t{}".format( obj.expire_at.strftime("%Y-%m-%d %H:%M"), queryset.model.__name__, "", @@ -104,7 +104,7 @@ def handle(self, *args, **options): for er in expired_revs: rev_data = er.content self.stdout.write( - "{0}\t{1}\t{2}".format( + "{}\t{}\t{}".format( dateparse.parse_datetime( rev_data.get("expire_at") ).strftime("%Y-%m-%d %H:%M"), @@ -133,7 +133,7 @@ def handle(self, *args, **options): model = rp.content_type.model_class() rev_data = rp.content self.stdout.write( - "{0}\t{1}\t{2}\t\t{3}".format( + "{}\t{}\t{}\t\t{}".format( rp.approved_go_live_at.strftime("%Y-%m-%d %H:%M"), model.__name__, rev_data.get("slug", ""), diff --git a/wagtail/migrations/0001_initial.py b/wagtail/migrations/0001_initial.py index d99bbfb2aca7..f367f6f36489 100644 --- a/wagtail/migrations/0001_initial.py +++ b/wagtail/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.conf import settings from django.db import migrations, models diff --git a/wagtail/migrations/0001_squashed_0016_change_page_url_path_to_text_field.py b/wagtail/migrations/0001_squashed_0016_change_page_url_path_to_text_field.py index ac1d0b3426a8..d4949e78ecdb 100644 --- a/wagtail/migrations/0001_squashed_0016_change_page_url_path_to_text_field.py +++ b/wagtail/migrations/0001_squashed_0016_change_page_url_path_to_text_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import django.db.models.deletion from django.conf import settings from django.db import migrations, models diff --git a/wagtail/migrations/0002_initial_data.py b/wagtail/migrations/0002_initial_data.py index 7f61de91990a..19fa5622b251 100644 --- a/wagtail/migrations/0002_initial_data.py +++ b/wagtail/migrations/0002_initial_data.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/migrations/0003_add_uniqueness_constraint_on_group_page_permission.py b/wagtail/migrations/0003_add_uniqueness_constraint_on_group_page_permission.py index 0e116d415ebb..5297911c7b4d 100644 --- a/wagtail/migrations/0003_add_uniqueness_constraint_on_group_page_permission.py +++ b/wagtail/migrations/0003_add_uniqueness_constraint_on_group_page_permission.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0004_page_locked.py b/wagtail/migrations/0004_page_locked.py index 49c860ba3d59..588f426a5621 100644 --- a/wagtail/migrations/0004_page_locked.py +++ b/wagtail/migrations/0004_page_locked.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0005_add_page_lock_permission_to_moderators.py b/wagtail/migrations/0005_add_page_lock_permission_to_moderators.py index 9fe7bcadcfa3..148a1d4eb476 100644 --- a/wagtail/migrations/0005_add_page_lock_permission_to_moderators.py +++ b/wagtail/migrations/0005_add_page_lock_permission_to_moderators.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/migrations/0006_add_lock_page_permission.py b/wagtail/migrations/0006_add_lock_page_permission.py index f31519384c9e..75c495c9d726 100644 --- a/wagtail/migrations/0006_add_lock_page_permission.py +++ b/wagtail/migrations/0006_add_lock_page_permission.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0007_page_latest_revision_created_at.py b/wagtail/migrations/0007_page_latest_revision_created_at.py index 08f057bcc75f..c23e4f616f0d 100644 --- a/wagtail/migrations/0007_page_latest_revision_created_at.py +++ b/wagtail/migrations/0007_page_latest_revision_created_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0008_populate_latest_revision_created_at.py b/wagtail/migrations/0008_populate_latest_revision_created_at.py index c41180be1117..f497df47992c 100644 --- a/wagtail/migrations/0008_populate_latest_revision_created_at.py +++ b/wagtail/migrations/0008_populate_latest_revision_created_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/migrations/0009_remove_auto_now_add_from_pagerevision_created_at.py b/wagtail/migrations/0009_remove_auto_now_add_from_pagerevision_created_at.py index 795383a8f981..cc2dff488593 100644 --- a/wagtail/migrations/0009_remove_auto_now_add_from_pagerevision_created_at.py +++ b/wagtail/migrations/0009_remove_auto_now_add_from_pagerevision_created_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0010_change_page_owner_to_null_on_delete.py b/wagtail/migrations/0010_change_page_owner_to_null_on_delete.py index 68c5f6d46287..c96f73e75d85 100644 --- a/wagtail/migrations/0010_change_page_owner_to_null_on_delete.py +++ b/wagtail/migrations/0010_change_page_owner_to_null_on_delete.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import django.db.models.deletion from django.conf import settings from django.db import migrations, models diff --git a/wagtail/migrations/0011_page_first_published_at.py b/wagtail/migrations/0011_page_first_published_at.py index 5efff8832aa4..c4b37a7bc2df 100644 --- a/wagtail/migrations/0011_page_first_published_at.py +++ b/wagtail/migrations/0011_page_first_published_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0012_extend_page_slug_field.py b/wagtail/migrations/0012_extend_page_slug_field.py index e8fd370466ec..959981b541e6 100644 --- a/wagtail/migrations/0012_extend_page_slug_field.py +++ b/wagtail/migrations/0012_extend_page_slug_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0013_update_golive_expire_help_text.py b/wagtail/migrations/0013_update_golive_expire_help_text.py index 782edf9a4b18..aad3ea6fc178 100644 --- a/wagtail/migrations/0013_update_golive_expire_help_text.py +++ b/wagtail/migrations/0013_update_golive_expire_help_text.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0014_add_verbose_name.py b/wagtail/migrations/0014_add_verbose_name.py index d82770a77ca2..15d30619801f 100644 --- a/wagtail/migrations/0014_add_verbose_name.py +++ b/wagtail/migrations/0014_add_verbose_name.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0015_add_more_verbose_names.py b/wagtail/migrations/0015_add_more_verbose_names.py index 7d2a31497fd2..3adecc3ecd91 100644 --- a/wagtail/migrations/0015_add_more_verbose_names.py +++ b/wagtail/migrations/0015_add_more_verbose_names.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import django.db.models.deletion from django.conf import settings from django.db import migrations, models diff --git a/wagtail/migrations/0016_change_page_url_path_to_text_field.py b/wagtail/migrations/0016_change_page_url_path_to_text_field.py index 497897b0eb9c..c76e6e32b13e 100644 --- a/wagtail/migrations/0016_change_page_url_path_to_text_field.py +++ b/wagtail/migrations/0016_change_page_url_path_to_text_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0017_change_edit_page_permission_description.py b/wagtail/migrations/0017_change_edit_page_permission_description.py index 2f12e241eaf9..36a6275dc3c1 100644 --- a/wagtail/migrations/0017_change_edit_page_permission_description.py +++ b/wagtail/migrations/0017_change_edit_page_permission_description.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0018_pagerevision_submitted_for_moderation_index.py b/wagtail/migrations/0018_pagerevision_submitted_for_moderation_index.py index 1f9e345e93c6..af68c9b0f503 100644 --- a/wagtail/migrations/0018_pagerevision_submitted_for_moderation_index.py +++ b/wagtail/migrations/0018_pagerevision_submitted_for_moderation_index.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0019_verbose_names_cleanup.py b/wagtail/migrations/0019_verbose_names_cleanup.py index bc1fc1f1cbb8..aa9115f11f0e 100644 --- a/wagtail/migrations/0019_verbose_names_cleanup.py +++ b/wagtail/migrations/0019_verbose_names_cleanup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/migrations/0020_add_index_on_page_first_published_at.py b/wagtail/migrations/0020_add_index_on_page_first_published_at.py index 3aca28ae4737..0b160267c714 100644 --- a/wagtail/migrations/0020_add_index_on_page_first_published_at.py +++ b/wagtail/migrations/0020_add_index_on_page_first_published_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0021_capitalizeverbose.py b/wagtail/migrations/0021_capitalizeverbose.py index ab3de9541de7..f19aadbbf7f9 100644 --- a/wagtail/migrations/0021_capitalizeverbose.py +++ b/wagtail/migrations/0021_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import django.db.models.deletion from django.conf import settings from django.db import migrations, models diff --git a/wagtail/migrations/0022_add_site_name.py b/wagtail/migrations/0022_add_site_name.py index 6d265d0b2857..3d1631e95885 100644 --- a/wagtail/migrations/0022_add_site_name.py +++ b/wagtail/migrations/0022_add_site_name.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0023_alter_page_revision_on_delete_behaviour.py b/wagtail/migrations/0023_alter_page_revision_on_delete_behaviour.py index eedd4b7dd3fd..1baa869f95b8 100644 --- a/wagtail/migrations/0023_alter_page_revision_on_delete_behaviour.py +++ b/wagtail/migrations/0023_alter_page_revision_on_delete_behaviour.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import django.db.models.deletion from django.conf import settings from django.db import migrations, models diff --git a/wagtail/migrations/0024_alter_page_content_type_on_delete_behaviour.py b/wagtail/migrations/0024_alter_page_content_type_on_delete_behaviour.py index 4a9f7f479ba0..9c18fc43ea79 100644 --- a/wagtail/migrations/0024_alter_page_content_type_on_delete_behaviour.py +++ b/wagtail/migrations/0024_alter_page_content_type_on_delete_behaviour.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9 on 2015-12-22 09:34 from django.db import migrations, models diff --git a/wagtail/migrations/0024_collection.py b/wagtail/migrations/0024_collection.py index 620120214e64..a0ab6ac67a70 100644 --- a/wagtail/migrations/0024_collection.py +++ b/wagtail/migrations/0024_collection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0025_collection_initial_data.py b/wagtail/migrations/0025_collection_initial_data.py index 61b82bd7341d..45adff6d254f 100644 --- a/wagtail/migrations/0025_collection_initial_data.py +++ b/wagtail/migrations/0025_collection_initial_data.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/migrations/0026_group_collection_permission.py b/wagtail/migrations/0026_group_collection_permission.py index 2f9b2b0b61d6..20fef8c6d4eb 100644 --- a/wagtail/migrations/0026_group_collection_permission.py +++ b/wagtail/migrations/0026_group_collection_permission.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/migrations/0027_fix_collection_path_collation.py b/wagtail/migrations/0027_fix_collection_path_collation.py index d657ad6eb1cd..a06aaa6a883e 100644 --- a/wagtail/migrations/0027_fix_collection_path_collation.py +++ b/wagtail/migrations/0027_fix_collection_path_collation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/migrations/0028_merge.py b/wagtail/migrations/0028_merge.py index 1fe5dde40fba..887781d80179 100644 --- a/wagtail/migrations/0028_merge.py +++ b/wagtail/migrations/0028_merge.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.1 on 2016-02-03 13:50 from django.db import migrations diff --git a/wagtail/migrations/0029_unicode_slugfield_dj19.py b/wagtail/migrations/0029_unicode_slugfield_dj19.py index df509576b00a..3e1590e1dba9 100644 --- a/wagtail/migrations/0029_unicode_slugfield_dj19.py +++ b/wagtail/migrations/0029_unicode_slugfield_dj19.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.4 on 2016-04-27 22:39 from django.db import migrations, models diff --git a/wagtail/migrations/0030_index_on_pagerevision_created_at.py b/wagtail/migrations/0030_index_on_pagerevision_created_at.py index 33c6f50981a5..379f7c4efe02 100644 --- a/wagtail/migrations/0030_index_on_pagerevision_created_at.py +++ b/wagtail/migrations/0030_index_on_pagerevision_created_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import models, migrations diff --git a/wagtail/migrations/0031_add_page_view_restriction_types.py b/wagtail/migrations/0031_add_page_view_restriction_types.py index bb273857ec0f..3173667e7b1c 100644 --- a/wagtail/migrations/0031_add_page_view_restriction_types.py +++ b/wagtail/migrations/0031_add_page_view_restriction_types.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.2 on 2016-10-07 15:33 from django.db import migrations, models diff --git a/wagtail/migrations/0032_add_bulk_delete_page_permission.py b/wagtail/migrations/0032_add_bulk_delete_page_permission.py index 0a59e9cf3d4d..ac4ea56d16b4 100644 --- a/wagtail/migrations/0032_add_bulk_delete_page_permission.py +++ b/wagtail/migrations/0032_add_bulk_delete_page_permission.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.1 on 2016-09-27 14:11 from django.db import migrations, models diff --git a/wagtail/migrations/0033_remove_golive_expiry_help_text.py b/wagtail/migrations/0033_remove_golive_expiry_help_text.py index fb5fd1913e23..2f0bac630b2f 100644 --- a/wagtail/migrations/0033_remove_golive_expiry_help_text.py +++ b/wagtail/migrations/0033_remove_golive_expiry_help_text.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.6 on 2017-03-31 14:33 from django.db import migrations, models diff --git a/wagtail/migrations/0034_page_live_revision.py b/wagtail/migrations/0034_page_live_revision.py index 41c06b205e4d..f2e348baadd4 100644 --- a/wagtail/migrations/0034_page_live_revision.py +++ b/wagtail/migrations/0034_page_live_revision.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.4 on 2017-01-26 21:32 from django.db import migrations, models import django.db.models.deletion diff --git a/wagtail/migrations/0035_page_last_published_at.py b/wagtail/migrations/0035_page_last_published_at.py index 66ce93e2ba82..394aa27f9e8f 100644 --- a/wagtail/migrations/0035_page_last_published_at.py +++ b/wagtail/migrations/0035_page_last_published_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.1 on 2017-05-22 13:35 from django.db import migrations, models diff --git a/wagtail/migrations/0036_populate_page_last_published_at.py b/wagtail/migrations/0036_populate_page_last_published_at.py index 75f960119dc1..51e50d1fbdd4 100644 --- a/wagtail/migrations/0036_populate_page_last_published_at.py +++ b/wagtail/migrations/0036_populate_page_last_published_at.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.1 on 2017-06-01 11:03 from django.db import migrations from django.db.models import F diff --git a/wagtail/migrations/0037_set_page_owner_editable.py b/wagtail/migrations/0037_set_page_owner_editable.py index 72295a190190..31762614a4df 100644 --- a/wagtail/migrations/0037_set_page_owner_editable.py +++ b/wagtail/migrations/0037_set_page_owner_editable.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.7 on 2017-05-03 12:05 from django.conf import settings from django.db import migrations, models diff --git a/wagtail/migrations/0038_make_first_published_at_editable.py b/wagtail/migrations/0038_make_first_published_at_editable.py index 034d9e9e68c4..ede2a4a6932e 100644 --- a/wagtail/migrations/0038_make_first_published_at_editable.py +++ b/wagtail/migrations/0038_make_first_published_at_editable.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.6 on 2017-03-24 09:12 from django.db import migrations, models diff --git a/wagtail/migrations/0039_collectionviewrestriction.py b/wagtail/migrations/0039_collectionviewrestriction.py index 3e48e4b47120..95d79cf2636e 100644 --- a/wagtail/migrations/0039_collectionviewrestriction.py +++ b/wagtail/migrations/0039_collectionviewrestriction.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.4 on 2016-12-19 15:32 from django.db import migrations, models import django.db.models.deletion diff --git a/wagtail/migrations/0040_page_draft_title.py b/wagtail/migrations/0040_page_draft_title.py index d3bc4b91d510..c3d9da80e4c0 100644 --- a/wagtail/migrations/0040_page_draft_title.py +++ b/wagtail/migrations/0040_page_draft_title.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.2 on 2017-01-20 15:34 from django.db import migrations, models from django.db.models import F diff --git a/wagtail/migrations/0048_add_default_workflows.py b/wagtail/migrations/0048_add_default_workflows.py index 113043c13522..dbb176fedf41 100644 --- a/wagtail/migrations/0048_add_default_workflows.py +++ b/wagtail/migrations/0048_add_default_workflows.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations from django.db.models import Count, Q from wagtail.models import Page as RealPage diff --git a/wagtail/migrations/0066_collection_management_permissions.py b/wagtail/migrations/0066_collection_management_permissions.py index 4e898f873717..558962d6bca9 100644 --- a/wagtail/migrations/0066_collection_management_permissions.py +++ b/wagtail/migrations/0066_collection_management_permissions.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/models/__init__.py b/wagtail/models/__init__.py index eb4fd133d876..04018ce4c45e 100644 --- a/wagtail/models/__init__.py +++ b/wagtail/models/__init__.py @@ -220,11 +220,11 @@ class PageBase(models.base.ModelBase): """Metaclass for Page""" def __init__(cls, name, bases, dct): - super(PageBase, cls).__init__(name, bases, dct) + super().__init__(name, bases, dct) if "template" not in dct: # Define a default template path derived from the app name and model name - cls.template = "%s/%s.html" % ( + cls.template = "{}/{}.html".format( cls._meta.app_label, camelcase_to_underscore(name), ) @@ -704,7 +704,7 @@ def _get_dummy_headers(self, original_request=None): http_host = hostname if port != (443 if scheme == "https" else 80): - http_host = "%s:%s" % (http_host, port) + http_host = f"{http_host}:{port}" dummy_values = { "REQUEST_METHOD": "GET", "PATH_INFO": path, @@ -1498,7 +1498,7 @@ def delete(self, *args, **kwargs): @classmethod def check(cls, **kwargs): - errors = super(Page, cls).check(**kwargs) + errors = super().check(**kwargs) # Check that foreign keys from pages are not configured to cascade # This is the default Django behaviour which must be explicitly overridden @@ -2118,7 +2118,7 @@ def get_site(self): @classmethod def get_indexed_objects(cls): content_type = ContentType.objects.get_for_model(cls) - return super(Page, cls).get_indexed_objects().filter(content_type=content_type) + return super().get_indexed_objects().filter(content_type=content_type) def get_indexed_instance(self): # This is accessed on save by the wagtailsearch signal handler, and in edge @@ -4548,7 +4548,7 @@ def log_state_change_action(self, user, action): next_task_data = {"id": next_task.id, "title": next_task.name} log( instance=obj, - action="wagtail.workflow.{}".format(action), + action=f"wagtail.workflow.{action}", user=user, data={ "workflow": { @@ -4707,7 +4707,7 @@ class Meta: verbose_name_plural = _("comments") def __str__(self): - return "Comment on Page '{0}', left by {1}: '{2}'".format( + return "Comment on Page '{}', left by {}: '{}'".format( self.page, self.user, self.text ) @@ -4779,7 +4779,7 @@ class Meta: verbose_name_plural = _("comment replies") def __str__(self): - return "CommentReply left by '{0}': '{1}'".format(self.user, self.text) + return f"CommentReply left by '{self.user}': '{self.text}'" def _log(self, action, page_revision=None, user=None): log( diff --git a/wagtail/models/i18n.py b/wagtail/models/i18n.py index b90033cbeff5..2931656c61b8 100644 --- a/wagtail/models/i18n.py +++ b/wagtail/models/i18n.py @@ -187,7 +187,7 @@ class Meta: @classmethod def check(cls, **kwargs): - errors = super(TranslatableMixin, cls).check(**kwargs) + errors = super().check(**kwargs) is_translation_model = cls.get_translation_model() is cls # Raise error if subclass has removed the unique_together constraint @@ -199,7 +199,7 @@ def check(cls, **kwargs): ): errors.append( checks.Error( - "{0}.{1} is missing a unique_together constraint for the translation key and locale fields".format( + "{}.{} is missing a unique_together constraint for the translation key and locale fields".format( cls._meta.app_label, cls.__name__ ), hint="Add ('translation_key', 'locale') to {}.Meta.unique_together".format( diff --git a/wagtail/models/sites.py b/wagtail/models/sites.py index d7e9e149480b..0643d88a05d3 100644 --- a/wagtail/models/sites.py +++ b/wagtail/models/sites.py @@ -63,7 +63,7 @@ def get_site_for_hostname(hostname, port): class SiteManager(models.Manager): def get_queryset(self): - return super(SiteManager, self).get_queryset().order_by(Lower("hostname")) + return super().get_queryset().order_by(Lower("hostname")) def get_by_natural_key(self, hostname, port): return self.get(hostname=hostname, port=port) diff --git a/wagtail/permission_policies/base.py b/wagtail/permission_policies/base.py index d4dd68055e58..deb349357b60 100644 --- a/wagtail/permission_policies/base.py +++ b/wagtail/permission_policies/base.py @@ -243,7 +243,7 @@ def _get_permission_name(self, action): Get the full app-label-qualified permission name (as required by user.has_perm(...) ) for the given action on this model """ - return "%s.%s" % ( + return "{}.{}".format( self.app_label, get_permission_codename(action, self.model._meta), ) diff --git a/wagtail/project_template/home/migrations/0001_initial.py b/wagtail/project_template/home/migrations/0001_initial.py index 77b74b9f8df4..67f201d32d87 100644 --- a/wagtail/project_template/home/migrations/0001_initial.py +++ b/wagtail/project_template/home/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/project_template/home/migrations/0002_create_homepage.py b/wagtail/project_template/home/migrations/0002_create_homepage.py index ca328faa5fb2..e84576f42d9a 100644 --- a/wagtail/project_template/home/migrations/0002_create_homepage.py +++ b/wagtail/project_template/home/migrations/0002_create_homepage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/search/backends/__init__.py b/wagtail/search/backends/__init__.py index cb82a91f4061..7aeaeac3c316 100644 --- a/wagtail/search/backends/__init__.py +++ b/wagtail/search/backends/__init__.py @@ -62,9 +62,7 @@ def get_search_backend(backend="default", **kwargs): # Trying to import the given backend, in case it's a dotted path import_backend(backend) except ImportError as e: - raise InvalidSearchBackendError( - "Could not find backend '%s': %s" % (backend, e) - ) + raise InvalidSearchBackendError(f"Could not find backend '{backend}': {e}") params = kwargs else: # Backend is a conf entry @@ -76,9 +74,7 @@ def get_search_backend(backend="default", **kwargs): try: backend_cls = import_backend(backend) except ImportError as e: - raise InvalidSearchBackendError( - "Could not find backend '%s': %s" % (backend, e) - ) + raise InvalidSearchBackendError(f"Could not find backend '{backend}': {e}") # Create backend return backend_cls(params) diff --git a/wagtail/search/backends/base.py b/wagtail/search/backends/base.py index 99eec0d64dc6..8ce5cd74a3e1 100644 --- a/wagtail/search/backends/base.py +++ b/wagtail/search/backends/base.py @@ -18,7 +18,7 @@ class FilterError(Exception): class FieldError(Exception): def __init__(self, *args, field_name=None, **kwargs): self.field_name = field_name - super(FieldError, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class SearchFieldError(FieldError): diff --git a/wagtail/search/backends/database/mysql/mysql.py b/wagtail/search/backends/database/mysql/mysql.py index d3db74cbd30e..ca8dbefa4fbb 100644 --- a/wagtail/search/backends/database/mysql/mysql.py +++ b/wagtail/search/backends/database/mysql/mysql.py @@ -107,7 +107,7 @@ def title(self): isinstance(current_field, SearchField) and current_field.field_name == "title" ): - texts.append((value)) + texts.append(value) return " ".join(texts) @@ -123,7 +123,7 @@ def body(self): isinstance(current_field, SearchField) and not current_field.field_name == "title" ): - texts.append((value)) + texts.append(value) return " ".join(texts) @@ -136,7 +136,7 @@ def autocomplete(self): for field in self.search_fields: for current_field, value in self.prepare_field(self.obj, field): if isinstance(current_field, AutocompleteField): - texts.append((value)) + texts.append(value) return " ".join(texts) diff --git a/wagtail/search/backends/database/mysql/query.py b/wagtail/search/backends/database/mysql/query.py index 803e3b3b4e06..13c5784b01ff 100644 --- a/wagtail/search/backends/database/mysql/query.py +++ b/wagtail/search/backends/database/mysql/query.py @@ -62,11 +62,11 @@ def as_sql(self, compiler, connection): template = "%s" if self.prefix: - param = "{}*".format(param) + param = f"{param}*" if self.invert: - param = "(-{})".format(param) + param = f"(-{param})" else: - param = "{}".format(param) + param = f"{param}" return template, [param] @@ -246,7 +246,7 @@ def as_sql(self, compiler, connection): compiled_query[1] ) # Substitute the params in the query column_list = ", ".join( - ["`{}`".format(column) for column in self.columns] + [f"`{column}`" for column in self.columns] ) # ['title', 'body'] becomes '`title`, `body`' params = [formatted_query] return (self.template % (column_list, "%s"), params) diff --git a/wagtail/search/backends/database/postgres/postgres.py b/wagtail/search/backends/database/postgres/postgres.py index dfe4b3d22c2a..8b0e3ffa9a15 100644 --- a/wagtail/search/backends/database/postgres/postgres.py +++ b/wagtail/search/backends/database/postgres/postgres.py @@ -273,7 +273,7 @@ def add_items_upsert(self, content_type_pk, indexers): data_sql = ", ".join( [ - "(%%s, %%s, %s, %s, %s, 1.0)" % (a, b, c) + f"(%s, %s, {a}, {b}, {c}, 1.0)" for a, b, c in zip(title_sql, autocomplete_sql, body_sql) ] ) diff --git a/wagtail/search/backends/database/postgres/query.py b/wagtail/search/backends/database/postgres/query.py index 71476766618c..67c63746f0d7 100644 --- a/wagtail/search/backends/database/postgres/query.py +++ b/wagtail/search/backends/database/postgres/query.py @@ -55,9 +55,9 @@ def as_sql(self, compiler, connection): label += self.weight if label: - param = "{}:{}".format(param, label) + param = f"{param}:{label}" if self.invert: - param = "!{}".format(param) + param = f"!{param}" return template, [param] @@ -79,6 +79,6 @@ def as_sql(self, compiler, connection): rsql, params = compiler.compile(self.rhs) value_params.extend(params) - combined_sql = "({} {} {})".format(lsql, self.connector, rsql) + combined_sql = f"({lsql} {self.connector} {rsql})" combined_value = combined_sql % tuple(value_params) return "%s", [combined_value] diff --git a/wagtail/search/backends/database/sqlite/query.py b/wagtail/search/backends/database/sqlite/query.py index c930b919c772..ee2b1d1121b3 100644 --- a/wagtail/search/backends/database/sqlite/query.py +++ b/wagtail/search/backends/database/sqlite/query.py @@ -98,7 +98,7 @@ def as_sql(self, compiler, connection): rsql, params = compiler.compile(self.rhs) value_params.extend(params) - combined_sql = "{} {} {}".format(lsql, self.connector, rsql) + combined_sql = f"{lsql} {self.connector} {rsql}" combined_value = combined_sql % tuple(value_params) return "%s", [combined_value] @@ -194,7 +194,7 @@ def as_sql(self, compiler, connection): return (self.template, params) def __repr__(self): - return "" % (self.columns, self.query) + return f"" class AndNot(SearchQuery): @@ -209,7 +209,7 @@ def __init__(self, subquery_a: SearchQuery, subquery_b: SearchQuery): self.subquery_b = subquery_b def __repr__(self): - return "<{} AndNot {}>".format(repr(self.subquery_a), repr(self.subquery_b)) + return f"<{repr(self.subquery_a)} AndNot {repr(self.subquery_b)}>" def normalize(search_query: SearchQuery) -> Tuple[SearchQuery]: diff --git a/wagtail/search/backends/database/sqlite/sqlite.py b/wagtail/search/backends/database/sqlite/sqlite.py index c130d8cdc942..c5d0d1c2095a 100644 --- a/wagtail/search/backends/database/sqlite/sqlite.py +++ b/wagtail/search/backends/database/sqlite/sqlite.py @@ -101,7 +101,7 @@ def title(self): isinstance(current_field, SearchField) and current_field.field_name == "title" ): - texts.append((value)) + texts.append(value) return " ".join(texts) @@ -117,7 +117,7 @@ def body(self): isinstance(current_field, SearchField) and not current_field.field_name == "title" ): - texts.append((value)) + texts.append(value) return " ".join(texts) @@ -130,7 +130,7 @@ def autocomplete(self): for field in self.search_fields: for current_field, value in self.prepare_field(self.obj, field): if isinstance(current_field, AutocompleteField): - texts.append((value)) + texts.append(value) return " ".join(texts) diff --git a/wagtail/search/backends/elasticsearch5.py b/wagtail/search/backends/elasticsearch5.py index 03f33f1d3eda..1905b49cdc6c 100644 --- a/wagtail/search/backends/elasticsearch5.py +++ b/wagtail/search/backends/elasticsearch5.py @@ -303,7 +303,7 @@ def get_document(self, obj): return doc def __repr__(self): - return "" % (self.model.__name__,) + return f"" class Elasticsearch5SearchQueryCompiler(BaseSearchQueryCompiler): @@ -311,7 +311,7 @@ class Elasticsearch5SearchQueryCompiler(BaseSearchQueryCompiler): DEFAULT_OPERATOR = "or" def __init__(self, *args, **kwargs): - super(Elasticsearch5SearchQueryCompiler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.mapping = self.mapping_class(self.queryset.model) # Convert field names into index column names @@ -1085,7 +1085,7 @@ class Elasticsearch5SearchBackend(BaseSearchBackend): } def __init__(self, params): - super(Elasticsearch5SearchBackend, self).__init__(params) + super().__init__(params) # Get settings self.hosts = params.pop("HOSTS", None) diff --git a/wagtail/search/index.py b/wagtail/search/index.py index c1efd7ba1c65..23a819aa8a82 100644 --- a/wagtail/search/index.py +++ b/wagtail/search/index.py @@ -104,7 +104,7 @@ def _has_field(cls, name): @classmethod def check(cls, **kwargs): - errors = super(Indexed, cls).check(**kwargs) + errors = super().check(**kwargs) errors.extend(cls._check_search_fields(**kwargs)) return errors @@ -291,7 +291,7 @@ def get_value(self, obj): return value def __repr__(self): - return "<%s: %s>" % (self.__class__.__name__, self.field_name) + return f"<{self.__class__.__name__}: {self.field_name}>" class SearchField(BaseField): diff --git a/wagtail/search/migrations/0001_initial.py b/wagtail/search/migrations/0001_initial.py index 57fc90eb18dc..6f818b5765f2 100644 --- a/wagtail/search/migrations/0001_initial.py +++ b/wagtail/search/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/search/migrations/0002_add_verbose_names.py b/wagtail/search/migrations/0002_add_verbose_names.py index 61e32e4268de..851105f19ba8 100644 --- a/wagtail/search/migrations/0002_add_verbose_names.py +++ b/wagtail/search/migrations/0002_add_verbose_names.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/search/migrations/0003_remove_editors_pick.py b/wagtail/search/migrations/0003_remove_editors_pick.py index fae29dc8f4d8..80e07910988f 100644 --- a/wagtail/search/migrations/0003_remove_editors_pick.py +++ b/wagtail/search/migrations/0003_remove_editors_pick.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/search/models.py b/wagtail/search/models.py index 315cf4d7e152..be15b5305797 100644 --- a/wagtail/search/models.py +++ b/wagtail/search/models.py @@ -176,7 +176,7 @@ class Meta: abstract = True def __str__(self): - return "%s: %s" % (self.content_type.name, self.content_object) + return f"{self.content_type.name}: {self.content_object}" @property def model(self): diff --git a/wagtail/search/query.py b/wagtail/search/query.py index 9deba3b7d33a..7debea763184 100644 --- a/wagtail/search/query.py +++ b/wagtail/search/query.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - # # Base classes # @@ -48,7 +46,7 @@ def __init__(self, query_string: str): self.query_string = query_string def __repr__(self): - return "".format(repr(self.query_string)) + return f"" class Fuzzy(SearchQuery): @@ -56,7 +54,7 @@ def __init__(self, query_string: str): self.query_string = query_string def __repr__(self): - return "".format(repr(self.query_string)) + return f"" class MatchAll(SearchQuery): @@ -70,7 +68,7 @@ def __init__(self, subquery: SearchQuery, boost: float): self.boost = boost def __repr__(self): - return "".format(repr(self.subquery), repr(self.boost)) + return f"" # @@ -103,7 +101,7 @@ def __init__(self, subquery: SearchQuery): self.subquery = subquery def __repr__(self): - return "".format(repr(self.subquery)) + return f"" MATCH_ALL = MatchAll() diff --git a/wagtail/search/tests/elasticsearch_common_tests.py b/wagtail/search/tests/elasticsearch_common_tests.py index e9d7877c6849..1927a6e2df5f 100644 --- a/wagtail/search/tests/elasticsearch_common_tests.py +++ b/wagtail/search/tests/elasticsearch_common_tests.py @@ -149,7 +149,7 @@ def test_more_than_one_hundred_results(self): for i in range(150): books.append( models.Book.objects.create( - title="Book {}".format(i), + title=f"Book {i}", publication_date=date(2017, 10, 21), number_of_pages=i, ) @@ -167,7 +167,7 @@ def test_slice_more_than_one_hundred_results(self): for i in range(150): books.append( models.Book.objects.create( - title="Book {}".format(i), + title=f"Book {i}", publication_date=date(2017, 10, 21), number_of_pages=i, ) @@ -187,7 +187,7 @@ def test_slice_to_next_page(self): for i in range(150): books.append( models.Book.objects.create( - title="Book {}".format(i), + title=f"Book {i}", publication_date=date(2017, 10, 21), number_of_pages=i, ) diff --git a/wagtail/search/tests/test_backends.py b/wagtail/search/tests/test_backends.py index 126721cd64b6..8d9c38e794b1 100644 --- a/wagtail/search/tests/test_backends.py +++ b/wagtail/search/tests/test_backends.py @@ -1,4 +1,3 @@ -# coding: utf-8 import unittest from collections import OrderedDict from datetime import date diff --git a/wagtail/search/tests/test_elasticsearch5_backend.py b/wagtail/search/tests/test_elasticsearch5_backend.py index d2d9207fbca9..7fc8e56f421c 100644 --- a/wagtail/search/tests/test_elasticsearch5_backend.py +++ b/wagtail/search/tests/test_elasticsearch5_backend.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import datetime import json from unittest import mock diff --git a/wagtail/search/tests/test_elasticsearch6_backend.py b/wagtail/search/tests/test_elasticsearch6_backend.py index f871a0246ac3..f4f339c23298 100644 --- a/wagtail/search/tests/test_elasticsearch6_backend.py +++ b/wagtail/search/tests/test_elasticsearch6_backend.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import datetime import json from unittest import mock diff --git a/wagtail/search/tests/test_elasticsearch7_backend.py b/wagtail/search/tests/test_elasticsearch7_backend.py index 505baca7076d..e548dcd97ec2 100644 --- a/wagtail/search/tests/test_elasticsearch7_backend.py +++ b/wagtail/search/tests/test_elasticsearch7_backend.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import datetime import json from unittest import mock diff --git a/wagtail/search/tests/test_indexed_class.py b/wagtail/search/tests/test_indexed_class.py index ab9a81ad517f..697601ac89bb 100644 --- a/wagtail/search/tests/test_indexed_class.py +++ b/wagtail/search/tests/test_indexed_class.py @@ -37,9 +37,7 @@ def test_qualified_content_type_name(self): class TestSearchFields(TestCase): def make_dummy_type(self, search_fields): - return type( - str("DummyType"), (index.Indexed,), {"search_fields": search_fields} - ) + return type("DummyType", (index.Indexed,), {"search_fields": search_fields}) def get_checks_result(warning_id=None): """Run Django checks on any with the 'search' tag used when registering the check""" diff --git a/wagtail/search/tests/test_page_search.py b/wagtail/search/tests/test_page_search.py index 694ce77633ec..5e279b9f6ceb 100644 --- a/wagtail/search/tests/test_page_search.py +++ b/wagtail/search/tests/test_page_search.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - from django.conf import settings from django.test import TestCase diff --git a/wagtail/search/tests/test_queries.py b/wagtail/search/tests/test_queries.py index a917193d718e..af36737ce050 100644 --- a/wagtail/search/tests/test_queries.py +++ b/wagtail/search/tests/test_queries.py @@ -124,14 +124,14 @@ def test_garbage_collect_command(self): # should be deleted by the search_garbage_collect command. querie_ids_to_be_deleted = [] for i in range(10): - q = models.Query.get("Hello {}".format(i)) + q = models.Query.get(f"Hello {i}") q.add_hit(date=old_hit_date) querie_ids_to_be_deleted.append(q.id) # Add 10 hits that are less than one week old. These ones should not be deleted. recent_querie_ids = [] for i in range(10): - q = models.Query.get("World {}".format(i)) + q = models.Query.get(f"World {i}") q.add_hit(date=recent_hit_date) recent_querie_ids.append(q.id) @@ -460,7 +460,7 @@ def __init__(self, a, b): self.b = b def __repr__(self): - return "(%s %s)" % (self.a, self.b) + return f"({self.a} {self.b})" self.assertEqual( repr( diff --git a/wagtail/search/utils.py b/wagtail/search/utils.py index 0e1f9f4fcea7..23ddce5bc58c 100644 --- a/wagtail/search/utils.py +++ b/wagtail/search/utils.py @@ -201,8 +201,7 @@ def get_search_fields(search_fields): if isinstance(search_field, SearchField): yield search_field elif isinstance(search_field, RelatedFields): - for sub_field in get_search_fields(search_field.fields): - yield sub_field + yield from get_search_fields(search_field.fields) def get_postgresql_connections(): diff --git a/wagtail/snippets/permissions.py b/wagtail/snippets/permissions.py index 230030fa831c..1bf6cfba58bb 100644 --- a/wagtail/snippets/permissions.py +++ b/wagtail/snippets/permissions.py @@ -4,7 +4,7 @@ def get_permission_name(action, model): - return "%s.%s" % ( + return "{}.{}".format( model._meta.app_label, get_permission_codename(action, model._meta), ) diff --git a/wagtail/snippets/tests/test_snippets.py b/wagtail/snippets/tests/test_snippets.py index c527a3d1ba6b..45040f897977 100644 --- a/wagtail/snippets/tests/test_snippets.py +++ b/wagtail/snippets/tests/test_snippets.py @@ -4882,7 +4882,7 @@ class TestSnippetViewWithCustomPrimaryKey(WagtailTestUtils, TestCase): fixtures = ["test.json"] def setUp(self): - super(TestSnippetViewWithCustomPrimaryKey, self).setUp() + super().setUp() self.login() self.snippet_a = StandardSnippetWithCustomPrimaryKey.objects.create( snippet_id="snippet/01", text="Hello" diff --git a/wagtail/templatetags/wagtailcore_tags.py b/wagtail/templatetags/wagtailcore_tags.py index ee0630b1228c..2deb0a3f8bea 100644 --- a/wagtail/templatetags/wagtailcore_tags.py +++ b/wagtail/templatetags/wagtailcore_tags.py @@ -188,7 +188,7 @@ def include_block(parser, token): if tokens: raise template.TemplateSyntaxError( - "Unexpected argument to %r tag: %r" % (tag_name, tokens[0]) + f"Unexpected argument to {tag_name!r} tag: {tokens[0]!r}" ) return IncludeBlockNode(block_var, extra_context, use_parent_context) diff --git a/wagtail/test/benchmark.py b/wagtail/test/benchmark.py index f1093eda0544..5ef5e52de85f 100644 --- a/wagtail/test/benchmark.py +++ b/wagtail/test/benchmark.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - import time import tracemalloc diff --git a/wagtail/test/customuser/fields.py b/wagtail/test/customuser/fields.py index 8b50a9b3c964..073bfdc6bf11 100644 --- a/wagtail/test/customuser/fields.py +++ b/wagtail/test/customuser/fields.py @@ -18,13 +18,13 @@ def __new__(cls, value): db_value = value display_value = value + SHIFT - self = super(ConvertedValue, cls).__new__(cls, display_value) + self = super().__new__(cls, display_value) self.db_value = db_value return self def __repr__(self): - return "<%s: %s>" % (self.__class__.__name__, self.db_value) + return f"<{self.__class__.__name__}: {self.db_value}>" def __eq__(self, other): if isinstance(other, self.__class__): diff --git a/wagtail/test/customuser/migrations/0001_initial.py b/wagtail/test/customuser/migrations/0001_initial.py index 842c13cfe510..5330c94839e8 100644 --- a/wagtail/test/customuser/migrations/0001_initial.py +++ b/wagtail/test/customuser/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models from ..fields import ConvertedValueField diff --git a/wagtail/test/customuser/migrations/0002_added_file_field.py b/wagtail/test/customuser/migrations/0002_added_file_field.py index e8245518cebf..0f4e76ef5689 100644 --- a/wagtail/test/customuser/migrations/0002_added_file_field.py +++ b/wagtail/test/customuser/migrations/0002_added_file_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/test/demosite/migrations/0001_initial.py b/wagtail/test/demosite/migrations/0001_initial.py index def19854976c..2e1ea4c9223f 100644 --- a/wagtail/test/demosite/migrations/0001_initial.py +++ b/wagtail/test/demosite/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import django.db.models.deletion import modelcluster.contrib.taggit import modelcluster.fields diff --git a/wagtail/test/demosite/migrations/0002_capitalizeverbose.py b/wagtail/test/demosite/migrations/0002_capitalizeverbose.py index 96396739197e..804b634403da 100644 --- a/wagtail/test/demosite/migrations/0002_capitalizeverbose.py +++ b/wagtail/test/demosite/migrations/0002_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/test/modeladmintest/migrations/0001_initial.py b/wagtail/test/modeladmintest/migrations/0001_initial.py index 1a98f4d826c0..647c98cdcd5a 100644 --- a/wagtail/test/modeladmintest/migrations/0001_initial.py +++ b/wagtail/test/modeladmintest/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9 on 2015-12-22 11:40 from django.db import migrations, models import django.db.models.deletion diff --git a/wagtail/test/modeladmintest/migrations/0002_token.py b/wagtail/test/modeladmintest/migrations/0002_token.py index 00ca4e29c318..51c58dd5c2e5 100644 --- a/wagtail/test/modeladmintest/migrations/0002_token.py +++ b/wagtail/test/modeladmintest/migrations/0002_token.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2016-06-07 11:22 from django.db import migrations, models diff --git a/wagtail/test/modeladmintest/migrations/0003_publisher.py b/wagtail/test/modeladmintest/migrations/0003_publisher.py index 04918c8eb51f..efc1eb3f00ee 100644 --- a/wagtail/test/modeladmintest/migrations/0003_publisher.py +++ b/wagtail/test/modeladmintest/migrations/0003_publisher.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2016-06-07 11:22 from django.db import migrations, models diff --git a/wagtail/test/modeladmintest/migrations/0004_venuepage.py b/wagtail/test/modeladmintest/migrations/0004_venuepage.py index 0ae1c9b7f469..04f8da0778e7 100644 --- a/wagtail/test/modeladmintest/migrations/0004_venuepage.py +++ b/wagtail/test/modeladmintest/migrations/0004_venuepage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2016-06-07 11:22 import django.db.models.deletion from django.db import migrations, models diff --git a/wagtail/test/modeladmintest/migrations/0005_book_cover_image.py b/wagtail/test/modeladmintest/migrations/0005_book_cover_image.py index 581b476061ba..a9b11a8a4e82 100644 --- a/wagtail/test/modeladmintest/migrations/0005_book_cover_image.py +++ b/wagtail/test/modeladmintest/migrations/0005_book_cover_image.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.11 on 2016-11-14 20:12 from django.db import migrations, models import django.db.models.deletion diff --git a/wagtail/test/modeladmintest/wagtail_hooks.py b/wagtail/test/modeladmintest/wagtail_hooks.py index 06a0aa494af1..e6bf09cb4089 100644 --- a/wagtail/test/modeladmintest/wagtail_hooks.py +++ b/wagtail/test/modeladmintest/wagtail_hooks.py @@ -44,9 +44,7 @@ def last_book(self, obj): return "" def get_extra_class_names_for_field_col(self, obj, field_name): - class_names = super(AuthorModelAdmin, self).get_extra_class_names_for_field_col( - field_name, obj - ) + class_names = super().get_extra_class_names_for_field_col(field_name, obj) if field_name == "first_book": class_names.append("for-author-%s" % obj.pk) return class_names diff --git a/wagtail/test/routablepage/migrations/0001_initial.py b/wagtail/test/routablepage/migrations/0001_initial.py index a288bbd99a4c..3adc4309792f 100644 --- a/wagtail/test/routablepage/migrations/0001_initial.py +++ b/wagtail/test/routablepage/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.1 on 2016-02-12 10:55 import django.db.models.deletion from django.db import migrations, models diff --git a/wagtail/test/routablepage/migrations/0002_routablepagewithoutindexroutetest.py b/wagtail/test/routablepage/migrations/0002_routablepagewithoutindexroutetest.py index 4722d7c82dd8..5128b1f8765f 100644 --- a/wagtail/test/routablepage/migrations/0002_routablepagewithoutindexroutetest.py +++ b/wagtail/test/routablepage/migrations/0002_routablepagewithoutindexroutetest.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.6 on 2016-05-10 10:31 from django.db import migrations, models import django.db.models.deletion diff --git a/wagtail/test/search/migrations/0001_initial.py b/wagtail/test/search/migrations/0001_initial.py index 79ff1a47ba66..a005f8369fa3 100644 --- a/wagtail/test/search/migrations/0001_initial.py +++ b/wagtail/test/search/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.6 on 2017-10-18 12:59 from django.db import migrations, models import django.db.models.deletion diff --git a/wagtail/test/search/models.py b/wagtail/test/search/models.py index ba45837d9e79..39293de2ad52 100644 --- a/wagtail/test/search/models.py +++ b/wagtail/test/search/models.py @@ -45,7 +45,7 @@ class Book(index.Indexed, models.Model): @classmethod def get_indexed_objects(cls): - indexed_objects = super(Book, cls).get_indexed_objects() + indexed_objects = super().get_indexed_objects() # Don't index books using Book class that they have a more specific type if cls is Book: diff --git a/wagtail/test/snippets/migrations/0001_initial.py b/wagtail/test/snippets/migrations/0001_initial.py index 02e773d00f99..eb0b9e287321 100644 --- a/wagtail/test/snippets/migrations/0001_initial.py +++ b/wagtail/test/snippets/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/test/snippets/migrations/0002_searchablesnippet.py b/wagtail/test/snippets/migrations/0002_searchablesnippet.py index 7d9d8322204f..245e559e7eaf 100644 --- a/wagtail/test/snippets/migrations/0002_searchablesnippet.py +++ b/wagtail/test/snippets/migrations/0002_searchablesnippet.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models import wagtail.search.index diff --git a/wagtail/test/snippets/migrations/0003_fancysnippet_standardsnippet.py b/wagtail/test/snippets/migrations/0003_fancysnippet_standardsnippet.py index 1148515dd4a3..4f1cdfe7d10e 100644 --- a/wagtail/test/snippets/migrations/0003_fancysnippet_standardsnippet.py +++ b/wagtail/test/snippets/migrations/0003_fancysnippet_standardsnippet.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.4 on 2016-03-29 04:28 from django.db import migrations, models diff --git a/wagtail/test/snippets/migrations/0004_fileuploadsnippet.py b/wagtail/test/snippets/migrations/0004_fileuploadsnippet.py index dda59f0cb5d0..0876bd3fb79a 100644 --- a/wagtail/test/snippets/migrations/0004_fileuploadsnippet.py +++ b/wagtail/test/snippets/migrations/0004_fileuploadsnippet.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.4 on 2016-03-31 00:30 from django.db import migrations, models diff --git a/wagtail/test/snippets/migrations/0005_multisectionrichtextsnippet_richtextsection.py b/wagtail/test/snippets/migrations/0005_multisectionrichtextsnippet_richtextsection.py index b644a57520cf..28db2944cfc4 100644 --- a/wagtail/test/snippets/migrations/0005_multisectionrichtextsnippet_richtextsection.py +++ b/wagtail/test/snippets/migrations/0005_multisectionrichtextsnippet_richtextsection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models import wagtail.fields import modelcluster.fields diff --git a/wagtail/test/snippets/migrations/0006_standarsnippetwithcustomprimarykey.py b/wagtail/test/snippets/migrations/0006_standarsnippetwithcustomprimarykey.py index 79944578a4f0..3e94d0100482 100644 --- a/wagtail/test/snippets/migrations/0006_standarsnippetwithcustomprimarykey.py +++ b/wagtail/test/snippets/migrations/0006_standarsnippetwithcustomprimarykey.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.4 on 2016-03-29 04:28 -from __future__ import unicode_literals from django.db import migrations, models diff --git a/wagtail/test/testapp/forms.py b/wagtail/test/testapp/forms.py index 89a3f559b074..6a234630e1cf 100644 --- a/wagtail/test/testapp/forms.py +++ b/wagtail/test/testapp/forms.py @@ -22,7 +22,7 @@ class FormClassAdditionalFieldPageForm(WagtailAdminPageForm): code = forms.CharField(help_text="Enter SMS authentication code", max_length=5) def clean(self): - cleaned_data = super(FormClassAdditionalFieldPageForm, self).clean() + cleaned_data = super().clean() # validate the user's code with our code check code = cleaned_data["code"] diff --git a/wagtail/test/testapp/models.py b/wagtail/test/testapp/models.py index 4064c46be94f..65b881dc6bd7 100644 --- a/wagtail/test/testapp/models.py +++ b/wagtail/test/testapp/models.py @@ -613,7 +613,7 @@ class FormPageWithRedirect(AbstractEmailForm): ) def get_context(self, request): - context = super(FormPageWithRedirect, self).get_context(request) + context = super().get_context(request) context["greeting"] = "hello world" return context @@ -624,9 +624,7 @@ def render_landing_page(self, request, form_submission=None, *args, **kwargs): if self.thank_you_redirect_page: return redirect(self.thank_you_redirect_page.url, permanent=False) - return super(FormPageWithRedirect, self).render_landing_page( - request, form_submission, *args, **kwargs - ) + return super().render_landing_page(request, form_submission, *args, **kwargs) content_panels = [ FieldPanel("title", classname="title"), @@ -1329,9 +1327,7 @@ class SingletonPage(Page): @classmethod def can_create_at(cls, parent): # You can only create one of these! - return ( - super(SingletonPage, cls).can_create_at(parent) and not cls.objects.exists() - ) + return super().can_create_at(parent) and not cls.objects.exists() class SingletonPageViaMaxCount(Page): diff --git a/wagtail/test/testapp/rich_text.py b/wagtail/test/testapp/rich_text.py index 141b836cf263..e40857b9c6a1 100644 --- a/wagtail/test/testapp/rich_text.py +++ b/wagtail/test/testapp/rich_text.py @@ -7,7 +7,7 @@ class CustomRichTextArea(WidgetWithScript, widgets.Textarea): def render_js_init(self, id_, name, value): - return "customEditorInitScript({0});".format(json.dumps(id_)) + return f"customEditorInitScript({json.dumps(id_)});" @property def media(self): @@ -16,7 +16,7 @@ def media(self): class LegacyRichTextArea(WidgetWithScript, widgets.Textarea): def render_js_init(self, id_, name, value): - return "legacyEditorInitScript({0});".format(json.dumps(id_)) + return f"legacyEditorInitScript({json.dumps(id_)});" @property def media(self): diff --git a/wagtail/test/urls_multilang.py b/wagtail/test/urls_multilang.py index f2744e740777..16125f731819 100644 --- a/wagtail/test/urls_multilang.py +++ b/wagtail/test/urls_multilang.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - from django.conf.urls.i18n import i18n_patterns from django.urls import include, path diff --git a/wagtail/test/utils/page_tests.py b/wagtail/test/utils/page_tests.py index 2b350fd539a4..0064643550ba 100644 --- a/wagtail/test/utils/page_tests.py +++ b/wagtail/test/utils/page_tests.py @@ -115,7 +115,7 @@ def assertCanCreate(self, parent, child_model, data, msg=None, publish=True): raise self.failureException(msg) errors = "\n".join( - " %s:\n %s" % (field, "\n ".join(errors)) + " {}:\n {}".format(field, "\n ".join(errors)) for field, errors in sorted(form.errors.items()) ) msg = self._formatMessage( diff --git a/wagtail/test/utils/wagtail_tests.py b/wagtail/test/utils/wagtail_tests.py index aeaed081eebc..fc738f9a82f0 100644 --- a/wagtail/test/utils/wagtail_tests.py +++ b/wagtail/test/utils/wagtail_tests.py @@ -185,8 +185,7 @@ def _find_template_script_tags(self, haystack): yield haystack else: for child in haystack.children: - for script_tag in self._find_template_script_tags(child): - yield script_tag + yield from self._find_template_script_tags(child) def assertTagInHTML( self, needle, haystack, count=None, msg_prefix="", allow_extra_attrs=False diff --git a/wagtail/tests/test_audit_log.py b/wagtail/tests/test_audit_log.py index e6a8b5602a70..311266e174e5 100644 --- a/wagtail/tests/test_audit_log.py +++ b/wagtail/tests/test_audit_log.py @@ -362,9 +362,7 @@ def test_workflow_actions(self): ) workflow_state.refresh_from_db() - entry = PageLogEntry.objects.filter( - action="wagtail.workflow.{}".format(action) - ) + entry = PageLogEntry.objects.filter(action=f"wagtail.workflow.{action}") self.assertEqual(entry.count(), 1) self.assertEqual( entry[0].data, diff --git a/wagtail/tests/test_blocks.py b/wagtail/tests/test_blocks.py index f91b00d26126..fb8eab507e54 100644 --- a/wagtail/tests/test_blocks.py +++ b/wagtail/tests/test_blocks.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -* import base64 import collections import copy diff --git a/wagtail/tests/test_migrations.py b/wagtail/tests/test_migrations.py index 91e0b0ee154c..5db6c0883bf4 100644 --- a/wagtail/tests/test_migrations.py +++ b/wagtail/tests/test_migrations.py @@ -30,7 +30,8 @@ def test__migrations(self): if conflicts: name_str = "; ".join( - "%s in %s" % (", ".join(names), app) for app, names in conflicts.items() + "{} in {}".format(", ".join(names), app) + for app, names in conflicts.items() ) self.fail("Conflicting migrations detected (%s)." % name_str) @@ -48,17 +49,15 @@ def test__migrations(self): if changes: migrations = "\n".join( - ( - " {migration}\n{changes}".format( - migration=migration, - changes="\n".join( - " {0}".format(operation.describe()) - for operation in migration.operations - ), - ) - for (_, migrations) in changes.items() - for migration in migrations + " {migration}\n{changes}".format( + migration=migration, + changes="\n".join( + f" {operation.describe()}" + for operation in migration.operations + ), ) + for (_, migrations) in changes.items() + for migration in migrations ) self.fail("Model changes with no migrations detected:\n%s" % migrations) diff --git a/wagtail/tests/test_page_model.py b/wagtail/tests/test_page_model.py index 6d97e8697c7a..dbfa2b2838e7 100644 --- a/wagtail/tests/test_page_model.py +++ b/wagtail/tests/test_page_model.py @@ -271,7 +271,7 @@ def test_unrecognised_port_on_known_hostname_routes_to_default_site_if_ambiguity def test_port_in_http_host_header_is_ignored(self): # port in the HTTP_HOST header is ignored request = get_dummy_request() - request.META["HTTP_HOST"] = "%s:%s" % ( + request.META["HTTP_HOST"] = "{}:{}".format( self.events_site.hostname, self.events_site.port, ) @@ -3017,7 +3017,9 @@ def test_url_path_can_exceed_255_characters(self): # Check that the url path updated correctly new_christmas_event = EventPage.objects.get(id=christmas_event.id) - expected_url_path = "/home/%s/%s/" % (new_event_index_slug, new_christmas_slug) + expected_url_path = "/home/{}/{}/".format( + new_event_index_slug, new_christmas_slug + ) self.assertEqual(new_christmas_event.url_path, expected_url_path) diff --git a/wagtail/tests/test_page_permissions.py b/wagtail/tests/test_page_permissions.py index 2d5886ae895c..c492133c7ef2 100644 --- a/wagtail/tests/test_page_permissions.py +++ b/wagtail/tests/test_page_permissions.py @@ -510,7 +510,7 @@ def test_explorable_pages_in_explorer(self): homepage = Page.objects.get(url_path="/home/") explorer_response = client.get( - "/admin/api/main/pages/?child_of={}&for_explorer=1".format(homepage.pk) + f"/admin/api/main/pages/?child_of={homepage.pk}&for_explorer=1" ) explorer_json = json.loads(explorer_response.content.decode("utf-8")) diff --git a/wagtail/tests/test_permission_policies.py b/wagtail/tests/test_permission_policies.py index 2a386a1fcbef..080c029898dd 100644 --- a/wagtail/tests/test_permission_policies.py +++ b/wagtail/tests/test_permission_policies.py @@ -34,7 +34,9 @@ def assertUserPermissionMatrix(self, test_cases, actions=()): if expected_result: self.assertTrue( self.policy.user_has_permission(user, action), - msg="User %s should be able to %s, but can't" % (user, action), + msg="User {} should be able to {}, but can't".format( + user, action + ), ) else: self.assertFalse( diff --git a/wagtail/tests/test_streamfield.py b/wagtail/tests/test_streamfield.py index c6c8789e3e75..f349d2026d64 100644 --- a/wagtail/tests/test_streamfield.py +++ b/wagtail/tests/test_streamfield.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -* import json from django.apps import apps @@ -260,7 +259,7 @@ def setUp(self): [ '

    Rich text

    ', '

    Привет, Микола

    ', - '
    {}
    '.format(img_tag), + f'
    {img_tag}
    ', '
    Hello, World!
    ', ] ) diff --git a/wagtail/tests/test_utils.py b/wagtail/tests/test_utils.py index 45659cac061b..8be3b2b76c95 100644 --- a/wagtail/tests/test_utils.py +++ b/wagtail/tests/test_utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -* import pickle from io import BytesIO, StringIO from pathlib import Path diff --git a/wagtail/users/migrations/0001_initial.py b/wagtail/users/migrations/0001_initial.py index 67a56702866c..bd1e57ef16ec 100644 --- a/wagtail/users/migrations/0001_initial.py +++ b/wagtail/users/migrations/0001_initial.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.conf import settings from django.db import migrations, models diff --git a/wagtail/users/migrations/0002_add_verbose_name_on_userprofile.py b/wagtail/users/migrations/0002_add_verbose_name_on_userprofile.py index df162900868b..bf3c574f4af5 100644 --- a/wagtail/users/migrations/0002_add_verbose_name_on_userprofile.py +++ b/wagtail/users/migrations/0002_add_verbose_name_on_userprofile.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/users/migrations/0003_add_verbose_names.py b/wagtail/users/migrations/0003_add_verbose_names.py index c180cb052618..0ac1223e1375 100644 --- a/wagtail/users/migrations/0003_add_verbose_names.py +++ b/wagtail/users/migrations/0003_add_verbose_names.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations diff --git a/wagtail/users/migrations/0004_capitalizeverbose.py b/wagtail/users/migrations/0004_capitalizeverbose.py index 6e1900477026..7482259c8d04 100644 --- a/wagtail/users/migrations/0004_capitalizeverbose.py +++ b/wagtail/users/migrations/0004_capitalizeverbose.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.db import migrations, models diff --git a/wagtail/users/migrations/0005_make_related_name_wagtail_specific.py b/wagtail/users/migrations/0005_make_related_name_wagtail_specific.py index 3752d99eb2ed..3e44743ea825 100644 --- a/wagtail/users/migrations/0005_make_related_name_wagtail_specific.py +++ b/wagtail/users/migrations/0005_make_related_name_wagtail_specific.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.1 on 2016-09-28 23:49 from django.conf import settings from django.db import migrations, models diff --git a/wagtail/users/migrations/0006_userprofile_prefered_language.py b/wagtail/users/migrations/0006_userprofile_prefered_language.py index 7bf5248e3237..97c39189cce9 100644 --- a/wagtail/users/migrations/0006_userprofile_prefered_language.py +++ b/wagtail/users/migrations/0006_userprofile_prefered_language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.10.5 on 2017-01-27 22:18 from django.db import migrations, models diff --git a/wagtail/users/tests/test_admin_views.py b/wagtail/users/tests/test_admin_views.py index 30dd9b6637a0..f5ed8e88e022 100644 --- a/wagtail/users/tests/test_admin_views.py +++ b/wagtail/users/tests/test_admin_views.py @@ -29,8 +29,8 @@ from wagtail.users.views.users import get_user_creation_form, get_user_edit_form from wagtail.users.wagtail_hooks import get_group_viewset_cls -delete_user_perm_codename = "delete_{0}".format(AUTH_USER_MODEL_NAME.lower()) -change_user_perm_codename = "change_{0}".format(AUTH_USER_MODEL_NAME.lower()) +delete_user_perm_codename = f"delete_{AUTH_USER_MODEL_NAME.lower()}" +change_user_perm_codename = f"change_{AUTH_USER_MODEL_NAME.lower()}" def test_avatar_provider(user, default, size=50): @@ -1963,8 +1963,7 @@ def flatten(perm_set): # iterates through perm_set dict, flattens the list if present for v in perm_set.values(): if isinstance(v, list): - for e in v: - yield e + yield from v else: yield v @@ -2079,7 +2078,7 @@ def test_simple(self): def test_authorised(self): for permission in ("add", "change", "delete"): - permission_name = "{}_{}".format(permission, AUTH_USER_MODEL_NAME.lower()) + permission_name = f"{permission}_{AUTH_USER_MODEL_NAME.lower()}" permission_object = Permission.objects.get(codename=permission_name) self._user.user_permissions.add(permission_object) @@ -2107,7 +2106,7 @@ def gain_permissions(self): self._user.user_permissions.add( Permission.objects.get( content_type__app_label=AUTH_USER_APP_LABEL, - codename="add_{}".format(AUTH_USER_MODEL_NAME.lower()), + codename=f"add_{AUTH_USER_MODEL_NAME.lower()}", ) ) @@ -2192,7 +2191,7 @@ def gain_permissions(self): self._user.user_permissions.add( Permission.objects.get( content_type__app_label=AUTH_USER_APP_LABEL, - codename="change_{}".format(AUTH_USER_MODEL_NAME.lower()), + codename=f"change_{AUTH_USER_MODEL_NAME.lower()}", ) ) @@ -2277,7 +2276,7 @@ def gain_permissions(self): self._user.user_permissions.add( Permission.objects.get( content_type__app_label=AUTH_USER_APP_LABEL, - codename="delete_{}".format(AUTH_USER_MODEL_NAME.lower()), + codename=f"delete_{AUTH_USER_MODEL_NAME.lower()}", ) ) diff --git a/wagtail/users/tests/test_bulk_actions/test_bulk_delete.py b/wagtail/users/tests/test_bulk_actions/test_bulk_delete.py index bf4d08c2b721..d508fd8af7fd 100644 --- a/wagtail/users/tests/test_bulk_actions/test_bulk_delete.py +++ b/wagtail/users/tests/test_bulk_actions/test_bulk_delete.py @@ -69,7 +69,7 @@ def test_user_cannot_delete_self(self): self.assertInHTML("

    You don't have permission to delete this user

    ", html) needle = "
      " - needle += "
    • {user_email}
    • ".format(user_email=self.current_user.email) + needle += f"
    • {self.current_user.email}
    • " needle += "
    " self.assertInHTML(needle, html) diff --git a/wagtail/users/tests/test_bulk_actions/test_bulk_set_active_state.py b/wagtail/users/tests/test_bulk_actions/test_bulk_set_active_state.py index 1814ca85e4df..0da48d9e9b84 100644 --- a/wagtail/users/tests/test_bulk_actions/test_bulk_set_active_state.py +++ b/wagtail/users/tests/test_bulk_actions/test_bulk_set_active_state.py @@ -66,7 +66,7 @@ def test_user_cannot_mark_self_as_inactive(self): self.assertInHTML("

    You cannot change your own active status

    ", html) needle = "
      " - needle += "
    • {user_email}
    • ".format(user_email=self.current_user.email) + needle += f"
    • {self.current_user.email}
    • " needle += "
    " self.assertInHTML(needle, html) diff --git a/wagtail/users/utils.py b/wagtail/users/utils.py index f568e8a71dea..ef3f0e6bb9c1 100644 --- a/wagtail/users/utils.py +++ b/wagtail/users/utils.py @@ -5,7 +5,7 @@ from wagtail.compat import AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME from wagtail.coreutils import safe_md5 -delete_user_perm = "{0}.delete_{1}".format( +delete_user_perm = "{}.delete_{}".format( AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower() ) diff --git a/wagtail/users/views/users.py b/wagtail/users/views/users.py index b0fd32be66f9..b71b4075b97f 100644 --- a/wagtail/users/views/users.py +++ b/wagtail/users/views/users.py @@ -20,11 +20,11 @@ # Typically we would check the permission 'auth.change_user' (and 'auth.add_user' / # 'auth.delete_user') for user management actions, but this may vary according to # the AUTH_USER_MODEL setting -add_user_perm = "{0}.add_{1}".format(AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower()) -change_user_perm = "{0}.change_{1}".format( +add_user_perm = f"{AUTH_USER_APP_LABEL}.add_{AUTH_USER_MODEL_NAME.lower()}" +change_user_perm = "{}.change_{}".format( AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower() ) -delete_user_perm = "{0}.delete_{1}".format( +delete_user_perm = "{}.delete_{}".format( AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower() ) diff --git a/wagtail/users/wagtail_hooks.py b/wagtail/users/wagtail_hooks.py index 4a55784aff46..2f57bf6828e8 100644 --- a/wagtail/users/wagtail_hooks.py +++ b/wagtail/users/wagtail_hooks.py @@ -55,11 +55,11 @@ def register_viewset(): # Typically we would check the permission 'auth.change_user' (and 'auth.add_user' / # 'auth.delete_user') for user management actions, but this may vary according to # the AUTH_USER_MODEL setting -add_user_perm = "{0}.add_{1}".format(AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower()) -change_user_perm = "{0}.change_{1}".format( +add_user_perm = f"{AUTH_USER_APP_LABEL}.add_{AUTH_USER_MODEL_NAME.lower()}" +change_user_perm = "{}.change_{}".format( AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower() ) -delete_user_perm = "{0}.delete_{1}".format( +delete_user_perm = "{}.delete_{}".format( AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME.lower() ) diff --git a/wagtail/utils/apps.py b/wagtail/utils/apps.py index e6fb96377151..5c4c33bbde60 100644 --- a/wagtail/utils/apps.py +++ b/wagtail/utils/apps.py @@ -20,4 +20,4 @@ def get_app_submodules(submodule_name): """ for name, module in get_app_modules(): if module_has_submodule(module, submodule_name): - yield name, import_module("%s.%s" % (name, submodule_name)) + yield name, import_module(f"{name}.{submodule_name}") diff --git a/wagtail/utils/setup.py b/wagtail/utils/setup.py index 9c14895ce662..f22e70763585 100644 --- a/wagtail/utils/setup.py +++ b/wagtail/utils/setup.py @@ -1,4 +1,3 @@ -import io import json import os import subprocess @@ -30,7 +29,7 @@ def bump_client_version(self): Writes the current Wagtail version number into package.json """ path = os.path.join(".", "client", "package.json") - input_file = io.open(path, "r") + input_file = open(path) try: package = json.loads(input_file.read().decode("utf-8")) @@ -41,9 +40,9 @@ def bump_client_version(self): package["version"] = __semver__ try: - with io.open(path, "w", encoding="utf-8") as f: + with open(path, "w", encoding="utf-8") as f: f.write(str(json.dumps(package, indent=2, ensure_ascii=False))) - except (IOError) as e: + except (OSError) as e: print( # noqa: T201 "Error setting the version for front-end assets: " + str(e) ) diff --git a/wagtail/utils/widgets.py b/wagtail/utils/widgets.py index 72a9c6831a45..426ca59a5d96 100644 --- a/wagtail/utils/widgets.py +++ b/wagtail/utils/widgets.py @@ -29,7 +29,7 @@ def render(self, name, value, attrs=None, renderer=None): widget_html = self.render_html(name, value_data, attrs) js = self.render_js_init(id_, name, value_data) - out = "{0}".format(widget_html, js) + out = f"{widget_html}" return mark_safe(out) def render_js_init(self, id_, name, value): From 5a6991dd8fc156f0386e85e15350951a22b2a368 Mon Sep 17 00:00:00 2001 From: zerolab Date: Thu, 13 Jul 2023 23:36:31 +0100 Subject: [PATCH 08/11] Run django-upgrade with a 3.2 target `git ls-files --others --cached --exclude-standard -- '*.py' | xargs django-upgrade --target 3.2` --- wagtail/test/middleware.py | 2 +- wagtail/test/testapp/wagtail_hooks.py | 2 +- wagtail/tests/test_page_model.py | 18 +++++++++--------- wagtail/utils/sendfile_streaming_backend.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/wagtail/test/middleware.py b/wagtail/test/middleware.py index cb6521edd3ce..ab3e16bd7481 100644 --- a/wagtail/test/middleware.py +++ b/wagtail/test/middleware.py @@ -13,6 +13,6 @@ class BlockDodgyUserAgentMiddleware(MiddlewareMixin): def process_request(self, request): if ( not request.path.startswith("/admin/") - and request.META.get("HTTP_USER_AGENT") == "EvilHacker" + and request.headers.get("user-agent") == "EvilHacker" ): return HttpResponseForbidden("Forbidden") diff --git a/wagtail/test/testapp/wagtail_hooks.py b/wagtail/test/testapp/wagtail_hooks.py index a987c5f5b481..2e7fb3e2354d 100644 --- a/wagtail/test/testapp/wagtail_hooks.py +++ b/wagtail/test/testapp/wagtail_hooks.py @@ -48,7 +48,7 @@ def editor_js(): def block_googlebot(page, request, serve_args, serve_kwargs): - if request.META.get("HTTP_USER_AGENT") == "GoogleBot": + if request.headers.get("user-agent") == "GoogleBot": return HttpResponse("

    bad googlebot no cookie

    ") diff --git a/wagtail/tests/test_page_model.py b/wagtail/tests/test_page_model.py index dbfa2b2838e7..9b978369c59d 100644 --- a/wagtail/tests/test_page_model.py +++ b/wagtail/tests/test_page_model.py @@ -3146,7 +3146,7 @@ def test_make_preview_request_for_accessible_page(self): # request should have the correct path and hostname for this page self.assertEqual(request.path, "/events/") - self.assertEqual(request.META["HTTP_HOST"], "localhost") + self.assertEqual(request.headers["host"], "localhost") # check other env vars required by the WSGI spec self.assertEqual(request.META["REQUEST_METHOD"], "GET") @@ -3173,7 +3173,7 @@ def test_make_preview_request_for_accessible_page_https(self): # request should have the correct path and hostname for this page self.assertEqual(request.path, "/events/") - self.assertEqual(request.META["HTTP_HOST"], "localhost") + self.assertEqual(request.headers["host"], "localhost") # check other env vars required by the WSGI spec self.assertEqual(request.META["REQUEST_METHOD"], "GET") @@ -3200,7 +3200,7 @@ def test_make_preview_request_for_accessible_page_non_standard_port(self): # request should have the correct path and hostname for this page self.assertEqual(request.path, "/events/") - self.assertEqual(request.META["HTTP_HOST"], "localhost:8888") + self.assertEqual(request.headers["host"], "localhost:8888") # check other env vars required by the WSGI spec self.assertEqual(request.META["REQUEST_METHOD"], "GET") @@ -3237,17 +3237,17 @@ def test_make_preview_request_for_accessible_page_with_original_request(self): request.META["REMOTE_ADDR"], original_request.META["REMOTE_ADDR"] ) self.assertEqual( - request.META["HTTP_X_FORWARDED_FOR"], + request.headers["x-forwarded-for"], original_request.META["HTTP_X_FORWARDED_FOR"], ) self.assertEqual( - request.META["HTTP_COOKIE"], original_request.META["HTTP_COOKIE"] + request.headers["cookie"], original_request.META["HTTP_COOKIE"] ) self.assertEqual( - request.META["HTTP_USER_AGENT"], original_request.META["HTTP_USER_AGENT"] + request.headers["user-agent"], original_request.META["HTTP_USER_AGENT"] ) self.assertEqual( - request.META["HTTP_AUTHORIZATION"], + request.headers["authorization"], original_request.META["HTTP_AUTHORIZATION"], ) @@ -3276,7 +3276,7 @@ def test_make_preview_request_for_inaccessible_page_should_use_valid_host(self): # in the absence of an actual Site record where we can access this page, # make_preview_request should still provide a hostname that Django's host header # validation won't reject - self.assertEqual(request.META["HTTP_HOST"], "production.example.com") + self.assertEqual(request.headers["host"], "production.example.com") @override_settings(ALLOWED_HOSTS=["*"]) def test_make_preview_request_for_inaccessible_page_with_wildcard_allowed_hosts( @@ -3288,7 +3288,7 @@ def test_make_preview_request_for_inaccessible_page_with_wildcard_allowed_hosts( request = response.context_data["request"] # '*' is not a valid hostname, so ensure that we replace it with something sensible - self.assertNotEqual(request.META["HTTP_HOST"], "*") + self.assertNotEqual(request.headers["host"], "*") def test_is_previewable(self): event_index = Page.objects.get(url_path="/home/events/") diff --git a/wagtail/utils/sendfile_streaming_backend.py b/wagtail/utils/sendfile_streaming_backend.py index 590ab15128d0..e92093f44b21 100644 --- a/wagtail/utils/sendfile_streaming_backend.py +++ b/wagtail/utils/sendfile_streaming_backend.py @@ -15,7 +15,7 @@ def sendfile(request, filename, **kwargs): statobj = os.stat(filename) if not was_modified_since( - request.META.get("HTTP_IF_MODIFIED_SINCE"), + request.headers.get("if-modified-since"), statobj[stat.ST_MTIME], ): return HttpResponseNotModified() From 1e49d2a63b2e5705f21877a0b8483f4fd72a7d5a Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Fri, 14 Jul 2023 12:10:15 +0100 Subject: [PATCH 09/11] Remove redundant format string in test_move_page.py Co-authored-by: Jake Howard --- wagtail/admin/tests/pages/test_move_page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wagtail/admin/tests/pages/test_move_page.py b/wagtail/admin/tests/pages/test_move_page.py index 97c8767e993b..3b6cd91e7cb4 100644 --- a/wagtail/admin/tests/pages/test_move_page.py +++ b/wagtail/admin/tests/pages/test_move_page.py @@ -124,7 +124,7 @@ def test_page_move_confirm(self): self.assertEqual(len(messages), 1) self.assertEqual(messages[0].level, message_constants.ERROR) # Slug should be in error message. - self.assertIn(f"{self.test_page_b.slug}", messages[0].message) + self.assertIn(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 From aca754aa366b855e2b1e92923e8e4636808fa183 Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Fri, 14 Jul 2023 13:09:55 +0100 Subject: [PATCH 10/11] Release note for dropping Python 3.7 support (#10676) --- CHANGELOG.txt | 1 + docs/releases/5.1.md | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 6b590ffdbe20..71767115796c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -64,6 +64,7 @@ Changelog * Docs: Switch the Getting started tutorial’s snippets example to be more understandable (Damilola Oladele) * Docs: Update the deployment documentation page and remove outdated information (Jake Howard) * Docs: Add more items to performance page regarding pre-fetching images and frontend caching (Jake Howard) + * Maintenance: Removed support for Python 3.7 (Dan Braghis) * Maintenance: Switch to ruff for flake8 / isort code checking (Oliver Parker) * Maintenance: Deprecate `insert_editor_css` in favour of `insert_global_admin_css` (Ester Beltrami) * Maintenance: Optimise use of `specific` on Task and TaskState (Matt Westcott) diff --git a/docs/releases/5.1.md b/docs/releases/5.1.md index e039444c1e82..bf059dee86e7 100644 --- a/docs/releases/5.1.md +++ b/docs/releases/5.1.md @@ -112,6 +112,7 @@ As part of tackling Wagtail’s technical debt and improving [CSP compatibility] ### Maintenance + * Removed support for Python 3.7 (Dan Braghis) * Switch to ruff for flake8 / isort code checking (Oliver Parker) * Deprecate `insert_editor_css` in favour of `insert_global_admin_css` (Ester Beltrami) * Optimise use of `specific` on Task and TaskState (Matt Westcott) @@ -138,6 +139,10 @@ As part of tackling Wagtail’s technical debt and improving [CSP compatibility] ## Upgrade considerations +### Removed support for Python 3.7 + +Python 3.7 is no longer supported as of this release; please upgrade to Python 3.8 or above before upgrading Wagtail. + ### Pillow dependency update Wagtail no longer supports Pillow versions below `9.1.0`. From 9881ec12b8736706425506d55dd38a070b0055fc Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Fri, 14 Jul 2023 13:44:02 +0100 Subject: [PATCH 11/11] Update black target version to 3.8 in circleci config --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c570d582b70f..15e0a4dc5785 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ jobs: paths: - .venv - run: pipenv run ruff check . - - run: pipenv run black --target-version py37 --check --diff . + - run: pipenv run black --target-version py38 --check --diff . - run: pipenv run semgrep --config .semgrep.yml --error . - run: git ls-files '*.html' | xargs pipenv run djhtml --check - run: pipenv run curlylint --parse-only wagtail