← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:black-translations into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:black-translations into launchpad:master.

Commit message:
lp.translations: Apply black

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/427289
-- 
The attached diff has been truncated due to its size.
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:black-translations into launchpad:master.
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index b4a5fd9..2b86d1c 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -92,3 +92,5 @@ cf7c6a08bd010dd260bff4690d64479fadf37e67
 15e1c80d57296e830e0dd85f1e03245281a88f02
 # apply black to lp.{testopenid,tests}
 c7dedd4d8a3c642f77570e525be0af9714703eba
+# apply black to lp.translations
+b56a741985ca580c281f142bea589b1ef05d3e93
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e4c4daa..7aa4211 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -61,6 +61,7 @@ repos:
             |testing
             |testopenid
             |tests
+            |translations
           )/
 -   repo: https://github.com/PyCQA/isort
     rev: 5.9.2
@@ -98,6 +99,7 @@ repos:
             |testing
             |testopenid
             |tests
+            |translations
           )/
     -   id: isort
         alias: isort-black
@@ -125,6 +127,7 @@ repos:
             |testing
             |testopenid
             |tests
+            |translations
           )/
 -   repo: https://github.com/PyCQA/flake8
     rev: 3.9.2
diff --git a/lib/lp/translations/browser/browser_helpers.py b/lib/lp/translations/browser/browser_helpers.py
index a4894a6..423d24a 100644
--- a/lib/lp/translations/browser/browser_helpers.py
+++ b/lib/lp/translations/browser/browser_helpers.py
@@ -4,16 +4,16 @@
 """Translation-related formatting functions."""
 
 __all__ = [
-    'contract_rosetta_escapes',
-    'convert_newlines_to_web_form',
-    'count_lines',
-    'expand_rosetta_escapes',
-    'parse_cformat_string',
-    'text_to_html',
-    ]
+    "contract_rosetta_escapes",
+    "convert_newlines_to_web_form",
+    "count_lines",
+    "expand_rosetta_escapes",
+    "parse_cformat_string",
+    "text_to_html",
+]
 
-from math import ceil
 import re
+from math import ceil
 
 from lp.services import helpers
 from lp.services.webapp.escaping import html_escape
@@ -26,40 +26,50 @@ class UnrecognisedCFormatString(ValueError):
 
 def contract_rosetta_escapes(text):
     """Replace Rosetta escape sequences with the real characters."""
-    return helpers.text_replaced(text, {'[tab]': '\t',
-                                        r'\[tab]': '[tab]',
-                                        '[nbsp]': '\u00a0',
-                                        r'\[nbsp]': '[nbsp]',
-                                        '[nnbsp]': '\u202f',
-                                        r'\[nnbsp]': '[nnbsp]'})
+    return helpers.text_replaced(
+        text,
+        {
+            "[tab]": "\t",
+            r"\[tab]": "[tab]",
+            "[nbsp]": "\u00a0",
+            r"\[nbsp]": "[nbsp]",
+            "[nnbsp]": "\u202f",
+            r"\[nnbsp]": "[nnbsp]",
+        },
+    )
 
 
 def expand_rosetta_escapes(unicode_text):
     """Replace characters needing a Rosetta escape sequences."""
-    escapes = {'\t': TranslationConstants.TAB_CHAR,
-               '[tab]': TranslationConstants.TAB_CHAR_ESCAPED,
-               '\u00a0': TranslationConstants.NO_BREAK_SPACE_CHAR,
-               '[nbsp]': TranslationConstants.NO_BREAK_SPACE_CHAR_ESCAPED,
-               '\u202f': TranslationConstants.NARROW_NO_BREAK_SPACE_CHAR,
-               '[nnbsp]':
-    TranslationConstants.NARROW_NO_BREAK_SPACE_CHAR_ESCAPED}
+    escapes = {
+        "\t": TranslationConstants.TAB_CHAR,
+        "[tab]": TranslationConstants.TAB_CHAR_ESCAPED,
+        "\u00a0": TranslationConstants.NO_BREAK_SPACE_CHAR,
+        "[nbsp]": TranslationConstants.NO_BREAK_SPACE_CHAR_ESCAPED,
+        "\u202f": TranslationConstants.NARROW_NO_BREAK_SPACE_CHAR,
+        "[nnbsp]": TranslationConstants.NARROW_NO_BREAK_SPACE_CHAR_ESCAPED,
+    }
     return helpers.text_replaced(unicode_text, escapes)
 
 
-def text_to_html(text, flags, space=TranslationConstants.SPACE_CHAR,
-               newline=TranslationConstants.NEWLINE_CHAR):
+def text_to_html(
+    text,
+    flags,
+    space=TranslationConstants.SPACE_CHAR,
+    newline=TranslationConstants.NEWLINE_CHAR,
+):
     """Convert a unicode text to a HTML representation."""
     if text is None:
         return None
 
     markup_lines = []
     # Replace leading and trailing spaces on each line with special markup.
-    if '\r\n' in text:
-        newline_chars = '\r\n'
-    elif '\r' in text:
-        newline_chars = '\r'
+    if "\r\n" in text:
+        newline_chars = "\r\n"
+    elif "\r" in text:
+        newline_chars = "\r"
     else:
-        newline_chars = '\n'
+        newline_chars = "\n"
     for line in text.split(newline_chars):
         # Pattern:
         # - group 1: zero or more spaces: leading whitespace
@@ -67,33 +77,35 @@ def text_to_html(text, flags, space=TranslationConstants.SPACE_CHAR,
         #   more spaces followed by one or more non-spaces): maximal string
         #   which doesn't begin or end with whitespace
         # - group 3: zero or more spaces: trailing whitespace
-        match = re.match('^( *)((?: *[^ ]+)*)( *)$', line)
+        match = re.match("^( *)((?: *[^ ]+)*)( *)$", line)
 
         if match:
             format_segments = None
-            if 'c-format' in flags:
+            if "c-format" in flags:
                 try:
                     format_segments = parse_cformat_string(match.group(2))
                 except UnrecognisedCFormatString:
                     pass
             if format_segments is not None:
-                markup = ''
+                markup = ""
                 for segment in format_segments:
                     type, content = segment
 
-                    if type == 'interpolation':
-                        markup += ('<code>%s</code>' % html_escape(content))
-                    elif type == 'string':
+                    if type == "interpolation":
+                        markup += "<code>%s</code>" % html_escape(content)
+                    elif type == "string":
                         markup += html_escape(content)
             else:
                 markup = html_escape(match.group(2))
             markup_lines.append(
                 space * len(match.group(1))
                 + markup
-                + space * len(match.group(3)))
+                + space * len(match.group(3))
+            )
         else:
             raise AssertionError(
-                "A regular expression that should always match didn't.")
+                "A regular expression that should always match didn't."
+            )
 
     return expand_rosetta_escapes(newline.join(markup_lines))
 
@@ -107,18 +119,19 @@ def convert_newlines_to_web_form(unicode_text):
     if unicode_text is None:
         return None
 
-    assert isinstance(unicode_text, str), (
-        "The given text must be unicode instead of %s" % type(unicode_text))
+    assert isinstance(
+        unicode_text, str
+    ), "The given text must be unicode instead of %s" % type(unicode_text)
 
     if unicode_text is None:
         return None
-    elif '\r\n' in unicode_text:
+    elif "\r\n" in unicode_text:
         # The text is already using the windows newline chars
         return unicode_text
-    elif '\n' in unicode_text:
-        return helpers.text_replaced(unicode_text, {'\n': '\r\n'})
+    elif "\n" in unicode_text:
+        return helpers.text_replaced(unicode_text, {"\n": "\r\n"})
     else:
-        return helpers.text_replaced(unicode_text, {'\r': '\r\n'})
+        return helpers.text_replaced(unicode_text, {"\r": "\r\n"})
 
 
 def count_lines(text):
@@ -133,7 +146,7 @@ def count_lines(text):
     CHARACTERS_PER_LINE = 60
     count = 0
 
-    for line in text.split('\n'):
+    for line in text.split("\n"):
         if len(line) == 0:
             count += 1
         else:
@@ -161,24 +174,24 @@ def parse_cformat_string(string):
     # interpolations, or a string beginning with an interpolation.
     segments = []
     end = string
-    plain_re = re.compile('(%%|[^%])+')
-    interpolation_re = re.compile('%[^diouxXeEfFgGcspmn]*[diouxXeEfFgGcspmn]')
+    plain_re = re.compile("(%%|[^%])+")
+    interpolation_re = re.compile("%[^diouxXeEfFgGcspmn]*[diouxXeEfFgGcspmn]")
 
     while end:
         # Check for a interpolation-less prefix.
         match = plain_re.match(end)
         if match:
             segment = match.group(0)
-            segments.append(('string', segment))
-            end = end[len(segment):]
+            segments.append(("string", segment))
+            end = end[len(segment) :]
             continue
 
         # Check for an interpolation sequence at the beginning.
         match = interpolation_re.match(end)
         if match:
             segment = match.group(0)
-            segments.append(('interpolation', segment))
-            end = end[len(segment):]
+            segments.append(("interpolation", segment))
+            end = end[len(segment) :]
             continue
 
         # Give up.
diff --git a/lib/lp/translations/browser/customlanguagecode.py b/lib/lp/translations/browser/customlanguagecode.py
index fd09592..cbee4a7 100644
--- a/lib/lp/translations/browser/customlanguagecode.py
+++ b/lib/lp/translations/browser/customlanguagecode.py
@@ -2,38 +2,34 @@
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __all__ = [
-    'CustomLanguageCodeAddView',
-    'CustomLanguageCodeBreadcrumb',
-    'CustomLanguageCodesIndexView',
-    'CustomLanguageCodeRemoveView',
-    'CustomLanguageCodeView',
-    'HasCustomLanguageCodesNavigation',
-    'HasCustomLanguageCodesTraversalMixin',
-    ]
+    "CustomLanguageCodeAddView",
+    "CustomLanguageCodeBreadcrumb",
+    "CustomLanguageCodesIndexView",
+    "CustomLanguageCodeRemoveView",
+    "CustomLanguageCodeView",
+    "HasCustomLanguageCodesNavigation",
+    "HasCustomLanguageCodesTraversalMixin",
+]
 
 
 import re
 
 from lazr.restful.utils import smartquote
 
-from lp.app.browser.launchpadform import (
-    action,
-    LaunchpadFormView,
-    )
+from lp.app.browser.launchpadform import LaunchpadFormView, action
 from lp.app.errors import NotFoundError
 from lp.services.webapp import (
-    canonical_url,
     LaunchpadView,
     Navigation,
+    canonical_url,
     stepthrough,
-    )
+)
 from lp.services.webapp.breadcrumb import Breadcrumb
 from lp.services.webapp.escaping import structured
 from lp.translations.interfaces.customlanguagecode import (
     ICustomLanguageCode,
     IHasCustomLanguageCodes,
-    )
-
+)
 
 # Regex for allowable custom language codes.
 CODE_PATTERN = "[a-zA-Z0-9_-]+$"
@@ -50,7 +46,8 @@ class CustomLanguageCodeBreadcrumb(Breadcrumb):
     @property
     def text(self):
         return smartquote(
-            'Custom language code "%s"' % self.context.language_code)
+            'Custom language code "%s"' % self.context.language_code
+        )
 
 
 class CustomLanguageCodesIndexView(LaunchpadView):
@@ -65,61 +62,68 @@ class CustomLanguageCodesIndexView(LaunchpadView):
 
 class CustomLanguageCodeAddView(LaunchpadFormView):
     """Create a new custom language code."""
+
     schema = ICustomLanguageCode
-    field_names = ['language_code', 'language']
+    field_names = ["language_code", "language"]
     page_title = "Add new code"
 
     create = False
 
     @property
     def label(self):
-        return (
-            "Add a custom language code for %s" % self.context.displayname)
+        return "Add a custom language code for %s" % self.context.displayname
 
     def validate(self, data):
-        self.language_code = data.get('language_code')
-        self.language = data.get('language')
+        self.language_code = data.get("language_code")
+        self.language = data.get("language")
         if self.language_code is not None:
             self.language_code = self.language_code.strip()
 
         if not self.language_code:
-            self.setFieldError('language_code', "No code was entered.")
+            self.setFieldError("language_code", "No code was entered.")
             return
 
         if not check_code(self.language_code):
-            self.setFieldError('language_code', "Invalid language code.")
+            self.setFieldError("language_code", "Invalid language code.")
             return
 
         existing_code = self.context.getCustomLanguageCode(self.language_code)
         if existing_code is not None:
             if existing_code.language != self.language:
                 self.setFieldError(
-                    'language_code',
+                    "language_code",
                     structured(
                         "There already is a custom language code '%s'.",
-                            self.language_code))
+                        self.language_code,
+                    ),
+                )
                 return
         else:
             self.create = True
 
-    @action('Add', name='add')
+    @action("Add", name="add")
     def add_action(self, action, data):
         if self.create:
             self.context.createCustomLanguageCode(
-                self.language_code, self.language)
+                self.language_code, self.language
+            )
 
     @property
     def action_url(self):
         return canonical_url(
-            self.context, rootsite='translations',
-            view_name='+add-custom-language-code')
+            self.context,
+            rootsite="translations",
+            view_name="+add-custom-language-code",
+        )
 
     @property
     def next_url(self):
         """See `LaunchpadFormView`."""
         return canonical_url(
-            self.context, rootsite='translations',
-            view_name='+custom-language-codes')
+            self.context,
+            rootsite="translations",
+            view_name="+custom-language-codes",
+        )
 
     cancel_url = next_url
 
@@ -131,12 +135,14 @@ class CustomLanguageCodeView(LaunchpadView):
     def label(self):
         target_displayname = self.context.translation_target.displayname
         return smartquote(
-            'Custom language code "%s" for %s' % (
-                self.context.language_code, target_displayname))
+            'Custom language code "%s" for %s'
+            % (self.context.language_code, target_displayname)
+        )
 
 
 class CustomLanguageCodeRemoveView(LaunchpadFormView):
     """View for removing a `CustomLanguageCode`."""
+
     schema = ICustomLanguageCode
     field_names = []
 
@@ -157,23 +163,25 @@ class CustomLanguageCodeRemoveView(LaunchpadFormView):
         code = self.code
         self.context.translation_target.removeCustomLanguageCode(self.context)
         self.request.response.addInfoNotification(
-            "Removed custom language code '%s'." % code)
+            "Removed custom language code '%s'." % code
+        )
 
     @property
     def next_url(self):
         """See `LaunchpadFormView`."""
         return canonical_url(
-            self.context.translation_target, rootsite='translations',
-            view_name='+custom-language-codes')
+            self.context.translation_target,
+            rootsite="translations",
+            view_name="+custom-language-codes",
+        )
 
     cancel_url = next_url
 
 
 class HasCustomLanguageCodesTraversalMixin:
-    """Navigate from an `IHasCustomLanguageCodes` to a `CustomLanguageCode`.
-    """
+    """Navigate from an `IHasCustomLanguageCodes` to a `CustomLanguageCode`."""
 
-    @stepthrough('+customcode')
+    @stepthrough("+customcode")
     def traverseCustomCode(self, name):
         """Traverse +customcode URLs."""
         if not check_code(name):
@@ -182,7 +190,9 @@ class HasCustomLanguageCodesTraversalMixin:
         return self.context.getCustomLanguageCode(name)
 
 
-class HasCustomLanguageCodesNavigation(Navigation,
-                                       HasCustomLanguageCodesTraversalMixin):
+class HasCustomLanguageCodesNavigation(
+    Navigation, HasCustomLanguageCodesTraversalMixin
+):
     """Generic navigation for `IHasCustomLanguageCodes`."""
+
     usedfor = IHasCustomLanguageCodes
diff --git a/lib/lp/translations/browser/distribution.py b/lib/lp/translations/browser/distribution.py
index 550b010..6488042 100644
--- a/lib/lp/translations/browser/distribution.py
+++ b/lib/lp/translations/browser/distribution.py
@@ -4,27 +4,20 @@
 """Translations browser views for distributions."""
 
 __all__ = [
-    'DistributionLanguagePackAdminView',
-    'DistributionSettingsView',
-    'DistributionView',
-    ]
+    "DistributionLanguagePackAdminView",
+    "DistributionSettingsView",
+    "DistributionView",
+]
 
 import operator
 
-from lp.app.browser.launchpadform import (
-    action,
-    LaunchpadEditFormView,
-    )
+from lp.app.browser.launchpadform import LaunchpadEditFormView, action
 from lp.app.enums import service_uses_launchpad
 from lp.registry.browser import RegistryEditFormView
 from lp.registry.interfaces.distribution import IDistribution
 from lp.registry.interfaces.series import SeriesStatus
 from lp.services.propertycache import cachedproperty
-from lp.services.webapp import (
-    canonical_url,
-    enabled_with_permission,
-    Link,
-    )
+from lp.services.webapp import Link, canonical_url, enabled_with_permission
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.menu import NavigationMenu
 from lp.services.webapp.publisher import LaunchpadView
@@ -34,29 +27,32 @@ from lp.translations.browser.translations import TranslationsMixin
 class DistributionTranslationsMenu(NavigationMenu):
 
     usedfor = IDistribution
-    facet = 'translations'
-    links = ['overview', 'settings', 'language_pack_admin', 'imports']
+    facet = "translations"
+    links = ["overview", "settings", "language_pack_admin", "imports"]
 
     def overview(self):
-        text = 'Overview'
-        link = canonical_url(self.context, rootsite='translations')
+        text = "Overview"
+        link = canonical_url(self.context, rootsite="translations")
         return Link(link, text)
 
-    @enabled_with_permission('launchpad.TranslationsAdmin')
+    @enabled_with_permission("launchpad.TranslationsAdmin")
     def settings(self):
-        text = 'Configure translations'
-        return Link('+settings', text, icon='edit', site='translations')
+        text = "Configure translations"
+        return Link("+settings", text, icon="edit", site="translations")
 
-    @enabled_with_permission('launchpad.TranslationsAdmin')
+    @enabled_with_permission("launchpad.TranslationsAdmin")
     def language_pack_admin(self):
-        text = 'Language pack admin'
+        text = "Language pack admin"
         return Link(
-            '+select-language-pack-admin', text, icon='edit',
-            site='translations')
+            "+select-language-pack-admin",
+            text,
+            icon="edit",
+            site="translations",
+        )
 
     def imports(self):
-        text = 'Import queue'
-        return Link('+imports', text, site='translations')
+        text = "Import queue"
+        return Link("+imports", text, site="translations")
 
 
 class DistributionLanguagePackAdminView(LaunchpadEditFormView):
@@ -64,7 +60,7 @@ class DistributionLanguagePackAdminView(LaunchpadEditFormView):
 
     schema = IDistribution
     label = "Select the language pack administrator"
-    field_names = ['language_pack_admin']
+    field_names = ["language_pack_admin"]
 
     @property
     def cancel_url(self):
@@ -74,10 +70,11 @@ class DistributionLanguagePackAdminView(LaunchpadEditFormView):
 
     @property
     def page_title(self):
-        return 'Change the %s language pack administrator' % (
-            self.context.displayname)
+        return "Change the %s language pack administrator" % (
+            self.context.displayname
+        )
 
-    @action("Change", name='change')
+    @action("Change", name="change")
     def change_action(self, action, data):
         self.updateContextFromData(data)
 
@@ -101,8 +98,10 @@ class DistributionView(LaunchpadView):
     @cachedproperty
     def show_page_content(self):
         """Whether the main content of the page should be shown."""
-        return (service_uses_launchpad(self.context.translations_usage) or
-               self.is_translations_admin)
+        return (
+            service_uses_launchpad(self.context.translations_usage)
+            or self.is_translations_admin
+        )
 
     def can_configure_translations(self):
         """Whether or not the user can configure translations."""
@@ -120,12 +119,16 @@ class DistributionView(LaunchpadView):
         series = [
             series
             for series in self.context.series
-            if (series.status != SeriesStatus.OBSOLETE
-                and (self.translation_focus is None or
-                     self.translation_focus.id != series.id))]
+            if (
+                series.status != SeriesStatus.OBSOLETE
+                and (
+                    self.translation_focus is None
+                    or self.translation_focus.id != series.id
+                )
+            )
+        ]
 
-        return sorted(series, key=operator.attrgetter('version'),
-                      reverse=True)
+        return sorted(series, key=operator.attrgetter("version"), reverse=True)
 
 
 class DistributionSettingsView(TranslationsMixin, RegistryEditFormView):
@@ -138,7 +141,7 @@ class DistributionSettingsView(TranslationsMixin, RegistryEditFormView):
         "translation_focus",
         "translationgroup",
         "translationpermission",
-        ]
+    ]
 
     @property
     def cancel_url(self):
@@ -146,6 +149,6 @@ class DistributionSettingsView(TranslationsMixin, RegistryEditFormView):
 
     next_url = cancel_url
 
-    @action('Change', name='change')
+    @action("Change", name="change")
     def edit(self, action, data):
         self.updateContextFromData(data)
diff --git a/lib/lp/translations/browser/distributionsourcepackage.py b/lib/lp/translations/browser/distributionsourcepackage.py
index eb2aa65..3b6893c 100644
--- a/lib/lp/translations/browser/distributionsourcepackage.py
+++ b/lib/lp/translations/browser/distributionsourcepackage.py
@@ -4,8 +4,8 @@
 """Translations browser views for DistributionSourcePackages."""
 
 __all__ = [
-    'DistributionSourcePackageView',
-    ]
+    "DistributionSourcePackageView",
+]
 
 import operator
 
@@ -25,7 +25,8 @@ class DistributionSourcePackageView(LaunchpadView):
         """
         series = (
             self.context.distribution.translation_focus
-            or self.context.distribution.currentseries)
+            or self.context.distribution.currentseries
+        )
         if series is not None:
             return series.getSourcePackage(self.context.sourcepackagename)
 
@@ -37,9 +38,17 @@ class DistributionSourcePackageView(LaunchpadView):
         series = [
             series.getSourcePackage(self.context.sourcepackagename)
             for series in self.context.distribution.series
-            if (series.status != SeriesStatus.OBSOLETE
-                and (self.translation_focus is None or
-                     self.translation_focus.distroseries != series))]
-
-        return sorted(series, key=operator.attrgetter('distroseries.version'),
-                      reverse=True)
+            if (
+                series.status != SeriesStatus.OBSOLETE
+                and (
+                    self.translation_focus is None
+                    or self.translation_focus.distroseries != series
+                )
+            )
+        ]
+
+        return sorted(
+            series,
+            key=operator.attrgetter("distroseries.version"),
+            reverse=True,
+        )
diff --git a/lib/lp/translations/browser/distroseries.py b/lib/lp/translations/browser/distroseries.py
index 21bddf4..563d9b0 100644
--- a/lib/lp/translations/browser/distroseries.py
+++ b/lib/lp/translations/browser/distroseries.py
@@ -4,20 +4,17 @@
 """Translations view classes related to `IDistroSeries`."""
 
 __all__ = [
-    'DistroSeriesLanguagePackView',
-    'DistroSeriesTemplatesView',
-    'DistroSeriesTranslationsAdminView',
-    'DistroSeriesTranslationsMenu',
-    'DistroSeriesView',
-    'check_distroseries_translations_viewable',
-    ]
+    "DistroSeriesLanguagePackView",
+    "DistroSeriesTemplatesView",
+    "DistroSeriesTranslationsAdminView",
+    "DistroSeriesTranslationsMenu",
+    "DistroSeriesView",
+    "check_distroseries_translations_viewable",
+]
 
 from zope.component import getUtility
 
-from lp.app.browser.launchpadform import (
-    action,
-    LaunchpadEditFormView,
-    )
+from lp.app.browser.launchpadform import LaunchpadEditFormView, action
 from lp.app.enums import service_uses_launchpad
 from lp.app.errors import TranslationUnavailable
 from lp.registry.interfaces.distroseries import IDistroSeries
@@ -25,26 +22,23 @@ from lp.registry.interfaces.series import SeriesStatus
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.menu import (
-    enabled_with_permission,
     Link,
     NavigationMenu,
-    )
-from lp.services.webapp.publisher import (
-    canonical_url,
-    LaunchpadView,
-    )
+    enabled_with_permission,
+)
+from lp.services.webapp.publisher import LaunchpadView, canonical_url
 from lp.translations.browser.potemplate import BaseSeriesTemplatesView
 from lp.translations.browser.translations import TranslationsMixin
 from lp.translations.interfaces.distroserieslanguage import (
     IDistroSeriesLanguageSet,
-    )
+)
 
 
 class DistroSeriesTranslationsAdminView(LaunchpadEditFormView):
     schema = IDistroSeries
     page_title = "Settings"
     label = "Translation settings"
-    field_names = ['hide_all_translations', 'defer_translation_imports']
+    field_names = ["hide_all_translations", "defer_translation_imports"]
 
     @property
     def cancel_url(self):
@@ -56,11 +50,13 @@ class DistroSeriesTranslationsAdminView(LaunchpadEditFormView):
     def change_action(self, action, data):
         self.updateContextFromData(data)
         self.request.response.addInfoNotification(
-            'Your changes have been applied.')
+            "Your changes have been applied."
+        )
 
 
 class DistroSeriesLanguagePackView(LaunchpadEditFormView):
     """Browser view to manage used language packs."""
+
     schema = IDistroSeries
     label = "Language packs"
     page_title = "Language packs"
@@ -73,9 +69,9 @@ class DistroSeriesLanguagePackView(LaunchpadEditFormView):
 
         :returns: True if the user is a Language Pack Admin (but not a
             Rosetta admin)."""
-        return (check_permission("launchpad.LanguagePacksAdmin",
-                                 self.context) and not
-                check_permission("launchpad.TranslationsAdmin", self.context))
+        return check_permission(
+            "launchpad.LanguagePacksAdmin", self.context
+        ) and not check_permission("launchpad.TranslationsAdmin", self.context)
 
     def is_translations_admin(self, action=None):
         """Find out if the current user is a Rosetta Admin.
@@ -90,27 +86,30 @@ class DistroSeriesLanguagePackView(LaunchpadEditFormView):
 
     def initialize(self):
         self.old_request_value = (
-            self.context.language_pack_full_export_requested)
+            self.context.language_pack_full_export_requested
+        )
         if self.is_translations_admin():
             self.field_names = [
-                'language_pack_base',
-                'language_pack_delta',
-                'language_pack_proposed',
-                'language_pack_full_export_requested',
+                "language_pack_base",
+                "language_pack_delta",
+                "language_pack_proposed",
+                "language_pack_full_export_requested",
             ]
         elif self.is_langpack_admin():
-            self.field_names = ['language_pack_full_export_requested']
+            self.field_names = ["language_pack_full_export_requested"]
         else:
             self.field_names = []
         super().initialize()
-        self.displayname = '%s %s' % (
+        self.displayname = "%s %s" % (
             self.context.distribution.displayname,
-            self.context.version)
+            self.context.version,
+        )
         if self.is_langpack_admin():
-            self.adminlabel = 'Request a full language pack export of %s' % (
-                self.displayname)
+            self.adminlabel = "Request a full language pack export of %s" % (
+                self.displayname
+            )
         else:
-            self.adminlabel = 'Settings for language packs'
+            self.adminlabel = "Settings for language packs"
 
     @cachedproperty
     def unused_language_packs(self):
@@ -132,9 +131,11 @@ class DistroSeriesLanguagePackView(LaunchpadEditFormView):
 
         current = self.context.language_pack_base
         latest = self.context.last_full_language_pack_exported
-        if (current is None or
-            latest is None or
-            current.file.http_url == latest.file.http_url):
+        if (
+            current is None
+            or latest is None
+            or current.file.http_url == latest.file.http_url
+        ):
             return False
         else:
             return True
@@ -146,48 +147,57 @@ class DistroSeriesLanguagePackView(LaunchpadEditFormView):
 
         current = self.context.language_pack_delta
         latest = self.context.last_delta_language_pack_exported
-        if (current is None or
-            latest is None or
-            current.file.http_url == latest.file.http_url):
+        if (
+            current is None
+            or latest is None
+            or current.file.http_url == latest.file.http_url
+        ):
             return False
         else:
             return True
 
     def _request_full_export(self):
-        if (self.old_request_value !=
-            self.context.language_pack_full_export_requested):
+        if (
+            self.old_request_value
+            != self.context.language_pack_full_export_requested
+        ):
             # There are changes.
             if self.context.language_pack_full_export_requested:
                 self.request.response.addInfoNotification(
                     "Your request has been noted. Next language pack export "
-                    "will include all available translations.")
+                    "will include all available translations."
+                )
             else:
                 self.request.response.addInfoNotification(
                     "Your request has been noted. Next language pack "
                     "export will be made relative to the current base "
-                    "language pack.")
+                    "language pack."
+                )
 
     @action("Change Settings", condition=is_translations_admin)
     def change_action(self, action, data):
-        if ('language_pack_base' in data and
-            data['language_pack_base'] != self.context.language_pack_base):
+        if (
+            "language_pack_base" in data
+            and data["language_pack_base"] != self.context.language_pack_base
+        ):
             # language_pack_base changed, the delta one must be invalidated.
-            data['language_pack_delta'] = None
+            data["language_pack_delta"] = None
         self.updateContextFromData(data)
         self._request_full_export()
         self.request.response.addInfoNotification(
-            'Your changes have been applied.')
+            "Your changes have been applied."
+        )
         self.next_url = canonical_url(
-            self.context, rootsite='translations',
-            view_name='+language-packs')
+            self.context, rootsite="translations", view_name="+language-packs"
+        )
 
     @action("Request", condition=is_langpack_admin)
     def request_action(self, action, data):
         self.updateContextFromData(data)
         self._request_full_export()
         self.next_url = canonical_url(
-            self.context, rootsite='translations',
-            view_name='+language-packs')
+            self.context, rootsite="translations", view_name="+language-packs"
+        )
 
 
 class DistroSeriesTemplatesView(BaseSeriesTemplatesView):
@@ -198,8 +208,10 @@ class DistroSeriesTemplatesView(BaseSeriesTemplatesView):
 
     def constructTemplateURL(self, template):
         """See `BaseSeriesTemplatesView`."""
-        return '+source/%s/+pots/%s' % (
-            template.sourcepackagename.name, template.name)
+        return "+source/%s/+pots/%s" % (
+            template.sourcepackagename.name,
+            template.name,
+        )
 
 
 class DistroSeriesView(LaunchpadView, TranslationsMixin):
@@ -207,12 +219,13 @@ class DistroSeriesView(LaunchpadView, TranslationsMixin):
     label = "Translation status by language"
 
     def initialize(self):
-        self.displayname = '%s %s' % (
+        self.displayname = "%s %s" % (
             self.context.distribution.displayname,
-            self.context.version)
+            self.context.version,
+        )
 
     def checkTranslationsViewable(self):
-        """ Check if user can view translations for this `IDistroSeries`"""
+        """Check if user can view translations for this `IDistroSeries`"""
 
         # Is user allowed to see translations for this distroseries?
         # If not, raise TranslationUnavailable.
@@ -239,7 +252,8 @@ class DistroSeriesView(LaunchpadView, TranslationsMixin):
         for lang in self.translatable_languages:
             if lang not in existing_languages:
                 distroserieslang = distroserieslangset.getEmpty(
-                    self.context, lang)
+                    self.context, lang
+                )
                 distroserieslangs.append(distroserieslang)
 
         return sorted(distroserieslangs, key=lambda a: a.language.englishname)
@@ -247,7 +261,7 @@ class DistroSeriesView(LaunchpadView, TranslationsMixin):
     def isPreferredLanguage(self, language):
         # if there are no preferred languages, mark all
         # languages as preferred
-        if (len(self.translatable_languages) == 0):
+        if len(self.translatable_languages) == 0:
             return True
         else:
             return language in self.translatable_languages
@@ -264,8 +278,10 @@ class DistroSeriesView(LaunchpadView, TranslationsMixin):
     @cachedproperty
     def show_page_content(self):
         """Whether the main content of the page should be shown."""
-        return (service_uses_launchpad(self.context.translations_usage) or
-               self.is_translations_admin)
+        return (
+            service_uses_launchpad(self.context.translations_usage)
+            or self.is_translations_admin
+        )
 
     def can_configure_translations(self):
         """Whether or not the user can configure translations."""
@@ -279,39 +295,47 @@ class DistroSeriesView(LaunchpadView, TranslationsMixin):
 class DistroSeriesTranslationsMenu(NavigationMenu):
 
     usedfor = IDistroSeries
-    facet = 'translations'
+    facet = "translations"
     links = [
-        'translations', 'templates', 'admin', 'language_packs',
-        'latest_full_language_pack', 'latest_delta_language_pack', 'imports']
+        "translations",
+        "templates",
+        "admin",
+        "language_packs",
+        "latest_full_language_pack",
+        "latest_delta_language_pack",
+        "imports",
+    ]
 
     def translations(self):
-        return Link('', 'Overview', site='translations')
+        return Link("", "Overview", site="translations")
 
     def imports(self):
-        return Link('+imports', 'Import queue', site='translations')
+        return Link("+imports", "Import queue", site="translations")
 
-    @enabled_with_permission('launchpad.TranslationsAdmin')
+    @enabled_with_permission("launchpad.TranslationsAdmin")
     def admin(self):
-        return Link('+translations-admin', 'Settings', site='translations')
+        return Link("+translations-admin", "Settings", site="translations")
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def templates(self):
-        return Link('+templates', 'Templates', site='translations')
+        return Link("+templates", "Templates", site="translations")
 
     def language_packs(self):
-        return Link('+language-packs', 'Language packs', site='translations')
+        return Link("+language-packs", "Language packs", site="translations")
 
     def latest_full_language_pack(self):
         return Link(
-            '+latest-full-language-pack',
-            'Latest full language pack',
-            site='translations')
+            "+latest-full-language-pack",
+            "Latest full language pack",
+            site="translations",
+        )
 
     def latest_delta_language_pack(self):
         return Link(
-            '+latest-delta-language-pack',
-            'Latest delta language pack',
-            site='translations')
+            "+latest-delta-language-pack",
+            "Latest delta language pack",
+            site="translations",
+        )
 
 
 def check_distroseries_translations_viewable(distroseries):
@@ -336,23 +360,25 @@ def check_distroseries_translations_viewable(distroseries):
         # Yup, viewable.
         return
 
-    if check_permission(
-        'launchpad.TranslationsAdmin', distroseries):
+    if check_permission("launchpad.TranslationsAdmin", distroseries):
         return
 
     future = [
         SeriesStatus.EXPERIMENTAL,
         SeriesStatus.DEVELOPMENT,
         SeriesStatus.FUTURE,
-        ]
+    ]
     if distroseries.status in future:
         raise TranslationUnavailable(
-            "Translations for this release series are not available yet.")
+            "Translations for this release series are not available yet."
+        )
     elif distroseries.status == SeriesStatus.OBSOLETE:
         raise TranslationUnavailable(
             "This release series is obsolete.  Its translations are no "
-            "longer available.")
+            "longer available."
+        )
     else:
         raise TranslationUnavailable(
             "Translations for this release series are not currently "
-            "available.  Please come back soon.")
+            "available.  Please come back soon."
+        )
diff --git a/lib/lp/translations/browser/hastranslationimports.py b/lib/lp/translations/browser/hastranslationimports.py
index cdcf5f8..c86d1c3 100644
--- a/lib/lp/translations/browser/hastranslationimports.py
+++ b/lib/lp/translations/browser/hastranslationimports.py
@@ -4,8 +4,8 @@
 """Browser view for IHasTranslationImports."""
 
 __all__ = [
-    'HasTranslationImportsView',
-    ]
+    "HasTranslationImportsView",
+]
 
 import datetime
 
@@ -19,17 +19,10 @@ from zope.formlib.widgets import DropdownWidget
 from zope.interface import implementer
 from zope.schema import Choice
 from zope.schema.interfaces import IContextSourceBinder
-from zope.schema.vocabulary import (
-    SimpleTerm,
-    SimpleVocabulary,
-    )
+from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
 
 from lp import _
-from lp.app.browser.launchpadform import (
-    action,
-    LaunchpadFormView,
-    safe_action,
-    )
+from lp.app.browser.launchpadform import LaunchpadFormView, action, safe_action
 from lp.app.browser.lazrjs import vocabulary_to_choice_edit_items
 from lp.app.errors import UnexpectedFormData
 from lp.registry.interfaces.distribution import IDistribution
@@ -41,29 +34,35 @@ from lp.services.webapp.vocabulary import ForgivingSimpleVocabulary
 from lp.translations.enums import RosettaImportStatus
 from lp.translations.interfaces.hastranslationimports import (
     IHasTranslationImports,
-    )
+)
 from lp.translations.interfaces.translationimportqueue import (
     ITranslationImportQueue,
     SpecialTranslationImportTargetFilter,
-    )
+)
 
 
 class HasTranslationImportsView(LaunchpadFormView):
     """View class used for objects with translation imports."""
+
     schema = IHasTranslationImports
     field_names = []
 
     custom_widget_filter_target = CustomWidgetFactory(
-        DropdownWidget, cssClass='inlined-widget')
+        DropdownWidget, cssClass="inlined-widget"
+    )
     custom_widget_filter_status = CustomWidgetFactory(
-        DropdownWidget, cssClass='inlined-widget')
+        DropdownWidget, cssClass="inlined-widget"
+    )
     custom_widget_filter_extension = CustomWidgetFactory(
-        DropdownWidget, cssClass='inlined-widget')
+        DropdownWidget, cssClass="inlined-widget"
+    )
     custom_widget_status = CustomWidgetFactory(
-        DropdownWidget, cssClass='inlined-widget')
+        DropdownWidget, cssClass="inlined-widget"
+    )
 
     translation_import_queue_macros = ViewPageTemplateFile(
-        '../templates/translation-import-queue-macros.pt')
+        "../templates/translation-import-queue-macros.pt"
+    )
 
     page_title = "Import queue"
 
@@ -83,14 +82,12 @@ class HasTranslationImportsView(LaunchpadFormView):
 
     def createFilterFieldHelper(self, name, source, title):
         """A helper method for creating filter fields."""
-        self._initial_values[name] = 'all'
+        self._initial_values[name] = "all"
         return form.Fields(
-            Choice(
-                __name__=name,
-                source=source,
-                title=_(title)),
-            custom_widget=getattr(self, 'custom_widget_%s' % name),
-            render_context=self.render_context)
+            Choice(__name__=name, source=source, title=_(title)),
+            custom_widget=getattr(self, "custom_widget_%s" % name),
+            render_context=self.render_context,
+        )
 
     def createFilterStatusField(self):
         """Create a field with a vocabulary to filter by import status.
@@ -98,9 +95,10 @@ class HasTranslationImportsView(LaunchpadFormView):
         :return: A form.Fields instance containing the status field.
         """
         return self.createFilterFieldHelper(
-            name='filter_status',
+            name="filter_status",
             source=TranslationImportStatusVocabularyFactory(),
-            title='Choose which status to show')
+            title="Choose which status to show",
+        )
 
     def createFilterFileExtensionField(self):
         """Create a field with a vocabulary to filter by file extension.
@@ -108,9 +106,10 @@ class HasTranslationImportsView(LaunchpadFormView):
         :return: A form.Fields instance containing the file extension field.
         """
         return self.createFilterFieldHelper(
-            name='filter_extension',
+            name="filter_extension",
             source=TranslationImportFileExtensionVocabularyFactory(),
-            title='Show entries with this extension')
+            title="Show entries with this extension",
+        )
 
     def createFilterTargetField(self):
         """Create a field with a vocabulary to filter by target.
@@ -126,15 +125,17 @@ class HasTranslationImportsView(LaunchpadFormView):
 
         :return: A form.Fields instance containing the status field.
         """
-        name = 'status_%d' % entry.id
+        name = "status_%d" % entry.id
         self._initial_values[name] = entry.status.name
         return form.Fields(
             Choice(
                 __name__=name,
                 source=EntryImportStatusVocabularyFactory(entry, self.user),
-                title=_('Select import status')),
+                title=_("Select import status"),
+            ),
             custom_widget=self.custom_widget_status,
-            render_context=self.render_context)
+            render_context=self.render_context,
+        )
 
     def setUpFields(self):
         """See `LaunchpadFormView`."""
@@ -142,12 +143,13 @@ class HasTranslationImportsView(LaunchpadFormView):
         # setup filter fields.
         target_field = self.createFilterTargetField()
         if target_field is not None:
-            self.form_fields = (target_field + self.form_fields)
+            self.form_fields = target_field + self.form_fields
 
         self.form_fields = (
-            self.createFilterStatusField() +
-            self.createFilterFileExtensionField() +
-            self.form_fields)
+            self.createFilterStatusField()
+            + self.createFilterFileExtensionField()
+            + self.form_fields
+        )
 
     def setUpWidgets(self):
         """See `LaunchpadFormView`."""
@@ -155,12 +157,21 @@ class HasTranslationImportsView(LaunchpadFormView):
         # filter_status widget.  Set up the widgets in two phases to make this
         # possible.
         self.widgets = form.setUpWidgets(
-            self.form_fields.select('filter_status'), self.prefix,
-            self.context, self.request, data=self.initial_values,
-            ignore_request=False)
+            self.form_fields.select("filter_status"),
+            self.prefix,
+            self.context,
+            self.request,
+            data=self.initial_values,
+            ignore_request=False,
+        )
         self.widgets += form.setUpWidgets(
-            self.form_fields.omit('filter_status'), self.prefix, self.context,
-            self.request, data=self.initial_values, ignore_request=False)
+            self.form_fields.omit("filter_status"),
+            self.prefix,
+            self.context,
+            self.request,
+            data=self.initial_values,
+            ignore_request=False,
+        )
 
         if not self.filter_action.submitted():
             self.setUpEntriesWidgets()
@@ -175,37 +186,47 @@ class HasTranslationImportsView(LaunchpadFormView):
             self.form_fields += fields
 
             self.widgets += form.setUpWidgets(
-                fields, self.prefix, self.context, self.request,
-                data=self.initial_values, ignore_request=False)
+                fields,
+                self.prefix,
+                self.context,
+                self.request,
+                data=self.initial_values,
+                ignore_request=False,
+            )
 
     @safe_action
-    @action('Filter', name='filter')
+    @action("Filter", name="filter")
     def filter_action(self, action, data):
         """Handle a filter action."""
-        target_option = ''
+        target_option = ""
         if self.has_target_filter:
-            target_option = 'field.filter_target=%s&' % (
-                self.widgets['filter_target'].getInputValue())
+            target_option = "field.filter_target=%s&" % (
+                self.widgets["filter_target"].getInputValue()
+            )
 
         # Redirect to the filtered URL.
         self.next_url = (
-            '%s?%sfield.filter_status=%s&field.filter_extension=%s' % (
+            "%s?%sfield.filter_status=%s&field.filter_extension=%s"
+            % (
                 self.request.URL,
                 target_option,
-                self.widgets['filter_status'].getInputValue(),
-                self.widgets['filter_extension'].getInputValue()))
+                self.widgets["filter_status"].getInputValue(),
+                self.widgets["filter_extension"].getInputValue(),
+            )
+        )
 
-    @action("Change status", name='change_status')
+    @action("Change status", name="change_status")
     def change_status_action(self, action, data):
         """Handle a queue submission changing the status of its entries."""
         # The user must be logged in.
         if self.user is None:
             raise UnexpectedFormData(
-                'Users not logged cannot submit this form.')
+                "Users not logged cannot submit this form."
+            )
 
         number_of_changes = 0
         for form_item in data:
-            if not form_item.startswith('status_'):
+            if not form_item.startswith("status_"):
                 # We are not interested on this form_item.
                 continue
 
@@ -213,7 +234,7 @@ class HasTranslationImportsView(LaunchpadFormView):
             try:
                 # 'ignored' is 'status' due to the previous check, so we could
                 # ignore that part.
-                ignored, id_string = form_item.split('_')
+                ignored, id_string = form_item.split("_")
                 # The id is an integer
                 id = int(id_string)
             except ValueError:
@@ -222,7 +243,8 @@ class HasTranslationImportsView(LaunchpadFormView):
                 # badly with our system so it's safe to just ignore the
                 # request.
                 raise UnexpectedFormData(
-                    'Ignored your request because it is broken.')
+                    "Ignored your request because it is broken."
+                )
             # Get the entry we are working on.
             import_queue_set = getUtility(ITranslationImportQueue)
             entry = import_queue_set.get(id)
@@ -245,36 +267,39 @@ class HasTranslationImportsView(LaunchpadFormView):
                 # We are trying to set a bogus status.
                 # That means that it's a broken request.
                 raise UnexpectedFormData(
-                    'Ignored the request to change the status from %s to %s.'
-                        % (entry.status.name, new_status_name))
+                    "Ignored the request to change the status from %s to %s."
+                    % (entry.status.name, new_status_name)
+                )
             else:
                 # This will raise an exception if the user is not authorized.
                 entry.setStatus(new_status, self.user)
 
             # Update the date_status_change field.
-            UTC = pytz.timezone('UTC')
+            UTC = pytz.timezone("UTC")
             entry.date_status_changed = datetime.datetime.now(UTC)
 
         if number_of_changes == 0:
             self.request.response.addWarningNotification(
                 "Ignored your status change request as you didn't select any"
-                " change.")
+                " change."
+            )
         else:
             self.request.response.addInfoNotification(
-                "Changed the status of %d queue entries." % number_of_changes)
+                "Changed the status of %d queue entries." % number_of_changes
+            )
 
     def getEntriesFilteringOptions(self):
         """Return the selected filtering."""
         target = None
         file_extension = None
         status = None
-        target_widget = self.widgets.get('filter_target')
+        target_widget = self.widgets.get("filter_target")
         if target_widget is not None and target_widget.hasValidInput():
             target = target_widget.getInputValue()
             pillar_name_set = getUtility(IPillarNameSet)
-            if target == 'all':
+            if target == "all":
                 target = None
-            elif target.startswith('[') and target.endswith(']'):
+            elif target.startswith("[") and target.endswith("]"):
                 # This is a SpecialTranslationImportTargetFilter.
                 target_code = target[1:-1]
                 target = None
@@ -284,29 +309,31 @@ class HasTranslationImportsView(LaunchpadFormView):
 
                 if target is None:
                     raise UnexpectedFormData(
-                        "Got a bad special target option: %s" % target)
+                        "Got a bad special target option: %s" % target
+                    )
 
-            elif '/' in target:
+            elif "/" in target:
                 # It's a distroseries, for them we have
                 # 'distribution.name/distroseries.name' to identify it.
-                distribution_name, distroseries_name = target.split('/', 1)
+                distribution_name, distroseries_name = target.split("/", 1)
                 pillar = pillar_name_set.getByName(distribution_name)
                 if IDistribution.providedBy(pillar):
                     target = pillar.getSeries(distroseries_name)
                 else:
                     raise UnexpectedFormData(
-                        "Got a bad target option %s" % target)
+                        "Got a bad target option %s" % target
+                    )
             else:
                 target = pillar_name_set.getByName(target)
-        filter_extension_widget = self.widgets.get('filter_extension')
+        filter_extension_widget = self.widgets.get("filter_extension")
         if filter_extension_widget.hasValidInput():
             file_extension = filter_extension_widget.getInputValue()
-            if file_extension == 'all':
+            if file_extension == "all":
                 file_extension = None
-        filter_status_widget = self.widgets.get('filter_status')
+        filter_status_widget = self.widgets.get("filter_status")
         if filter_status_widget.hasValidInput():
             status = filter_status_widget.getInputValue()
-            if status == 'all':
+            if status == "all":
                 status = None
             else:
                 status = RosettaImportStatus.items[status]
@@ -316,23 +343,26 @@ class HasTranslationImportsView(LaunchpadFormView):
     def translation_import_queue_content(self):
         """Macro displaying the import queue content."""
         macros = self.translation_import_queue_macros.macros
-        return macros['translation-import-queue-content']
+        return macros["translation-import-queue-content"]
 
     @property
     def entries(self):
         """Return the entries in the queue for this context."""
         target, file_extension, status = self.getEntriesFilteringOptions()
-        assert target is None, (
-            'Inherit from this view class if target filter is being used.')
+        assert (
+            target is None
+        ), "Inherit from this view class if target filter is being used."
 
         return IHasTranslationImports(
-            self.context).getTranslationImportQueueEntries(
-                import_status=status, file_extension=file_extension)
+            self.context
+        ).getTranslationImportQueueEntries(
+            import_status=status, file_extension=file_extension
+        )
 
     @property
     def has_target_filter(self):
         """Whether the form should show the target filter."""
-        return self.widgets.get('filter_target') is not None
+        return self.widgets.get("filter_target") is not None
 
     @cachedproperty
     def batchnav(self):
@@ -341,26 +371,28 @@ class HasTranslationImportsView(LaunchpadFormView):
 
     @property
     def choice_confs_js(self):
-        """"Generate configuration for lazr-js widget.
+        """ "Generate configuration for lazr-js widget.
 
         Only editable items are included in the list.
         """
         confs = []
         for entry in self.batchnav.batch:
-            if check_permission('launchpad.Edit', entry):
+            if check_permission("launchpad.Edit", entry):
                 confs.append(self.generateChoiceConfForEntry(entry))
-        return 'var choice_confs = %s;' % simplejson.dumps(confs)
+        return "var choice_confs = %s;" % simplejson.dumps(confs)
 
     def generateChoiceConfForEntry(self, entry):
         disabled_items = [
-            item.value for item in RosettaImportStatus
-                       if not entry.canSetStatus(item.value, self.user)]
+            item.value
+            for item in RosettaImportStatus
+            if not entry.canSetStatus(item.value, self.user)
+        ]
         items = vocabulary_to_choice_edit_items(
-                RosettaImportStatus, disabled_items=disabled_items,
-                css_class_prefix='translationimportstatus')
-        return {
-            'value': entry.status.title,
-            'items': items}
+            RosettaImportStatus,
+            disabled_items=disabled_items,
+            css_class_prefix="translationimportstatus",
+        )
+        return {"value": entry.status.title, "items": items}
 
 
 @implementer(IContextSourceBinder)
@@ -379,10 +411,12 @@ class EntryImportStatusVocabularyFactory:
     def __call__(self, context):
         terms = []
         for status in RosettaImportStatus.items:
-            if (status == self.entry.status or
-                self.entry.canSetStatus(status, self.user)):
+            if status == self.entry.status or self.entry.canSetStatus(
+                status, self.user
+            ):
                 terms.append(
-                    SimpleTerm(status.name, status.name, status.title))
+                    SimpleTerm(status.name, status.name, status.title)
+                )
         return SimpleVocabulary(terms)
 
 
@@ -391,7 +425,7 @@ class TranslationImportStatusVocabularyFactory:
     """Factory for a vocabulary containing a list of import statuses."""
 
     def __call__(self, context):
-        terms = [SimpleTerm('all', 'all', 'All statuses')]
+        terms = [SimpleTerm("all", "all", "All statuses")]
         for status in RosettaImportStatus.items:
             terms.append(SimpleTerm(status.name, status.name, status.title))
         return SimpleVocabulary(terms)
@@ -402,11 +436,11 @@ class TranslationImportFileExtensionVocabularyFactory:
     """Factory for a vocabulary containing a list of available extensions."""
 
     def __call__(self, context):
-        file_extensions = ('po', 'pot')
-        all_files = SimpleTerm('all', 'all', 'All files')
+        file_extensions = ("po", "pot")
+        all_files = SimpleTerm("all", "all", "All files")
         terms = [all_files]
         for extension in file_extensions:
-            title = 'Only %s files' % extension
+            title = "Only %s files" % extension
             terms.append(SimpleTerm(extension, extension, title))
 
         # We use a ForgivingSimpleVocabulary because we don't care if a user
diff --git a/lib/lp/translations/browser/language.py b/lib/lp/translations/browser/language.py
index 918b7ed..7a0b15a 100644
--- a/lib/lp/translations/browser/language.py
+++ b/lib/lp/translations/browser/language.py
@@ -4,14 +4,14 @@
 """Browser code for Language table."""
 
 __all__ = [
-    'LanguageAddView',
-    'LanguageAdminView',
-    'LanguageSetBreadcrumb',
-    'LanguageSetContextMenu',
-    'LanguageSetNavigation',
-    'LanguageSetView',
-    'LanguageView',
-    ]
+    "LanguageAddView",
+    "LanguageAdminView",
+    "LanguageSetBreadcrumb",
+    "LanguageSetContextMenu",
+    "LanguageSetNavigation",
+    "LanguageSetView",
+    "LanguageView",
+]
 
 from zope.component import getUtility
 from zope.event import notify
@@ -22,34 +22,31 @@ from zope.lifecycleevent import ObjectCreatedEvent
 from zope.schema import TextLine
 
 from lp.app.browser.launchpadform import (
-    action,
     LaunchpadEditFormView,
     LaunchpadFormView,
-    )
+    action,
+)
 from lp.app.browser.tales import LanguageFormatterAPI
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.app.widgets.itemswidgets import LabeledMultiCheckBoxWidget
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp import (
-    canonical_url,
     ContextMenu,
-    enabled_with_permission,
     GetitemNavigation,
     LaunchpadView,
     Link,
     NavigationMenu,
-    )
+    canonical_url,
+    enabled_with_permission,
+)
 from lp.services.webapp.breadcrumb import Breadcrumb
-from lp.services.worlddata.interfaces.language import (
-    ILanguage,
-    ILanguageSet,
-    )
+from lp.services.worlddata.interfaces.language import ILanguage, ILanguageSet
 from lp.translations.browser.translations import TranslationsMixin
 from lp.translations.interfaces.translationsperson import ITranslationsPerson
 from lp.translations.utilities.pluralforms import (
     BadPluralExpression,
     make_friendly_plural_forms,
-    )
+)
 
 
 def describe_language(language):
@@ -75,28 +72,29 @@ class LanguageSetNavigation(GetitemNavigation):
 
 class LanguageSetBreadcrumb(Breadcrumb):
     """`Breadcrumb` for `ILanguageSet`."""
+
     text = "Languages"
 
 
 class LanguageSetContextMenu(ContextMenu):
     usedfor = ILanguageSet
-    links = ['add']
+    links = ["add"]
 
-    @enabled_with_permission('launchpad.Admin')
+    @enabled_with_permission("launchpad.Admin")
     def add(self):
-        text = 'Add Language'
-        return Link('+add', text, icon='add')
+        text = "Add Language"
+        return Link("+add", text, icon="add")
 
 
 class LanguageNavigationMenu(NavigationMenu):
     usedfor = ILanguage
-    facet = 'translations'
-    links = ['administer']
+    facet = "translations"
+    links = ["administer"]
 
-    @enabled_with_permission('launchpad.Admin')
+    @enabled_with_permission("launchpad.Admin")
     def administer(self):
-        text = 'Administer'
-        return Link('+admin', text, icon='edit')
+        text = "Administer"
+        return Link("+admin", text, icon="edit")
 
 
 def _format_language(language):
@@ -108,19 +106,21 @@ class ILanguageSetSearch(Interface):
     """The collection of languages."""
 
     search_lang = TextLine(
-        title='Name of the language to search for.',
-        required=True)
+        title="Name of the language to search for.", required=True
+    )
 
 
 class LanguageSetView(LaunchpadFormView):
     """View class to render main ILanguageSet page."""
+
     label = "Languages in Launchpad"
     page_title = "Languages"
 
     schema = ILanguageSetSearch
 
     custom_widget_search_lang = CustomWidgetFactory(
-        TextWidget, displayWidth=30)
+        TextWidget, displayWidth=30
+    )
 
     def initialize(self):
         """See `LaunchpadFormView`."""
@@ -128,9 +128,11 @@ class LanguageSetView(LaunchpadFormView):
 
         self.language_search = None
 
-        search_lang_widget = self.widgets.get('search_lang')
-        if (search_lang_widget is not None and
-            search_lang_widget.hasValidInput()):
+        search_lang_widget = self.widgets.get("search_lang")
+        if (
+            search_lang_widget is not None
+            and search_lang_widget.hasValidInput()
+        ):
             self.language_search = search_lang_widget.getInputValue()
         self.search_requested = self.language_search is not None
 
@@ -157,28 +159,36 @@ class LanguageSetView(LaunchpadFormView):
 class LanguageAddView(LaunchpadFormView):
     """View to handle ILanguage creation form."""
 
-    rootsite = 'translations'
+    rootsite = "translations"
 
     schema = ILanguage
-    field_names = ['code', 'englishname', 'nativename', 'pluralforms',
-                   'pluralexpression', 'visible', 'direction']
+    field_names = [
+        "code",
+        "englishname",
+        "nativename",
+        "pluralforms",
+        "pluralexpression",
+        "visible",
+        "direction",
+    ]
     invariant_context = None
     language = None
 
     page_title = "Register a language"
     label = "Register a language in Launchpad"
 
-    @action('Add', name='add')
+    @action("Add", name="add")
     def add_action(self, action, data):
         """Create the new Language from the form details."""
         self.language = getUtility(ILanguageSet).createLanguage(
-            code=data['code'],
-            englishname=data['englishname'],
-            nativename=data['nativename'],
-            pluralforms=data['pluralforms'],
-            pluralexpression=data['pluralexpression'],
-            visible=data['visible'],
-            direction=data['direction'])
+            code=data["code"],
+            englishname=data["englishname"],
+            nativename=data["nativename"],
+            pluralforms=data["pluralforms"],
+            pluralexpression=data["pluralexpression"],
+            visible=data["visible"],
+            direction=data["direction"],
+        )
         notify(ObjectCreatedEvent(self.language))
 
     @property
@@ -188,17 +198,18 @@ class LanguageAddView(LaunchpadFormView):
 
     @property
     def next_url(self):
-        assert self.language is not None, 'No language has been created'
+        assert self.language is not None, "No language has been created"
         return canonical_url(self.language, rootsite=self.rootsite)
 
     def validate(self, data):
         # XXX CarlosPerelloMarin 2007-04-04 bug=102898:
         # Pluralform expression should be validated.
-        new_code = data.get('code')
+        new_code = data.get("code")
         language_set = getUtility(ILanguageSet)
         if language_set.getLanguageByCode(new_code) is not None:
             self.setFieldError(
-                'code', 'There is already a language with that code.')
+                "code", "There is already a language with that code."
+            )
 
 
 class LanguageView(TranslationsMixin, LaunchpadView):
@@ -221,11 +232,14 @@ class LanguageView(TranslationsMixin, LaunchpadView):
         translation_teams = []
         for translation_team in self.context.translation_teams:
             # translation_team would be either a person or a team.
-            translation_teams.append({
-                'expert': translation_team,
-                'groups': ITranslationsPerson(
-                    translation_team).translation_groups,
-                })
+            translation_teams.append(
+                {
+                    "expert": translation_team,
+                    "groups": ITranslationsPerson(
+                        translation_team
+                    ).translation_groups,
+                }
+            )
         return translation_teams
 
     @property
@@ -239,7 +253,7 @@ class LanguageView(TranslationsMixin, LaunchpadView):
         top_translators = []
         for translator in self.context.translators[:30]:
             # Get only the top 20 contributors
-            if (len(top_translators) >= 20):
+            if len(top_translators) >= 20:
                 break
 
             # For merged account add the target account
@@ -263,15 +277,16 @@ class LanguageView(TranslationsMixin, LaunchpadView):
         comma separated list to be displayed.
         """
         pluralforms_list = make_friendly_plural_forms(
-                self.context.pluralexpression, self.context.pluralforms)
+            self.context.pluralexpression, self.context.pluralforms
+        )
 
         for item in pluralforms_list:
-            examples = ", ".join(map(str, item['examples']))
-            if len(item['examples']) != 1:
+            examples = ", ".join(map(str, item["examples"]))
+            if len(item["examples"]) != 1:
                 examples += "..."
             else:
                 examples += "."
-            item['examples'] = examples
+            item["examples"] = examples
 
         return pluralforms_list
 
@@ -279,23 +294,31 @@ class LanguageView(TranslationsMixin, LaunchpadView):
     def add_question_url(self):
         launchpad = getUtility(ILaunchpadCelebrities).launchpad
         return canonical_url(
-            launchpad,
-            view_name='+addquestion',
-            rootsite='answers')
+            launchpad, view_name="+addquestion", rootsite="answers"
+        )
 
 
 class LanguageAdminView(LaunchpadEditFormView):
     """Handle an admin form submission."""
 
-    rootsite = 'translations'
+    rootsite = "translations"
 
     schema = ILanguage
 
     custom_widget_countries = CustomWidgetFactory(
-        LabeledMultiCheckBoxWidget, orientation='vertical')
+        LabeledMultiCheckBoxWidget, orientation="vertical"
+    )
 
-    field_names = ['code', 'englishname', 'nativename', 'pluralforms',
-                   'pluralexpression', 'visible', 'direction', 'countries']
+    field_names = [
+        "code",
+        "englishname",
+        "nativename",
+        "pluralforms",
+        "pluralexpression",
+        "visible",
+        "direction",
+        "countries",
+    ]
 
     page_title = "Change details"
 
@@ -322,21 +345,22 @@ class LanguageAdminView(LaunchpadEditFormView):
         language_set = getUtility(ILanguageSet)
         if language_set.getLanguageByCode(new_code) is not None:
             self.setFieldError(
-                'code', 'There is already a language with that code.')
+                "code", "There is already a language with that code."
+            )
 
     def _validatePluralData(self, pluralforms, pluralexpression):
         """Validate plural expression and number of plural forms."""
         try:
             make_friendly_plural_forms(pluralexpression, pluralforms)
         except BadPluralExpression as e:
-            self.setFieldError('pluralexpression', str(e))
+            self.setFieldError("pluralexpression", str(e))
 
     def validate(self, data):
-        new_code = data.get('code')
+        new_code = data.get("code")
         if new_code != self.context.code:
             self._validateCode(new_code)
 
-        pluralexpression = data.get('pluralexpression')
-        pluralforms = data.get('pluralforms')
+        pluralexpression = data.get("pluralexpression")
+        pluralforms = data.get("pluralforms")
         if pluralexpression is not None:
             self._validatePluralData(pluralforms, pluralexpression)
diff --git a/lib/lp/translations/browser/person.py b/lib/lp/translations/browser/person.py
index ec90dde..12e0c34 100644
--- a/lib/lp/translations/browser/person.py
+++ b/lib/lp/translations/browser/person.py
@@ -4,15 +4,12 @@
 """Person-related translations view classes."""
 
 __all__ = [
-    'PersonTranslationView',
-    'PersonTranslationRelicensingView',
-    'TranslationActivityView',
+    "PersonTranslationView",
+    "PersonTranslationRelicensingView",
+    "TranslationActivityView",
 ]
 
-from datetime import (
-    datetime,
-    timedelta,
-    )
+from datetime import datetime, timedelta
 from itertools import islice
 from urllib.parse import urlencode
 
@@ -21,24 +18,15 @@ from zope.browserpage import ViewPageTemplateFile
 from zope.component import getUtility
 from zope.formlib.widget import CustomWidgetFactory
 from zope.formlib.widgets import TextWidget
-from zope.interface import (
-    implementer,
-    Interface,
-    )
+from zope.interface import Interface, implementer
 
 from lp import _
-from lp.app.browser.launchpadform import (
-    action,
-    LaunchpadFormView,
-    )
+from lp.app.browser.launchpadform import LaunchpadFormView, action
 from lp.app.enums import ServiceUsage
 from lp.app.widgets.itemswidgets import LaunchpadRadioWidget
 from lp.registry.interfaces.sourcepackage import ISourcePackage
 from lp.services.propertycache import cachedproperty
-from lp.services.webapp import (
-    canonical_url,
-    Link,
-    )
+from lp.services.webapp import Link, canonical_url
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.batching import BatchNavigator
 from lp.services.webapp.interfaces import ILaunchBag
@@ -46,12 +34,12 @@ from lp.services.webapp.menu import NavigationMenu
 from lp.services.webapp.publisher import LaunchpadView
 from lp.translations.browser.translationlinksaggregator import (
     TranslationLinksAggregator,
-    )
+)
 from lp.translations.interfaces.pofiletranslator import IPOFileTranslatorSet
 from lp.translations.interfaces.translationrelicensingagreement import (
     ITranslationRelicensingAgreementEdit,
     TranslationRelicensingAgreementOptions,
-    )
+)
 from lp.translations.interfaces.translationsperson import ITranslationsPerson
 
 
@@ -68,9 +56,9 @@ class WorkListLinksAggregator(TranslationLinksAggregator):
     def describe(self, target, link, covered_files):
         """See `TranslationLinksAggregator.describe`."""
         strings_count = sum(
-            self.countStrings(pofile) for pofile in covered_files)
-        languages = {
-            pofile.language.englishname for pofile in covered_files}
+            self.countStrings(pofile) for pofile in covered_files
+        )
+        languages = {pofile.language.englishname for pofile in covered_files}
         languages_list = ", ".join(sorted(languages))
 
         if strings_count == 1:
@@ -79,19 +67,20 @@ class WorkListLinksAggregator(TranslationLinksAggregator):
             strings_wording = "%d strings"
 
         return {
-            'target': target,
-            'count': strings_count,
-            'count_wording': strings_wording % strings_count,
-            'is_product': not ISourcePackage.providedBy(target),
-            'link': link,
-            'languages': languages_list,
+            "target": target,
+            "count": strings_count,
+            "count_wording": strings_wording % strings_count,
+            "is_product": not ISourcePackage.providedBy(target),
+            "link": link,
+            "languages": languages_list,
         }
 
 
 class ReviewLinksAggregator(WorkListLinksAggregator):
     """A `TranslationLinksAggregator` for translations to review."""
+
     # Link to unreviewed suggestions.
-    pofile_link_suffix = '/+translate?show=new_suggestions'
+    pofile_link_suffix = "/+translate?show=new_suggestions"
 
     # Strings that need work are ones with unreviewed suggestions.
     def countStrings(self, pofile):
@@ -101,8 +90,9 @@ class ReviewLinksAggregator(WorkListLinksAggregator):
 
 class TranslateLinksAggregator(WorkListLinksAggregator):
     """A `TranslationLinksAggregator` for translations to complete."""
+
     # Link to untranslated strings.
-    pofile_link_suffix = '/+translate?show=untranslated'
+    pofile_link_suffix = "/+translate?show=untranslated"
 
     # Strings that need work are untranslated ones.
     def countStrings(self, pofile):
@@ -112,7 +102,7 @@ class TranslateLinksAggregator(WorkListLinksAggregator):
 
 def compose_pofile_filter_url(pofile, person):
     """Compose URL for `Person`'s contributions to `POFile`."""
-    person_name = urlencode({'person': person.name})
+    person_name = urlencode({"person": person.name})
     return canonical_url(pofile) + "/+filter?%s" % person_name
 
 
@@ -132,8 +122,9 @@ class ActivityDescriptor:
         """
         assert person == pofiletranslator.person, (
             "Got POFileTranslator record for user %s "
-            "while listing activity for %s." % (
-                person.name, pofiletranslator.person.name))
+            "while listing activity for %s."
+            % (person.name, pofiletranslator.person.name)
+        )
 
         self._person = person
         self._pofiletranslator = pofiletranslator
@@ -168,33 +159,42 @@ class IPersonTranslationsMenu(Interface):
 class PersonTranslationsMenu(NavigationMenu):
 
     usedfor = IPersonTranslationsMenu
-    facet = 'translations'
-    links = ('overview', 'licensing', 'imports', 'translations_to_review')
+    facet = "translations"
+    links = ("overview", "licensing", "imports", "translations_to_review")
 
     @property
     def person(self):
         return self.context.context
 
     def overview(self):
-        text = 'Overview'
-        return Link('', text, icon='info', site='translations')
+        text = "Overview"
+        return Link("", text, icon="info", site="translations")
 
     def imports(self):
-        text = 'Import queue'
-        return Link('+imports', text, icon='info', site='translations')
+        text = "Import queue"
+        return Link("+imports", text, icon="info", site="translations")
 
     def licensing(self):
-        text = 'Translations licensing'
-        enabled = (self.person == self.user)
-        return Link('+licensing', text, enabled=enabled, icon='info',
-                    site='translations')
+        text = "Translations licensing"
+        enabled = self.person == self.user
+        return Link(
+            "+licensing",
+            text,
+            enabled=enabled,
+            icon="info",
+            site="translations",
+        )
 
     def translations_to_review(self):
-        text = 'Translations to review'
+        text = "Translations to review"
         enabled = person_is_reviewer(self.person)
         return Link(
-            '+translations-to-review', text, enabled=enabled, icon='info',
-            site='translations')
+            "+translations-to-review",
+            text,
+            enabled=enabled,
+            icon="info",
+            site="translations",
+        )
 
 
 @implementer(IPersonTranslationsMenu)
@@ -205,12 +205,12 @@ class PersonTranslationView(LaunchpadView):
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        now = datetime.now(pytz.timezone('UTC'))
+        now = datetime.now(pytz.timezone("UTC"))
         # Down-to-the-second detail isn't important so the hope is that this
         # will result in faster queries (cache effects).
         today = now.replace(minute=0, second=0, microsecond=0)
         self.history_horizon = today - timedelta(90, 0, 0)
-        self.user_can_edit = check_permission('launchpad.Edit', self.context)
+        self.user_can_edit = check_permission("launchpad.Edit", self.context)
 
     @property
     def page_title(self):
@@ -230,15 +230,17 @@ class PersonTranslationView(LaunchpadView):
             if potemplate is None:
                 return True
             product = potemplate.product
-            product_is_active = (
-                product is None or (
-                product.active and
-                product.translations_usage == ServiceUsage.LAUNCHPAD))
+            product_is_active = product is None or (
+                product.active
+                and product.translations_usage == ServiceUsage.LAUNCHPAD
+            )
             return product_is_active
 
         active_entries = (entry for entry in all_entries if is_active(entry))
-        return [ActivityDescriptor(self.context, entry)
-            for entry in islice(active_entries, 10)]
+        return [
+            ActivityDescriptor(self.context, entry)
+            for entry in islice(active_entries, 10)
+        ]
 
     @cachedproperty
     def latest_activity(self):
@@ -301,7 +303,8 @@ class PersonTranslationView(LaunchpadView):
         if self.user:
             return True
         return not (
-            translationmessage.potmsgset.hide_translations_from_anonymous)
+            translationmessage.potmsgset.hide_translations_from_anonymous
+        )
 
     @cachedproperty
     def _review_targets(self):
@@ -312,7 +315,8 @@ class PersonTranslationView(LaunchpadView):
         """
         person = ITranslationsPerson(self.context)
         pofiles = person.getReviewableTranslationFiles(
-            no_older_than=self.history_horizon)
+            no_older_than=self.history_horizon
+        )
 
         return ReviewLinksAggregator().aggregate(pofiles)
 
@@ -322,12 +326,13 @@ class PersonTranslationView(LaunchpadView):
         Results are ordered from most to fewest untranslated messages.
         """
         person = ITranslationsPerson(self.context)
-        urgent_first = (max_fetch is not None and max_fetch >= 0)
+        urgent_first = max_fetch is not None and max_fetch >= 0
         pofiles = person.getTranslatableFiles(
-            no_older_than=self.history_horizon, urgent_first=urgent_first)
+            no_older_than=self.history_horizon, urgent_first=urgent_first
+        )
 
         if max_fetch is not None:
-            pofiles = pofiles[:abs(max_fetch)]
+            pofiles = pofiles[: abs(max_fetch)]
 
         return TranslateLinksAggregator().aggregate(pofiles)
 
@@ -336,8 +341,9 @@ class PersonTranslationView(LaunchpadView):
         """Top projects and packages for this person to review."""
         return self._review_targets
 
-    def _addToTargetsList(self, existing_targets, new_targets, max_items,
-                          max_overall):
+    def _addToTargetsList(
+        self, existing_targets, new_targets, max_items, max_overall
+    ):
         """Add `new_targets` to `existing_targets` list.
 
         This is for use in showing top-10 ists of translations a user
@@ -361,12 +367,10 @@ class PersonTranslationView(LaunchpadView):
         if remaining_slots <= 0:
             return existing_targets
 
-        known_targets = {item['target'] for item in existing_targets}
+        known_targets = {item["target"] for item in existing_targets}
         really_new = [
-            item
-            for item in new_targets
-            if item['target'] not in known_targets
-            ]
+            item for item in new_targets if item["target"] not in known_targets
+        ]
 
         return existing_targets + really_new[:maximum_addition]
 
@@ -383,7 +387,8 @@ class PersonTranslationView(LaunchpadView):
         # worked on.
         recent = self._review_targets
         return self._addToTargetsList(
-            [], recent, max_known_targets, list_length)
+            [], recent, max_known_targets, list_length
+        )
 
     @cachedproperty
     def num_projects_and_packages_to_review(self):
@@ -405,24 +410,27 @@ class PersonTranslationView(LaunchpadView):
         fetch = 5 * max_urgent_targets
         urgent = self._getTargetsForTranslation(fetch)
         overall = self._addToTargetsList(
-            [], urgent, max_urgent_targets, list_length)
+            [], urgent, max_urgent_targets, list_length
+        )
 
         fetch = 5 * max_almost_complete_targets
         almost_complete = self._getTargetsForTranslation(-fetch)
         overall = self._addToTargetsList(
-            overall, almost_complete, max_almost_complete_targets,
-            list_length)
+            overall, almost_complete, max_almost_complete_targets, list_length
+        )
 
         return overall
 
     to_complete_template = ViewPageTemplateFile(
-        '../templates/person-translations-to-complete-table.pt')
+        "../templates/person-translations-to-complete-table.pt"
+    )
 
     def translations_to_complete_table(self):
         return self.to_complete_template(dict(view=self))
 
     to_review_template = ViewPageTemplateFile(
-        '../templates/person-translations-to-review-table.pt')
+        "../templates/person-translations-to-review-table.pt"
+    )
 
     def translations_to_review_table(self):
         return self.to_review_template(dict(view=self))
@@ -439,10 +447,12 @@ class PersonTranslationReviewView(PersonTranslationView):
 
 class PersonTranslationRelicensingView(LaunchpadFormView):
     """View for Person's translation relicensing page."""
+
     schema = ITranslationRelicensingAgreementEdit
-    field_names = ['allow_relicensing', 'back_to']
+    field_names = ["allow_relicensing", "back_to"]
     custom_widget_allow_relicensing = CustomWidgetFactory(
-        LaunchpadRadioWidget, orientation='vertical')
+        LaunchpadRadioWidget, orientation="vertical"
+    )
     custom_widget_back_to = CustomWidgetFactory(TextWidget, visible=False)
 
     page_title = "Licensing"
@@ -463,26 +473,27 @@ class PersonTranslationRelicensingView(LaunchpadFormView):
             default = TranslationRelicensingAgreementOptions.BSD
         return {
             "allow_relicensing": default,
-            "back_to": self.request.get('back_to'),
-            }
+            "back_to": self.request.get("back_to"),
+        }
 
     @property
     def relicensing_url(self):
         """Return an URL for this view."""
-        return canonical_url(self.context, view_name='+licensing',
-                             rootsite='translations')
+        return canonical_url(
+            self.context, view_name="+licensing", rootsite="translations"
+        )
 
     @property
     def cancel_url(self):
         """Escape to the person's main Translations page."""
-        return canonical_url(self.context, rootsite='translations')
+        return canonical_url(self.context, rootsite="translations")
 
     def getSafeRedirectURL(self, url):
         """Successful form submission should send to this URL."""
         if url and url.startswith(self.request.getApplicationURL()):
             return url
         else:
-            return canonical_url(self.context, rootsite='translations')
+            return canonical_url(self.context, rootsite="translations")
 
     @action(_("Confirm"), name="submit")
     def submit_action(self, action, data):
@@ -493,21 +504,27 @@ class PersonTranslationRelicensingView(LaunchpadFormView):
         which is backed by the TranslationRelicensingAgreement table.
         """
         translations_person = ITranslationsPerson(self.context)
-        allow_relicensing = data['allow_relicensing']
+        allow_relicensing = data["allow_relicensing"]
         if allow_relicensing == TranslationRelicensingAgreementOptions.BSD:
             translations_person.translations_relicensing_agreement = True
-            self.request.response.addInfoNotification(_(
-                "Thank you for BSD-licensing your translations."))
-        elif (allow_relicensing ==
-            TranslationRelicensingAgreementOptions.REMOVE):
+            self.request.response.addInfoNotification(
+                _("Thank you for BSD-licensing your translations.")
+            )
+        elif (
+            allow_relicensing == TranslationRelicensingAgreementOptions.REMOVE
+        ):
             translations_person.translations_relicensing_agreement = False
-            self.request.response.addInfoNotification(_(
-                "We respect your choice. "
-                "Thanks for trying out Launchpad Translations."))
+            self.request.response.addInfoNotification(
+                _(
+                    "We respect your choice. "
+                    "Thanks for trying out Launchpad Translations."
+                )
+            )
         else:
             raise AssertionError(
-                "Unknown allow_relicensing value: %r" % allow_relicensing)
-        self.next_url = self.getSafeRedirectURL(data['back_to'])
+                "Unknown allow_relicensing value: %r" % allow_relicensing
+            )
+        self.next_url = self.getSafeRedirectURL(data["back_to"])
 
 
 class TranslationActivityView(LaunchpadView):
@@ -526,12 +543,14 @@ class TranslationActivityView(LaunchpadView):
         """Iterate over person's translation_history."""
         translations_person = ITranslationsPerson(self.context)
         batchnav = BatchNavigator(
-            translations_person.translation_history, self.request)
+            translations_person.translation_history, self.request
+        )
 
         pofiletranslatorset = getUtility(IPOFileTranslatorSet)
         batch = batchnav.currentBatch()
         self._pofiletranslator_cache = (
-            pofiletranslatorset.prefetchPOFileTranslatorRelations(batch))
+            pofiletranslatorset.prefetchPOFileTranslatorRelations(batch)
+        )
 
         return batchnav
 
diff --git a/lib/lp/translations/browser/poexportrequest.py b/lib/lp/translations/browser/poexportrequest.py
index 7182c93..ecfcc4a 100644
--- a/lib/lp/translations/browser/poexportrequest.py
+++ b/lib/lp/translations/browser/poexportrequest.py
@@ -3,7 +3,7 @@
 
 """View class for requesting translation exports."""
 
-__all__ = ['BaseExportView']
+__all__ = ["BaseExportView"]
 
 
 from datetime import timedelta
@@ -13,20 +13,15 @@ from zope.component import getUtility
 from lp import _
 from lp.app.browser.tales import DurationFormatterAPI
 from lp.services.propertycache import cachedproperty
-from lp.services.webapp import (
-    canonical_url,
-    LaunchpadView,
-    )
+from lp.services.webapp import LaunchpadView, canonical_url
 from lp.translations.interfaces.hastranslationtemplates import (
     IHasTranslationTemplates,
-    )
+)
 from lp.translations.interfaces.poexportrequest import IPOExportRequestSet
-from lp.translations.interfaces.translationexporter import (
-    ITranslationExporter,
-    )
+from lp.translations.interfaces.translationexporter import ITranslationExporter
 from lp.translations.interfaces.translationfileformat import (
     TranslationFileFormat,
-    )
+)
 
 
 class BaseExportView(LaunchpadView):
@@ -55,8 +50,8 @@ class BaseExportView(LaunchpadView):
             return "There is 1 file request on the export queue."
         else:
             return (
-                "There are %d file requests on the export queue."
-                % queue_size)
+                "There are %d file requests on the export queue." % queue_size
+            )
 
     def describeBacklog(self, estimated_backlog):
         """Return string describing the current export backlog."""
@@ -72,9 +67,10 @@ class BaseExportView(LaunchpadView):
         """Overridable: return default file format to use for the export."""
         if not IHasTranslationTemplates.providedBy(self.context):
             raise NotImplementedError(
-                'Subclass not implementing `IHasTranslationsTemplates` '
-                'interface.  Either override getDefaultFormat implementation '
-                'or implement `IHasTranslationsTemplates`.')
+                "Subclass not implementing `IHasTranslationsTemplates` "
+                "interface.  Either override getDefaultFormat implementation "
+                "or implement `IHasTranslationsTemplates`."
+            )
 
         templates = self.context.getCurrentTranslationTemplates()
         if not bool(templates.any()):
@@ -85,7 +81,8 @@ class BaseExportView(LaunchpadView):
             self.request.response.addInfoNotification(
                 "This package has templates with different native "
                 "file formats.  If you proceed, all translations will be "
-                "exported in the single format you specify.")
+                "exported in the single format you specify."
+            )
         return format
 
     def processForm(self):
@@ -99,12 +96,14 @@ class BaseExportView(LaunchpadView):
         """
         if not IHasTranslationTemplates.providedBy(self.context):
             raise NotImplementedError(
-                'Subclass not implementing `IHasTranslationsTemplates` '
-                'interface.  Either override getDefaultFormat implementation '
-                'or implement `IHasTranslationsTemplates`.')
+                "Subclass not implementing `IHasTranslationsTemplates` "
+                "interface.  Either override getDefaultFormat implementation "
+                "or implement `IHasTranslationsTemplates`."
+            )
 
         translation_templates_ids = (
-            self.context.getCurrentTranslationTemplates(just_ids=True))
+            self.context.getCurrentTranslationTemplates(just_ids=True)
+        )
         pofiles_ids = self.context.getCurrentTranslationFiles(just_ids=True)
         if not bool(pofiles_ids.any()):
             pofiles_ids = None
@@ -143,23 +142,27 @@ class BaseExportView(LaunchpadView):
         templates, pofiles = requested_files
         if not templates and not pofiles:
             self.request.response.addErrorNotification(
-                "Please select at least one translation or template.")
+                "Please select at least one translation or template."
+            )
         else:
             self.request_set.addRequest(self.user, templates, pofiles, format)
             self.nextURL()
 
     def nextURL(self):
-        self.request.response.addInfoNotification(_(
-            "Your request has been received. Expect to receive an email "
-            "shortly."))
+        self.request.response.addInfoNotification(
+            _(
+                "Your request has been received. Expect to receive an email "
+                "shortly."
+            )
+        )
         self.request.response.redirect(
-            canonical_url(self.context, rootsite='translations'))
+            canonical_url(self.context, rootsite="translations")
+        )
 
     def formats(self):
         """Return a list of formats available for translation exports."""
 
         class BrowserFormat:
-
             def __init__(self, title, value, is_default=False):
                 self.title = title
                 self.value = value
@@ -167,7 +170,8 @@ class BaseExportView(LaunchpadView):
 
         translation_exporter = getUtility(ITranslationExporter)
         exporters = translation_exporter.getExportersForSupportedFileFormat(
-            self.default_format)
+            self.default_format
+        )
         for exporter in exporters:
             format = exporter.format
             if format == self.default_format:
diff --git a/lib/lp/translations/browser/pofile.py b/lib/lp/translations/browser/pofile.py
index 594bce4..fa958c2 100644
--- a/lib/lp/translations/browser/pofile.py
+++ b/lib/lp/translations/browser/pofile.py
@@ -4,40 +4,37 @@
 """Browser code for Translation files."""
 
 __all__ = [
-    'POExportView',
-    'POFileFilteredView',
-    'POFileNavigation',
-    'POFileNavigationMenu',
-    'POFileTranslateView',
-    'POFileUploadView',
-    'POFileView',
-    ]
+    "POExportView",
+    "POFileFilteredView",
+    "POFileNavigation",
+    "POFileNavigationMenu",
+    "POFileTranslateView",
+    "POFileUploadView",
+    "POFileView",
+]
 
 import os.path
 import re
 from urllib.parse import urlencode
 
-from lazr.restful.utils import smartquote
 import six
+from lazr.restful.utils import smartquote
 from zope.component import getUtility
 from zope.publisher.browser import FileUpload
 
 from lp import _
-from lp.app.errors import (
-    NotFoundError,
-    UnexpectedFormData,
-    )
+from lp.app.errors import NotFoundError, UnexpectedFormData
 from lp.registry.interfaces.person import IPersonSet
 from lp.services.config import config
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp import (
-    canonical_url,
-    enabled_with_permission,
     LaunchpadView,
     Link,
     Navigation,
     NavigationMenu,
-    )
+    canonical_url,
+    enabled_with_permission,
+)
 from lp.services.webapp.batching import BatchNavigator
 from lp.services.webapp.escaping import structured
 from lp.services.webapp.interfaces import ILaunchBag
@@ -45,15 +42,13 @@ from lp.translations.browser.poexportrequest import BaseExportView
 from lp.translations.browser.translationmessage import (
     BaseTranslationView,
     CurrentTranslationMessageView,
-    )
+)
 from lp.translations.interfaces.pofile import IPOFile
 from lp.translations.interfaces.side import TranslationSide
-from lp.translations.interfaces.translationimporter import (
-    ITranslationImporter,
-    )
+from lp.translations.interfaces.translationimporter import ITranslationImporter
 from lp.translations.interfaces.translationimportqueue import (
     ITranslationImportQueue,
-    )
+)
 from lp.translations.interfaces.translationsperson import ITranslationsPerson
 
 
@@ -63,57 +58,59 @@ class POFileNavigation(Navigation):
 
     def traverse(self, name):
         """Return the IPOMsgSet associated with the given name."""
-        assert self.request.method in ['GET', 'HEAD', 'POST'], (
-            'We only know about GET, HEAD, and POST')
+        assert self.request.method in [
+            "GET",
+            "HEAD",
+            "POST",
+        ], "We only know about GET, HEAD, and POST"
 
         try:
             sequence = int(name)
         except ValueError:
             # The URL does not have a number to do the traversal.
-            raise NotFoundError(
-                "%r is not a valid sequence number." % name)
+            raise NotFoundError("%r is not a valid sequence number." % name)
 
         if sequence < 1:
             # We got an invalid sequence number.
-            raise NotFoundError(
-                "%r is not a valid sequence number." % name)
+            raise NotFoundError("%r is not a valid sequence number." % name)
 
         potmsgset = self.context.potemplate.getPOTMsgSetBySequence(sequence)
 
         if potmsgset is None:
-            raise NotFoundError(
-                "%r is not a valid sequence number." % name)
+            raise NotFoundError("%r is not a valid sequence number." % name)
 
         return potmsgset.getCurrentTranslationMessageOrPlaceholder(
-            self.context)
+            self.context
+        )
 
 
 class POFileMenuMixin:
     """Mixin class to share code between navigation and action menus."""
 
     def details(self):
-        text = 'Translation details'
-        return Link('+details', text, icon='info')
+        text = "Translation details"
+        return Link("+details", text, icon="info")
 
     def translate(self):
-        text = 'Translate'
-        return Link('+translate', text, icon='language')
+        text = "Translate"
+        return Link("+translate", text, icon="language")
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def upload(self):
-        text = 'Upload translation'
-        return Link('+upload', text, icon='add')
+        text = "Upload translation"
+        return Link("+upload", text, icon="add")
 
     def download(self):
-        text = 'Download translation'
-        return Link('+export', text, icon='download')
+        text = "Download translation"
+        return Link("+export", text, icon="download")
 
 
 class POFileNavigationMenu(NavigationMenu, POFileMenuMixin):
     """Navigation menus for `IPOFile` objects."""
+
     usedfor = IPOFile
-    facet = 'translations'
-    links = ('details', 'translate', 'upload', 'download')
+    facet = "translations"
+    links = ("details", "translate", "upload", "download")
 
 
 class POFileMetadataViewMixin:
@@ -181,9 +178,10 @@ class POFileMetadataViewMixin:
     def has_any_documentation(self):
         """Return whether there is any documentation for this POFile."""
         return (
-            self.translation_group_guide is not None or
-            self.translation_team_guide is not None or
-            self.user_is_new_translator)
+            self.translation_group_guide is not None
+            or self.translation_team_guide is not None
+            or self.user_is_new_translator
+        )
 
     @property
     def introduction_link(self):
@@ -216,7 +214,10 @@ class POFileMetadataViewMixin:
             links.append(
                 structured(
                     '<a class="style-guide-url" href="%s">%s instructions</a>',
-                    group_guide, self.translation_group.title).escapedtext)
+                    group_guide,
+                    self.translation_group.title,
+                ).escapedtext
+            )
 
         if team_guide is not None:
             if group_guide is None:
@@ -229,9 +230,12 @@ class POFileMetadataViewMixin:
             links.append(
                 structured(
                     '<a class="style-guide-url" href="%s"> %s guidelines</a>',
-                    team_guide, name).escapedtext)
+                    team_guide,
+                    name,
+                ).escapedtext
+            )
 
-        text = ' and '.join(links).rstrip()
+        text = " and ".join(links).rstrip()
 
         return "Before translating, be sure to go through %s." % text
 
@@ -256,8 +260,9 @@ class POFileMetadataViewMixin:
                     </span>
                 </div>
             </div>
-            """ % ' '.join([
-                self.introduction_link, self.guide_links])
+            """ % " ".join(
+            [self.introduction_link, self.guide_links]
+        )
 
 
 class POFileView(LaunchpadView):
@@ -267,8 +272,11 @@ class POFileView(LaunchpadView):
     def contributors(self):
         people = list(self.context.contributors)
         # Preload ValidPersonCache.
-        list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
-            [person.id for person in people], need_validity=True))
+        list(
+            getUtility(IPersonSet).getPrecachedPersonsFromIDs(
+                [person.id for person in people], need_validity=True
+            )
+        )
         return people
 
     @cachedproperty
@@ -316,11 +324,13 @@ class POFileView(LaunchpadView):
                 style_guide_url = None
             else:
                 style_guide_url = translator.style_guide_url
-            managers.append({
-                'group': group,
-                'team': team,
-                'style_guide_url': style_guide_url,
-            })
+            managers.append(
+                {
+                    "group": group,
+                    "team": team,
+                    "style_guide_url": style_guide_url,
+                }
+            )
         return managers
 
 
@@ -332,7 +342,8 @@ class POFileDetailsView(POFileView):
     @property
     def label(self):
         return _("Details for %s translation") % (
-                    self.context.language.englishname)
+            self.context.language.englishname
+        )
 
 
 class TranslationMessageContainer:
@@ -349,12 +360,12 @@ class TranslationMessageContainer:
         # depending on whether it's used, suggested,
         # or an obsolete suggestion.
         if translation.is_current_ubuntu:
-            self.usage_class = 'usedtranslation'
+            self.usage_class = "usedtranslation"
         else:
             if translation.isHidden(pofile):
-                self.usage_class = 'hiddentranslation'
+                self.usage_class = "hiddentranslation"
             else:
-                self.usage_class = 'suggestedtranslation'
+                self.usage_class = "suggestedtranslation"
 
 
 class FilteredPOTMsgSets:
@@ -367,20 +378,24 @@ class FilteredPOTMsgSets:
             self.potmsgsets = None
         else:
             for translation in translations:
-                if (current_potmsgset is not None and
-                    current_potmsgset['potmsgset'] == translation.potmsgset):
-                    current_potmsgset['translations'].append(
-                        TranslationMessageContainer(translation, pofile))
+                if (
+                    current_potmsgset is not None
+                    and current_potmsgset["potmsgset"] == translation.potmsgset
+                ):
+                    current_potmsgset["translations"].append(
+                        TranslationMessageContainer(translation, pofile)
+                    )
                 else:
                     if current_potmsgset is not None:
                         potmsgsets.append(current_potmsgset)
                     translation.setPOFile(pofile)
                     current_potmsgset = {
-                        'potmsgset': translation.potmsgset,
-                        'translations': [
-                            TranslationMessageContainer(translation, pofile)],
-                        'context': translation,
-                        }
+                        "potmsgset": translation.potmsgset,
+                        "translations": [
+                            TranslationMessageContainer(translation, pofile)
+                        ],
+                        "context": translation,
+                    }
             if current_potmsgset is not None:
                 potmsgsets.append(current_potmsgset)
 
@@ -404,7 +419,9 @@ class POFileFilteredView(LaunchpadView):
     def page_title(self):
         """See `LaunchpadView`."""
         return smartquote('Translations by %s in "%s"') % (
-            self._person_name, self.context.title)
+            self._person_name,
+            self.context.title,
+        )
 
     def label(self):
         """See `LaunchpadView`."""
@@ -413,22 +430,26 @@ class POFileFilteredView(LaunchpadView):
     def initialize(self):
         """See `LaunchpadView`."""
         self.person = None
-        person = self.request.form.get('person')
+        person = self.request.form.get("person")
         if person is None:
             self.request.response.addErrorNotification(
-                "No person to filter by specified.")
+                "No person to filter by specified."
+            )
             translations = None
         else:
             self.person = getUtility(IPersonSet).getByName(person)
             if self.person is None:
                 self.request.response.addErrorNotification(
-                    "Requested person not found.")
+                    "Requested person not found."
+                )
                 translations = None
             else:
                 translations = self.context.getTranslationsFilteredBy(
-                    person=self.person)
-        self.batchnav = BatchNavigator(translations, self.request,
-                                       size=self.DEFAULT_BATCH_SIZE)
+                    person=self.person
+                )
+        self.batchnav = BatchNavigator(
+            translations, self.request, size=self.DEFAULT_BATCH_SIZE
+        )
 
     @property
     def translations(self):
@@ -438,8 +459,9 @@ class POFileFilteredView(LaunchpadView):
         display them grouped by English string, we transform the
         current batch.
         """
-        return FilteredPOTMsgSets(self.batchnav.currentBatch(),
-                                  self.context).potmsgsets
+        return FilteredPOTMsgSets(
+            self.batchnav.currentBatch(), self.context
+        ).potmsgsets
 
 
 class POFileUploadView(POFileView):
@@ -464,17 +486,18 @@ class POFileUploadView(POFileView):
         # XXX henninge 2008-12-03 bug=192925: This code is duplicated for
         # productseries and potemplate and should be unified.
 
-        if self.request.method != 'POST' or self.user is None:
+        if self.request.method != "POST" or self.user is None:
             # The form was not submitted or the user is not logged in.
             return
 
-        upload_file = self.form.get('file', None)
+        upload_file = self.form.get("file", None)
 
         if not isinstance(upload_file, FileUpload):
-            if upload_file is None or upload_file == '':
+            if upload_file is None or upload_file == "":
                 self.request.response.addErrorNotification(
                     "Ignored your upload because you didn't select a file to"
-                    " upload.")
+                    " upload."
+                )
             else:
                 # XXX: Carlos Perello Marin 2004-12-30 bug=116:
                 # Epiphany seems to have an unpredictable bug with upload
@@ -485,7 +508,8 @@ class POFileUploadView(POFileView):
                 # behaviour.
                 self.request.response.addErrorNotification(
                     "The upload failed because there was a problem receiving"
-                    " the data.")
+                    " the data."
+                )
             return
 
         filename = upload_file.filename
@@ -493,16 +517,18 @@ class POFileUploadView(POFileView):
 
         if len(content) == 0:
             self.request.response.addWarningNotification(
-                "Ignored your upload because the uploaded file is empty.")
+                "Ignored your upload because the uploaded file is empty."
+            )
             return
 
         translation_import_queue = getUtility(ITranslationImportQueue)
         root, ext = os.path.splitext(filename)
         translation_importer = getUtility(ITranslationImporter)
-        if (ext not in translation_importer.supported_file_extensions):
+        if ext not in translation_importer.supported_file_extensions:
             self.request.response.addErrorNotification(
                 "Ignored your upload because the file you uploaded was not"
-                " recognised as a file that can be imported.")
+                " recognised as a file that can be imported."
+            )
             return
 
         # Uploads on this form are never done by the maintainer.
@@ -515,22 +541,29 @@ class POFileUploadView(POFileView):
             path = self.context.path
         # Add it to the queue.
         translation_import_queue.addOrUpdateEntry(
-            path, content, by_maintainer, self.user,
+            path,
+            content,
+            by_maintainer,
+            self.user,
             sourcepackagename=self.context.potemplate.sourcepackagename,
             distroseries=self.context.potemplate.distroseries,
             productseries=self.context.potemplate.productseries,
-            potemplate=self.context.potemplate, pofile=self.context)
+            potemplate=self.context.potemplate,
+            pofile=self.context,
+        )
 
         self.request.response.addInfoNotification(
             structured(
-            'Thank you for your upload.  It will be automatically '
-            'reviewed in the next hours.  If that is not '
-            'enough to determine whether and where your file '
-            'should be imported, it will be reviewed manually by an '
-            'administrator in the coming few days.  You can track '
-            'your upload\'s status in the '
-            '<a href="%s/+imports">Translation Import Queue</a>',
-            canonical_url(self.context.potemplate.translationtarget)))
+                "Thank you for your upload.  It will be automatically "
+                "reviewed in the next hours.  If that is not "
+                "enough to determine whether and where your file "
+                "should be imported, it will be reviewed manually by an "
+                "administrator in the coming few days.  You can track "
+                "your upload's status in the "
+                '<a href="%s/+imports">Translation Import Queue</a>',
+                canonical_url(self.context.potemplate.translationtarget),
+            )
+        )
 
 
 class POFileBatchNavigator(BatchNavigator):
@@ -553,22 +586,27 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
     or a `PlaceholderPOFile`.
     """
 
-    DEFAULT_SHOW = 'all'
+    DEFAULT_SHOW = "all"
     DEFAULT_SIZE = 10
 
     def initialize(self):
         self.pofile = self.context
         translations_person = ITranslationsPerson(self.user, None)
-        if (self.user is not None and
-            translations_person.translations_relicensing_agreement is None):
-            url = six.ensure_text(str(self.request.URL), 'US-ASCII', 'replace')
-            if self.request.get('QUERY_STRING', None):
-                url = url + '?' + self.request['QUERY_STRING']
+        if (
+            self.user is not None
+            and translations_person.translations_relicensing_agreement is None
+        ):
+            url = six.ensure_text(str(self.request.URL), "US-ASCII", "replace")
+            if self.request.get("QUERY_STRING", None):
+                url = url + "?" + self.request["QUERY_STRING"]
 
             return self.request.response.redirect(
-                canonical_url(self.user, view_name='+licensing',
-                              rootsite='translations') +
-                '?' + urlencode({'back_to': url}))
+                canonical_url(
+                    self.user, view_name="+licensing", rootsite="translations"
+                )
+                + "?"
+                + urlencode({"back_to": url})
+            )
 
         # The handling of errors is slightly tricky here. Because this
         # form displays multiple POMsgSetViews, we need to track the
@@ -593,18 +631,22 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
         """See BaseTranslationView._buildBatchNavigator."""
 
         # Changing the "show" option resets batching.
-        old_show_option = self.request.form_ng.getOne('old_show')
+        old_show_option = self.request.form_ng.getOne("old_show")
         show_option_changed = (
-            old_show_option is not None and old_show_option != self.show)
+            old_show_option is not None and old_show_option != self.show
+        )
         if show_option_changed:
             # Start will be 0 by default.
             force_start = True
         else:
             force_start = False
-        return POFileBatchNavigator(self._getSelectedPOTMsgSets(),
-                                    self.request, size=self.DEFAULT_SIZE,
-                                    transient_parameters=["old_show"],
-                                    force_start=force_start)
+        return POFileBatchNavigator(
+            self._getSelectedPOTMsgSets(),
+            self.request,
+            size=self.DEFAULT_SIZE,
+            transient_parameters=["old_show"],
+            force_start=force_start,
+        )
 
     def _initializeTranslationMessageViews(self):
         """See BaseTranslationView._initializeTranslationMessageViews."""
@@ -616,19 +658,25 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
         for potmsgset in for_potmsgsets:
             translationmessage = (
                 potmsgset.getCurrentTranslationMessageOrPlaceholder(
-                    self.context))
+                    self.context
+                )
+            )
             error = self.errors.get(potmsgset)
 
             view = self._prepareView(
-                CurrentTranslationMessageView, translationmessage,
-                pofile=self.context, can_edit=can_edit, error=error)
+                CurrentTranslationMessageView,
+                translationmessage,
+                pofile=self.context,
+                can_edit=can_edit,
+                error=error,
+            )
             view.zoomed_in_view = False
             self.translationmessage_views.append(view)
 
     def _submitTranslations(self):
         """See BaseTranslationView._submitTranslations."""
         for key in self.request.form:
-            match = re.match(r'msgset_(\d+)$', key)
+            match = re.match(r"msgset_(\d+)$", key)
             if not match:
                 continue
 
@@ -640,7 +688,8 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
                 # does not exist for this POTemplate.
                 raise UnexpectedFormData(
                     "Got translation for POTMsgID %d which is not in the "
-                    "template." % id)
+                    "template." % id
+                )
 
             error = self._receiveTranslations(potmsgset)
             if error and potmsgset.getSequence(self.context.potemplate) != 0:
@@ -661,12 +710,16 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
 
         if self.errors:
             if len(self.errors) == 1:
-                message = ("There is an error in a translation you provided. "
-                           "Please correct it before continuing.")
+                message = (
+                    "There is an error in a translation you provided. "
+                    "Please correct it before continuing."
+                )
             else:
-                message = ("There are %d errors in the translations you "
-                           "provided. Please correct them before "
-                           "continuing." % len(self.errors))
+                message = (
+                    "There are %d errors in the translations you "
+                    "provided. Please correct them before "
+                    "continuing." % len(self.errors)
+                )
             self.request.response.addErrorNotification(message)
             return False
 
@@ -682,15 +735,18 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
 
         Update the start_offset when the filtered batch has mutated.
         """
-        if self.show == 'untranslated':
+        if self.show == "untranslated":
             translationmessage = potmsgset.getCurrentTranslation(
-                self.pofile.potemplate, self.pofile.language,
-                self.pofile.potemplate.translation_side)
+                self.pofile.potemplate,
+                self.pofile.language,
+                self.pofile.potemplate.translation_side,
+            )
             if translationmessage is not None:
                 self.start_offset += 1
-        elif self.show == 'new_suggestions':
+        elif self.show == "new_suggestions":
             new_suggestions = potmsgset.getLocalTranslationMessages(
-                self.pofile.potemplate, self.pofile.language)
+                self.pofile.potemplate, self.pofile.language
+            )
             if new_suggestions.count() == 0:
                 self.start_offset += 1
         else:
@@ -700,7 +756,7 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
     def _buildRedirectParams(self):
         parameters = BaseTranslationView._buildRedirectParams(self)
         if self.show and self.show != self.DEFAULT_SHOW:
-            parameters['show'] = self.show
+            parameters["show"] = self.show
         return parameters
 
     #
@@ -709,20 +765,20 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
 
     def _initializeShowOption(self):
         # Get any value given by the user
-        self.show = self.request.form_ng.getOne('show')
-        self.search_text = self.request.form_ng.getOne('search')
+        self.show = self.request.form_ng.getOne("show")
+        self.search_text = self.request.form_ng.getOne("search")
         if self.search_text is not None:
-            self.show = 'all'
+            self.show = "all"
 
         # Functions that deliver the correct message counts for each
         # valid option value.
         count_functions = {
-            'all': self.context.messageCount,
-            'translated': self.context.translatedCount,
-            'untranslated': self.context.untranslatedCount,
-            'new_suggestions': self.context.unreviewedCount,
-            'changed_in_ubuntu': self.context.updatesCount,
-            }
+            "all": self.context.messageCount,
+            "translated": self.context.translatedCount,
+            "untranslated": self.context.untranslatedCount,
+            "new_suggestions": self.context.unreviewedCount,
+            "changed_in_ubuntu": self.context.updatesCount,
+        }
 
         if self.show not in count_functions:
             self.show = self.DEFAULT_SHOW
@@ -740,7 +796,8 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
 
         if len(self.search_text) <= 1:
             self.request.response.addWarningNotification(
-                "Please try searching for a longer string.")
+                "Please try searching for a longer string."
+            )
             return self.context.potemplate.getPOTMsgSets()
 
         return self.context.findPOTMsgSetsContaining(text=self.search_text)
@@ -750,13 +807,14 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
         # The set of message sets we get is based on the selection of kind
         # of strings we have in our form.
         get_functions = {
-            'all': self._handleShowAll,
-            'translated': self.context.getPOTMsgSetTranslated,
-            'untranslated': self.context.getPOTMsgSetUntranslated,
-            'new_suggestions': self.context.getPOTMsgSetWithNewSuggestions,
-            'changed_in_ubuntu':
-                self.context.getPOTMsgSetDifferentTranslations,
-            }
+            "all": self._handleShowAll,
+            "translated": self.context.getPOTMsgSetTranslated,
+            "untranslated": self.context.getPOTMsgSetUntranslated,
+            "new_suggestions": self.context.getPOTMsgSetWithNewSuggestions,
+            "changed_in_ubuntu": (
+                self.context.getPOTMsgSetDifferentTranslations
+            ),
+        }
 
         if self.show not in get_functions:
             raise UnexpectedFormData('show = "%s"' % self.show)
@@ -770,27 +828,28 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
 
     @property
     def completeness(self):
-        return '%.0f%%' % self.context.translatedPercentage()
+        return "%.0f%%" % self.context.translatedPercentage()
 
     def _messages_html_id(self):
         order = []
         if self.form_is_writeable:
             for message in self.translationmessage_views:
                 order += [
-                    dictionary['html_id_translation'] + '_new'
-                    for dictionary in message.translation_dictionaries]
+                    dictionary["html_id_translation"] + "_new"
+                    for dictionary in message.translation_dictionaries
+                ]
         return order
 
     @property
     def autofocus_html_id(self):
-        if (len(self._messages_html_id()) > 0):
+        if len(self._messages_html_id()) > 0:
             return self._messages_html_id()[0]
         else:
             return ""
 
     @property
     def translations_order(self):
-        return ' '.join(self._messages_html_id())
+        return " ".join(self._messages_html_id())
 
     @property
     def is_upstream_pofile(self):
@@ -809,7 +868,8 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
         pofile = potemplate.getPOFileByLang(self.context.language.code)
         if pofile is None:
             pofile = potemplate.getPlaceholderPOFile(
-                self.context.language, check_for_existing=False)
+                self.context.language, check_for_existing=False
+            )
         return pofile
 
 
@@ -820,15 +880,16 @@ class POExportView(BaseExportView):
     def getExportFormat(self):
         format = self.request.form.get("format")
         pochanged = self.request.form.get("pochanged")
-        if format == 'PO' and pochanged == 'POCHANGED':
-            return 'POCHANGED'
+        if format == "PO" and pochanged == "POCHANGED":
+            return "POCHANGED"
         return format
 
     def processForm(self):
         is_upstream = (
-            self.context.potemplate.translation_side ==
-                TranslationSide.UPSTREAM)
-        if is_upstream and self.getExportFormat() == 'POCHANGED':
+            self.context.potemplate.translation_side
+            == TranslationSide.UPSTREAM
+        )
+        if is_upstream and self.getExportFormat() == "POCHANGED":
             other_side_pofile = self.context.getOtherSidePOFile()
             if other_side_pofile is None:
                 return None
@@ -841,8 +902,8 @@ class POExportView(BaseExportView):
     @property
     def has_pochanged_option(self):
         is_ubuntu = (
-            self.context.potemplate.translation_side ==
-                TranslationSide.UBUNTU)
+            self.context.potemplate.translation_side == TranslationSide.UBUNTU
+        )
         if is_ubuntu:
             return True
         other_side_pofile = self.context.getOtherSidePOFile()
diff --git a/lib/lp/translations/browser/potemplate.py b/lib/lp/translations/browser/potemplate.py
index c707927..fe4fb89 100644
--- a/lib/lp/translations/browser/potemplate.py
+++ b/lib/lp/translations/browser/potemplate.py
@@ -3,34 +3,31 @@
 """Browser code for PO templates."""
 
 __all__ = [
-    'POTemplateAdminView',
-    'POTemplateBreadcrumb',
-    'POTemplateEditView',
-    'POTemplateExportView',
-    'POTemplateMenu',
-    'POTemplateNavigation',
-    'POTemplateSetNavigation',
-    'POTemplateSubsetNavigation',
-    'POTemplateSubsetURL',
-    'POTemplateSubsetView',
-    'POTemplateURL',
-    'POTemplateUploadView',
-    'POTemplateView',
-    'POTemplateViewPreferred',
-    'BaseSeriesTemplatesView',
-    ]
+    "POTemplateAdminView",
+    "POTemplateBreadcrumb",
+    "POTemplateEditView",
+    "POTemplateExportView",
+    "POTemplateMenu",
+    "POTemplateNavigation",
+    "POTemplateSetNavigation",
+    "POTemplateSubsetNavigation",
+    "POTemplateSubsetURL",
+    "POTemplateSubsetView",
+    "POTemplateURL",
+    "POTemplateUploadView",
+    "POTemplateView",
+    "POTemplateViewPreferred",
+    "BaseSeriesTemplatesView",
+]
 
 import datetime
 import operator
 import os.path
 
+import pytz
 from lazr.restful.interface import copy_field
 from lazr.restful.utils import smartquote
-import pytz
-from storm.expr import (
-    And,
-    Or,
-    )
+from storm.expr import And, Or
 from storm.info import ClassAlias
 from zope.component import getUtility
 from zope.interface import implementer
@@ -39,20 +36,17 @@ from zope.security.proxy import removeSecurityProxy
 
 from lp import _
 from lp.app.browser.launchpadform import (
-    action,
     LaunchpadEditFormView,
     ReturnToReferrerMixin,
-    )
+    action,
+)
 from lp.app.browser.tales import DateTimeFormatterAPI
-from lp.app.enums import (
-    service_uses_launchpad,
-    ServiceUsage,
-    )
+from lp.app.enums import ServiceUsage, service_uses_launchpad
 from lp.app.errors import NotFoundError
 from lp.app.validators.name import valid_name
 from lp.registry.interfaces.distributionsourcepackage import (
     IDistributionSourcePackage,
-    )
+)
 from lp.registry.interfaces.role import IPersonRoles
 from lp.registry.model.packaging import Packaging
 from lp.registry.model.product import Product
@@ -62,50 +56,39 @@ from lp.services.features import getFeatureFlag
 from lp.services.helpers import is_tar_filename
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp import (
-    canonical_url,
-    enabled_with_permission,
     GetitemNavigation,
     Link,
     Navigation,
     NavigationMenu,
-    )
+    canonical_url,
+    enabled_with_permission,
+)
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.breadcrumb import Breadcrumb
-from lp.services.webapp.escaping import (
-    html_escape,
-    structured,
-    )
-from lp.services.webapp.interfaces import (
-    ICanonicalUrlData,
-    ILaunchBag,
-    )
-from lp.services.webapp.publisher import (
-    LaunchpadView,
-    RedirectionView,
-    )
+from lp.services.webapp.escaping import html_escape, structured
+from lp.services.webapp.interfaces import ICanonicalUrlData, ILaunchBag
+from lp.services.webapp.publisher import LaunchpadView, RedirectionView
 from lp.services.worlddata.interfaces.language import ILanguageSet
 from lp.translations.browser.poexportrequest import BaseExportView
 from lp.translations.browser.translations import TranslationsMixin
 from lp.translations.browser.translationsharing import (
     TranslationSharingDetailsMixin,
-    )
+)
 from lp.translations.browser.widgets.potemplate import (
     POTemplateAdminSourcePackageNameWidget,
     POTemplateEditSourcePackageNameWidget,
-    )
+)
 from lp.translations.interfaces.pofile import IPOFileSet
 from lp.translations.interfaces.potemplate import (
     IPOTemplate,
     IPOTemplateSet,
     IPOTemplateSubset,
-    )
+)
 from lp.translations.interfaces.side import TranslationSide
-from lp.translations.interfaces.translationimporter import (
-    ITranslationImporter,
-    )
+from lp.translations.interfaces.translationimporter import ITranslationImporter
 from lp.translations.interfaces.translationimportqueue import (
     ITranslationImportQueue,
-    )
+)
 from lp.translations.model.potemplate import POTemplate
 
 
@@ -116,14 +99,17 @@ class POTemplateNavigation(Navigation):
     def traverse(self, name):
         """Return the IPOFile associated with the given name."""
 
-        assert self.request.method in ['GET', 'HEAD', 'POST'], (
-            'We only know about GET, HEAD, and POST')
+        assert self.request.method in [
+            "GET",
+            "HEAD",
+            "POST",
+        ], "We only know about GET, HEAD, and POST"
 
         user = getUtility(ILaunchBag).user
 
         # We do not want users to see the 'en' potemplate because
         # we store the messages we want to translate as English.
-        if name == 'en':
+        if name == "en":
             raise NotFoundError(name)
 
         pofile = self.context.getPOFileByLang(name)
@@ -131,14 +117,15 @@ class POTemplateNavigation(Navigation):
         if pofile is not None:
             # Already have a valid POFile entry, just return it.
             return pofile
-        elif self.request.method in ['GET', 'HEAD']:
+        elif self.request.method in ["GET", "HEAD"]:
             # It's just a query, get a fake one so we don't create new
             # POFiles just because someone is browsing the web.
             language = getUtility(ILanguageSet).getLanguageByCode(name)
             if language is None:
                 raise NotFoundError(name)
             return self.context.getPlaceholderPOFile(
-                language, requester=user, check_for_existing=False)
+                language, requester=user, check_for_existing=False
+            )
         else:
             # It's a POST.
             # XXX CarlosPerelloMarin 2006-04-20 bug=40275: We should
@@ -149,45 +136,46 @@ class POTemplateNavigation(Navigation):
 
 class POTemplateMenu(NavigationMenu):
     """Navigation menus for `IPOTemplate` objects."""
+
     usedfor = IPOTemplate
-    facet = 'translations'
+    facet = "translations"
     # XXX: henninge 2009-04-22 bug=365112: The order in this list was
     # rearranged so that the last item is public. The desired order is:
     # links = ['overview', 'upload', 'download', 'edit', 'administer']
-    links = ['overview', 'edit', 'administer', 'upload', 'download']
+    links = ["overview", "edit", "administer", "upload", "download"]
 
     def overview(self):
-        text = 'Overview'
-        return Link('', text)
+        text = "Overview"
+        return Link("", text)
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def upload(self):
-        text = 'Upload'
-        return Link('+upload', text, icon='add')
+        text = "Upload"
+        return Link("+upload", text, icon="add")
 
     def download(self):
-        text = 'Download'
-        return Link('+export', text, icon='download')
+        text = "Download"
+        return Link("+export", text, icon="download")
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def edit(self):
-        text = 'Edit'
-        return Link('+edit', text, icon='edit')
+        text = "Edit"
+        return Link("+edit", text, icon="edit")
 
-    @enabled_with_permission('launchpad.TranslationsAdmin')
+    @enabled_with_permission("launchpad.TranslationsAdmin")
     def administer(self):
-        text = 'Administer'
-        return Link('+admin', text, icon='edit')
+        text = "Administer"
+        return Link("+admin", text, icon="edit")
 
 
 class POTemplateSubsetView(RedirectionView):
-
     def __init__(self, context, request):
-        super().__init__('../+translations', request)
+        super().__init__("../+translations", request)
 
 
-class POTemplateView(LaunchpadView,
-                     TranslationsMixin, TranslationSharingDetailsMixin):
+class POTemplateView(
+    LaunchpadView, TranslationsMixin, TranslationSharingDetailsMixin
+):
 
     SHOW_RELATED_TEMPLATES = 4
 
@@ -252,47 +240,57 @@ class POTemplateView(LaunchpadView,
     def has_translation_documentation(self):
         """Are there translation instructions for this project."""
         translation_group = self.group_parent.translationgroup
-        return (translation_group is not None and
-                translation_group.translation_guide_url is not None)
+        return (
+            translation_group is not None
+            and translation_group.translation_guide_url is not None
+        )
 
     @cachedproperty
     def related_templates_by_source(self):
         by_source = list(
-            self.context.relatives_by_source[:self.SHOW_RELATED_TEMPLATES])
+            self.context.relatives_by_source[: self.SHOW_RELATED_TEMPLATES]
+        )
         return by_source
 
     @property
     def more_templates_by_source_link(self):
         by_source_count = self.context.relatives_by_source.count()
-        if (by_source_count > self.SHOW_RELATED_TEMPLATES):
+        if by_source_count > self.SHOW_RELATED_TEMPLATES:
             other = by_source_count - self.SHOW_RELATED_TEMPLATES
-            if (self.context.distroseries):
+            if self.context.distroseries:
                 sourcepackage = self.context.distroseries.getSourcePackage(
-                    self.context.sourcepackagename)
+                    self.context.sourcepackagename
+                )
                 url = canonical_url(
-                    sourcepackage, rootsite="translations",
-                    view_name='+translations')
+                    sourcepackage,
+                    rootsite="translations",
+                    view_name="+translations",
+                )
             else:
                 url = canonical_url(
                     self.context.productseries,
                     rootsite="translations",
-                    view_name="+templates")
+                    view_name="+templates",
+                )
             if other == 1:
-                return " and <a href=\"%s\">one other template</a>" % url
+                return ' and <a href="%s">one other template</a>' % url
             else:
-                return " and <a href=\"%s\">%d other templates</a>" % (
-                    url, other)
+                return ' and <a href="%s">%d other templates</a>' % (
+                    url,
+                    other,
+                )
         else:
             return ""
 
     @property
     def has_pofiles(self):
-        languages = set(
-            self.context.languages()).union(self.translatable_languages)
+        languages = set(self.context.languages()).union(
+            self.translatable_languages
+        )
         return len(languages) > 0
 
     def _sortLanguages(self, languages):
-        return sorted(languages, key=operator.attrgetter('englishname'))
+        return sorted(languages, key=operator.attrgetter("englishname"))
 
     def _getPOFileOrPlaceholder(self, language):
         pofile = self.context.getPOFileByLang(language.code)
@@ -339,8 +337,8 @@ class POTemplateUploadView(LaunchpadView, TranslationsMixin):
     def submitForm(self):
         """Process any uploaded files."""
 
-        if self.request.method == 'POST':
-            if 'UPLOAD' in self.request.form:
+        if self.request.method == "POST":
+            if "UPLOAD" in self.request.form:
                 self.upload()
 
     def upload(self):
@@ -352,12 +350,13 @@ class POTemplateUploadView(LaunchpadView, TranslationsMixin):
         failure with a warning message."""
         # XXX henninge 20008-12-03 bug=192925: This code is duplicated for
         # productseries and pofile and should be unified.
-        file = self.request.form.get('file')
+        file = self.request.form.get("file")
         if not isinstance(file, FileUpload):
             if not file:
                 self.request.response.addErrorNotification(
                     "Your upload was ignored because you didn't select a "
-                    "file. Please select a file and try again.")
+                    "file. Please select a file and try again."
+                )
             else:
                 # XXX: Carlos Perello Marin 2004-12-30 bug=116:
                 # Epiphany seems to have an unpredictable bug with upload
@@ -367,7 +366,8 @@ class POTemplateUploadView(LaunchpadView, TranslationsMixin):
                 # object in "file". We show an error if we see that behaviour.
                 self.request.response.addErrorNotification(
                     "Your upload failed because there was a problem receiving"
-                    " data. Please try again.")
+                    " data. Please try again."
+                )
             return
 
         filename = file.filename
@@ -375,7 +375,8 @@ class POTemplateUploadView(LaunchpadView, TranslationsMixin):
 
         if len(content) == 0:
             self.request.response.addWarningNotification(
-                "Ignored your upload because the uploaded file is empty.")
+                "Ignored your upload because the uploaded file is empty."
+            )
             return
 
         translation_import_queue = getUtility(ITranslationImportQueue)
@@ -384,11 +385,15 @@ class POTemplateUploadView(LaunchpadView, TranslationsMixin):
         if ext in translation_importer.supported_file_extensions:
             # Add it to the queue.
             entry = translation_import_queue.addOrUpdateEntry(
-                filename, content, True, self.user,
+                filename,
+                content,
+                True,
+                self.user,
                 sourcepackagename=self.context.sourcepackagename,
                 distroseries=self.context.distroseries,
                 productseries=self.context.productseries,
-                potemplate=self.context)
+                potemplate=self.context,
+            )
 
             if entry is None:
                 self.request.response.addWarningNotification(
@@ -399,82 +404,108 @@ class POTemplateUploadView(LaunchpadView, TranslationsMixin):
                     "upload was for.  Try uploading to a specific "
                     "template: visit the page for the template that you "
                     "want to upload to, and select the upload option "
-                    "from there.")
+                    "from there."
+                )
             else:
                 self.request.response.addInfoNotification(
                     structured(
-                    'Thank you for your upload.  It will be automatically '
-                    'reviewed in the next few hours.  If that is not '
-                    'enough to determine whether and where your file '
-                    'should be imported, it will be reviewed manually by an '
-                    'administrator in the coming few days.  You can track '
-                    'your upload\'s status in the '
-                    '<a href="%s/+imports">Translation Import Queue</a>',
-                        canonical_url(self.context.translationtarget)))
+                        "Thank you for your upload.  It will be automatically "
+                        "reviewed in the next few hours.  If that is not "
+                        "enough to determine whether and where your file "
+                        "should be imported, it will be reviewed manually by "
+                        "an administrator in the coming few days.  You can "
+                        "track your upload's status in the "
+                        '<a href="%s/+imports">Translation Import Queue</a>',
+                        canonical_url(self.context.translationtarget),
+                    )
+                )
 
         elif is_tar_filename(filename):
             # Add the whole tarball to the import queue.
-            (num, conflicts) = (
-                translation_import_queue.addOrUpdateEntriesFromTarball(
-                    content, True, self.user,
-                    sourcepackagename=self.context.sourcepackagename,
-                    distroseries=self.context.distroseries,
-                    productseries=self.context.productseries,
-                    potemplate=self.context))
+            (
+                num,
+                conflicts,
+            ) = translation_import_queue.addOrUpdateEntriesFromTarball(
+                content,
+                True,
+                self.user,
+                sourcepackagename=self.context.sourcepackagename,
+                distroseries=self.context.distroseries,
+                productseries=self.context.productseries,
+                potemplate=self.context,
+            )
 
             if num > 0:
                 if num == 1:
-                    plural_s = ''
-                    itthey = 'it'
+                    plural_s = ""
+                    itthey = "it"
                 else:
-                    plural_s = 's'
-                    itthey = 'they'
+                    plural_s = "s"
+                    itthey = "they"
                 self.request.response.addInfoNotification(
                     structured(
-                    'Thank you for your upload. %s file%s from the tarball '
-                    'will be automatically '
-                    'reviewed in the next few hours.  If that is not enough '
-                    'to determine whether and where your file%s should '
-                    'be imported, %s will be reviewed manually by an '
-                    'administrator in the coming few days.  You can track '
-                    'your upload\'s status in the '
-                    '<a href="%s/+imports">Translation Import Queue</a>',
-                    num, plural_s, plural_s, itthey,
-                    canonical_url(self.context.translationtarget)))
+                        "Thank you for your upload. %s file%s from the "
+                        "tarball will be automatically reviewed in the next "
+                        "few hours.  If that is not enough to determine "
+                        "whether and where your file%s should "
+                        "be imported, %s will be reviewed manually by an "
+                        "administrator in the coming few days.  You can track "
+                        "your upload's status in the "
+                        '<a href="%s/+imports">Translation Import Queue</a>',
+                        num,
+                        plural_s,
+                        plural_s,
+                        itthey,
+                        canonical_url(self.context.translationtarget),
+                    )
+                )
                 if len(conflicts) > 0:
                     if len(conflicts) == 1:
                         warning = (
                             "A file could not be uploaded because its "
                             "name matched multiple existing uploads, for "
-                            "different templates.")
+                            "different templates."
+                        )
                         ul_conflicts = structured(
                             "The conflicting file name was:<br /> "
-                            "<ul><li>%s</li></ul>", conflicts[0])
+                            "<ul><li>%s</li></ul>",
+                            conflicts[0],
+                        )
                     else:
                         warning = structured(
                             "%s files could not be uploaded because their "
                             "names matched multiple existing uploads, for "
-                            "different templates.", len(conflicts))
+                            "different templates.",
+                            len(conflicts),
+                        )
                         conflict_str = structured(
                             "</li><li>".join(["%s" % len(conflicts)]),
-                            *conflicts)
+                            *conflicts,
+                        )
                         ul_conflicts = structured(
                             "The conflicting file names were:<br /> "
-                            "<ul><li>%s</li></ul>", conflict_str)
+                            "<ul><li>%s</li></ul>",
+                            conflict_str,
+                        )
                     self.request.response.addWarningNotification(
                         structured(
-                        "%s  This makes it "
-                        "impossible to determine which template the new "
-                        "upload was for.  Try uploading to a specific "
-                        "template: visit the page for the template that you "
-                        "want to upload to, and select the upload option "
-                        "from there.<br />%s", warning, ul_conflicts))
+                            "%s  This makes it "
+                            "impossible to determine which template the new "
+                            "upload was for.  Try uploading to a specific "
+                            "template: visit the page for the template that "
+                            "you want to upload to, and select the upload "
+                            "option from there.<br />%s",
+                            warning,
+                            ul_conflicts,
+                        )
+                    )
             else:
                 if len(conflicts) == 0:
                     self.request.response.addWarningNotification(
                         "Upload ignored.  The tarball you uploaded did not "
                         "contain any files that the system recognized as "
-                        "translation files.")
+                        "translation files."
+                    )
                 else:
                     self.request.response.addWarningNotification(
                         "Upload failed.  One or more of the files you "
@@ -484,11 +515,13 @@ class POTemplateUploadView(LaunchpadView, TranslationsMixin):
                         "upload was for.  Try uploading to a specific "
                         "template: visit the page for the template that you "
                         "want to upload to, and select the upload option "
-                        "from there.")
+                        "from there."
+                    )
         else:
             self.request.response.addWarningNotification(
                 "Upload failed because the file you uploaded was not"
-                " recognised as a file that can be imported.")
+                " recognised as a file that can be imported."
+            )
 
 
 class POTemplateViewPreferred(POTemplateView):
@@ -501,12 +534,14 @@ class POTemplateViewPreferred(POTemplateView):
 class IPOTemplateEditForm(IPOTemplate):
 
     sourcepackagename = copy_field(
-        IPOTemplate['sourcepackagename'],
-        vocabularyName='DistributionSourcePackage')
+        IPOTemplate["sourcepackagename"],
+        vocabularyName="DistributionSourcePackage",
+    )
 
     from_sourcepackagename = copy_field(
-        IPOTemplate['from_sourcepackagename'],
-        vocabularyName='DistributionSourcePackage')
+        IPOTemplate["from_sourcepackagename"],
+        vocabularyName="DistributionSourcePackage",
+    )
 
 
 class POTemplateEditView(ReturnToReferrerMixin, LaunchpadEditFormView):
@@ -515,35 +550,42 @@ class POTemplateEditView(ReturnToReferrerMixin, LaunchpadEditFormView):
     @property
     def schema(self):
         """See `LaunchpadFormView`."""
-        if bool(getFeatureFlag('disclosure.dsp_picker.enabled')):
+        if bool(getFeatureFlag("disclosure.dsp_picker.enabled")):
             return IPOTemplateEditForm
         else:
             return IPOTemplate
 
     custom_widget_sourcepackagename = POTemplateEditSourcePackageNameWidget
-    label = 'Edit translation template details'
-    page_title = 'Edit details'
+    label = "Edit translation template details"
+    page_title = "Edit details"
     PRIORITY_MIN_VALUE = 0
     PRIORITY_MAX_VALUE = 100000
 
     @property
     def field_names(self):
         field_names = [
-            'name', 'translation_domain', 'description', 'priority',
-            'path', 'iscurrent']
+            "name",
+            "translation_domain",
+            "description",
+            "priority",
+            "path",
+            "iscurrent",
+        ]
         if self.context.distroseries:
-            field_names.extend([
-                'sourcepackagename',
-                'languagepack',
-                ])
+            field_names.extend(
+                [
+                    "sourcepackagename",
+                    "languagepack",
+                ]
+            )
         else:
-            field_names.append('owner')
+            field_names.append("owner")
         return field_names
 
     @property
     def adapters(self):
         """See `LaunchpadFormView`."""
-        if bool(getFeatureFlag('disclosure.dsp_picker.enabled')):
+        if bool(getFeatureFlag("disclosure.dsp_picker.enabled")):
             return {IPOTemplateEditForm: self.context}
         else:
             return {}
@@ -556,40 +598,44 @@ class POTemplateEditView(ReturnToReferrerMixin, LaunchpadEditFormView):
         # only supports watching changes to a single attribute.
 
         # The referer header is a hidden input in the form.
-        referrer = self.request.form.get('_return_url')
+        referrer = self.request.form.get("_return_url")
         returnChanged = False
         if referrer is None:
             # "referer" is misspelled in the HTTP specification.
-            referrer = self.request.getHeader('referer')
+            referrer = self.request.getHeader("referer")
             # If we were looking at the actual template, we want a new
             # URL constructed.
-            if referrer is not None and '/+pots/' in referrer:
+            if referrer is not None and "/+pots/" in referrer:
                 returnChanged = True
 
-        if (referrer is not None
+        if (
+            referrer is not None
             and not returnChanged
             and referrer.startswith(self.request.getApplicationURL())
-            and referrer != self.request.getHeader('location')):
+            and referrer != self.request.getHeader("location")
+        ):
             return referrer
         else:
             return canonical_url(self.context)
 
-    @action(_('Change'), name='change')
+    @action(_("Change"), name="change")
     def change_action(self, action, data):
         context = self.context
-        iscurrent = data.get('iscurrent', context.iscurrent)
+        iscurrent = data.get("iscurrent", context.iscurrent)
         context.setActive(iscurrent)
         old_description = context.description
         old_translation_domain = context.translation_domain
-        for field in ('sourcepackagename', 'from_sourcepackagename'):
+        for field in ("sourcepackagename", "from_sourcepackagename"):
             if IDistributionSourcePackage.providedBy(data.get(field)):
                 data[field] = data[field].sourcepackagename
         self.updateContextFromData(data)
         if old_description != context.description:
             self.user.assignKarma(
-                'translationtemplatedescriptionchanged',
-                product=context.product, distribution=context.distribution,
-                sourcepackagename=context.sourcepackagename)
+                "translationtemplatedescriptionchanged",
+                product=context.product,
+                distribution=context.distribution,
+                sourcepackagename=context.sourcepackagename,
+            )
         if old_translation_domain != context.translation_domain:
             # We only change date_last_updated when the translation_domain
             # field is changed because it is the only relevant field we
@@ -599,88 +645,118 @@ class POTemplateEditView(ReturnToReferrerMixin, LaunchpadEditFormView):
 
     def _validateTargetAndGetTemplates(self, data):
         """Return a POTemplateSubset corresponding to the chosen target."""
-        sourcepackagename = data.get('sourcepackagename',
-                                     self.context.sourcepackagename)
+        sourcepackagename = data.get(
+            "sourcepackagename", self.context.sourcepackagename
+        )
         if IDistributionSourcePackage.providedBy(sourcepackagename):
             sourcepackagename = sourcepackagename.sourcepackagename
         return getUtility(IPOTemplateSet).getSubset(
             distroseries=self.context.distroseries,
             sourcepackagename=sourcepackagename,
-            productseries=self.context.productseries)
+            productseries=self.context.productseries,
+        )
 
     def validate(self, data):
-        name = data.get('name', None)
+        name = data.get("name", None)
         if name is None or not valid_name(name):
             self.setFieldError(
-                'name',
-                'Template name can only start with lowercase letters a-z '
-                'or digits 0-9, and other than those characters, can only '
-                'contain "-", "+" and "." characters.')
+                "name",
+                "Template name can only start with lowercase letters a-z "
+                "or digits 0-9, and other than those characters, can only "
+                'contain "-", "+" and "." characters.',
+            )
 
-        distroseries = data.get('distroseries', self.context.distroseries)
+        distroseries = data.get("distroseries", self.context.distroseries)
         sourcepackagename = data.get(
-            'sourcepackagename', self.context.sourcepackagename)
+            "sourcepackagename", self.context.sourcepackagename
+        )
         if IDistributionSourcePackage.providedBy(sourcepackagename):
             sourcepackagename = sourcepackagename.sourcepackagename
-        productseries = data.get('productseries', None)
-        sourcepackage_changed = (
-            distroseries is not None and
-            (distroseries != self.context.distroseries or
-             sourcepackagename != self.context.sourcepackagename))
-        productseries_changed = (productseries is not None and
-                                 productseries != self.context.productseries)
+        productseries = data.get("productseries", None)
+        sourcepackage_changed = distroseries is not None and (
+            distroseries != self.context.distroseries
+            or sourcepackagename != self.context.sourcepackagename
+        )
+        productseries_changed = (
+            productseries is not None
+            and productseries != self.context.productseries
+        )
         similar_templates = self._validateTargetAndGetTemplates(data)
         if similar_templates is not None:
             self.validateName(
-                name, similar_templates, sourcepackage_changed,
-                productseries_changed)
+                name,
+                similar_templates,
+                sourcepackage_changed,
+                productseries_changed,
+            )
             self.validateDomain(
-                data.get('translation_domain'), similar_templates,
-                sourcepackage_changed, productseries_changed)
+                data.get("translation_domain"),
+                similar_templates,
+                sourcepackage_changed,
+                productseries_changed,
+            )
 
-        priority = data.get('priority')
+        priority = data.get("priority")
         if priority is None:
             return
 
-        if (priority < self.PRIORITY_MIN_VALUE or
-            priority > self.PRIORITY_MAX_VALUE):
+        if (
+            priority < self.PRIORITY_MIN_VALUE
+            or priority > self.PRIORITY_MAX_VALUE
+        ):
             self.setFieldError(
-                'priority',
-                'The priority value must be between %s and %s.' % (
-                self.PRIORITY_MIN_VALUE, self.PRIORITY_MAX_VALUE))
-
-    def validateName(self, name, similar_templates,
-                     sourcepackage_changed, productseries_changed):
+                "priority",
+                "The priority value must be between %s and %s."
+                % (self.PRIORITY_MIN_VALUE, self.PRIORITY_MAX_VALUE),
+            )
+
+    def validateName(
+        self,
+        name,
+        similar_templates,
+        sourcepackage_changed,
+        productseries_changed,
+    ):
         """Check that the name does not clash with an existing template."""
         if similar_templates.getPOTemplateByName(name) is not None:
             if sourcepackage_changed:
                 self.setFieldError(
-                    'sourcepackagename',
+                    "sourcepackagename",
                     "Source package already has a template with "
-                    "that same name.")
+                    "that same name.",
+                )
             elif productseries_changed:
                 self.setFieldError(
-                    'productseries',
-                    "Series already has a template with that same name.")
+                    "productseries",
+                    "Series already has a template with that same name.",
+                )
             elif name != self.context.name:
-                self.setFieldError('name', "Name is already in use.")
-
-    def validateDomain(self, domain, similar_templates,
-                       sourcepackage_changed, productseries_changed):
+                self.setFieldError("name", "Name is already in use.")
+
+    def validateDomain(
+        self,
+        domain,
+        similar_templates,
+        sourcepackage_changed,
+        productseries_changed,
+    ):
         clashes = similar_templates.getPOTemplatesByTranslationDomain(domain)
         if not clashes.is_empty():
             if sourcepackage_changed:
                 self.setFieldError(
-                    'sourcepackagename',
+                    "sourcepackagename",
                     "Source package already has a template with "
-                    "that same domain.")
+                    "that same domain.",
+                )
             elif productseries_changed:
                 self.setFieldError(
-                    'productseries',
-                    "Series already has a template with that same domain.")
+                    "productseries",
+                    "Series already has a template with that same domain.",
+                )
             elif domain != self.context.translation_domain:
                 self.setFieldError(
-                    'translation_domain', "Domain is already in use.")
+                    "translation_domain", "Domain is already in use."
+                )
 
     @property
     def _return_attribute_name(self):
@@ -690,32 +766,50 @@ class POTemplateEditView(ReturnToReferrerMixin, LaunchpadEditFormView):
 
 class POTemplateAdminView(POTemplateEditView):
     """View class that lets you admin a POTemplate object."""
+
     field_names = [
-        'name', 'translation_domain', 'description', 'header', 'iscurrent',
-        'owner', 'productseries', 'distroseries', 'sourcepackagename',
-        'from_sourcepackagename', 'sourcepackageversion',
-        'languagepack', 'path', 'source_file_format', 'priority',
-        'date_last_updated']
+        "name",
+        "translation_domain",
+        "description",
+        "header",
+        "iscurrent",
+        "owner",
+        "productseries",
+        "distroseries",
+        "sourcepackagename",
+        "from_sourcepackagename",
+        "sourcepackageversion",
+        "languagepack",
+        "path",
+        "source_file_format",
+        "priority",
+        "date_last_updated",
+    ]
     custom_widget_sourcepackagename = POTemplateAdminSourcePackageNameWidget
     custom_widget_from_sourcepackagename = (
-        POTemplateAdminSourcePackageNameWidget)
-    label = 'Administer translation template'
+        POTemplateAdminSourcePackageNameWidget
+    )
+    label = "Administer translation template"
     page_title = "Administer"
 
     def _validateTargetAndGetTemplates(self, data):
         """Return a POTemplateSubset corresponding to the chosen target."""
-        distroseries = data.get('distroseries')
-        sourcepackagename = data.get('sourcepackagename')
+        distroseries = data.get("distroseries")
+        sourcepackagename = data.get("sourcepackagename")
         if IDistributionSourcePackage.providedBy(sourcepackagename):
             sourcepackagename = sourcepackagename.sourcepackagename
-        productseries = data.get('productseries')
+        productseries = data.get("productseries")
 
         if distroseries is not None and productseries is not None:
-            message = ("Choose a distribution release series or a project "
-                "release series, but not both.")
+            message = (
+                "Choose a distribution release series or a project "
+                "release series, but not both."
+            )
         elif distroseries is None and productseries is None:
-            message = ("Choose either a distribution release series or a "
-                "project release series.")
+            message = (
+                "Choose either a distribution release series or a "
+                "project release series."
+            )
         else:
             message = None
 
@@ -723,8 +817,10 @@ class POTemplateAdminView(POTemplateEditView):
             self.addError(message)
             return None
         return getUtility(IPOTemplateSet).getSubset(
-            distroseries=distroseries, sourcepackagename=sourcepackagename,
-            productseries=productseries)
+            distroseries=distroseries,
+            sourcepackagename=sourcepackagename,
+            productseries=productseries,
+        )
 
 
 class POTemplateExportView(BaseExportView):
@@ -739,14 +835,14 @@ class POTemplateExportView(BaseExportView):
 
     def processForm(self):
         """Process a form submission requesting a translation export."""
-        what = self.request.form.get('what')
-        if what == 'all':
+        what = self.request.form.get("what")
+        if what == "all":
             export_potemplate = True
 
             pofiles = self.context.pofiles
-        elif what == 'some':
+        elif what == "some":
             pofiles = []
-            export_potemplate = 'potemplate' in self.request.form
+            export_potemplate = "potemplate" in self.request.form
 
             for code in self.request.form:
                 pofile = self.context.getPOFileByLang(code)
@@ -754,8 +850,9 @@ class POTemplateExportView(BaseExportView):
                     pofiles.append(pofile)
         else:
             self.request.response.addErrorNotification(
-                'Please choose whether you would like all files or only some '
-                'of them.')
+                "Please choose whether you would like all files or only some "
+                "of them."
+            )
             return
 
         if export_potemplate:
@@ -769,7 +866,6 @@ class POTemplateExportView(BaseExportView):
         """Return a list of PO files available for export."""
 
         class BrowserPOFile:
-
             def __init__(self, value, browsername):
                 self.value = value
                 self.browsername = browsername
@@ -790,8 +886,8 @@ class POTemplateExportView(BaseExportView):
 @implementer(ICanonicalUrlData)
 class POTemplateSubsetURL:
 
-    rootsite = 'mainsite'
-    path = '+pots'
+    rootsite = "mainsite"
+    path = "+pots"
 
     def __init__(self, context):
         self.context = context
@@ -802,7 +898,8 @@ class POTemplateSubsetURL:
         if potemplatesubset.distroseries is not None:
             assert potemplatesubset.productseries is None
             return potemplatesubset.distroseries.getSourcePackage(
-                potemplatesubset.sourcepackagename)
+                potemplatesubset.sourcepackagename
+            )
         else:
             assert potemplatesubset.productseries is not None
             return potemplatesubset.productseries
@@ -811,7 +908,7 @@ class POTemplateSubsetURL:
 @implementer(ICanonicalUrlData)
 class POTemplateURL:
 
-    rootsite = 'translations'
+    rootsite = "translations"
 
     def __init__(self, context):
         self.context = context
@@ -821,11 +918,13 @@ class POTemplateURL:
             assert potemplate.productseries is None
             self.potemplatesubset = potemplateset.getSubset(
                 distroseries=potemplate.distroseries,
-                sourcepackagename=potemplate.sourcepackagename)
+                sourcepackagename=potemplate.sourcepackagename,
+            )
         else:
             assert potemplate.productseries is not None
             self.potemplatesubset = potemplateset.getSubset(
-                productseries=potemplate.productseries)
+                productseries=potemplate.productseries
+            )
 
     @property
     def path(self):
@@ -849,8 +948,12 @@ class POTemplateSubsetNavigation(Navigation):
     def traverse(self, name):
         """Return the IPOTemplate associated with the given name."""
 
-        assert self.request.method in ['GET', 'HEAD', 'PATCH', 'POST'], (
-            'We only know about GET, HEAD, PATCH and POST')
+        assert self.request.method in [
+            "GET",
+            "HEAD",
+            "PATCH",
+            "POST",
+        ], "We only know about GET, HEAD, PATCH and POST"
 
         # Get the requested potemplate.
         potemplate = self.context.getPOTemplateByName(name)
@@ -866,11 +969,10 @@ class POTemplateSubsetNavigation(Navigation):
             product_or_distro = potemplate.distroseries.distribution
         translations_usage = product_or_distro.translations_usage
 
-        if (service_uses_launchpad(translations_usage) and
-           potemplate.iscurrent):
+        if service_uses_launchpad(translations_usage) and potemplate.iscurrent:
             # This template is available for translation.
             return potemplate
-        elif check_permission('launchpad.TranslationsAdmin', potemplate):
+        elif check_permission("launchpad.TranslationsAdmin", potemplate):
             # User has Edit privileges for this template and can access it.
             return potemplate
         else:
@@ -905,13 +1007,14 @@ class BaseSeriesTemplatesView(LaunchpadView):
         else:
             self.productseries = series
         user = IPersonRoles(self.user, None)
-        self.can_admin = (user is not None and
-                          (user.in_admin or user.in_rosetta_experts))
-        self.can_edit = (
-            self.can_admin or
-            check_permission('launchpad.TranslationsAdmin', series))
+        self.can_admin = user is not None and (
+            user.in_admin or user.in_rosetta_experts
+        )
+        self.can_edit = self.can_admin or check_permission(
+            "launchpad.TranslationsAdmin", series
+        )
 
-        self.user_is_logged_in = (self.user is not None)
+        self.user_is_logged_in = self.user is not None
 
     def iter_data(self):
         # If this is not a distroseries, then the query is much simpler.
@@ -919,35 +1022,63 @@ class BaseSeriesTemplatesView(LaunchpadView):
             potemplateset = getUtility(IPOTemplateSet)
             # The "shape" of the data returned by POTemplateSubset isn't quite
             # right so we have to run it through zip first.
-            return zip(potemplateset.getSubset(
-                productseries=self.productseries,
-                distroseries=self.distroseries,
-                ordered_by_names=True))
+            return zip(
+                potemplateset.getSubset(
+                    productseries=self.productseries,
+                    distroseries=self.distroseries,
+                    ordered_by_names=True,
+                )
+            )
 
         # Otherwise we have to do more work, primarily for the "sharing"
         # column.
         OtherTemplate = ClassAlias(POTemplate)
-        join = (self.context.getTemplatesCollection()
-            .joinOuter(Packaging, And(
-                Packaging.distroseries == self.context.id,
-                Packaging.sourcepackagename ==
-                    POTemplate.sourcepackagenameID))
-            .joinOuter(ProductSeries,
-                ProductSeries.id == Packaging.productseriesID)
-            .joinOuter(Product, And(
-                Product.id == ProductSeries.productID,
-                Or(
-                    Product.translations_usage == ServiceUsage.LAUNCHPAD,
-                    Product.translations_usage == ServiceUsage.EXTERNAL)))
-            .joinOuter(OtherTemplate, And(
-                OtherTemplate.productseriesID == ProductSeries.id,
-                OtherTemplate.name == POTemplate.name))
-            .joinInner(SourcePackageName,
-                SourcePackageName.id == POTemplate.sourcepackagenameID))
-
-        return join.select(POTemplate, Packaging, ProductSeries, Product,
-            OtherTemplate, SourcePackageName).order_by(
-                SourcePackageName.name, POTemplate.priority, POTemplate.name)
+        join = (
+            self.context.getTemplatesCollection()
+            .joinOuter(
+                Packaging,
+                And(
+                    Packaging.distroseries == self.context.id,
+                    Packaging.sourcepackagename
+                    == POTemplate.sourcepackagenameID,
+                ),
+            )
+            .joinOuter(
+                ProductSeries, ProductSeries.id == Packaging.productseriesID
+            )
+            .joinOuter(
+                Product,
+                And(
+                    Product.id == ProductSeries.productID,
+                    Or(
+                        Product.translations_usage == ServiceUsage.LAUNCHPAD,
+                        Product.translations_usage == ServiceUsage.EXTERNAL,
+                    ),
+                ),
+            )
+            .joinOuter(
+                OtherTemplate,
+                And(
+                    OtherTemplate.productseriesID == ProductSeries.id,
+                    OtherTemplate.name == POTemplate.name,
+                ),
+            )
+            .joinInner(
+                SourcePackageName,
+                SourcePackageName.id == POTemplate.sourcepackagenameID,
+            )
+        )
+
+        return join.select(
+            POTemplate,
+            Packaging,
+            ProductSeries,
+            Product,
+            OtherTemplate,
+            SourcePackageName,
+        ).order_by(
+            SourcePackageName.name, POTemplate.priority, POTemplate.name
+        )
 
     def rowCSSClass(self, template):
         if template.iscurrent:
@@ -971,11 +1102,18 @@ class BaseSeriesTemplatesView(LaunchpadView):
         """
         text = '<a href="%s">%s</a>' % (url, html_escape(template.name))
         if not template.iscurrent:
-            text += ' (inactive)'
+            text += " (inactive)"
         return text
 
-    def _renderSharing(self, template, packaging, productseries, upstream,
-            other_template, sourcepackagename):
+    def _renderSharing(
+        self,
+        template,
+        packaging,
+        productseries,
+        upstream,
+        other_template,
+        sourcepackagename,
+    ):
         """Render a link to `template`.
 
         :param template: The target `POTemplate`.
@@ -987,35 +1125,44 @@ class BaseSeriesTemplatesView(LaunchpadView):
             sourcepackagename = template.sourcepackagename
         # Build the edit link.
         escaped_source = html_escape(sourcepackagename.name)
-        source_url = '+source/%s' % escaped_source
-        details_url = source_url + '/+sharing-details'
+        source_url = "+source/%s" % escaped_source
+        details_url = source_url + "/+sharing-details"
         edit_link = (
-            '<a class="sprite edit action-icon" href="%s">Edit</a>' %
-            details_url)
+            '<a class="sprite edit action-icon" href="%s">Edit</a>'
+            % details_url
+        )
 
         # If all the conditions are met for sharing...
         if packaging and upstream and other_template is not None:
             escaped_series = html_escape(productseries.name)
             escaped_template = html_escape(template.name)
-            pot_url = ('/%s/%s/+pots/%s' %
-                (escaped_source, escaped_series, escaped_template))
-            return (edit_link + '<a href="%s">%s/%s</a>'
-                % (pot_url, escaped_source, escaped_series))
+            pot_url = "/%s/%s/+pots/%s" % (
+                escaped_source,
+                escaped_series,
+                escaped_template,
+            )
+            return edit_link + '<a href="%s">%s/%s</a>' % (
+                pot_url,
+                escaped_source,
+                escaped_series,
+            )
         else:
             # Otherwise just say that the template isn't shared and give them
             # a link to change the sharing.
-            return edit_link + 'not shared'
+            return edit_link + "not shared"
 
     def _renderLastUpdateDate(self, template):
         """Render a template's "last updated" column."""
         formatter = DateTimeFormatterAPI(template.date_last_updated)
         full_time = formatter.datetime()
         date = formatter.approximatedate()
-        return ''.join([
-            '<span class="sortkey">%s</span>' % full_time,
-            '<span class="lastupdate_column" title="%s">%s</span>' % (
-                full_time, date),
-            ])
+        return "".join(
+            [
+                '<span class="sortkey">%s</span>' % full_time,
+                '<span class="lastupdate_column" title="%s">%s</span>'
+                % (full_time, date),
+            ]
+        )
 
     def _renderAction(self, base_url, name, path, sprite, enabled):
         """Render an action for the "actions" column.
@@ -1028,18 +1175,19 @@ class BaseSeriesTemplatesView(LaunchpadView):
         :return: HTML for the contents of the "actions" column.
         """
         if not enabled:
-            return ''
+            return ""
 
         parameters = {
-            'base_url': base_url,
-            'name': name,
-            'path': path,
-            'sprite': sprite,
+            "base_url": base_url,
+            "name": name,
+            "path": path,
+            "sprite": sprite,
         }
         return (
             '<a class="sprite %(sprite)s" href="%(base_url)s/%(path)s">'
-            '%(name)s'
-            '</a>') % parameters
+            "%(name)s"
+            "</a>"
+        ) % parameters
 
     def _renderActionsColumn(self, template, base_url):
         """Render a template's "actions" column."""
@@ -1047,17 +1195,16 @@ class BaseSeriesTemplatesView(LaunchpadView):
             return None
 
         actions = [
-            ('Edit', '+edit', 'edit', self.can_edit),
-            ('Upload', '+upload', 'add', self.can_edit),
-            ('Download', '+export', 'download', self.user_is_logged_in),
-            ('Administer', '+admin', 'edit', self.can_admin),
+            ("Edit", "+edit", "edit", self.can_edit),
+            ("Upload", "+upload", "add", self.can_edit),
+            ("Download", "+export", "download", self.user_is_logged_in),
+            ("Administer", "+admin", "edit", self.can_admin),
         ]
-        links = [
-            self._renderAction(base_url, *action) for action in actions]
+        links = [self._renderAction(base_url, *action) for action in actions]
         html = '<div class="template_links">\n%s</div>'
-        return html % '\n'.join(links)
+        return html % "\n".join(links)
 
-    def _renderField(self, column_class, content, tag='td'):
+    def _renderField(self, column_class, content, tag="td"):
         """Create a table field of the given class and contents.
 
         :param column_class: CSS class for this column.
@@ -1069,10 +1216,9 @@ class BaseSeriesTemplatesView(LaunchpadView):
             `content` was None.
         """
         if content is None:
-            return ''
+            return ""
         else:
-            return '<%s class="%s">%s</%s>' % (
-                tag, column_class, content, tag)
+            return '<%s class="%s">%s</%s>' % (tag, column_class, content, tag)
 
     def constructTemplateURL(self, template):
         """Build the URL for `template`.
@@ -1094,23 +1240,30 @@ class BaseSeriesTemplatesView(LaunchpadView):
             actions_header = None
 
         columns = [
-            ('priority_column', "Priority"),
-            ('sourcepackage_column', sourcepackage_header),
-            ('template_column', "Template name"),
-            ('length_column', "Length"),
-            ('lastupdate_column', "Updated"),
-            ('actions_column', actions_header),
-            ]
+            ("priority_column", "Priority"),
+            ("sourcepackage_column", sourcepackage_header),
+            ("template_column", "Template name"),
+            ("length_column", "Length"),
+            ("lastupdate_column", "Updated"),
+            ("actions_column", actions_header),
+        ]
 
         if self.is_distroseries:
-            columns[3:3] = [('sharing', "Shared with")]
-
-        return '\n'.join([
-            self._renderField(css, text, tag='th')
-            for (css, text) in columns])
-
-    def renderTemplateRow(self, template, packaging=None, productseries=None,
-            upstream=None, other_template=None, sourcepackagename=None):
+            columns[3:3] = [("sharing", "Shared with")]
+
+        return "\n".join(
+            [self._renderField(css, text, tag="th") for (css, text) in columns]
+        )
+
+    def renderTemplateRow(
+        self,
+        template,
+        packaging=None,
+        productseries=None,
+        upstream=None,
+        other_template=None,
+        sourcepackagename=None,
+    ):
         """Render HTML for an entire template row."""
         if not self.can_edit and not template.iscurrent:
             return ""
@@ -1119,23 +1272,33 @@ class BaseSeriesTemplatesView(LaunchpadView):
         base_url = self.constructTemplateURL(template)
 
         fields = [
-            ('priority_column', template.priority),
-            ('sourcepackage_column', self._renderSourcePackage(template)),
-            ('template_column', self._renderTemplateLink(template, base_url)),
-            ('length_column', template.messagecount),
-            ('lastupdate_column', self._renderLastUpdateDate(template)),
-            ('actions_column', self._renderActionsColumn(template, base_url)),
+            ("priority_column", template.priority),
+            ("sourcepackage_column", self._renderSourcePackage(template)),
+            ("template_column", self._renderTemplateLink(template, base_url)),
+            ("length_column", template.messagecount),
+            ("lastupdate_column", self._renderLastUpdateDate(template)),
+            ("actions_column", self._renderActionsColumn(template, base_url)),
         ]
 
         if self.is_distroseries:
-            fields[3:3] = [(
-                'sharing', self._renderSharing(template, packaging,
-                    productseries, upstream, other_template,
-                    sourcepackagename)
-                )]
+            fields[3:3] = [
+                (
+                    "sharing",
+                    self._renderSharing(
+                        template,
+                        packaging,
+                        productseries,
+                        upstream,
+                        other_template,
+                        sourcepackagename,
+                    ),
+                )
+            ]
 
         tds = [self._renderField(*field) for field in fields]
 
         css = self.rowCSSClass(template)
         return '<tr class="template_row %s">\n%s</tr>\n' % (
-            css, '\n'.join(tds))
+            css,
+            "\n".join(tds),
+        )
diff --git a/lib/lp/translations/browser/product.py b/lib/lp/translations/browser/product.py
index 6f83a02..844252f 100644
--- a/lib/lp/translations/browser/product.py
+++ b/lib/lp/translations/browser/product.py
@@ -4,10 +4,10 @@
 """Translations browser views for products."""
 
 __all__ = [
-    'ProductSettingsView',
-    'ProductTranslationsMenu',
-    'ProductView',
-    ]
+    "ProductSettingsView",
+    "ProductTranslationsMenu",
+    "ProductView",
+]
 
 from lp.app.enums import service_uses_launchpad
 from lp.registry.browser.product import ProductConfigureBase
@@ -16,11 +16,11 @@ from lp.registry.interfaces.productseries import IProductSeries
 from lp.registry.interfaces.series import SeriesStatus
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp import (
-    canonical_url,
-    enabled_with_permission,
     LaunchpadView,
     Link,
-    )
+    canonical_url,
+    enabled_with_permission,
+)
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.menu import NavigationMenu
 from lp.translations.browser.translations import TranslationsMixin
@@ -29,44 +29,46 @@ from lp.translations.browser.translations import TranslationsMixin
 class ProductTranslationsMenu(NavigationMenu):
 
     usedfor = IProduct
-    facet = 'translations'
+    facet = "translations"
     links = (
-        'overview',
-        'settings',
-        'translationdownload',
-        'imports',
-        )
+        "overview",
+        "settings",
+        "translationdownload",
+        "imports",
+    )
 
     def imports(self):
-        text = 'Import queue'
-        return Link('+imports', text, site='translations')
+        text = "Import queue"
+        return Link("+imports", text, site="translations")
 
-    @enabled_with_permission('launchpad.TranslationsAdmin')
+    @enabled_with_permission("launchpad.TranslationsAdmin")
     def settings(self):
-        text = 'Configure translations'
+        text = "Configure translations"
         return Link(
-            '+configure-translations', text, icon='edit', site='translations')
+            "+configure-translations", text, icon="edit", site="translations"
+        )
 
-    @enabled_with_permission('launchpad.AnyPerson')
+    @enabled_with_permission("launchpad.AnyPerson")
     def translationdownload(self):
-        text = 'Download'
+        text = "Download"
         preferred_series = self.context.primary_translatable
-        enabled = (service_uses_launchpad(self.context.translations_usage)
-            and preferred_series is not None)
-        link = ''
+        enabled = (
+            service_uses_launchpad(self.context.translations_usage)
+            and preferred_series is not None
+        )
+        link = ""
         if enabled:
             link = canonical_url(
-                preferred_series,
-                rootsite='translations',
-                view_name='+export')
+                preferred_series, rootsite="translations", view_name="+export"
+            )
             text = 'Download "%s"' % preferred_series.name
 
-        return Link(link, text, icon='download', enabled=enabled)
+        return Link(link, text, icon="download", enabled=enabled)
 
     def overview(self):
-        text = 'Overview'
-        link = canonical_url(self.context, rootsite='translations')
-        return Link(link, text, icon='translation')
+        text = "Overview"
+        link = canonical_url(self.context, rootsite="translations")
+        return Link(link, text, icon="translation")
 
 
 class ProductSettingsView(TranslationsMixin, ProductConfigureBase):
@@ -74,11 +76,11 @@ class ProductSettingsView(TranslationsMixin, ProductConfigureBase):
     page_title = "Configure translations"
     usage_fieldname = "translations_usage"
     field_names = [
-            usage_fieldname,
-            "translation_focus",
-            "translationgroup",
-            "translationpermission",
-            ]
+        usage_fieldname,
+        "translation_focus",
+        "translationgroup",
+        "translationpermission",
+    ]
 
 
 class ProductView(LaunchpadView):
@@ -88,20 +90,26 @@ class ProductView(LaunchpadView):
     @cachedproperty
     def uses_translations(self):
         """Whether this product has translatable templates."""
-        return (service_uses_launchpad(self.context.translations_usage)
-                and self.primary_translatable is not None)
+        return (
+            service_uses_launchpad(self.context.translations_usage)
+            and self.primary_translatable is not None
+        )
 
     @cachedproperty
     def no_translations_available(self):
         """Has no translation templates but does support translations."""
-        return (service_uses_launchpad(self.context.translations_usage)
-                and self.primary_translatable is None)
+        return (
+            service_uses_launchpad(self.context.translations_usage)
+            and self.primary_translatable is None
+        )
 
     @cachedproperty
     def show_page_content(self):
         """Whether the main content of the page should be shown."""
-        return (service_uses_launchpad(self.context.translations_usage) or
-               self.is_translations_admin)
+        return (
+            service_uses_launchpad(self.context.translations_usage)
+            or self.is_translations_admin
+        )
 
     def can_configure_translations(self):
         """Whether or not the user can configure translations."""
@@ -113,8 +121,7 @@ class ProductView(LaunchpadView):
 
     @cachedproperty
     def primary_translatable(self):
-        """Return the context's primary translatable if it's a product series.
-        """
+        """Return the context's primary translatable if a product series."""
         translatable = self.context.primary_translatable
 
         if not IProductSeries.providedBy(translatable):
@@ -131,11 +138,18 @@ class ProductView(LaunchpadView):
         """
 
         translatable = self.context.translatable_series
-        return [series for series in self.context.series if (
-            series.status != SeriesStatus.OBSOLETE and
-            series not in translatable)]
+        return [
+            series
+            for series in self.context.series
+            if (
+                series.status != SeriesStatus.OBSOLETE
+                and series not in translatable
+            )
+        ]
 
     @property
     def allow_series_translation(self):
-        return (check_permission("launchpad.Edit", self.context) and not
-                self.context.private)
+        return (
+            check_permission("launchpad.Edit", self.context)
+            and not self.context.private
+        )
diff --git a/lib/lp/translations/browser/productseries.py b/lib/lp/translations/browser/productseries.py
index f5c875d..9990657 100644
--- a/lib/lp/translations/browser/productseries.py
+++ b/lib/lp/translations/browser/productseries.py
@@ -4,15 +4,15 @@
 """View classes for `IProductSeries`."""
 
 __all__ = [
-    'LinkTranslationsBranchView',
-    'ProductSeriesTemplatesView',
-    'ProductSeriesTranslationsBzrImportView',
-    'ProductSeriesTranslationsExportView',
-    'ProductSeriesTranslationsMenu',
-    'ProductSeriesTranslationsSettingsView',
-    'ProductSeriesUploadView',
-    'ProductSeriesView',
-    ]
+    "LinkTranslationsBranchView",
+    "ProductSeriesTemplatesView",
+    "ProductSeriesTranslationsBzrImportView",
+    "ProductSeriesTranslationsExportView",
+    "ProductSeriesTranslationsMenu",
+    "ProductSeriesTranslationsSettingsView",
+    "ProductSeriesUploadView",
+    "ProductSeriesView",
+]
 
 import os.path
 
@@ -22,11 +22,11 @@ from zope.publisher.browser import FileUpload
 
 from lp import _
 from lp.app.browser.launchpadform import (
-    action,
     LaunchpadEditFormView,
     LaunchpadFormView,
     ReturnToReferrerMixin,
-    )
+    action,
+)
 from lp.app.enums import service_uses_launchpad
 from lp.app.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription
 from lp.code.interfaces.branchjob import IRosettaUploadJobSource
@@ -34,12 +34,12 @@ from lp.registry.interfaces.productseries import IProductSeries
 from lp.services.helpers import is_tar_filename
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp import (
-    canonical_url,
-    enabled_with_permission,
     LaunchpadView,
     Link,
     NavigationMenu,
-    )
+    canonical_url,
+    enabled_with_permission,
+)
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.escaping import structured
 from lp.translations.browser.poexportrequest import BaseExportView
@@ -47,19 +47,17 @@ from lp.translations.browser.potemplate import BaseSeriesTemplatesView
 from lp.translations.browser.translations import TranslationsMixin
 from lp.translations.browser.translationsharing import (
     TranslationSharingDetailsMixin,
-    )
+)
 from lp.translations.interfaces.productserieslanguage import (
     IProductSeriesLanguageSet,
-    )
-from lp.translations.interfaces.translationimporter import (
-    ITranslationImporter,
-    )
+)
+from lp.translations.interfaces.translationimporter import ITranslationImporter
 from lp.translations.interfaces.translationimportqueue import (
     ITranslationImportQueue,
-    )
+)
 from lp.translations.interfaces.translations import (
     TranslationsBranchImportMode,
-    )
+)
 
 
 class ProductSeriesTranslationsMenuMixIn:
@@ -67,48 +65,60 @@ class ProductSeriesTranslationsMenuMixIn:
 
     def overview(self):
         """Return a link to the overview page."""
-        return Link('', 'Overview', site='translations')
+        return Link("", "Overview", site="translations")
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def templates(self):
         """Return a link to series PO templates."""
-        return Link('+templates', 'Templates', site='translations')
+        return Link("+templates", "Templates", site="translations")
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def settings(self):
         """Return a link to configure the translations settings."""
         return Link(
-            '+translations-settings', 'Settings',
-            site='translations', icon='edit')
+            "+translations-settings",
+            "Settings",
+            site="translations",
+            icon="edit",
+        )
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def requestbzrimport(self):
         """Return a link to request a bazaar import."""
         return Link(
-            '+request-bzr-import', 'Request Bazaar import',
-            site="translations")
+            "+request-bzr-import", "Request Bazaar import", site="translations"
+        )
 
-    @enabled_with_permission('launchpad.Edit')
+    @enabled_with_permission("launchpad.Edit")
     def translationupload(self):
         """Return a link to upload translations."""
-        return Link('+translations-upload', 'Upload', site="translations")
+        return Link("+translations-upload", "Upload", site="translations")
 
     def translationdownload(self):
         """Return a link to download the translations."""
-        return Link('+export', 'Download', site="translations")
+        return Link("+export", "Download", site="translations")
 
     def imports(self):
         """Return a link to the import queue."""
-        return Link('+imports', 'Import queue', site="translations")
+        return Link("+imports", "Import queue", site="translations")
 
 
-class ProductSeriesTranslationsMenu(NavigationMenu,
-                                    ProductSeriesTranslationsMenuMixIn):
+class ProductSeriesTranslationsMenu(
+    NavigationMenu, ProductSeriesTranslationsMenuMixIn
+):
     """Translations navigation menus for `IProductSeries` objects."""
+
     usedfor = IProductSeries
-    facet = 'translations'
-    links = ('overview', 'templates', 'settings', 'requestbzrimport',
-             'translationupload', 'translationdownload', 'imports')
+    facet = "translations"
+    links = (
+        "overview",
+        "templates",
+        "settings",
+        "requestbzrimport",
+        "translationupload",
+        "translationdownload",
+        "imports",
+    )
 
 
 class ProductSeriesTranslationsExportView(BaseExportView):
@@ -126,11 +136,12 @@ class ProductSeriesTranslationsExportView(BaseExportView):
         """Current context description used inline in paragraphs."""
         return "%s %s series" % (
             self.context.product.displayname,
-            self.context.name)
+            self.context.name,
+        )
 
     @property
     def cancel_url(self):
-        return canonical_url(self.context, rootsite='translations')
+        return canonical_url(self.context, rootsite="translations")
 
 
 class ProductSeriesTranslationsMixin(TranslationsMixin):
@@ -139,7 +150,7 @@ class ProductSeriesTranslationsMixin(TranslationsMixin):
     @property
     def series_title(self):
         """The series title."""
-        return self.context.title.replace(' ', '&nbsp;')
+        return self.context.title.replace(" ", "&nbsp;")
 
     @property
     def has_imports_enabled(self):
@@ -147,30 +158,37 @@ class ProductSeriesTranslationsMixin(TranslationsMixin):
 
         Will be True if imports are enabled for the series and if the user
         is allowed to view to the import branch."""
-        return (self.context.branch is not None and
-                check_permission("launchpad.View", self.context.branch) and
-                self.context.translations_autoimport_mode !=
-                TranslationsBranchImportMode.NO_IMPORT)
+        return (
+            self.context.branch is not None
+            and check_permission("launchpad.View", self.context.branch)
+            and self.context.translations_autoimport_mode
+            != TranslationsBranchImportMode.NO_IMPORT
+        )
 
     @property
     def request_bzr_import_url(self):
         """URL to request a bazaar import."""
         return canonical_url(
-            self.context, view_name="+request-bzr-import",
-            rootsite="translations")
+            self.context,
+            view_name="+request-bzr-import",
+            rootsite="translations",
+        )
 
     @property
     def set_branch_url(self):
         """URL to link the series to a branch."""
         return canonical_url(
-            self.context, rootsite="mainsite", view_name="+setbranch")
+            self.context, rootsite="mainsite", view_name="+setbranch"
+        )
 
     @property
     def translations_settings_url(self):
         """URL to change the translations for the series."""
         return canonical_url(
-            self.context, rootsite="translations",
-            view_name="+translations-settings")
+            self.context,
+            rootsite="translations",
+            view_name="+translations-settings",
+        )
 
 
 class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
@@ -186,7 +204,7 @@ class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
 
     @property
     def cancel_url(self):
-        return canonical_url(self.context, rootsite='translations')
+        return canonical_url(self.context, rootsite="translations")
 
     def processForm(self):
         """Process a form if it was submitted."""
@@ -205,12 +223,13 @@ class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
         # XXX henninge 2008-12-03 bug=192925: This code is duplicated for
         # potemplate and pofile and should be unified.
 
-        file = self.request.form['file']
+        file = self.request.form["file"]
         if not isinstance(file, FileUpload):
-            if file == '':
+            if file == "":
                 self.request.response.addErrorNotification(
                     "Ignored your upload because you didn't select a file to"
-                    " upload.")
+                    " upload."
+                )
             else:
                 # XXX: Carlos Perello Marin 2004-12-30 bug=116:
                 # Epiphany seems to have an unpredictable bug with upload
@@ -220,7 +239,8 @@ class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
                 # object in "file". We show an error if we see that behaviour.
                 self.request.response.addErrorNotification(
                     "The upload failed because there was a problem receiving"
-                    " the data.")
+                    " the data."
+                )
             return
 
         filename = file.filename
@@ -228,7 +248,8 @@ class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
 
         if len(content) == 0:
             self.request.response.addWarningNotification(
-                "Ignored your upload because the uploaded file is empty.")
+                "Ignored your upload because the uploaded file is empty."
+            )
             return
 
         translation_import_queue_set = getUtility(ITranslationImportQueue)
@@ -238,8 +259,8 @@ class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
         if ext in translation_importer.supported_file_extensions:
             # Add it to the queue.
             entry = translation_import_queue_set.addOrUpdateEntry(
-                filename, content, True, self.user,
-                productseries=self.context)
+                filename, content, True, self.user, productseries=self.context
+            )
             if entry is None:
                 self.request.response.addWarningNotification(
                     "Upload failed.  The name of the file you "
@@ -249,79 +270,102 @@ class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
                     "upload was for.  Try uploading to a specific "
                     "template: visit the page for the template that you "
                     "want to upload to, and select the upload option "
-                    "from there.")
+                    "from there."
+                )
             else:
                 self.request.response.addInfoNotification(
                     structured(
-                    'Thank you for your upload.  It will be automatically '
-                    'reviewed in the next few hours.  If that is not '
-                    'enough to determine whether and where your file '
-                    'should be imported, it will be reviewed manually by an '
-                    'administrator in the coming few days.  You can track '
-                    'your upload\'s status in the '
-                    '<a href="%s/+imports">Translation Import Queue</a>',
-                        canonical_url(self.context, rootsite='translations')))
+                        "Thank you for your upload.  It will be automatically "
+                        "reviewed in the next few hours.  If that is not "
+                        "enough to determine whether and where your file "
+                        "should be imported, it will be reviewed manually by "
+                        "an administrator in the coming few days.  You can "
+                        "track your upload's status in the "
+                        '<a href="%s/+imports">Translation Import Queue</a>',
+                        canonical_url(self.context, rootsite="translations"),
+                    )
+                )
 
         elif is_tar_filename(filename):
             # Add the whole tarball to the import queue.
-            (num, conflicts) = (
-                translation_import_queue_set.addOrUpdateEntriesFromTarball(
-                    content, True, self.user,
-                    productseries=self.context))
+            (
+                num,
+                conflicts,
+            ) = translation_import_queue_set.addOrUpdateEntriesFromTarball(
+                content, True, self.user, productseries=self.context
+            )
 
             if num > 0:
                 if num == 1:
-                    plural_s = ''
-                    itthey = 'it'
+                    plural_s = ""
+                    itthey = "it"
                 else:
-                    plural_s = 's'
-                    itthey = 'they'
+                    plural_s = "s"
+                    itthey = "they"
                 self.request.response.addInfoNotification(
                     structured(
-                    'Thank you for your upload. %s file%s from the tarball '
-                    'will be automatically '
-                    'reviewed in the next few hours.  If that is not enough '
-                    'to determine whether and where your file%s should '
-                    'be imported, %s will be reviewed manually by an '
-                    'administrator in the coming few days.  You can track '
-                    'your upload\'s status in the '
-                    '<a href="%s/+imports">Translation Import Queue</a>',
-                        num, plural_s, plural_s, itthey,
-                        canonical_url(self.context, rootsite='translations')))
+                        "Thank you for your upload. %s file%s from the "
+                        "tarball will be automatically reviewed in the next "
+                        "few hours.  If that is not enough to determine "
+                        "whether and where your file%s should "
+                        "be imported, %s will be reviewed manually by an "
+                        "administrator in the coming few days.  You can track "
+                        "your upload's status in the "
+                        '<a href="%s/+imports">Translation Import Queue</a>',
+                        num,
+                        plural_s,
+                        plural_s,
+                        itthey,
+                        canonical_url(self.context, rootsite="translations"),
+                    )
+                )
                 if len(conflicts) > 0:
                     if len(conflicts) == 1:
                         warning = (
                             "A file could not be uploaded because its "
                             "name matched multiple existing uploads, for "
-                            "different templates.")
+                            "different templates."
+                        )
                         ul_conflicts = structured(
                             "The conflicting file name was:<br /> "
-                            "<ul><li>%s</li></ul>", conflicts[0])
+                            "<ul><li>%s</li></ul>",
+                            conflicts[0],
+                        )
                     else:
                         warning = structured(
                             "%s files could not be uploaded because their "
                             "names matched multiple existing uploads, for "
-                            "different templates.", len(conflicts))
+                            "different templates.",
+                            len(conflicts),
+                        )
                         conflict_str = structured(
                             "</li><li>".join(["%s" % len(conflicts)]),
-                            *conflicts)
+                            *conflicts,
+                        )
                         ul_conflicts = structured(
                             "The conflicting file names were:<br /> "
-                            "<ul><li>%s</li></ul>", conflict_str)
+                            "<ul><li>%s</li></ul>",
+                            conflict_str,
+                        )
                     self.request.response.addWarningNotification(
                         structured(
-                        "%s  This makes it "
-                        "impossible to determine which template the new "
-                        "upload was for.  Try uploading to a specific "
-                        "template: visit the page for the template that you "
-                        "want to upload to, and select the upload option "
-                        "from there.<br />%s", warning, ul_conflicts))
+                            "%s  This makes it "
+                            "impossible to determine which template the new "
+                            "upload was for.  Try uploading to a specific "
+                            "template: visit the page for the template that "
+                            "you want to upload to, and select the upload "
+                            "option from there.<br />%s",
+                            warning,
+                            ul_conflicts,
+                        )
+                    )
             else:
                 if len(conflicts) == 0:
                     self.request.response.addWarningNotification(
                         "Upload ignored.  The tarball you uploaded did not "
                         "contain any files that the system recognized as "
-                        "translation files.")
+                        "translation files."
+                    )
                 else:
                     self.request.response.addWarningNotification(
                         "Upload failed.  One or more of the files you "
@@ -331,20 +375,24 @@ class ProductSeriesUploadView(LaunchpadView, TranslationsMixin):
                         "upload was for.  Try uploading to a specific "
                         "template: visit the page for the template that you "
                         "want to upload to, and select the upload option "
-                        "from there.")
+                        "from there."
+                    )
         else:
             self.request.response.addWarningNotification(
                 "Upload failed because the file you uploaded was not"
-                " recognised as a file that can be imported.")
+                " recognised as a file that can be imported."
+            )
 
     def can_configure_translations(self):
         """Whether or not the user can configure translations."""
         return check_permission("launchpad.Edit", self.context)
 
 
-class ProductSeriesView(LaunchpadView,
-                        ProductSeriesTranslationsMixin,
-                        TranslationSharingDetailsMixin):
+class ProductSeriesView(
+    LaunchpadView,
+    ProductSeriesTranslationsMixin,
+    TranslationSharingDetailsMixin,
+):
     """A view to show a series with translations."""
 
     label = "Translation status by language"
@@ -353,7 +401,8 @@ class ProductSeriesView(LaunchpadView,
         """See `LaunchpadFormView`."""
         # Whether there is more than one PO template.
         self.has_multiple_templates = (
-            self.context.getCurrentTranslationTemplates().count() > 1)
+            self.context.getCurrentTranslationTemplates().count() > 1
+        )
 
     @property
     def has_exports_enabled(self):
@@ -363,7 +412,9 @@ class ProductSeriesView(LaunchpadView,
         user is allowed to view that branch branch."""
         return self.context.translations_branch is not None and (
             check_permission(
-                "launchpad.View", self.context.translations_branch))
+                "launchpad.View", self.context.translations_branch
+            )
+        )
 
     @property
     def uses_bzr_sync(self):
@@ -396,7 +447,7 @@ class ProductSeriesView(LaunchpadView,
         if self.user is not None:
             productserieslangset = getUtility(IProductSeriesLanguageSet)
             for lang in self.user.languages:
-                if lang.code != 'en' and lang not in existing_languages:
+                if lang.code != "en" and lang not in existing_languages:
                     if self.single_potemplate:
                         pot = self.context.getCurrentTranslationTemplates()[0]
                         pofile = pot.getPOFileByLang(lang.code)
@@ -404,23 +455,25 @@ class ProductSeriesView(LaunchpadView,
                             pofile = pot.getPlaceholderPOFile(lang)
                         productserieslang = (
                             productserieslangset.getProductSeriesLanguage(
-                                self.context, lang, pofile=pofile))
+                                self.context, lang, pofile=pofile
+                            )
+                        )
                         productserieslang.recalculateCounts()
                     else:
                         productserieslang = (
                             productserieslangset.getProductSeriesLanguage(
-                                self.context, lang))
+                                self.context, lang
+                            )
+                        )
                         productserieslang.recalculateCounts()
-                    productserieslangs.append(
-                        productserieslang)
+                    productserieslangs.append(productserieslang)
 
-        return sorted(productserieslangs,
-                      key=lambda a: a.language.englishname)
+        return sorted(productserieslangs, key=lambda a: a.language.englishname)
 
     def isPreferredLanguage(self, language):
         # if there are no preferred languages, mark all
         # languages as preferred
-        if (len(self.translatable_languages) == 0):
+        if len(self.translatable_languages) == 0:
             return True
         else:
             return language in self.translatable_languages
@@ -429,8 +482,10 @@ class ProductSeriesView(LaunchpadView,
     def has_translation_documentation(self):
         """Are there translation instructions for this product."""
         translation_group = self.context.product.translationgroup
-        return (translation_group is not None and
-                translation_group.translation_guide_url is not None)
+        return (
+            translation_group is not None
+            and translation_group.translation_guide_url is not None
+        )
 
     @cachedproperty
     def single_potemplate(self):
@@ -440,8 +495,10 @@ class ProductSeriesView(LaunchpadView,
     @cachedproperty
     def show_page_content(self):
         """Whether the main content of the page should be shown."""
-        return (service_uses_launchpad(self.context.translations_usage) or
-               self.is_translations_admin)
+        return (
+            service_uses_launchpad(self.context.translations_usage)
+            or self.is_translations_admin
+        )
 
     def can_configure_translations(self):
         """Whether or not the user can configure translations."""
@@ -471,10 +528,11 @@ class SettingsRadioWidget(LaunchpadRadioWidgetWithDescription):
         self.hint = None
 
 
-class ProductSeriesTranslationsSettingsView(ReturnToReferrerMixin,
-                                            LaunchpadEditFormView,
-                                            ProductSeriesTranslationsMixin,
-                                            ):
+class ProductSeriesTranslationsSettingsView(
+    ReturnToReferrerMixin,
+    LaunchpadEditFormView,
+    ProductSeriesTranslationsMixin,
+):
     """Edit settings for translations import and export."""
 
     schema = IProductSeries
@@ -482,26 +540,31 @@ class ProductSeriesTranslationsSettingsView(ReturnToReferrerMixin,
     label = "Translations synchronization settings"
     page_title = "Settings"
 
-    field_names = ['translations_autoimport_mode']
+    field_names = ["translations_autoimport_mode"]
     custom_widget_translations_autoimport_mode = SettingsRadioWidget
 
     @action("Save settings", name="save_settings")
     def change_settings_action(self, action, data):
         """Change the translation settings."""
-        if (self.context.translations_autoimport_mode !=
-            data['translations_autoimport_mode']):
+        if (
+            self.context.translations_autoimport_mode
+            != data["translations_autoimport_mode"]
+        ):
             self.updateContextFromData(data)
             # Request an initial upload of translation files.
             getUtility(IRosettaUploadJobSource).create(
-                self.context.branch, NULL_REVISION)
+                self.context.branch, NULL_REVISION
+            )
         else:
             self.updateContextFromData(data)
         self.request.response.addInfoNotification(
-            _("The settings have been updated."))
+            _("The settings have been updated.")
+        )
 
 
-class ProductSeriesTranslationsBzrImportView(LaunchpadFormView,
-                                             ProductSeriesTranslationsMixin):
+class ProductSeriesTranslationsBzrImportView(
+    LaunchpadFormView, ProductSeriesTranslationsMixin
+):
     """Edit settings for translations import and export."""
 
     schema = IProductSeries
@@ -512,27 +575,27 @@ class ProductSeriesTranslationsBzrImportView(LaunchpadFormView,
 
     @property
     def next_url(self):
-        return canonical_url(self.context, rootsite='translations')
+        return canonical_url(self.context, rootsite="translations")
 
     cancel_url = next_url
 
     def validate(self, action):
         """See `LaunchpadFormView`."""
         if self.context.branch is None:
-            self.addError(
-                "Please set the official Bazaar branch first.")
+            self.addError("Please set the official Bazaar branch first.")
 
     @action("Request one-time import", name="request_import")
     def request_import_action(self, action, data):
-        """ Request an upload of translation files. """
+        """Request an upload of translation files."""
         job = getUtility(IRosettaUploadJobSource).create(
-            self.context.branch, NULL_REVISION, True)
+            self.context.branch, NULL_REVISION, True
+        )
         if job is None:
-            self.addError(
-                _("Your request could not be filed."))
+            self.addError(_("Your request could not be filed."))
         else:
             self.request.response.addInfoNotification(
-                _("The import has been requested."))
+                _("The import has been requested.")
+            )
 
 
 class ProductSeriesTemplatesView(BaseSeriesTemplatesView):
@@ -543,14 +606,14 @@ class ProductSeriesTemplatesView(BaseSeriesTemplatesView):
 
     def constructTemplateURL(self, template):
         """See `BaseSeriesTemplatesView`."""
-        return '+pots/%s' % template.name
+        return "+pots/%s" % template.name
 
 
 class LinkTranslationsBranchView(LaunchpadEditFormView):
     """View to set the series' translations export branch."""
 
     schema = IProductSeries
-    field_names = ['translations_branch']
+    field_names = ["translations_branch"]
 
     label = "Set translations export branch"
     page_title = "Export to branch"
@@ -558,13 +621,16 @@ class LinkTranslationsBranchView(LaunchpadEditFormView):
     @property
     def next_url(self):
         return canonical_url(
-            self.context, rootsite='translations',
-            view_name='+translations-settings')
+            self.context,
+            rootsite="translations",
+            view_name="+translations-settings",
+        )
 
     cancel_url = next_url
 
-    @action(_('Update'), name='update')
+    @action(_("Update"), name="update")
     def update_action(self, action, data):
         self.updateContextFromData(data)
         self.request.response.addInfoNotification(
-            'Translations export branch updated.')
+            "Translations export branch updated."
+        )
diff --git a/lib/lp/translations/browser/project.py b/lib/lp/translations/browser/project.py
index b21d722..64d98b7 100644
--- a/lib/lp/translations/browser/project.py
+++ b/lib/lp/translations/browser/project.py
@@ -4,19 +4,15 @@
 """ProjectGroup-related View Classes"""
 
 __all__ = [
-    'ProjectSettingsView',
-    'ProjectTranslationsMenu',
-    'ProjectView',
-    ]
+    "ProjectSettingsView",
+    "ProjectTranslationsMenu",
+    "ProjectView",
+]
 
 from lp.app.browser.launchpadform import action
 from lp.registry.browser.project import ProjectEditView
 from lp.registry.interfaces.projectgroup import IProjectGroup
-from lp.services.webapp import (
-    canonical_url,
-    enabled_with_permission,
-    Link,
-    )
+from lp.services.webapp import Link, canonical_url, enabled_with_permission
 from lp.services.webapp.menu import NavigationMenu
 from lp.services.webapp.publisher import LaunchpadView
 from lp.translations.browser.translations import TranslationsMixin
@@ -25,22 +21,22 @@ from lp.translations.browser.translations import TranslationsMixin
 class ProjectTranslationsMenu(NavigationMenu):
 
     usedfor = IProjectGroup
-    facet = 'translations'
-    links = ['products', 'settings', 'overview']
+    facet = "translations"
+    links = ["products", "settings", "overview"]
 
-    @enabled_with_permission('launchpad.TranslationsAdmin')
+    @enabled_with_permission("launchpad.TranslationsAdmin")
     def settings(self):
-        text = 'Change permissions'
-        return Link('+settings', text, icon='edit', site='translations')
+        text = "Change permissions"
+        return Link("+settings", text, icon="edit", site="translations")
 
     def products(self):
-        text = 'Products'
-        return Link('', text, site='translations')
+        text = "Products"
+        return Link("", text, site="translations")
 
     def overview(self):
-        text = 'Overview'
-        link = canonical_url(self.context, rootsite='translations')
-        return Link(link, text, icon='translation')
+        text = "Overview"
+        link = canonical_url(self.context, rootsite="translations")
+        return Link(link, text, icon="translation")
 
 
 class ProjectView(LaunchpadView):
@@ -66,6 +62,6 @@ class ProjectSettingsView(TranslationsMixin, ProjectEditView):
 
     next_url = cancel_url
 
-    @action('Change', name='change')
+    @action("Change", name="change")
     def edit(self, action, data):
         self.updateContextFromData(data)
diff --git a/lib/lp/translations/browser/serieslanguage.py b/lib/lp/translations/browser/serieslanguage.py
index 6004a18..e515105 100644
--- a/lib/lp/translations/browser/serieslanguage.py
+++ b/lib/lp/translations/browser/serieslanguage.py
@@ -4,11 +4,11 @@
 """Browser code for Distro Series Languages."""
 
 __all__ = [
-    'DistroSeriesLanguageNavigation',
-    'DistroSeriesLanguageView',
-    'ProductSeriesLanguageNavigation',
-    'ProductSeriesLanguageView',
-    ]
+    "DistroSeriesLanguageNavigation",
+    "DistroSeriesLanguageView",
+    "ProductSeriesLanguageNavigation",
+    "ProductSeriesLanguageView",
+]
 
 from lp.app.browser.tales import PersonFormatterAPI
 from lp.registry.model.sourcepackagename import SourcePackageName
@@ -20,10 +20,10 @@ from lp.services.webapp.publisher import Navigation
 from lp.translations.enums import TranslationPermission
 from lp.translations.interfaces.distroserieslanguage import (
     IDistroSeriesLanguage,
-    )
+)
 from lp.translations.interfaces.productserieslanguage import (
     IProductSeriesLanguage,
-    )
+)
 from lp.translations.interfaces.translationsperson import ITranslationsPerson
 
 
@@ -47,13 +47,16 @@ class BaseSeriesLanguageView(LaunchpadView):
 
         if IDistroSeriesLanguage.providedBy(self.context):
             self.batchnav = BatchNavigator(
-                self.series.getCurrentTranslationTemplates(),
-                self.request)
+                self.series.getCurrentTranslationTemplates(), self.request
+            )
             self.pofiles = self.context.getPOFilesFor(
-                self.batchnav.currentBatch())
+                self.batchnav.currentBatch()
+            )
             load_related(
-                SourcePackageName, self.batchnav.currentBatch(),
-                ['sourcepackagenameID'])
+                SourcePackageName,
+                self.batchnav.currentBatch(),
+                ["sourcepackagenameID"],
+            )
         else:
             self.batchnav = BatchNavigator(self.context.pofiles, self.request)
             self.pofiles = self.batchnav.currentBatch()
@@ -74,7 +77,8 @@ class BaseSeriesLanguageView(LaunchpadView):
         """
         if self.translation_group is not None:
             team = self.translation_group.query_translator(
-                self.context.language)
+                self.context.language
+            )
         else:
             team = None
         return team
@@ -83,31 +87,36 @@ class BaseSeriesLanguageView(LaunchpadView):
     def access_level_description(self):
         """Must not be called when there's no translation group."""
         if self.user is None:
-            return ("You are not logged in. Please log in to work "
-                    "on translations.")
+            return (
+                "You are not logged in. Please log in to work "
+                "on translations."
+            )
 
         translations_person = ITranslationsPerson(self.user)
         translations_contact_link = None
 
         if self.translation_team:
             translations_contact_link = PersonFormatterAPI(
-                self.translation_team.translator).link(None)
+                self.translation_team.translator
+            ).link(None)
         elif self.translation_group:
             translations_contact_link = PersonFormatterAPI(
-                self.translation_group.owner).link(None)
+                self.translation_group.owner
+            ).link(None)
         else:
-            assert self.translation_group is not None, (
-                "Must not be called when there's no translation group.")
+            assert (
+                self.translation_group is not None
+            ), "Must not be called when there's no translation group."
 
         if not translations_person.translations_relicensing_agreement:
-            translation_license_url = PersonFormatterAPI(
-                self.user).url(
-                    view_name='+licensing',
-                    rootsite='translations')
-            return ("To make translations in Launchpad you need to "
-                    "agree with the "
-                    "<a href='%s'>Translations licensing</a>.") % (
-                        translation_license_url)
+            translation_license_url = PersonFormatterAPI(self.user).url(
+                view_name="+licensing", rootsite="translations"
+            )
+            return (
+                "To make translations in Launchpad you need to "
+                "agree with the "
+                "<a href='%s'>Translations licensing</a>."
+            ) % (translation_license_url)
 
         if len(self.pofiles) > 0:
             sample_pofile = self.pofiles[0]
@@ -115,28 +124,32 @@ class BaseSeriesLanguageView(LaunchpadView):
                 return "You can add and review translations."
 
             if sample_pofile.canAddSuggestions(self.user):
-                return ("Your suggestions will be held for review by "
-                        "%s. If you need help, or your translations are "
-                        "not being reviewed, please get in touch with "
-                        "%s.") % (
-                            translations_contact_link,
-                            translations_contact_link)
+                return (
+                    "Your suggestions will be held for review by "
+                    "%s. If you need help, or your translations are "
+                    "not being reviewed, please get in touch with "
+                    "%s."
+                ) % (translations_contact_link, translations_contact_link)
 
             permission = sample_pofile.translationpermission
             if permission == TranslationPermission.CLOSED:
-                return ("These templates can be translated only by "
-                        "their managers.")
+                return (
+                    "These templates can be translated only by "
+                    "their managers."
+                )
 
         if self.translation_team is None:
-            return ("Since there is nobody to manage translation "
-                    "approvals into this language, you cannot add "
-                    "new suggestions. If you are interested in making "
-                    "translations, please contact %s.") % (
-                        translations_contact_link)
+            return (
+                "Since there is nobody to manage translation "
+                "approvals into this language, you cannot add "
+                "new suggestions. If you are interested in making "
+                "translations, please contact %s."
+            ) % (translations_contact_link)
 
         raise AssertionError(
             "BUG! Couldn't identify the user's access level for these "
-            "translations.")
+            "translations."
+        )
 
 
 class DistroSeriesLanguageView(BaseSeriesLanguageView):
@@ -146,7 +159,8 @@ class DistroSeriesLanguageView(BaseSeriesLanguageView):
         series = self.context.distroseries
         super().initialize(
             series=series,
-            translationgroup=series.distribution.translationgroup)
+            translationgroup=series.distribution.translationgroup,
+        )
         self.parent = self.series.distribution
 
 
@@ -156,17 +170,19 @@ class ProductSeriesLanguageView(BaseSeriesLanguageView):
     def initialize(self):
         series = self.context.productseries
         super().initialize(
-            series=series,
-            translationgroup=series.product.translationgroup)
+            series=series, translationgroup=series.product.translationgroup
+        )
         self.context.recalculateCounts()
         self.parent = self.series.product
 
 
 class DistroSeriesLanguageNavigation(Navigation):
     """Navigation for `IDistroSeriesLanguage`."""
+
     usedfor = IDistroSeriesLanguage
 
 
 class ProductSeriesLanguageNavigation(Navigation):
     """Navigation for `IProductSeriesLanguage`."""
+
     usedfor = IProductSeriesLanguage
diff --git a/lib/lp/translations/browser/sourcepackage.py b/lib/lp/translations/browser/sourcepackage.py
index 1cf947a..23eea43 100644
--- a/lib/lp/translations/browser/sourcepackage.py
+++ b/lib/lp/translations/browser/sourcepackage.py
@@ -4,9 +4,9 @@
 """Browser views for translation pages for sourcepackages."""
 
 __all__ = [
-    'SourcePackageTranslationsExportView',
-    'SourcePackageTranslationsView',
-    ]
+    "SourcePackageTranslationsExportView",
+    "SourcePackageTranslationsView",
+]
 
 
 from lazr.restful.interfaces import IJSONRequestCache
@@ -16,32 +16,30 @@ from lp.registry.browser.productseries import ProductSeriesOverviewMenu
 from lp.registry.browser.sourcepackage import SourcePackageOverviewMenu
 from lp.registry.interfaces.sourcepackage import ISourcePackage
 from lp.services.webapp import (
-    canonical_url,
-    enabled_with_permission,
     Link,
     NavigationMenu,
-    )
+    canonical_url,
+    enabled_with_permission,
+)
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.escaping import structured
 from lp.services.webapp.publisher import LaunchpadView
 from lp.translations.browser.poexportrequest import BaseExportView
 from lp.translations.browser.product import ProductTranslationsMenu
-from lp.translations.browser.productseries import (
-    ProductSeriesTranslationsMenu,
-    )
+from lp.translations.browser.productseries import ProductSeriesTranslationsMenu
 from lp.translations.browser.translations import TranslationsMixin
 from lp.translations.browser.translationsharing import (
     TranslationSharingDetailsMixin,
-    )
+)
 from lp.translations.interfaces.translations import (
     TranslationsBranchImportMode,
-    )
+)
 from lp.translations.model.translationpackagingjob import TranslationMergeJob
 
 
-class SourcePackageTranslationsView(LaunchpadView, TranslationsMixin,
-                                    TranslationSharingDetailsMixin):
-
+class SourcePackageTranslationsView(
+    LaunchpadView, TranslationsMixin, TranslationSharingDetailsMixin
+):
     @property
     def potemplates(self):
         return list(self.context.getCurrentTranslationTemplates())
@@ -64,22 +62,27 @@ class SourcePackageTranslationsView(LaunchpadView, TranslationsMixin,
 
 class SourcePackageTranslationsMenu(NavigationMenu):
     usedfor = ISourcePackage
-    facet = 'translations'
-    links = ('overview', 'download', 'imports')
+    facet = "translations"
+    links = ("overview", "download", "imports")
 
     def imports(self):
-        text = 'Import queue'
-        return Link('+imports', text, site='translations')
+        text = "Import queue"
+        return Link("+imports", text, site="translations")
 
-    @enabled_with_permission('launchpad.ExpensiveRequest')
+    @enabled_with_permission("launchpad.ExpensiveRequest")
     def download(self):
-        text = 'Download'
+        text = "Download"
         enabled = bool(self.context.getCurrentTranslationTemplates().any())
-        return Link('+export', text, icon='download', enabled=enabled,
-                    site='translations')
+        return Link(
+            "+export",
+            text,
+            icon="download",
+            enabled=enabled,
+            site="translations",
+        )
 
     def overview(self):
-        return Link('', 'Overview', icon='info', site='translations')
+        return Link("", "Overview", icon="info", site="translations")
 
 
 class SourcePackageTranslationsExportView(BaseExportView):
@@ -93,7 +96,8 @@ class SourcePackageTranslationsExportView(BaseExportView):
         return "%s package in %s %s" % (
             self.context.sourcepackagename.name,
             self.context.distroseries.distribution.displayname,
-            self.context.distroseries.displayname)
+            self.context.distroseries.displayname,
+        )
 
     @property
     def cancel_url(self):
@@ -113,31 +117,38 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
         return self.context.has_sharing_translation_templates
 
     def can_edit_sharing_details(self):
-        return check_permission('launchpad.Edit', self.context.productseries)
+        return check_permission("launchpad.Edit", self.context.productseries)
 
     def initialize(self):
         super().initialize()
         if self.is_configuration_complete and not self.is_sharing():
             self.request.response.addInfoNotification(
                 structured(
-                'No upstream templates have been found yet. Please follow '
-                'the import process by going to the '
-                '<a href="%s">Translation Import Queue</a> of the '
-                'upstream project series.',
-                canonical_url(
-                    self.context.productseries, rootsite='translations',
-                    view_name="+imports")))
+                    "No upstream templates have been found yet. Please follow "
+                    "the import process by going to the "
+                    '<a href="%s">Translation Import Queue</a> of the '
+                    "upstream project series.",
+                    canonical_url(
+                        self.context.productseries,
+                        rootsite="translations",
+                        view_name="+imports",
+                    ),
+                )
+            )
         if self.is_merge_job_running:
             self.request.response.addInfoNotification(
-                'Translations are currently being linked by a background '
-                'job. When that job has finished, translations will be '
-                'shared with the upstream project.')
+                "Translations are currently being linked by a background "
+                "job. When that job has finished, translations will be "
+                "shared with the upstream project."
+            )
         cache = IJSONRequestCache(self.request)
-        cache.objects.update({
-            'productseries': self.context.productseries,
-            'upstream_branch': self.upstream_branch,
-            'product': self.product,
-        })
+        cache.objects.update(
+            {
+                "productseries": self.context.productseries,
+                "upstream_branch": self.upstream_branch,
+                "product": self.product,
+            }
+        )
         cache.objects.update(self.context.getSharingDetailPermissions())
 
     @property
@@ -145,24 +156,25 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
         if self.has_upstream_branch:
             # Normally should use BranchFormatterAPI(branch).link(None), but
             # on this page, that information is redundant.
-            title = 'lp:' + self.upstream_branch.unique_name
+            title = "lp:" + self.upstream_branch.unique_name
             url = canonical_url(self.upstream_branch)
         else:
-            title = ''
-            url = '#'
+            title = ""
+            url = "#"
         return structured(
-            '<a class="sprite branch link" href="%s">%s</a>', url, title)
+            '<a class="sprite branch link" href="%s">%s</a>', url, title
+        )
 
     def makeConfigCompleteCSS(self, complete, disable, lowlight):
         if complete:
-            classes = ['sprite', 'yes']
+            classes = ["sprite", "yes"]
         else:
-            classes = ['sprite', 'no']
+            classes = ["sprite", "no"]
         if disable:
-            classes.append('hidden')
+            classes.append("hidden")
         if lowlight:
             classes.append("lowlight")
-        return ' '.join(classes)
+        return " ".join(classes)
 
     @property
     def configuration_complete_class(self):
@@ -179,47 +191,60 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
     @property
     def packaging_incomplete_class(self):
         return self.makeConfigCompleteCSS(
-            False, self.is_packaging_configured, False)
+            False, self.is_packaging_configured, False
+        )
 
     @property
     def packaging_complete_class(self):
         return self.makeConfigCompleteCSS(
-            True, not self.is_packaging_configured, False)
+            True, not self.is_packaging_configured, False
+        )
 
     @property
     def branch_incomplete_class(self):
         return self.makeConfigCompleteCSS(
-            False, self.has_upstream_branch, not self.is_packaging_configured)
+            False, self.has_upstream_branch, not self.is_packaging_configured
+        )
 
     @property
     def branch_complete_class(self):
         return self.makeConfigCompleteCSS(
-            True, not self.has_upstream_branch,
-            not self.is_packaging_configured)
+            True,
+            not self.has_upstream_branch,
+            not self.is_packaging_configured,
+        )
 
     @property
     def translations_disabled_class(self):
         return self.makeConfigCompleteCSS(
-            False, self.is_upstream_translations_enabled,
-            not self.is_packaging_configured)
+            False,
+            self.is_upstream_translations_enabled,
+            not self.is_packaging_configured,
+        )
 
     @property
     def translations_enabled_class(self):
         return self.makeConfigCompleteCSS(
-            True, not self.is_upstream_translations_enabled,
-            not self.is_packaging_configured)
+            True,
+            not self.is_upstream_translations_enabled,
+            not self.is_packaging_configured,
+        )
 
     @property
     def upstream_sync_disabled_class(self):
         return self.makeConfigCompleteCSS(
-            False, self.is_upstream_synchronization_enabled,
-            not self.is_packaging_configured)
+            False,
+            self.is_upstream_synchronization_enabled,
+            not self.is_packaging_configured,
+        )
 
     @property
     def upstream_sync_enabled_class(self):
         return self.makeConfigCompleteCSS(
-            True, not self.is_upstream_synchronization_enabled,
-            not self.is_packaging_configured)
+            True,
+            not self.is_upstream_synchronization_enabled,
+            not self.is_packaging_configured,
+        )
 
     @property
     def is_packaging_configured(self):
@@ -259,7 +284,9 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
             return False
         product = self.context.direct_packaging.productseries.product
         return product.translations_usage in (
-            ServiceUsage.LAUNCHPAD, ServiceUsage.EXTERNAL)
+            ServiceUsage.LAUNCHPAD,
+            ServiceUsage.EXTERNAL,
+        )
 
     @property
     def is_upstream_synchronization_enabled(self):
@@ -268,8 +295,9 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
             return False
         series = self.context.direct_packaging.productseries
         return (
-            series.translations_autoimport_mode ==
-            TranslationsBranchImportMode.IMPORT_TRANSLATIONS)
+            series.translations_autoimport_mode
+            == TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+        )
 
     @property
     def is_configuration_complete(self):
@@ -277,17 +305,20 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
         # A check if the required packaging link exists is implicitly
         # done in the implementation of the other properties.
         return (
-            self.has_upstream_branch and
-            self.is_upstream_translations_enabled and
-            self.is_upstream_synchronization_enabled)
+            self.has_upstream_branch
+            and self.is_upstream_translations_enabled
+            and self.is_upstream_synchronization_enabled
+        )
 
     @property
     def is_merge_job_running(self):
         """Is a merge job running for this source package?"""
         if not self.is_packaging_configured:
             return False
-        return TranslationMergeJob.getNextJobStatus(
-            self.context.direct_packaging) is not None
+        return (
+            TranslationMergeJob.getNextJobStatus(self.context.direct_packaging)
+            is not None
+        )
 
     def template_info(self):
         """Details about translation templates.
@@ -305,40 +336,41 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
         templates_on_this_side = self.context.getCurrentTranslationTemplates()
         for template in templates_on_this_side:
             info[template.name] = {
-                'name': template.name,
-                'package_template': template,
-                'upstream_template': None,
-                'status': 'only in Ubuntu',
-                }
+                "name": template.name,
+                "package_template": template,
+                "upstream_template": None,
+                "status": "only in Ubuntu",
+            }
         if self.is_packaging_configured:
             upstream_templates = (
-                self.context.productseries.getCurrentTranslationTemplates())
+                self.context.productseries.getCurrentTranslationTemplates()
+            )
             for template in upstream_templates:
                 if template.name in info:
-                    info[template.name]['upstream_template'] = template
+                    info[template.name]["upstream_template"] = template
                     if self.is_merge_job_running:
-                        info[template.name]['status'] = 'linking'
+                        info[template.name]["status"] = "linking"
                     else:
-                        info[template.name]['status'] = 'shared'
+                        info[template.name]["status"] = "shared"
                 else:
                     info[template.name] = {
-                        'name': template.name,
-                        'package_template': None,
-                        'upstream_template': template,
-                        'status': 'only in upstream',
-                        }
+                        "name": template.name,
+                        "package_template": None,
+                        "upstream_template": template,
+                        "status": "only in upstream",
+                    }
         info = info.values()
-        return sorted(info, key=lambda template: template['name'])
+        return sorted(info, key=lambda template: template["name"])
 
     def icon_link(self, id, icon, url, text, hidden):
         """The HTML link to a configuration page."""
         if hidden:
-            css_class = 'sprite %s action-icon hidden' % icon
+            css_class = "sprite %s action-icon hidden" % icon
         else:
-            css_class = 'sprite %s action-icon' % icon
+            css_class = "sprite %s action-icon" % icon
         return structured(
-            '<a id="%s" class="%s" href="%s">%s</a>',
-            id, css_class, url, text)
+            '<a id="%s" class="%s" href="%s">%s</a>', id, css_class, url, text
+        )
 
     @property
     def set_packaging_link(self):
@@ -347,25 +379,28 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
         # ink itself because it is not rendered when the current
         # user cannot change an existing packaging.
         link = SourcePackageOverviewMenu(self.context).set_upstream()
-        url = '%s/%s' % (canonical_url(self.context), link.target)
+        url = "%s/%s" % (canonical_url(self.context), link.target)
         return self.icon_link(
-            'set-packaging', link.icon, url, link.text, not link.enabled)
+            "set-packaging", link.icon, url, link.text, not link.enabled
+        )
 
     @property
     def change_packaging_link(self):
         """The HTML link to change an existing packaging link."""
         link = SourcePackageOverviewMenu(self.context).edit_packaging()
-        url = '%s/%s' % (canonical_url(self.context), link.target)
+        url = "%s/%s" % (canonical_url(self.context), link.target)
         return self.icon_link(
-            'change-packaging', link.icon, url, link.text, not link.enabled)
+            "change-packaging", link.icon, url, link.text, not link.enabled
+        )
 
     @property
     def remove_packaging_link(self):
         """The HTML link to delete an existing packaging link"""
         link = SourcePackageOverviewMenu(self.context).remove_packaging()
-        url = '%s/%s' % (canonical_url(self.context), link.target)
+        url = "%s/%s" % (canonical_url(self.context), link.target)
         return self.icon_link(
-            'remove-packaging', link.icon, url, link.text, not link.enabled)
+            "remove-packaging", link.icon, url, link.text, not link.enabled
+        )
 
     def edit_branch_link(self, id, icon, text):
         """The HTML link to define or edit a product series branch.
@@ -379,39 +414,38 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
             productseries = self.context.direct_packaging.productseries
             productseries_menu = ProductSeriesOverviewMenu(productseries)
             branch_link = productseries_menu.set_branch()
-            url = '%s/%s' % (canonical_url(productseries), branch_link.target)
+            url = "%s/%s" % (canonical_url(productseries), branch_link.target)
             if branch_link.enabled:
                 return self.icon_link(id, icon, url, text, hidden=False)
             else:
                 return self.icon_link(id, icon, url, text, hidden=True)
-        return self.icon_link(id, icon, '#', text, hidden=True)
+        return self.icon_link(id, icon, "#", text, hidden=True)
 
     @property
     def new_branch_link(self):
         """The HTML link to define a product series branch."""
-        return self.edit_branch_link('add-branch', 'add', 'Link to branch')
+        return self.edit_branch_link("add-branch", "add", "Link to branch")
 
     @property
     def change_branch_link(self):
         """The HTML link to change a product series branch."""
-        return self.edit_branch_link('change-branch', 'edit', 'Change branch')
+        return self.edit_branch_link("change-branch", "edit", "Change branch")
 
     def getConfigureTranslationsLink(self, id):
-        """The HTML link to the product translation configuration page.
-        """
+        """The HTML link to the product translation configuration page."""
         packaging = self.context.direct_packaging
         if packaging is not None:
             productseries = self.context.direct_packaging.productseries
             product = productseries.product
             product_menu = ProductTranslationsMenu(product)
             settings_link = product_menu.settings()
-            url = '%s/%s' % (canonical_url(product), settings_link.target)
+            url = "%s/%s" % (canonical_url(product), settings_link.target)
             hidden = not settings_link.enabled
         else:
-            url = '#'
+            url = "#"
             hidden = True
-        icon = 'edit'
-        text = 'Configure Upstream Translations'
+        icon = "edit"
+        text = "Configure Upstream Translations"
         return self.icon_link(id, icon, url, text, hidden)
 
     @property
@@ -420,7 +454,7 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
 
         Variant for the status "not configured"
         """
-        id = 'upstream-translations-incomplete'
+        id = "upstream-translations-incomplete"
         return self.getConfigureTranslationsLink(id)
 
     @property
@@ -429,25 +463,26 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
 
         Variant for the status "configured"
         """
-        id = 'upstream-translations-complete'
+        id = "upstream-translations-complete"
         return self.getConfigureTranslationsLink(id)
 
     def getTranslationSynchronisationLink(self, id):
-        """The HTML link to the series translation synchronisation page.
-        """
+        """The HTML link to the series translation synchronisation page."""
         packaging = self.context.direct_packaging
         if packaging is not None:
             productseries = self.context.direct_packaging.productseries
             productseries_menu = ProductSeriesTranslationsMenu(productseries)
             settings_link = productseries_menu.settings()
-            url = '%s/%s' % (
-                canonical_url(productseries), settings_link.target)
+            url = "%s/%s" % (
+                canonical_url(productseries),
+                settings_link.target,
+            )
             hidden = not settings_link.enabled
         else:
-            url = '#'
+            url = "#"
             hidden = True
-        icon = 'edit'
-        text = 'Configure Translation Synchronisation'
+        icon = "edit"
+        text = "Configure Translation Synchronisation"
         return self.icon_link(id, icon, url, text, hidden)
 
     @property
@@ -456,7 +491,7 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
 
         Variant for the status "not configured"
         """
-        id = 'translation-synchronisation-incomplete'
+        id = "translation-synchronisation-incomplete"
         return self.getTranslationSynchronisationLink(id)
 
     @property
@@ -465,5 +500,5 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
 
         Variant for the status "configured"
         """
-        id = 'translation-synchronisation-complete'
+        id = "translation-synchronisation-complete"
         return self.getTranslationSynchronisationLink(id)
diff --git a/lib/lp/translations/browser/tests/test_baseexportview.py b/lib/lp/translations/browser/tests/test_baseexportview.py
index d4f3488..9ac120f 100644
--- a/lib/lp/translations/browser/tests/test_baseexportview.py
+++ b/lib/lp/translations/browser/tests/test_baseexportview.py
@@ -1,8 +1,8 @@
 # Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from datetime import timedelta
 import unittest
+from datetime import timedelta
 
 import transaction
 
@@ -12,13 +12,13 @@ from lp.testing import TestCaseWithFactory
 from lp.testing.layers import ZopelessDatabaseLayer
 from lp.translations.browser.productseries import (
     ProductSeriesTranslationsExportView,
-    )
+)
 from lp.translations.browser.sourcepackage import (
     SourcePackageTranslationsExportView,
-    )
+)
 from lp.translations.interfaces.translationfileformat import (
     TranslationFileFormat,
-    )
+)
 from lp.translations.model.poexportrequest import POExportRequest
 
 
@@ -40,7 +40,8 @@ class BaseExportViewMixin(TestCaseWithFactory):
     def createTranslationTemplate(self, name, priority=0):
         """Attaches a template to appropriate container."""
         raise NotImplementedError(
-            'This must be provided by an executable test.')
+            "This must be provided by an executable test."
+        )
 
     def test_uses_translations_no_templates(self):
         # With no templates in an object, it's not using translations yet.
@@ -65,22 +66,22 @@ class BaseExportViewMixin(TestCaseWithFactory):
         template1 = self.createTranslationTemplate("one")
         template1.source_file_format = TranslationFileFormat.XPI
         self.assertEqual(
-            TranslationFileFormat.XPI,
-            self.view.getDefaultFormat())
+            TranslationFileFormat.XPI, self.view.getDefaultFormat()
+        )
 
         # With multiple templates, format with a lower ID is returned
         # if they are different, where PO (1) < XPI (3).
         template2 = self.createTranslationTemplate("two")
         template2.source_file_format = TranslationFileFormat.PO
         self.assertEqual(
-            TranslationFileFormat.PO,
-            self.view.getDefaultFormat())
+            TranslationFileFormat.PO, self.view.getDefaultFormat()
+        )
 
         # Obsolete templates do not affect default file format.
         template2.iscurrent = False
         self.assertEqual(
-            TranslationFileFormat.XPI,
-            self.view.getDefaultFormat())
+            TranslationFileFormat.XPI, self.view.getDefaultFormat()
+        )
 
     def test_processForm_empty(self):
         # With no templates, empty ResultSet is returned for templates,
@@ -113,23 +114,23 @@ class BaseExportViewMixin(TestCaseWithFactory):
         self.assertIsNone(translations)
 
         # Adding a PO file to this template makes it returned.
-        pofile_sr = self.factory.makePOFile('sr', potemplate=template1)
+        pofile_sr = self.factory.makePOFile("sr", potemplate=template1)
         templates, translations = self.view.processForm()
         self.assertContentEqual([pofile_sr.id], translations)
 
         # If there are two PO files on the same template, they are
         # both returned.
-        pofile_es = self.factory.makePOFile('es', potemplate=template1)
+        pofile_es = self.factory.makePOFile("es", potemplate=template1)
         templates, translations = self.view.processForm()
         self.assertContentEqual([pofile_sr.id, pofile_es.id], translations)
 
         # With more than one template, PO files from both are returned.
         template2 = self.createTranslationTemplate("two", priority=2)
-        pofile_sr2 = self.factory.makePOFile('sr', potemplate=template2)
+        pofile_sr2 = self.factory.makePOFile("sr", potemplate=template2)
         templates, translations = self.view.processForm()
         self.assertContentEqual(
-            [pofile_sr.id, pofile_es.id, pofile_sr2.id],
-            translations)
+            [pofile_sr.id, pofile_es.id, pofile_sr2.id], translations
+        )
 
 
 class TestProductSeries(BaseExportViewMixin):
@@ -137,7 +138,8 @@ class TestProductSeries(BaseExportViewMixin):
 
     def createTranslationTemplate(self, name, priority=0):
         potemplate = self.factory.makePOTemplate(
-            name=name, productseries=self.container)
+            name=name, productseries=self.container
+        )
         potemplate.priority = priority
         return potemplate
 
@@ -145,7 +147,8 @@ class TestProductSeries(BaseExportViewMixin):
         super().setUp()
         self.container = self.factory.makeProductSeries()
         self.view = ProductSeriesTranslationsExportView(
-            self.container, LaunchpadTestRequest())
+            self.container, LaunchpadTestRequest()
+        )
 
 
 class TestSourcePackage(BaseExportViewMixin):
@@ -153,8 +156,10 @@ class TestSourcePackage(BaseExportViewMixin):
 
     def createTranslationTemplate(self, name, priority=0):
         potemplate = self.factory.makePOTemplate(
-            name=name, distroseries=self.container.distroseries,
-            sourcepackagename=self.container.sourcepackagename)
+            name=name,
+            distroseries=self.container.distroseries,
+            sourcepackagename=self.container.sourcepackagename,
+        )
         potemplate.priority = priority
         return potemplate
 
@@ -162,7 +167,8 @@ class TestSourcePackage(BaseExportViewMixin):
         super().setUp()
         self.container = self.factory.makeSourcePackage()
         self.view = SourcePackageTranslationsExportView(
-            self.container, LaunchpadTestRequest())
+            self.container, LaunchpadTestRequest()
+        )
 
 
 class TestPOExportQueueStatusDescriptions(TestCaseWithFactory):
@@ -173,20 +179,24 @@ class TestPOExportQueueStatusDescriptions(TestCaseWithFactory):
         super().setUp()
         self.container = self.factory.makeProductSeries()
         self.view = ProductSeriesTranslationsExportView(
-            self.container, LaunchpadTestRequest())
+            self.container, LaunchpadTestRequest()
+        )
 
     def test_describeQueueSize(self):
         self.assertEqual(
             "The export queue is currently empty.",
-            self.view.describeQueueSize(0))
+            self.view.describeQueueSize(0),
+        )
 
         self.assertEqual(
             "There is 1 file request on the export queue.",
-            self.view.describeQueueSize(1))
+            self.view.describeQueueSize(1),
+        )
 
         self.assertEqual(
             "There are 2 file requests on the export queue.",
-            self.view.describeQueueSize(2))
+            self.view.describeQueueSize(2),
+        )
 
     def test_describeBacklog(self):
         backlog = None
@@ -195,7 +205,8 @@ class TestPOExportQueueStatusDescriptions(TestCaseWithFactory):
         backlog = timedelta(hours=2)
         self.assertEqual(
             "The backlog is approximately 2 hours.",
-            self.view.describeBacklog(backlog).strip())
+            self.view.describeBacklog(backlog).strip(),
+        )
 
     def test_export_queue_status(self):
         self.view.initialize()
@@ -207,8 +218,7 @@ class TestPOExportQueueStatusDescriptions(TestCaseWithFactory):
         size = self.view.describeQueueSize(0)
         backlog = self.view.describeBacklog(None)
         status = "%s %s" % (size, backlog)
-        self.assertEqual(
-            status.strip(), self.view.export_queue_status.strip())
+        self.assertEqual(status.strip(), self.view.export_queue_status.strip())
 
         potemplate = self.factory.makePOTemplate()
         queue.addRequest(requester, potemplates=[potemplate])
@@ -217,8 +227,7 @@ class TestPOExportQueueStatusDescriptions(TestCaseWithFactory):
         size = self.view.describeQueueSize(1)
         backlog = self.view.describeBacklog(queue.estimateBacklog())
         status = "%s %s" % (size, backlog)
-        self.assertEqual(
-            status.strip(), self.view.export_queue_status.strip())
+        self.assertEqual(status.strip(), self.view.export_queue_status.strip())
 
 
 def test_suite():
@@ -226,6 +235,7 @@ def test_suite():
     loader = unittest.TestLoader()
     suite.addTest(loader.loadTestsFromTestCase(TestProductSeries))
     suite.addTest(loader.loadTestsFromTestCase(TestSourcePackage))
-    suite.addTest(loader.loadTestsFromTestCase(
-        TestPOExportQueueStatusDescriptions))
+    suite.addTest(
+        loader.loadTestsFromTestCase(TestPOExportQueueStatusDescriptions)
+    )
     return suite
diff --git a/lib/lp/translations/browser/tests/test_breadcrumbs.py b/lib/lp/translations/browser/tests/test_breadcrumbs.py
index b368e22..a4b6e91 100644
--- a/lib/lp/translations/browser/tests/test_breadcrumbs.py
+++ b/lib/lp/translations/browser/tests/test_breadcrumbs.py
@@ -10,143 +10,225 @@ from lp.testing.breadcrumbs import BaseBreadcrumbTestCase
 from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
 from lp.translations.interfaces.distroserieslanguage import (
     IDistroSeriesLanguageSet,
-    )
+)
 from lp.translations.interfaces.productserieslanguage import (
     IProductSeriesLanguageSet,
-    )
+)
 from lp.translations.interfaces.translationgroup import ITranslationGroupSet
 
 
 class TestTranslationsFacetBreadcrumb(BaseBreadcrumbTestCase):
-
     def test_product(self):
         product = self.factory.makeProduct(
-            name='crumb-tester', displayname="Crumb Tester")
+            name="crumb-tester", displayname="Crumb Tester"
+        )
         self.assertBreadcrumbs(
-            [("Crumb Tester", 'http://launchpad.test/crumb-tester'),
-             ("Translations",
-              'http://translations.launchpad.test/crumb-tester')],
-            product, rootsite='translations')
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+            ],
+            product,
+            rootsite="translations",
+        )
 
     def test_productseries(self):
         product = self.factory.makeProduct(
-            name='crumb-tester', displayname="Crumb Tester")
+            name="crumb-tester", displayname="Crumb Tester"
+        )
         series = self.factory.makeProductSeries(name="test", product=product)
         self.assertBreadcrumbs(
-            [("Crumb Tester", 'http://launchpad.test/crumb-tester'),
-             ("Translations",
-              'http://translations.launchpad.test/crumb-tester'),
-             ("Series test",
-              'http://translations.launchpad.test/crumb-tester/test')],
-            series, rootsite='translations')
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+                (
+                    "Series test",
+                    "http://translations.launchpad.test/crumb-tester/test";,
+                ),
+            ],
+            series,
+            rootsite="translations",
+        )
 
     def test_distribution(self):
         distribution = self.factory.makeDistribution(
-            name='crumb-tester', displayname="Crumb Tester")
+            name="crumb-tester", displayname="Crumb Tester"
+        )
         self.assertBreadcrumbs(
-            [("Crumb Tester", 'http://launchpad.test/crumb-tester'),
-             ("Translations",
-              'http://translations.launchpad.test/crumb-tester')],
-            distribution, rootsite='translations')
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+            ],
+            distribution,
+            rootsite="translations",
+        )
 
     def test_distroseries(self):
         distribution = self.factory.makeDistribution(
-            name='crumb-tester', displayname="Crumb Tester")
+            name="crumb-tester", displayname="Crumb Tester"
+        )
         series = self.factory.makeDistroSeries(
-            name="test", version="1.0", distribution=distribution)
+            name="test", version="1.0", distribution=distribution
+        )
         self.assertBreadcrumbs(
-            [("Crumb Tester", 'http://launchpad.test/crumb-tester'),
-             ("Translations",
-              'http://translations.launchpad.test/crumb-tester'),
-             ("Test (1.0)",
-              'http://translations.launchpad.test/crumb-tester/test')],
-            series, rootsite='translations')
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+                (
+                    "Test (1.0)",
+                    "http://translations.launchpad.test/crumb-tester/test";,
+                ),
+            ],
+            series,
+            rootsite="translations",
+        )
 
     def test_project(self):
         project = self.factory.makeProject(
-            name='crumb-tester', displayname="Crumb Tester")
+            name="crumb-tester", displayname="Crumb Tester"
+        )
         self.assertBreadcrumbs(
-            [("Crumb Tester", 'http://launchpad.test/crumb-tester'),
-             ("Translations",
-              'http://translations.launchpad.test/crumb-tester')],
-            project, rootsite='translations')
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+            ],
+            project,
+            rootsite="translations",
+        )
 
     def test_person(self):
         person = self.factory.makePerson(
-            name='crumb-tester', displayname="Crumb Tester")
+            name="crumb-tester", displayname="Crumb Tester"
+        )
         self.assertBreadcrumbs(
-            [("Crumb Tester", 'http://launchpad.test/~crumb-tester'),
-             ("Translations",
-              'http://translations.launchpad.test/~crumb-tester')],
-            person, rootsite='translations')
+            [
+                ("Crumb Tester", "http://launchpad.test/~crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/~crumb-tester";,
+                ),
+            ],
+            person,
+            rootsite="translations",
+        )
 
 
 class TestTranslationGroupsBreadcrumbs(BaseBreadcrumbTestCase):
-
     def test_translationgroupset(self):
         group_set = getUtility(ITranslationGroupSet)
         self.assertBreadcrumbs(
-            [("Translation groups",
-              'http://translations.launchpad.test/+groups')],
-            group_set, rootsite='translations')
+            [
+                (
+                    "Translation groups",
+                    "http://translations.launchpad.test/+groups";,
+                )
+            ],
+            group_set,
+            rootsite="translations",
+        )
 
     def test_translationgroup(self):
         group = self.factory.makeTranslationGroup(
-            name='test-translators', title='Test translators')
+            name="test-translators", title="Test translators"
+        )
         self.assertBreadcrumbs(
-            [("Translation groups",
-              'http://translations.launchpad.test/+groups'),
-             ("Test translators",
-              'http://translations.launchpad.test/+groups/test-translators')],
-            group, rootsite='translations')
+            [
+                (
+                    "Translation groups",
+                    "http://translations.launchpad.test/+groups";,
+                ),
+                (
+                    "Test translators",
+                    "http://translations.launchpad.test/+groups/";
+                    "test-translators",
+                ),
+            ],
+            group,
+            rootsite="translations",
+        )
 
 
 class TestSeriesLanguageBreadcrumbs(BaseBreadcrumbTestCase):
-
     def setUp(self):
         super().setUp()
-        self.language = getUtility(ILanguageSet)['sr']
+        self.language = getUtility(ILanguageSet)["sr"]
 
     def test_distroserieslanguage(self):
         distribution = self.factory.makeDistribution(
-            name='crumb-tester', displayname="Crumb Tester")
+            name="crumb-tester", displayname="Crumb Tester"
+        )
         series = self.factory.makeDistroSeries(
-            name="test", version="1.0", distribution=distribution)
+            name="test", version="1.0", distribution=distribution
+        )
         naked_series = remove_security_proxy_and_shout_at_engineer(series)
         naked_series.hide_all_translations = False
         serieslanguage = getUtility(IDistroSeriesLanguageSet).getEmpty(
-            series, self.language)
+            series, self.language
+        )
 
         self.assertBreadcrumbs(
-            [("Crumb Tester", "http://launchpad.test/crumb-tester";),
-             ("Translations",
-              "http://translations.launchpad.test/crumb-tester";),
-             ("Test (1.0)",
-              "http://translations.launchpad.test/crumb-tester/test";),
-             ("Serbian (sr)",
-              "http://translations.launchpad.test/";
-              "crumb-tester/test/+lang/sr")],
-            serieslanguage)
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+                (
+                    "Test (1.0)",
+                    "http://translations.launchpad.test/crumb-tester/test";,
+                ),
+                (
+                    "Serbian (sr)",
+                    "http://translations.launchpad.test/";
+                    "crumb-tester/test/+lang/sr",
+                ),
+            ],
+            serieslanguage,
+        )
 
     def test_productserieslanguage(self):
         product = self.factory.makeProduct(
-            name='crumb-tester', displayname="Crumb Tester")
-        series = self.factory.makeProductSeries(
-            name="test", product=product)
+            name="crumb-tester", displayname="Crumb Tester"
+        )
+        series = self.factory.makeProductSeries(name="test", product=product)
         psl_set = getUtility(IProductSeriesLanguageSet)
         serieslanguage = psl_set.getProductSeriesLanguage(
-            series, self.language)
+            series, self.language
+        )
 
         self.assertBreadcrumbs(
-            [("Crumb Tester", "http://launchpad.test/crumb-tester";),
-             ("Translations",
-              "http://translations.launchpad.test/crumb-tester";),
-             ("Series test",
-              "http://translations.launchpad.test/crumb-tester/test";),
-             ("Serbian (sr)",
-              "http://translations.launchpad.test/";
-              "crumb-tester/test/+lang/sr")],
-            serieslanguage)
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+                (
+                    "Series test",
+                    "http://translations.launchpad.test/crumb-tester/test";,
+                ),
+                (
+                    "Serbian (sr)",
+                    "http://translations.launchpad.test/";
+                    "crumb-tester/test/+lang/sr",
+                ),
+            ],
+            serieslanguage,
+        )
 
 
 class TestPOTemplateBreadcrumbs(BaseBreadcrumbTestCase):
@@ -154,47 +236,70 @@ class TestPOTemplateBreadcrumbs(BaseBreadcrumbTestCase):
 
     def test_potemplate(self):
         product = self.factory.makeProduct(
-            name='crumb-tester', displayname="Crumb Tester",
-            translations_usage=ServiceUsage.LAUNCHPAD)
-        series = self.factory.makeProductSeries(
-            name="test", product=product)
+            name="crumb-tester",
+            displayname="Crumb Tester",
+            translations_usage=ServiceUsage.LAUNCHPAD,
+        )
+        series = self.factory.makeProductSeries(name="test", product=product)
         potemplate = self.factory.makePOTemplate(
-            name="template", productseries=series)
+            name="template", productseries=series
+        )
         self.assertBreadcrumbs(
-            [("Crumb Tester", "http://launchpad.test/crumb-tester";),
-             ("Translations",
-              "http://translations.launchpad.test/crumb-tester";),
-             ("Series test",
-              "http://translations.launchpad.test/crumb-tester/test";),
-             (smartquote('Template "template"'),
-              "http://translations.launchpad.test/";
-              "crumb-tester/test/+pots/template")],
-            potemplate)
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+                (
+                    "Series test",
+                    "http://translations.launchpad.test/crumb-tester/test";,
+                ),
+                (
+                    smartquote('Template "template"'),
+                    "http://translations.launchpad.test/";
+                    "crumb-tester/test/+pots/template",
+                ),
+            ],
+            potemplate,
+        )
 
 
 class TestPOFileBreadcrumbs(BaseBreadcrumbTestCase):
-
     def setUp(self):
         super().setUp()
 
     def test_pofiletranslate(self):
         product = self.factory.makeProduct(
-            name='crumb-tester', displayname="Crumb Tester",
-            translations_usage=ServiceUsage.LAUNCHPAD)
+            name="crumb-tester",
+            displayname="Crumb Tester",
+            translations_usage=ServiceUsage.LAUNCHPAD,
+        )
         series = self.factory.makeProductSeries(name="test", product=product)
         potemplate = self.factory.makePOTemplate(series, name="test-template")
-        pofile = self.factory.makePOFile('eo', potemplate)
+        pofile = self.factory.makePOFile("eo", potemplate)
 
         self.assertBreadcrumbs(
-            [("Crumb Tester", "http://launchpad.test/crumb-tester";),
-             ("Translations",
-              "http://translations.launchpad.test/crumb-tester";),
-             ("Series test",
-              "http://translations.launchpad.test/crumb-tester/test";),
-             (smartquote('Template "test-template"'),
-              "http://translations.launchpad.test/crumb-tester/test";
-              "/+pots/test-template"),
-             ("Esperanto (eo)",
-              "http://translations.launchpad.test/crumb-tester/test";
-              "/+pots/test-template/eo")],
-            pofile)
+            [
+                ("Crumb Tester", "http://launchpad.test/crumb-tester";),
+                (
+                    "Translations",
+                    "http://translations.launchpad.test/crumb-tester";,
+                ),
+                (
+                    "Series test",
+                    "http://translations.launchpad.test/crumb-tester/test";,
+                ),
+                (
+                    smartquote('Template "test-template"'),
+                    "http://translations.launchpad.test/crumb-tester/test";
+                    "/+pots/test-template",
+                ),
+                (
+                    "Esperanto (eo)",
+                    "http://translations.launchpad.test/crumb-tester/test";
+                    "/+pots/test-template/eo",
+                ),
+            ],
+            pofile,
+        )
diff --git a/lib/lp/translations/browser/tests/test_distribution_views.py b/lib/lp/translations/browser/tests/test_distribution_views.py
index a92d5eb..8a805c6 100644
--- a/lib/lp/translations/browser/tests/test_distribution_views.py
+++ b/lib/lp/translations/browser/tests/test_distribution_views.py
@@ -7,10 +7,7 @@ from fixtures import FakeLogger
 from zope.security.interfaces import Unauthorized
 
 from lp.services.webapp import canonical_url
-from lp.testing import (
-    person_logged_in,
-    TestCaseWithFactory,
-    )
+from lp.testing import TestCaseWithFactory, person_logged_in
 from lp.testing.layers import LaunchpadFunctionalLayer
 from lp.testing.views import create_initialized_view
 
@@ -25,14 +22,17 @@ class TestDistributionSettingsView(TestCaseWithFactory):
         # in the distribution translation settings form view.
         distribution = self.factory.makeDistribution()
         view = create_initialized_view(
-            distribution, '+configure-translations', rootsite='translations')
+            distribution, "+configure-translations", rootsite="translations"
+        )
         self.assertContentEqual(
-            ["translations_usage",
-             "translation_focus",
-             "translationgroup",
-             "translationpermission",
-             ],
-            view.field_names)
+            [
+                "translations_usage",
+                "translation_focus",
+                "translationgroup",
+                "translationpermission",
+            ],
+            view.field_names,
+        )
 
     def test_unprivileged_users(self):
         # Unprivileged users cannot access distribution translation settings
@@ -40,8 +40,11 @@ class TestDistributionSettingsView(TestCaseWithFactory):
         self.useFixture(FakeLogger())
         unprivileged = self.factory.makePerson()
         distribution = self.factory.makeDistribution()
-        url = canonical_url(distribution, view_name='+configure-translations',
-                            rootsite='translations')
+        url = canonical_url(
+            distribution,
+            view_name="+configure-translations",
+            rootsite="translations",
+        )
         browser = self.getUserBrowser(user=unprivileged)
         self.assertRaises(Unauthorized, browser.open, url)
 
@@ -53,8 +56,11 @@ class TestDistributionSettingsView(TestCaseWithFactory):
         distribution = self.factory.makeDistribution()
         with person_logged_in(distribution.owner):
             distribution.translationgroup = group
-        url = canonical_url(distribution, view_name='+configure-translations',
-                            rootsite='translations')
+        url = canonical_url(
+            distribution,
+            view_name="+configure-translations",
+            rootsite="translations",
+        )
         browser = self.getUserBrowser(user=group.owner)
         # No "Unauthorized" exception is thrown.
         browser.open(url)
@@ -64,8 +70,11 @@ class TestDistributionSettingsView(TestCaseWithFactory):
         # launchpad.TranslationsAdmin privileges on it, meaning they
         # can access Distribution:+configure-translations page.
         distribution = self.factory.makeDistribution()
-        url = canonical_url(distribution, view_name='+configure-translations',
-                            rootsite='translations')
+        url = canonical_url(
+            distribution,
+            view_name="+configure-translations",
+            rootsite="translations",
+        )
         browser = self.getUserBrowser(user=distribution.owner)
         # No "Unauthorized" exception is thrown.
         browser.open(url)
diff --git a/lib/lp/translations/browser/tests/test_distroseries_views.py b/lib/lp/translations/browser/tests/test_distroseries_views.py
index 9d08fa5..48c7bf0 100644
--- a/lib/lp/translations/browser/tests/test_distroseries_views.py
+++ b/lib/lp/translations/browser/tests/test_distroseries_views.py
@@ -10,16 +10,13 @@ from testtools.matchers import (
     MatchesAll,
     MatchesListwise,
     StartsWith,
-    )
+)
 from zope.component import getUtility
 
 from lp.services.beautifulsoup import BeautifulSoup
 from lp.services.config import config
 from lp.services.webapp import canonical_url
-from lp.testing import (
-    person_logged_in,
-    TestCaseWithFactory,
-    )
+from lp.testing import TestCaseWithFactory, person_logged_in
 from lp.testing.layers import LaunchpadFunctionalLayer
 from lp.testing.pages import extract_link_from_tag
 from lp.testing.views import create_initialized_view
@@ -32,7 +29,7 @@ def get_librarian_download_links_on_page(page_content):
     librarian_base_domain = urlsplit(config.librarian.download_url).netloc
 
     soup = BeautifulSoup(page_content)
-    for anchor_tag in soup.find_all('a'):
+    for anchor_tag in soup.find_all("a"):
         href = extract_link_from_tag(anchor_tag)
         if urlsplit(href).netloc == librarian_base_domain:
             librarian_download_links.append(href)
@@ -50,25 +47,26 @@ class TestLanguagePacksView(TestCaseWithFactory):
         language_pack_set.addLanguagePack(
             distroseries,
             self.factory.makeLibraryFileAlias(
-                filename='test-translations-unused.tar.gz'
+                filename="test-translations-unused.tar.gz"
             ),
-            LanguagePackType.FULL
+            LanguagePackType.FULL,
         )
         with person_logged_in(distroseries.owner):
-            distroseries.language_pack_base = \
+            distroseries.language_pack_base = (
                 language_pack_set.addLanguagePack(
                     distroseries,
                     self.factory.makeLibraryFileAlias(
-                        filename='test-translations.tar.gz'
+                        filename="test-translations.tar.gz"
                     ),
-                    LanguagePackType.FULL
+                    LanguagePackType.FULL,
                 )
+            )
             delta_pack = language_pack_set.addLanguagePack(
                 distroseries,
                 self.factory.makeLibraryFileAlias(
-                    filename='test-translations-update.tar.gz'
+                    filename="test-translations-update.tar.gz"
                 ),
-                LanguagePackType.DELTA
+                LanguagePackType.DELTA,
             )
             distroseries.language_pack_delta = delta_pack
             distroseries.language_pack_proposed = delta_pack
@@ -81,10 +79,12 @@ class TestLanguagePacksView(TestCaseWithFactory):
             self.factory.makeLanguagePack(distroseries)
 
         view = create_initialized_view(
-            distroseries, '+language-packs', rootsite='translations')
+            distroseries, "+language-packs", rootsite="translations"
+        )
         # This should not trigger a shortlist warning.
         self.assertEqual(
-            number_of_language_packs, len(view.unused_language_packs))
+            number_of_language_packs, len(view.unused_language_packs)
+        )
 
     def test_unused_language_packs_identical_base_proposed_pack(self):
         distroseries = self.factory.makeUbuntuDistroSeries()
@@ -94,58 +94,65 @@ class TestLanguagePacksView(TestCaseWithFactory):
             distroseries.language_pack_proposed = pack
 
         view = create_initialized_view(
-            distroseries, '+language-packs', rootsite='translations')
+            distroseries, "+language-packs", rootsite="translations"
+        )
         self.assertEqual(0, len(view.unused_language_packs))
 
     def test_unused_language_packs_identical_delta_proposed_pack(self):
         distroseries = self.factory.makeUbuntuDistroSeries()
         with person_logged_in(distroseries.distribution.owner):
             distroseries.language_pack_base = self.factory.makeLanguagePack(
-                distroseries)
+                distroseries
+            )
             delta_pack = self.factory.makeLanguagePack(
-                distroseries, LanguagePackType.DELTA)
+                distroseries, LanguagePackType.DELTA
+            )
             distroseries.language_pack_delta = delta_pack
             distroseries.language_pack_proposed = delta_pack
 
         view = create_initialized_view(
-            distroseries, '+language-packs', rootsite='translations')
+            distroseries, "+language-packs", rootsite="translations"
+        )
         self.assertEqual(0, len(view.unused_language_packs))
 
     def test_languagepack_urls_use_http_when_librarian_uses_http(self):
         distroseries = self.factory.makeUbuntuDistroSeries()
         self.set_up_language_packs_for_distroseries(distroseries)
 
-        url = canonical_url(distroseries, view_name='+language-packs',
-                            rootsite='translations')
+        url = canonical_url(
+            distroseries, view_name="+language-packs", rootsite="translations"
+        )
         browser = self.getUserBrowser(user=self.factory.makePerson())
         browser.open(url)
 
         download_urls = get_librarian_download_links_on_page(browser.contents)
-        expected_scheme = 'http://'
+        expected_scheme = "http://";
 
         # In the test environment, librarian defaults to http.
         # There is a link each for the unused, base, delta,
         # and proposed language packs in this page.
         self.assertThat(
             download_urls,
-            MatchesListwise([
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations.tar.gz')
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-update.tar.gz'),
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-update.tar.gz'),
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-unused.tar.gz'),
-                ),
-            ])
+            MatchesListwise(
+                [
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-update.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-update.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-unused.tar.gz"),
+                    ),
+                ]
+            ),
         )
 
     def test_languagepack_urls_use_https_when_librarian_uses_https(self):
@@ -154,38 +161,41 @@ class TestLanguagePacksView(TestCaseWithFactory):
         distroseries = self.factory.makeUbuntuDistroSeries()
         self.set_up_language_packs_for_distroseries(distroseries)
 
-        url = canonical_url(distroseries, view_name='+language-packs',
-                            rootsite='translations')
+        url = canonical_url(
+            distroseries, view_name="+language-packs", rootsite="translations"
+        )
 
         browser = self.getUserBrowser(user=self.factory.makePerson())
         browser.open(url)
 
         download_urls = get_librarian_download_links_on_page(browser.contents)
 
-        expected_scheme = 'https://'
+        expected_scheme = "https://";
 
         # There is a link each for the unused, base, delta,
         # and proposed language packs.
         self.assertThat(
             download_urls,
-            MatchesListwise([
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations.tar.gz')
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-update.tar.gz'),
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-update.tar.gz'),
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-unused.tar.gz'),
-                ),
-            ])
+            MatchesListwise(
+                [
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-update.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-update.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-unused.tar.gz"),
+                    ),
+                ]
+            ),
         )
 
 
@@ -197,20 +207,21 @@ class TestDistroseriesTranslationsView(TestCaseWithFactory):
     def set_up_language_packs_for_distroseries(self, distroseries):
         language_pack_set = getUtility(ILanguagePackSet)
         with person_logged_in(distroseries.owner):
-            distroseries.language_pack_base = \
+            distroseries.language_pack_base = (
                 language_pack_set.addLanguagePack(
                     distroseries,
                     self.factory.makeLibraryFileAlias(
-                        filename='test-translations.tar.gz'
+                        filename="test-translations.tar.gz"
                     ),
-                    LanguagePackType.FULL
+                    LanguagePackType.FULL,
                 )
+            )
             delta_pack = language_pack_set.addLanguagePack(
                 distroseries,
                 self.factory.makeLibraryFileAlias(
-                    filename='test-translations-update.tar.gz'
+                    filename="test-translations-update.tar.gz"
                 ),
-                LanguagePackType.DELTA
+                LanguagePackType.DELTA,
             )
             distroseries.language_pack_delta = delta_pack
 
@@ -218,29 +229,32 @@ class TestDistroseriesTranslationsView(TestCaseWithFactory):
         distroseries = self.factory.makeUbuntuDistroSeries()
         self.set_up_language_packs_for_distroseries(distroseries)
 
-        url = canonical_url(distroseries, view_name='+translations',
-                            rootsite='translations')
+        url = canonical_url(
+            distroseries, view_name="+translations", rootsite="translations"
+        )
         browser = self.getUserBrowser(user=self.factory.makePerson())
         browser.open(url)
 
         download_urls = get_librarian_download_links_on_page(browser.contents)
-        expected_scheme = 'http://'
+        expected_scheme = "http://";
 
         # In the test environment, librarian defaults to http.
         # There is a link each for the base and delta language packs
         # in this page.
         self.assertThat(
             download_urls,
-            MatchesListwise([
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations.tar.gz')
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-update.tar.gz'),
-                )
-            ])
+            MatchesListwise(
+                [
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-update.tar.gz"),
+                    ),
+                ]
+            ),
         )
 
     def test_languagepack_urls_use_https_when_librarian_uses_https(self):
@@ -249,28 +263,31 @@ class TestDistroseriesTranslationsView(TestCaseWithFactory):
         distroseries = self.factory.makeUbuntuDistroSeries()
         self.set_up_language_packs_for_distroseries(distroseries)
 
-        url = canonical_url(distroseries, view_name='+translations',
-                            rootsite='translations')
+        url = canonical_url(
+            distroseries, view_name="+translations", rootsite="translations"
+        )
 
         browser = self.getUserBrowser(user=self.factory.makePerson())
         browser.open(url)
 
         download_urls = get_librarian_download_links_on_page(browser.contents)
 
-        expected_scheme = 'https://'
+        expected_scheme = "https://";
 
         # There is a link each for the unused, base, delta,
         # and proposed language packs.
         self.assertThat(
             download_urls,
-            MatchesListwise([
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations.tar.gz')
-                ),
-                MatchesAll(
-                    StartsWith(expected_scheme),
-                    EndsWith('test-translations-update.tar.gz'),
-                )
-            ])
+            MatchesListwise(
+                [
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations.tar.gz"),
+                    ),
+                    MatchesAll(
+                        StartsWith(expected_scheme),
+                        EndsWith("test-translations-update.tar.gz"),
+                    ),
+                ]
+            ),
         )
diff --git a/lib/lp/translations/browser/tests/test_distroserieslanguage_views.py b/lib/lp/translations/browser/tests/test_distroserieslanguage_views.py
index 57ff080..d8f3d03 100644
--- a/lib/lp/translations/browser/tests/test_distroserieslanguage_views.py
+++ b/lib/lp/translations/browser/tests/test_distroserieslanguage_views.py
@@ -1,16 +1,13 @@
 # Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from testtools.matchers import Equals
 import transaction
+from testtools.matchers import Equals
 from zope.component import getUtility
 
 from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.services.worlddata.interfaces.language import ILanguageSet
-from lp.testing import (
-    StormStatementRecorder,
-    TestCaseWithFactory,
-    )
+from lp.testing import StormStatementRecorder, TestCaseWithFactory
 from lp.testing.layers import LaunchpadZopelessLayer
 from lp.testing.matchers import HasQueryCount
 from lp.translations.browser.serieslanguage import DistroSeriesLanguageView
@@ -26,16 +23,15 @@ class TestDistroSeriesLanguage(TestCaseWithFactory):
         # Create a distroseries that uses translations.
         TestCaseWithFactory.setUp(self)
         self.distroseries = self.factory.makeDistroSeries()
-        self.language = getUtility(ILanguageSet).getLanguageByCode('sr')
+        self.language = getUtility(ILanguageSet).getLanguageByCode("sr")
         sourcepackagename = self.factory.makeSourcePackageName()
         potemplate = self.factory.makePOTemplate(
-            distroseries=self.distroseries,
-            sourcepackagename=sourcepackagename)
-        self.factory.makePOFile('sr', potemplate)
+            distroseries=self.distroseries, sourcepackagename=sourcepackagename
+        )
+        self.factory.makePOFile("sr", potemplate)
         self.distroseries.updateStatistics(transaction)
         self.dsl = self.distroseries.distroserieslanguages[0]
-        self.view = DistroSeriesLanguageView(
-            self.dsl, LaunchpadTestRequest())
+        self.view = DistroSeriesLanguageView(self.dsl, LaunchpadTestRequest())
 
     def test_empty_view(self):
         self.assertIsNone(self.view.translation_group)
@@ -44,10 +40,10 @@ class TestDistroSeriesLanguage(TestCaseWithFactory):
 
     def test_translation_group(self):
         group = self.factory.makeTranslationGroup(
-            self.distroseries.distribution.owner, url=None)
+            self.distroseries.distribution.owner, url=None
+        )
         self.distroseries.distribution.translationgroup = group
-        self.view = DistroSeriesLanguageView(
-            self.dsl, LaunchpadTestRequest())
+        self.view = DistroSeriesLanguageView(self.dsl, LaunchpadTestRequest())
         self.view.initialize()
         self.assertEqual(self.view.translation_group, group)
 
@@ -55,18 +51,17 @@ class TestDistroSeriesLanguage(TestCaseWithFactory):
         # Just having a group doesn't mean there's a translation
         # team as well.
         group = self.factory.makeTranslationGroup(
-            self.distroseries.distribution.owner, url=None)
+            self.distroseries.distribution.owner, url=None
+        )
         self.distroseries.distribution.translationgroup = group
         self.assertIsNone(self.view.translation_team)
 
         # Setting a translator for this languages makes it
         # appear as the translation_team.
         team = self.factory.makeTeam()
-        translator = getUtility(ITranslatorSet).new(
-            group, self.language, team)
+        translator = getUtility(ITranslatorSet).new(group, self.language, team)
         # Recreate the view because we are using a cached property.
-        self.view = DistroSeriesLanguageView(
-            self.dsl, LaunchpadTestRequest())
+        self.view = DistroSeriesLanguageView(self.dsl, LaunchpadTestRequest())
         self.view.initialize()
         self.assertEqual(self.view.translation_team, translator)
 
diff --git a/lib/lp/translations/browser/tests/test_language.py b/lib/lp/translations/browser/tests/test_language.py
index c9a4f7c..9bcc986 100644
--- a/lib/lp/translations/browser/tests/test_language.py
+++ b/lib/lp/translations/browser/tests/test_language.py
@@ -3,10 +3,7 @@
 
 """Tests for the language views."""
 
-from lp.testing import (
-    login_celebrity,
-    TestCaseWithFactory,
-    )
+from lp.testing import TestCaseWithFactory, login_celebrity
 from lp.testing.layers import DatabaseFunctionalLayer
 from lp.testing.views import create_initialized_view
 
@@ -20,23 +17,28 @@ class LanguageAdminViewTestCase(TestCaseWithFactory):
         # Both the number of plural forms and the plural form expression
         # fields must be provided together, or not at all.
         language = self.factory.makeLanguage(
-            language_code='qq', name='Queque',
-            pluralforms=None, plural_expression=None)
+            language_code="qq",
+            name="Queque",
+            pluralforms=None,
+            plural_expression=None,
+        )
         form = {
-            'field.code': 'qq',
-            'field.englishname': 'Queque',
-            'field.nativename': '',
-            'field.pluralforms': '2',
-            'field.pluralexpression': '',
-            'field.visible': True,
-            'field.direction': 'LTR',
-            'field.actions.admin': 'Admin Language',
-            }
-        login_celebrity('admin')
+            "field.code": "qq",
+            "field.englishname": "Queque",
+            "field.nativename": "",
+            "field.pluralforms": "2",
+            "field.pluralexpression": "",
+            "field.visible": True,
+            "field.direction": "LTR",
+            "field.actions.admin": "Admin Language",
+        }
+        login_celebrity("admin")
         view = create_initialized_view(
-             language, '+admin', rootsite='translations', form=form)
+            language, "+admin", rootsite="translations", form=form
+        )
         self.assertEqual(1, len(view.errors), view.errors)
         self.assertEqual(
-            'The number of plural forms and the plural form expression '
-            'must be set together, or not at all.',
-            view.errors[0])
+            "The number of plural forms and the plural form expression "
+            "must be set together, or not at all.",
+            view.errors[0],
+        )
diff --git a/lib/lp/translations/browser/tests/test_noindex.py b/lib/lp/translations/browser/tests/test_noindex.py
index 5383319..0230a90 100644
--- a/lib/lp/translations/browser/tests/test_noindex.py
+++ b/lib/lp/translations/browser/tests/test_noindex.py
@@ -7,10 +7,7 @@ from lp.app.enums import ServiceUsage
 from lp.services.beautifulsoup import BeautifulSoup
 from lp.services.propertycache import cachedproperty
 from lp.services.webapp import canonical_url
-from lp.testing import (
-    BrowserTestCase,
-    login_person,
-    )
+from lp.testing import BrowserTestCase, login_person
 from lp.testing.layers import DatabaseFunctionalLayer
 
 
@@ -32,7 +29,7 @@ class TestRobotsMixin:
 
     @cachedproperty
     def url(self):
-        return canonical_url(self.target, rootsite='translations')
+        return canonical_url(self.target, rootsite="translations")
 
     @cachedproperty
     def user_browser(self):
@@ -54,24 +51,27 @@ class TestRobotsMixin:
     def getRobotsDirective(self):
         contents = self.getRenderedContents()
         soup = BeautifulSoup(contents)
-        return soup.find('meta', attrs={'name': 'robots'})
+        return soup.find("meta", attrs={"name": "robots"})
 
     def verifyRobotsAreBlocked(self, usage):
         self.setUsage(usage)
         robots = self.getRobotsDirective()
-        self.assertIsNot(None, robots,
-                         "Robot blocking meta information not present.")
-        self.assertEqual('noindex,nofollow', robots['content'])
-        expected = ('noindex', 'nofollow')
-        actual = robots['content'].split(',')
+        self.assertIsNot(
+            None, robots, "Robot blocking meta information not present."
+        )
+        self.assertEqual("noindex,nofollow", robots["content"])
+        expected = ("noindex", "nofollow")
+        actual = robots["content"].split(",")
         self.assertContentEqual(expected, actual)
 
     def verifyRobotsNotBlocked(self, usage):
         self.setUsage(usage)
         robots = self.getRobotsDirective()
         self.assertIs(
-            None, robots,
-            "Robot blocking metadata present when it should not be.")
+            None,
+            robots,
+            "Robot blocking metadata present when it should not be.",
+        )
 
     def test_robots(self):
         # Robots are blocked for usage that is not Launchpad.
@@ -89,7 +89,8 @@ class TestRobotsProduct(BrowserTestCase, TestRobotsMixin):
         super().setUp()
         self.target = self.factory.makeProduct()
         self.factory.makePOTemplate(
-            productseries=self.target.development_focus)
+            productseries=self.target.development_focus
+        )
         self.naked_translatable = removeSecurityProxy(self.target)
 
 
@@ -101,7 +102,8 @@ class TestRobotsProjectGroup(BrowserTestCase, TestRobotsMixin):
         self.target = self.factory.makeProject()
         self.product = self.factory.makeProduct()
         self.factory.makePOTemplate(
-            productseries=self.product.development_focus)
+            productseries=self.product.development_focus
+        )
         self.naked_translatable = removeSecurityProxy(self.product)
         self.naked_translatable.projectgroup = self.target
 
@@ -113,8 +115,7 @@ class TestRobotsProductSeries(BrowserTestCase, TestRobotsMixin):
         super().setUp()
         self.product = self.factory.makeProduct()
         self.target = self.product.development_focus
-        self.factory.makePOTemplate(
-            productseries=self.target)
+        self.factory.makePOTemplate(productseries=self.target)
         self.naked_translatable = removeSecurityProxy(self.product)
 
 
@@ -125,14 +126,16 @@ class TestRobotsDistroSeries(BrowserTestCase, TestRobotsMixin):
         super().setUp()
         login_person(self.user)
         self.distro = self.factory.makeDistribution(
-            name="whobuntu", owner=self.user)
+            name="whobuntu", owner=self.user
+        )
         self.target = self.factory.makeDistroSeries(
-            name="zephyr", distribution=self.distro)
+            name="zephyr", distribution=self.distro
+        )
         self.target.hide_all_translations = False
         new_sourcepackagename = self.factory.makeSourcePackageName()
         self.factory.makePOTemplate(
-            distroseries=self.target,
-            sourcepackagename=new_sourcepackagename)
+            distroseries=self.target, sourcepackagename=new_sourcepackagename
+        )
         self.naked_translatable = removeSecurityProxy(self.distro)
 
 
@@ -143,12 +146,15 @@ class TestRobotsDistro(BrowserTestCase, TestRobotsMixin):
         super().setUp()
         login_person(self.user)
         self.target = self.factory.makeDistribution(
-            name="whobuntu", owner=self.user)
+            name="whobuntu", owner=self.user
+        )
         self.distroseries = self.factory.makeDistroSeries(
-            name="zephyr", distribution=self.target)
+            name="zephyr", distribution=self.target
+        )
         self.distroseries.hide_all_translations = False
         new_sourcepackagename = self.factory.makeSourcePackageName()
         self.factory.makePOTemplate(
             distroseries=self.distroseries,
-            sourcepackagename=new_sourcepackagename)
+            sourcepackagename=new_sourcepackagename,
+        )
         self.naked_translatable = removeSecurityProxy(self.target)
diff --git a/lib/lp/translations/browser/tests/test_persontranslationview.py b/lib/lp/translations/browser/tests/test_persontranslationview.py
index aa0d873..34fa8f5 100644
--- a/lib/lp/translations/browser/tests/test_persontranslationview.py
+++ b/lib/lp/translations/browser/tests/test_persontranslationview.py
@@ -8,15 +8,8 @@ from zope.security.proxy import removeSecurityProxy
 from lp.app.enums import ServiceUsage
 from lp.services.webapp import canonical_url
 from lp.services.webapp.servers import LaunchpadTestRequest
-from lp.testing import (
-    BrowserTestCase,
-    person_logged_in,
-    TestCaseWithFactory,
-    )
-from lp.testing.layers import (
-    DatabaseFunctionalLayer,
-    LaunchpadZopelessLayer,
-    )
+from lp.testing import BrowserTestCase, TestCaseWithFactory, person_logged_in
+from lp.testing.layers import DatabaseFunctionalLayer, LaunchpadZopelessLayer
 from lp.translations.browser.person import PersonTranslationView
 from lp.translations.model.translator import TranslatorSet
 
@@ -39,8 +32,10 @@ class TestPersonTranslationView(TestCaseWithFactory):
         owner = self.factory.makePerson()
         self.translationgroup = self.factory.makeTranslationGroup(owner=owner)
         TranslatorSet().new(
-            translationgroup=self.translationgroup, language=self.language,
-            translator=self.view.context)
+            translationgroup=self.translationgroup,
+            language=self.language,
+            translator=self.view.context,
+        )
 
     def _makePOFiles(self, count, previously_worked_on, languages=None):
         """Create `count` `POFile`s that the view's person can review.
@@ -61,7 +56,8 @@ class TestPersonTranslationView(TestCaseWithFactory):
                 pofile = self.factory.makePOFile(language=self.language)
             else:
                 pofile = self.factory.makePOFile(
-                    potemplate=potemplate, language=languages[counter])
+                    potemplate=potemplate, language=languages[counter]
+                )
 
             if self.translationgroup:
                 product = pofile.potemplate.productseries.product
@@ -73,10 +69,13 @@ class TestPersonTranslationView(TestCaseWithFactory):
                 else:
                     sequence = 1
                 potmsgset = self.factory.makePOTMsgSet(
-                    potemplate=pofile.potemplate, sequence=sequence)
+                    potemplate=pofile.potemplate, sequence=sequence
+                )
                 self.factory.makeCurrentTranslationMessage(
-                    potmsgset=potmsgset, pofile=pofile,
-                    translator=self.view.context)
+                    potmsgset=potmsgset,
+                    pofile=pofile,
+                    translator=self.view.context,
+                )
 
             removeSecurityProxy(pofile).unreviewed_count = 1
             pofiles.append(pofile)
@@ -92,8 +91,7 @@ class TestPersonTranslationView(TestCaseWithFactory):
         # translation_groups lists the translation groups a person is
         # in.
         self._makeReviewer()
-        self.assertEqual(
-            [self.translationgroup], self.view.translation_groups)
+        self.assertEqual([self.translationgroup], self.view.translation_groups)
 
     def test_person_is_reviewer_false(self):
         # A regular person is not a reviewer.
@@ -123,7 +121,7 @@ class TestPersonTranslationView(TestCaseWithFactory):
         descriptions = self.view.all_projects_and_packages_to_review
 
         self.assertEqual(1, len(descriptions))
-        self.assertEqual(product, descriptions[0]['target'])
+        self.assertEqual(product, descriptions[0]["target"])
 
     def test_all_projects_and_packages_to_review_none(self):
         # all_projects_and_packages_to_review works even if there is
@@ -143,8 +141,8 @@ class TestPersonTranslationView(TestCaseWithFactory):
 
         description = self.view.all_projects_and_packages_to_review[0]
 
-        self.assertEqual(1, description['count'])
-        self.assertEqual("1 string", description['count_wording'])
+        self.assertEqual(1, description["count"])
+        self.assertEqual("1 string", description["count_wording"])
 
     def test_all_projects_and_packages_to_review_string_plural(self):
         # For multiple strings, count_wording uses the plural.
@@ -154,8 +152,8 @@ class TestPersonTranslationView(TestCaseWithFactory):
 
         description = self.view.all_projects_and_packages_to_review[0]
 
-        self.assertEqual(2, description['count'])
-        self.assertEqual("2 strings", description['count_wording'])
+        self.assertEqual(2, description["count"])
+        self.assertEqual("2 strings", description["count_wording"])
 
     def test_num_projects_and_packages_to_review_zero(self):
         # num_projects_and_packages does not count new suggestions.
@@ -172,10 +170,11 @@ class TestPersonTranslationView(TestCaseWithFactory):
         pofile_worked_on = self._makePOFiles(1, previously_worked_on=True)[0]
         targets = self.view.top_projects_and_packages_to_review
 
-        pofile_suffix = '/+translate?show=new_suggestions'
+        pofile_suffix = "/+translate?show=new_suggestions"
         expected_links = [canonical_url(pofile_worked_on) + pofile_suffix]
         self.assertEqual(
-            set(expected_links), {item['link'] for item in targets})
+            set(expected_links), {item["link"] for item in targets}
+        )
 
     def test_recent_translation_activity(self):
         # the recent_activity property lists the most recent translation
@@ -198,16 +197,21 @@ class TestPersonTranslationView(TestCaseWithFactory):
         pofiles_worked_on = self._makePOFiles(11, previously_worked_on=True)
 
         # the expected results
-        person_name = urlencode({'person': self.view.context.name})
+        person_name = urlencode({"person": self.view.context.name})
         expected_links = [
-            (pofile.potemplate.translationtarget.title,
-            canonical_url(pofile, view_name="+filter") + "?%s" % person_name)
-            for pofile in pofiles_worked_on[:10]]
+            (
+                pofile.potemplate.translationtarget.title,
+                canonical_url(pofile, view_name="+filter")
+                + "?%s" % person_name,
+            )
+            for pofile in pofiles_worked_on[:10]
+        ]
 
         recent_activity = self.view.recent_activity
         self.assertContentEqual(
             expected_links,
-            ((item.title, item.url) for item in recent_activity))
+            ((item.title, item.url) for item in recent_activity),
+        )
 
     def test_top_p_n_p_to_review_caps_existing_involvement(self):
         # top_projects_and_packages will return at most 9 POFiles that
@@ -218,7 +222,7 @@ class TestPersonTranslationView(TestCaseWithFactory):
         targets = self.view.top_projects_and_packages_to_review
 
         self.assertEqual(9, len(targets))
-        self.assertEqual(9, len({item['link'] for item in targets}))
+        self.assertEqual(9, len({item["link"] for item in targets}))
 
     def test_top_p_n_p_to_review_caps_total(self):
         # top_projects_and_packages will show at most 9 POFiles
@@ -229,7 +233,7 @@ class TestPersonTranslationView(TestCaseWithFactory):
         targets = self.view.top_projects_and_packages_to_review
 
         self.assertEqual(9, len(targets))
-        self.assertEqual(9, len({item['link'] for item in targets}))
+        self.assertEqual(9, len({item["link"] for item in targets}))
 
     def test_person_is_translator_false(self):
         # By default, a user is not a translator.
@@ -258,10 +262,9 @@ class TestPersonTranslationView(TestCaseWithFactory):
 
         self.assertEqual(1, len(descriptions))
         description = descriptions[0]
-        self.assertEqual(product, description['target'])
-        self.assertTrue(description['link'].startswith(canonical_url(pofile)))
-        self.assertEqual(
-            pofile.language.englishname, description['languages'])
+        self.assertEqual(product, description["target"])
+        self.assertTrue(description["link"].startswith(canonical_url(pofile)))
+        self.assertEqual(pofile.language.englishname, description["languages"])
 
     def test_getTargetsForTranslation_multiple_languages(self):
         # Translations in different languages are aggregated to one target
@@ -269,17 +272,20 @@ class TestPersonTranslationView(TestCaseWithFactory):
         other_language = self.factory.makeLanguage()
         self.view.context.addLanguage(other_language)
         pofiles = self._makePOFiles(
-            2, previously_worked_on=True,
-            languages=[self.language, other_language])
+            2,
+            previously_worked_on=True,
+            languages=[self.language, other_language],
+        )
         for pofile in pofiles:
             self._addUntranslatedMessages(pofile, 1)
 
         descriptions = self.view._getTargetsForTranslation()
         self.assertEqual(1, len(descriptions))
         description = descriptions[0]
-        expected_languages = ', '.join(sorted([
-            self.language.englishname, other_language.englishname]))
-        self.assertContentEqual(expected_languages, description['languages'])
+        expected_languages = ", ".join(
+            sorted([self.language.englishname, other_language.englishname])
+        )
+        self.assertContentEqual(expected_languages, description["languages"])
 
     def test_getTargetsForTranslation_max_fetch(self):
         # The max_fetch parameter limits how many POFiles are considered
@@ -297,7 +303,8 @@ class TestPersonTranslationView(TestCaseWithFactory):
         self.assertEqual(1, len(descriptions))
         self.assertEqual(
             urgent_pofile.potemplate.productseries.product,
-            descriptions[0]['target'])
+            descriptions[0]["target"],
+        )
 
         # Passing a negative max_fetch makes _getTargetsForTranslation
         # pick translations with the fewest untranslated messages.
@@ -305,7 +312,8 @@ class TestPersonTranslationView(TestCaseWithFactory):
         self.assertEqual(1, len(descriptions))
         self.assertEqual(
             nonurgent_pofile.potemplate.productseries.product,
-            descriptions[0]['target'])
+            descriptions[0]["target"],
+        )
 
     def test_top_projects_and_packages_to_translate(self):
         # top_projects_and_packages_to_translate lists targets that the
@@ -320,7 +328,8 @@ class TestPersonTranslationView(TestCaseWithFactory):
         self.assertEqual(1, len(descriptions))
         self.assertEqual(
             worked_on.potemplate.productseries.product,
-            descriptions[0]['target'])
+            descriptions[0]["target"],
+        )
 
     def test_top_p_n_p_to_translate_caps_existing_involvement(self):
         # top_projects_and_packages_to_translate shows up to ten
@@ -343,12 +352,13 @@ class TestPersonTranslationView(TestCaseWithFactory):
         for number, pofile in enumerate(pofiles):
             self._addUntranslatedMessages(pofile, number + 1)
         products = [
-            pofile.potemplate.productseries.product for pofile in pofiles]
+            pofile.potemplate.productseries.product for pofile in pofiles
+        ]
 
         descriptions = self.view.top_projects_and_packages_to_translate
 
         self.assertEqual(10, len(descriptions))
-        targets = [item['target'] for item in descriptions]
+        targets = [item["target"] for item in descriptions]
 
         # We happen to know that no more than 25 POFiles are fetched for
         # each of the two categories, so the top 5 targets must be taken
@@ -364,7 +374,8 @@ class TestPersonTranslationView(TestCaseWithFactory):
         # The list never shows more than 10 entries.
         for previously_worked_on in (True, False):
             pofiles = self._makePOFiles(
-                11, previously_worked_on=previously_worked_on)
+                11, previously_worked_on=previously_worked_on
+            )
             for pofile in pofiles:
                 self._addUntranslatedMessages(pofile, 1)
 
@@ -397,12 +408,15 @@ class TestPersonTranslationViewPermissions(BrowserTestCase):
         owner = self.factory.makePerson()
         self.translationgroup = self.factory.makeTranslationGroup(owner=owner)
         TranslatorSet().new(
-            translationgroup=self.translationgroup, language=self.language,
-            translator=self.context)
+            translationgroup=self.translationgroup,
+            language=self.language,
+            translator=self.context,
+        )
 
     def test_links_anon(self):
         browser = self.getViewBrowser(
-            self.context, "+translations", no_login=True)
+            self.context, "+translations", no_login=True
+        )
         self.assertFalse("+editmylanguages" in browser.contents)
         self.assertFalse("+edit" in browser.contents)
 
@@ -415,6 +429,7 @@ class TestPersonTranslationViewPermissions(BrowserTestCase):
     def test_links_authorized(self):
         self.factory.makeTranslationGroup()
         browser = self.getViewBrowser(
-            self.context, "+translations", user=self.context)
+            self.context, "+translations", user=self.context
+        )
         self.assertTrue("+editmylanguages" in browser.contents)
         self.assertTrue("+edit" in browser.contents)
diff --git a/lib/lp/translations/browser/tests/test_poexportrequest_views.py b/lib/lp/translations/browser/tests/test_poexportrequest_views.py
index cda3a05..5ddf965 100644
--- a/lib/lp/translations/browser/tests/test_poexportrequest_views.py
+++ b/lib/lp/translations/browser/tests/test_poexportrequest_views.py
@@ -5,17 +5,14 @@ from zope.security.proxy import removeSecurityProxy
 
 from lp.services.database.interfaces import IStore
 from lp.services.webapp.servers import LaunchpadTestRequest
-from lp.testing import (
-    login_person,
-    TestCaseWithFactory,
-    )
+from lp.testing import TestCaseWithFactory, login_person
 from lp.testing.layers import DatabaseFunctionalLayer
 from lp.translations.browser.pofile import POExportView
 from lp.translations.browser.potemplate import POTemplateExportView
 from lp.translations.interfaces.side import TranslationSide
 from lp.translations.interfaces.translationfileformat import (
     TranslationFileFormat,
-    )
+)
 from lp.translations.model.poexportrequest import POExportRequest
 
 
@@ -29,11 +26,10 @@ def get_poexportrequests(include_format=False):
     if include_format:
         return [
             (request.potemplate, request.pofile, request.format)
-            for request in requests]
+            for request in requests
+        ]
     else:
-        return [
-            (request.potemplate, request.pofile)
-            for request in requests]
+        return [(request.potemplate, request.pofile) for request in requests]
 
 
 class TestPOTEmplateExportView(TestCaseWithFactory):
@@ -49,73 +45,81 @@ class TestPOTEmplateExportView(TestCaseWithFactory):
 
     def _createView(self, form):
         login_person(self.translator)
-        request = LaunchpadTestRequest(method='POST', form=form)
+        request = LaunchpadTestRequest(method="POST", form=form)
         view = POTemplateExportView(self.potemplate, request)
         view.initialize()
         return view
 
     def test_request_all_only_template(self):
         # Selecting 'all' will place the template into the request queue.
-        self._createView({'what': 'all', 'format': 'PO'})
+        self._createView({"what": "all", "format": "PO"})
 
         self.assertContentEqual(
-            [(self.potemplate, None)], get_poexportrequests())
+            [(self.potemplate, None)], get_poexportrequests()
+        )
 
     def test_request_all_add_pofile(self):
         # Selecting 'all' will also place any pofiles for the template into
         # the request queue.
         pofile = self.factory.makePOFile(potemplate=self.potemplate)
-        self._createView({'what': 'all', 'format': 'PO'})
+        self._createView({"what": "all", "format": "PO"})
 
         self.assertContentEqual(
             [(self.potemplate, None), (self.potemplate, pofile)],
-            get_poexportrequests())
+            get_poexportrequests(),
+        )
 
     def test_request_some_potemplate(self):
         # Using 'some' allows to select only the template.
         self.factory.makePOFile(potemplate=self.potemplate)
-        self._createView({'what': 'some', 'potemplate': True, 'format': 'PO'})
+        self._createView({"what": "some", "potemplate": True, "format": "PO"})
 
         self.assertContentEqual(
-            [(self.potemplate, None)], get_poexportrequests())
+            [(self.potemplate, None)], get_poexportrequests()
+        )
 
     def test_request_some_pofile(self):
         # Using 'some' allows to select only a pofile.
         pofile = self.factory.makePOFile(potemplate=self.potemplate)
-        self._createView({
-            'what': 'some',
-            pofile.language.code: True,
-            'format': 'PO'})
+        self._createView(
+            {"what": "some", pofile.language.code: True, "format": "PO"}
+        )
 
     def test_request_some_various(self):
         # Using 'some' allows to select various files.
         self.factory.makePOFile(potemplate=self.potemplate)
         pofile2 = self.factory.makePOFile(potemplate=self.potemplate)
-        self._createView({
-            'what': 'some',
-            'potemplate': True,
-            pofile2.language.code: True,
-            'format': 'PO'})
+        self._createView(
+            {
+                "what": "some",
+                "potemplate": True,
+                pofile2.language.code: True,
+                "format": "PO",
+            }
+        )
 
         self.assertContentEqual(
             [(self.potemplate, None), (self.potemplate, pofile2)],
-            get_poexportrequests())
+            get_poexportrequests(),
+        )
 
     def test_request_format_po(self):
         # It is possible to request the PO format.
-        self._createView({'what': 'all', 'format': 'PO'})
+        self._createView({"what": "all", "format": "PO"})
 
         self.assertContentEqual(
             [(self.potemplate, None, TranslationFileFormat.PO)],
-            get_poexportrequests(include_format=True))
+            get_poexportrequests(include_format=True),
+        )
 
     def test_request_format_mo(self):
         # It is possible to request the MO format.
-        self._createView({'what': 'all', 'format': 'MO'})
+        self._createView({"what": "all", "format": "MO"})
 
         self.assertContentEqual(
             [(self.potemplate, None, TranslationFileFormat.MO)],
-            get_poexportrequests(include_format=True))
+            get_poexportrequests(include_format=True),
+        )
 
 
 class TestPOExportView(TestCaseWithFactory):
@@ -129,7 +133,7 @@ class TestPOExportView(TestCaseWithFactory):
         if form is None:
             request = LaunchpadTestRequest()
         else:
-            request = LaunchpadTestRequest(method='POST', form=form)
+            request = LaunchpadTestRequest(method="POST", form=form)
         view = POExportView(pofile, request)
         view.initialize()
         return view
@@ -137,20 +141,22 @@ class TestPOExportView(TestCaseWithFactory):
     def test_request_format_po(self):
         # It is possible to request an export in the PO format.
         pofile = self.factory.makePOFile()
-        self._createView(pofile, {'format': 'PO'})
+        self._createView(pofile, {"format": "PO"})
 
         self.assertContentEqual(
             [(pofile.potemplate, pofile, TranslationFileFormat.PO)],
-            get_poexportrequests(include_format=True))
+            get_poexportrequests(include_format=True),
+        )
 
     def test_request_format_mo(self):
         # It is possible to request an export in the MO format.
         pofile = self.factory.makePOFile()
-        self._createView(pofile, {'format': 'MO'})
+        self._createView(pofile, {"format": "MO"})
 
         self.assertContentEqual(
             [(pofile.potemplate, pofile, TranslationFileFormat.MO)],
-            get_poexportrequests(include_format=True))
+            get_poexportrequests(include_format=True),
+        )
 
     def _makeUbuntuTemplateAndPOFile(self, upstream_pofile=None):
         """Create a sharing template in Ubuntu with a POFile to go with it."""
@@ -162,13 +168,16 @@ class TestPOExportView(TestCaseWithFactory):
         language = upstream_pofile.language
 
         packaging = self.factory.makePackagingLink(
-            productseries=upstream_series, in_ubuntu=True)
+            productseries=upstream_series, in_ubuntu=True
+        )
         naked_distribution = removeSecurityProxy(
-            packaging.distroseries.distribution)
+            packaging.distroseries.distribution
+        )
         naked_distribution.translation_focus = packaging.distroseries
 
         potemplate = self.factory.makePOTemplate(
-            sourcepackage=packaging.sourcepackage, name=template_name)
+            sourcepackage=packaging.sourcepackage, name=template_name
+        )
 
         # The sharing POFile is created automatically when the template is
         # created because self.pofile already exists.
@@ -181,47 +190,58 @@ class TestPOExportView(TestCaseWithFactory):
         ubuntu_potemplate, ubuntu_pofile = self._makeUbuntuTemplateAndPOFile()
 
         self._createView(
-            ubuntu_pofile, {'format': 'PO', 'pochanged': 'POCHANGED'})
+            ubuntu_pofile, {"format": "PO", "pochanged": "POCHANGED"}
+        )
 
         expected = (
             ubuntu_potemplate,
             ubuntu_pofile,
             TranslationFileFormat.POCHANGED,
-            )
+        )
         self.assertContentEqual(
-            [expected], get_poexportrequests(include_format=True))
+            [expected], get_poexportrequests(include_format=True)
+        )
 
     def test_request_partial_po_ubuntu(self):
         # Partial po exports are requested by an extra check box.
         # For an Ubuntu package, the export is requested on the file itself.
         upstream_pofile = self.factory.makePOFile()
         ubuntu_potemplate, ubuntu_pofile = self._makeUbuntuTemplateAndPOFile(
-            upstream_pofile)
+            upstream_pofile
+        )
 
         self._createView(
-            upstream_pofile, {'format': 'PO', 'pochanged': 'POCHANGED'})
+            upstream_pofile, {"format": "PO", "pochanged": "POCHANGED"}
+        )
 
         self.assertContentEqual(
-            [(ubuntu_potemplate, ubuntu_pofile,
-                TranslationFileFormat.POCHANGED)],
-            get_poexportrequests(include_format=True))
+            [
+                (
+                    ubuntu_potemplate,
+                    ubuntu_pofile,
+                    TranslationFileFormat.POCHANGED,
+                )
+            ],
+            get_poexportrequests(include_format=True),
+        )
 
     def test_request_partial_po_no_link(self):
         # Partial po exports are requested by an extra check box.
         # Without a packaging link, no request is created.
         pofile = self.factory.makePOFile()
-        self._createView(pofile, {'format': 'PO', 'pochanged': 'POCHANGED'})
+        self._createView(pofile, {"format": "PO", "pochanged": "POCHANGED"})
 
         self.assertContentEqual([], get_poexportrequests())
 
     def test_request_partial_mo(self):
         # With the MO format, the partial export check box is ignored.
         pofile = self.factory.makePOFile()
-        self._createView(pofile, {'format': 'MO', 'pochanged': 'POCHANGED'})
+        self._createView(pofile, {"format": "MO", "pochanged": "POCHANGED"})
 
         self.assertContentEqual(
             [(pofile.potemplate, pofile, TranslationFileFormat.MO)],
-            get_poexportrequests(include_format=True))
+            get_poexportrequests(include_format=True),
+        )
 
     def test_pochanged_option_available_ubuntu(self):
         # The option for partial exports is always available on a source
diff --git a/lib/lp/translations/browser/tests/test_pofile_view.py b/lib/lp/translations/browser/tests/test_pofile_view.py
index 3c50614..f68f2ff 100644
--- a/lib/lp/translations/browser/tests/test_pofile_view.py
+++ b/lib/lp/translations/browser/tests/test_pofile_view.py
@@ -9,16 +9,13 @@ from lp.services.webapp.interfaces import ILaunchBag
 from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.testing import (
     BrowserTestCase,
+    TestCaseWithFactory,
     login,
     login_person,
     person_logged_in,
     record_two_runs,
-    TestCaseWithFactory,
-    )
-from lp.testing.layers import (
-    DatabaseFunctionalLayer,
-    ZopelessDatabaseLayer,
-    )
+)
+from lp.testing.layers import DatabaseFunctionalLayer, ZopelessDatabaseLayer
 from lp.testing.matchers import HasQueryCount
 from lp.testing.views import create_initialized_view
 from lp.translations.browser.pofile import POFileTranslateView
@@ -39,10 +36,13 @@ class TestQueryCount(TestCaseWithFactory):
         product.translationpermission = TranslationPermission.OPEN
         pofile = self.factory.makePOFile(
             potemplate=self.factory.makePOTemplate(
-                productseries=product.series[0]))
+                productseries=product.series[0]
+            )
+        )
         pofile.potemplate.productseries.product
         potmsgsets = [
-            self.factory.makePOTMsgSet(pofile.potemplate) for i in range(10)]
+            self.factory.makePOTMsgSet(pofile.potemplate) for i in range(10)
+        ]
 
         # Preload a few transaction-crossing caches that would give
         # extra queries to the first request.
@@ -56,16 +56,17 @@ class TestQueryCount(TestCaseWithFactory):
                 pot = self.factory.makePOTemplate()
                 self.factory.makeCurrentTranslationMessage(
                     potmsgset=self.factory.makePOTMsgSet(
-                        singular=potmsgset.msgid_singular.msgid,
-                        potemplate=pot),
+                        singular=potmsgset.msgid_singular.msgid, potemplate=pot
+                    ),
                     language=pofile.language,
-                    translations=[self.factory.getUniqueUnicode()])
+                    translations=[self.factory.getUniqueUnicode()],
+                )
                 # A suggestion only shows up if it's actually in a
                 # POFile.
                 self.factory.makePOFile(
-                    potemplate=pot, language=pofile.language)
-                self.factory.makeSuggestion(
-                    pofile=pofile, potmsgset=potmsgset)
+                    potemplate=pot, language=pofile.language
+                )
+                self.factory.makeSuggestion(pofile=pofile, potmsgset=potmsgset)
 
             # Ensure that these are valid suggestions.
             templateset = getUtility(IPOTemplateSet)
@@ -75,8 +76,11 @@ class TestQueryCount(TestCaseWithFactory):
         nb_objects = 2
         recorder1, recorder2 = record_two_runs(
             lambda: create_initialized_view(
-                pofile, '+translate', principal=person)(),
-            create_suggestions, nb_objects)
+                pofile, "+translate", principal=person
+            )(),
+            create_suggestions,
+            nb_objects,
+        )
         self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))
 
 
@@ -88,29 +92,30 @@ class TestPOFileTranslateViewInvalidFiltering(TestCaseWithFactory):
     raising UnexpectedFormData which is communicated to the user instead of
     being recorded as an OOPS.
     """
+
     layer = ZopelessDatabaseLayer
     view_class = POFileTranslateView
 
     def setUp(self):
         super().setUp()
-        self.pofile = self.factory.makePOFile('eo')
+        self.pofile = self.factory.makePOFile("eo")
 
     def _test_parameter_list(self, parameter_name):
         # When a parameter is entered multiple times in an URL, it will be
         # converted to a list. This view has no such parameters but it must
         # not throw a TypeError when it gets a list.
-        form = {parameter_name: ['foo', 'bar']}
+        form = {parameter_name: ["foo", "bar"]}
         view = self.view_class(self.pofile, LaunchpadTestRequest(form=form))
         self.assertRaises(UnexpectedFormData, view.initialize)
 
     def test_parameter_list_old_show(self):
-        self._test_parameter_list('old_show')
+        self._test_parameter_list("old_show")
 
     def test_parameter_list_search(self):
-        self._test_parameter_list('search')
+        self._test_parameter_list("search")
 
     def test_parameter_list_show(self):
-        self._test_parameter_list('show')
+        self._test_parameter_list("show")
 
 
 class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
@@ -119,7 +124,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
 
     def _makeLoggedInUser(self):
         """Create a user, and log in as that user."""
-        email = self.factory.getUniqueString() + '@example.com'
+        email = self.factory.getUniqueString() + "@example.com"
         user = self.factory.makePerson(email=email)
         login(email)
         return user
@@ -139,7 +144,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
             given, one will be created.
         """
         if pofile is None:
-            pofile = self.factory.makePOFile('cy')
+            pofile = self.factory.makePOFile("cy")
         if request is None:
             request = LaunchpadTestRequest()
         return self.view_class(pofile, request)
@@ -200,7 +205,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
 
     def test_translation_group_guide_noguide(self):
         # The translation group may not have a translation guide.
-        pofile = self.factory.makePOFile('ca')
+        pofile = self.factory.makePOFile("ca")
         self._makeTranslationGroup(pofile)
 
         view = self._makeView(pofile=pofile)
@@ -209,7 +214,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
     def test_translation_group_guide(self):
         # translation_group_guide returns the translation group's style
         # guide URL if there is one.
-        pofile = self.factory.makePOFile('ce')
+        pofile = self.factory.makePOFile("ce")
         url = self._setGroupGuide(pofile)
 
         view = self._makeView(pofile=pofile)
@@ -223,7 +228,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
     def test_translation_team_guide_noteam(self):
         # If there is no translation team for this language, there is on
         # translation team style guide.
-        pofile = self.factory.makePOFile('ch')
+        pofile = self.factory.makePOFile("ch")
         self._makeTranslationGroup(pofile)
 
         view = self._makeView(pofile=pofile)
@@ -231,7 +236,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
 
     def test_translation_team_guide_noguide(self):
         # A translation team may not have a translation style guide.
-        pofile = self.factory.makePOFile('co')
+        pofile = self.factory.makePOFile("co")
         self._makeTranslationTeam(pofile)
 
         view = self._makeView(pofile=pofile)
@@ -240,7 +245,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
     def test_translation_team_guide(self):
         # translation_team_guide returns the translation team's
         # style guide, if there is one.
-        pofile = self.factory.makePOFile('cy')
+        pofile = self.factory.makePOFile("cy")
         url = self._setTeamGuide(pofile)
 
         view = self._makeView(pofile=pofile)
@@ -250,11 +255,11 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
         # If the user is not a new translator and neither a translation
         # group nor a team style guide applies, the documentation bubble
         # is empty.
-        pofile = self.factory.makePOFile('da')
+        pofile = self.factory.makePOFile("da")
         self._useNonnewTranslator()
 
         view = self._makeView(pofile=pofile)
-        self.assertEqual('', view.documentation_link_bubble)
+        self.assertEqual("", view.documentation_link_bubble)
         self.assertFalse(self._showsIntro(view.documentation_link_bubble))
         self.assertFalse(self._showsGuides(view.documentation_link_bubble))
 
@@ -269,7 +274,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
     def test_documentation_link_bubble_group_guide(self):
         # A translation group's guide shows up in the documentation
         # bubble.
-        pofile = self.factory.makePOFile('de')
+        pofile = self.factory.makePOFile("de")
         self._setGroupGuide(pofile)
 
         view = self._makeView(pofile=pofile)
@@ -279,7 +284,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
     def test_documentation_link_bubble_team_guide(self):
         # A translation team's style guide shows up in the documentation
         # bubble.
-        pofile = self.factory.makePOFile('de')
+        pofile = self.factory.makePOFile("de")
         self._setTeamGuide(pofile)
 
         view = self._makeView(pofile=pofile)
@@ -289,7 +294,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
     def test_documentation_link_bubble_both_guides(self):
         # The documentation bubble can show both a translation group's
         # guidelines and a translation team's style guide.
-        pofile = self.factory.makePOFile('dv')
+        pofile = self.factory.makePOFile("dv")
         self._setGroupGuide(pofile)
         self._setTeamGuide(pofile)
 
@@ -301,7 +306,7 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
     def test_documentation_link_bubble_shows_all(self):
         # So in all, the bubble can show 3 different documentation
         # links.
-        pofile = self.factory.makePOFile('dz')
+        pofile = self.factory.makePOFile("dz")
         self._makeLoggedInUser()
         self._setGroupGuide(pofile)
         self._setTeamGuide(pofile)
@@ -313,41 +318,46 @@ class TestPOFileTranslateViewDocumentation(TestCaseWithFactory):
 
     def test_documentation_link_bubble_escapes_group_title(self):
         # Translation group titles in the bubble are HTML-escaped.
-        pofile = self.factory.makePOFile('eo')
+        pofile = self.factory.makePOFile("eo")
         group = self._makeTranslationGroup(pofile)
         self._setGroupGuide(pofile)
         group.title = "<blink>X</blink>"
 
         view = self._makeView(pofile=pofile)
         self.assertIn(
-            "&lt;blink&gt;X&lt;/blink&gt;", view.documentation_link_bubble)
+            "&lt;blink&gt;X&lt;/blink&gt;", view.documentation_link_bubble
+        )
         self.assertNotIn(group.title, view.documentation_link_bubble)
 
     def test_documentation_link_bubble_escapes_team_name(self):
         # Translation team names in the bubble are HTML-escaped.
-        pofile = self.factory.makePOFile('ie')
+        pofile = self.factory.makePOFile("ie")
         translator_entry = self._makeTranslationTeam(pofile)
         self._setTeamGuide(pofile, team=translator_entry)
         translator_entry.translator.display_name = "<blink>Y</blink>"
 
         view = self._makeView(pofile=pofile)
         self.assertIn(
-            "&lt;blink&gt;Y&lt;/blink&gt;", view.documentation_link_bubble)
+            "&lt;blink&gt;Y&lt;/blink&gt;", view.documentation_link_bubble
+        )
         self.assertNotIn(
             translator_entry.translator.displayname,
-            view.documentation_link_bubble)
+            view.documentation_link_bubble,
+        )
 
     def test_documentation_link_bubble_escapes_language_name(self):
         # Language names in the bubble are HTML-escaped.
         language = self.factory.makeLanguage(
-            language_code='wtf', name="<blink>Z</blink>")
-        pofile = self.factory.makePOFile('wtf')
+            language_code="wtf", name="<blink>Z</blink>"
+        )
+        pofile = self.factory.makePOFile("wtf")
         self._setGroupGuide(pofile)
         self._setTeamGuide(pofile)
 
         view = self._makeView(pofile=pofile)
         self.assertIn(
-            "&lt;blink&gt;Z&lt;/blink&gt;", view.documentation_link_bubble)
+            "&lt;blink&gt;Z&lt;/blink&gt;", view.documentation_link_bubble
+        )
         self.assertNotIn(language.englishname, view.documentation_link_bubble)
 
 
@@ -366,18 +376,22 @@ class TestBrowser(BrowserTestCase):
             product.translationpermission = TranslationPermission.CLOSED
         # Add credits so that they show in the UI
         self.factory.makePOTMsgSet(
-            potemplate=pofile.potemplate, singular='translator-credits')
+            potemplate=pofile.potemplate, singular="translator-credits"
+        )
         browser = self.getViewBrowser(pofile)
-        self.assertNotIn('This is a dummy translation', browser.contents)
-        self.assertIn('(no translation yet)', browser.contents)
+        self.assertNotIn("This is a dummy translation", browser.contents)
+        self.assertIn("(no translation yet)", browser.contents)
 
     def test_anonymous_translation_credits(self):
         """Credits should be hidden for non-logged-in users."""
         pofile = self.factory.makePOFile()
         # Add credits so that they show in the UI
         self.factory.makePOTMsgSet(
-            potemplate=pofile.potemplate, singular='translator-credits')
+            potemplate=pofile.potemplate, singular="translator-credits"
+        )
         browser = self.getViewBrowser(pofile, no_login=True)
         self.assertTextMatchesExpressionIgnoreWhitespace(
-            'To prevent privacy issues, this translation is not available to'
-            ' anonymous users', browser.contents)
+            "To prevent privacy issues, this translation is not available to"
+            " anonymous users",
+            browser.contents,
+        )
diff --git a/lib/lp/translations/browser/tests/test_potemplate_navigation.py b/lib/lp/translations/browser/tests/test_potemplate_navigation.py
index 647dcac..c307afe 100644
--- a/lib/lp/translations/browser/tests/test_potemplate_navigation.py
+++ b/lib/lp/translations/browser/tests/test_potemplate_navigation.py
@@ -14,29 +14,29 @@ from lp.translations.model.pofile import PlaceholderPOFile
 class TestPOTemplateNavigation(TestCaseWithFactory):
     layer = DatabaseFunctionalLayer
 
-    def _makeNavigation(self, potemplate, method='GET'):
+    def _makeNavigation(self, potemplate, method="GET"):
         """Create a `POTemplateNavigation` for `potemplate`."""
         request = LaunchpadTestRequest()
         request.method = method
         return POTemplateNavigation(potemplate, request)
 
     def test_traverse_to_existing_pofile(self):
-        pofile = self.factory.makePOFile('nl')
+        pofile = self.factory.makePOFile("nl")
         nav = self._makeNavigation(pofile.potemplate)
-        destination = nav.traverse('nl')
+        destination = nav.traverse("nl")
         self.assertEqual(pofile, destination)
 
     def test_traverse_to_placeholder_pofile(self):
         nav = self._makeNavigation(self.factory.makePOTemplate())
-        destination = nav.traverse('de')
+        destination = nav.traverse("de")
         self.assertIsInstance(destination, PlaceholderPOFile)
-        self.assertEqual('de', destination.language.code)
+        self.assertEqual("de", destination.language.code)
 
     def test_traverse_nonexistent_language(self):
         nav = self._makeNavigation(self.factory.makePOTemplate())
-        self.assertRaises(NotFoundError, nav.traverse, 'bzyzzyx_GRQ@UTF-13')
+        self.assertRaises(NotFoundError, nav.traverse, "bzyzzyx_GRQ@UTF-13")
 
     def test_unsupported_method(self):
-        pofile = self.factory.makePOFile('sr')
-        nav = self._makeNavigation(pofile.potemplate, method='PUT')
-        self.assertRaises(AssertionError, nav.traverse, 'sr')
+        pofile = self.factory.makePOFile("sr")
+        nav = self._makeNavigation(pofile.potemplate, method="PUT")
+        self.assertRaises(AssertionError, nav.traverse, "sr")
diff --git a/lib/lp/translations/browser/tests/test_potemplate_views.py b/lib/lp/translations/browser/tests/test_potemplate_views.py
index 4a85ac4..779cd80 100644
--- a/lib/lp/translations/browser/tests/test_potemplate_views.py
+++ b/lib/lp/translations/browser/tests/test_potemplate_views.py
@@ -3,24 +3,18 @@
 
 """Module doc."""
 
-from testscenarios import (
-    load_tests_apply_scenarios,
-    WithScenarios,
-    )
+from testscenarios import WithScenarios, load_tests_apply_scenarios
 
 from lp.services.features.testing import FeatureFixture
 from lp.services.webapp.escaping import html_escape
 from lp.services.webapp.servers import LaunchpadTestRequest
-from lp.testing import (
-    celebrity_logged_in,
-    TestCaseWithFactory,
-    )
+from lp.testing import TestCaseWithFactory, celebrity_logged_in
 from lp.testing.layers import DatabaseFunctionalLayer
 from lp.testing.views import create_initialized_view
 from lp.translations.browser.potemplate import (
     POTemplateAdminView,
     POTemplateEditView,
-    )
+)
 
 
 class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
@@ -30,7 +24,7 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
     scenarios = [
         ("spn_picker", {"features": {}}),
         ("dsp_picker", {"features": {"disclosure.dsp_picker.enabled": "on"}}),
-        ]
+    ]
 
     def setUp(self):
         super().setUp()
@@ -43,10 +37,13 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
         The attributes are only those considered by the validate method.
         """
         attributes = [
-            'distroseries', 'sourcepackagename', 'productseries',
-            'name', 'translation_domain']
-        data = {
-            name: getattr(potemplate, name) for name in attributes}
+            "distroseries",
+            "sourcepackagename",
+            "productseries",
+            "name",
+            "translation_domain",
+        ]
+        data = {name: getattr(potemplate, name) for name in attributes}
         data.update(**kwargs)
         return data
 
@@ -56,9 +53,17 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
         potemplate = self.factory.makePOTemplate()
         view = POTemplateEditView(potemplate, LaunchpadTestRequest())
         self.assertContentEqual(
-            ['name', 'translation_domain', 'description', 'priority',
-             'path', 'iscurrent', 'owner'],
-            view.field_names)
+            [
+                "name",
+                "translation_domain",
+                "description",
+                "priority",
+                "path",
+                "iscurrent",
+                "owner",
+            ],
+            view.field_names,
+        )
 
     def test_field_names_sourcepackage(self):
         # A sourcepackage template has two more fields compared to the
@@ -66,26 +71,40 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
         sourcepackage = self.factory.makeSourcePackage()
         potemplate = self.factory.makePOTemplate(
             distroseries=sourcepackage.distroseries,
-            sourcepackagename=sourcepackage.sourcepackagename)
+            sourcepackagename=sourcepackage.sourcepackagename,
+        )
         view = POTemplateEditView(potemplate, LaunchpadTestRequest())
         self.assertContentEqual(
-            ['name', 'translation_domain', 'description', 'priority',
-             'path', 'iscurrent', 'sourcepackagename', 'languagepack'],
-            view.field_names)
+            [
+                "name",
+                "translation_domain",
+                "description",
+                "priority",
+                "path",
+                "iscurrent",
+                "sourcepackagename",
+                "languagepack",
+            ],
+            view.field_names,
+        )
 
     def test_detects_invalid_names(self):
         # A template name must be satisfying the valid_name constraint.
-        invalid_name = 'name!'
+        invalid_name = "name!"
         potemplate = self.factory.makePOTemplate()
         data = self._makeData(potemplate, name=invalid_name)
         view = POTemplateEditView(potemplate, LaunchpadTestRequest())
         view.validate(data)
         self.assertEqual(
-            [html_escape(
-                'Template name can only start with lowercase letters a-z '
-                'or digits 0-9, and other than those characters, can only '
-                'contain "-", "+" and "." characters.')],
-            view.errors)
+            [
+                html_escape(
+                    "Template name can only start with lowercase letters a-z "
+                    "or digits 0-9, and other than those characters, can only "
+                    'contain "-", "+" and "." characters.'
+                )
+            ],
+            view.errors,
+        )
 
     def test_detects_name_clash_on_name_change(self):
         # A template name may not already be used.
@@ -97,56 +116,65 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
         view = POTemplateEditView(potemplate, LaunchpadTestRequest())
         data = self._makeData(potemplate, name=existing_name)
         view.validate(data)
-        self.assertEqual(['Name is already in use.'], view.errors)
+        self.assertEqual(["Name is already in use."], view.errors)
 
     def test_detects_domain_clash_on_domain_change(self):
         # A translation domain may not already be used.
         existing_domain = self.factory.getUniqueString()
         existing_potemplate = self.factory.makePOTemplate(
-            translation_domain=existing_domain)
+            translation_domain=existing_domain
+        )
         series = existing_potemplate.productseries
         potemplate = self.factory.makePOTemplate(productseries=series)
 
         view = POTemplateEditView(potemplate, LaunchpadTestRequest())
         data = self._makeData(potemplate, translation_domain=existing_domain)
         view.validate(data)
-        self.assertEqual(['Domain is already in use.'], view.errors)
+        self.assertEqual(["Domain is already in use."], view.errors)
 
     def test_detects_name_clash_on_sourcepackage_change(self):
         # Detect changing to a source package that already has a template of
         # the same name.
         sourcepackage = self.factory.makeSourcePackage()
         existing_potemplate = self.factory.makePOTemplate(
-            sourcepackage=sourcepackage)
+            sourcepackage=sourcepackage
+        )
         potemplate = self.factory.makePOTemplate(
             distroseries=sourcepackage.distroseries,
-            name=existing_potemplate.name)
+            name=existing_potemplate.name,
+        )
 
         view = POTemplateEditView(potemplate, LaunchpadTestRequest())
         data = self._makeData(
-            potemplate, sourcepackagename=sourcepackage.sourcepackagename)
+            potemplate, sourcepackagename=sourcepackage.sourcepackagename
+        )
         view.validate(data)
         self.assertEqual(
-            ['Source package already has a template with that same name.'],
-            view.errors)
+            ["Source package already has a template with that same name."],
+            view.errors,
+        )
 
     def test_detects_domain_clash_on_sourcepackage_change(self):
         # Detect changing to a source package that already has a template with
         # the same translation domain.
         sourcepackage = self.factory.makeSourcePackage()
         existing_potemplate = self.factory.makePOTemplate(
-            sourcepackage=sourcepackage)
+            sourcepackage=sourcepackage
+        )
         potemplate = self.factory.makePOTemplate(
             distroseries=sourcepackage.distroseries,
-            translation_domain=existing_potemplate.translation_domain)
+            translation_domain=existing_potemplate.translation_domain,
+        )
 
         view = POTemplateEditView(potemplate, LaunchpadTestRequest())
         data = self._makeData(
-            potemplate, sourcepackagename=sourcepackage.sourcepackagename)
+            potemplate, sourcepackagename=sourcepackage.sourcepackagename
+        )
         view.validate(data)
         self.assertEqual(
-            ['Source package already has a template with that same domain.'],
-            view.errors)
+            ["Source package already has a template with that same domain."],
+            view.errors,
+        )
 
     def test_change_sourcepackage(self):
         # Changing the source package is honoured.
@@ -154,20 +182,20 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
         potemplate = self.factory.makePOTemplate(distroseries=distroseries)
         dsp = self.factory.makeDSPCache(distroseries=distroseries)
         form = {
-            'field.name': potemplate.name,
-            'field.distroseries': distroseries.name,
-            'field.sourcepackagename': dsp.sourcepackagename.name,
-            'field.actions.change': 'Change',
-            }
-        with celebrity_logged_in('rosetta_experts'):
-            view = create_initialized_view(potemplate, '+edit', form=form)
+            "field.name": potemplate.name,
+            "field.distroseries": distroseries.name,
+            "field.sourcepackagename": dsp.sourcepackagename.name,
+            "field.actions.change": "Change",
+        }
+        with celebrity_logged_in("rosetta_experts"):
+            view = create_initialized_view(potemplate, "+edit", form=form)
         self.assertEqual([], view.errors)
         self.assertEqual(
-            dsp.sourcepackagename.name, potemplate.sourcepackagename.name)
+            dsp.sourcepackagename.name, potemplate.sourcepackagename.name
+        )
 
 
 class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
-
     def test_detects_name_clash_on_productseries_change(self):
         # Detect changing to a productseries that already has a template of
         # the same name.
@@ -180,25 +208,28 @@ class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
         data = self._makeData(potemplate, productseries=new_series)
         view.validate(data)
         self.assertEqual(
-            ['Series already has a template with that same name.'],
-            view.errors)
+            ["Series already has a template with that same name."], view.errors
+        )
 
     def test_detects_domain_clash_on_productseries_change(self):
         # Detect changing to a productseries that already has a template with
         # the same translation domain.
         translation_domain = self.factory.getUniqueString()
         existing_potemplate = self.factory.makePOTemplate(
-            translation_domain=translation_domain)
+            translation_domain=translation_domain
+        )
         new_series = existing_potemplate.productseries
         potemplate = self.factory.makePOTemplate(
-            translation_domain=translation_domain)
+            translation_domain=translation_domain
+        )
 
         view = POTemplateAdminView(potemplate, LaunchpadTestRequest())
         data = self._makeData(potemplate, productseries=new_series)
         view.validate(data)
         self.assertEqual(
-            ['Series already has a template with that same domain.'],
-            view.errors)
+            ["Series already has a template with that same domain."],
+            view.errors,
+        )
 
     def test_detects_no_sourcepackage_or_productseries(self):
         # Detect if no source package or productseries was selected.
@@ -207,11 +238,18 @@ class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
         view = POTemplateAdminView(potemplate, LaunchpadTestRequest())
         data = self._makeData(
             potemplate,
-            distroseries=None, sourcepackagename=None, productseries=None)
+            distroseries=None,
+            sourcepackagename=None,
+            productseries=None,
+        )
         view.validate(data)
         self.assertEqual(
-            ['Choose either a distribution release series or a project '
-             'release series.'], view.errors)
+            [
+                "Choose either a distribution release series or a project "
+                "release series."
+            ],
+            view.errors,
+        )
 
     def test_detects_sourcepackage_and_productseries(self):
         # Detect if no source package or productseries was selected.
@@ -223,35 +261,43 @@ class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
             potemplate,
             distroseries=sourcepackage.distroseries,
             sourcepackagename=sourcepackage.sourcepackagename,
-            productseries=potemplate.productseries)
+            productseries=potemplate.productseries,
+        )
         view.validate(data)
         self.assertEqual(
-            ['Choose a distribution release series or a project '
-             'release series, but not both.'], view.errors)
+            [
+                "Choose a distribution release series or a project "
+                "release series, but not both."
+            ],
+            view.errors,
+        )
 
     def test_change_from_sourcepackage(self):
         # Changing the source package the template comes from is honoured.
         distroseries = self.factory.makeDistroSeries()
         dsp = self.factory.makeDSPCache(distroseries=distroseries)
         potemplate = self.factory.makePOTemplate(
-            distroseries=distroseries, sourcepackagename=dsp.sourcepackagename)
+            distroseries=distroseries, sourcepackagename=dsp.sourcepackagename
+        )
         from_dsp = self.factory.makeDSPCache(distroseries=distroseries)
         form = {
-            'field.name': potemplate.name,
-            'field.distroseries': '%s/%s' % (
-                distroseries.distribution.name, distroseries.name),
-            'field.sourcepackagename': dsp.sourcepackagename.name,
-            'field.from_sourcepackagename': from_dsp.sourcepackagename.name,
-            'field.actions.change': 'Change',
-            }
-        with celebrity_logged_in('rosetta_experts'):
-            view = create_initialized_view(potemplate, '+admin', form=form)
+            "field.name": potemplate.name,
+            "field.distroseries": "%s/%s"
+            % (distroseries.distribution.name, distroseries.name),
+            "field.sourcepackagename": dsp.sourcepackagename.name,
+            "field.from_sourcepackagename": from_dsp.sourcepackagename.name,
+            "field.actions.change": "Change",
+        }
+        with celebrity_logged_in("rosetta_experts"):
+            view = create_initialized_view(potemplate, "+admin", form=form)
         self.assertEqual([], view.errors)
         self.assertEqual(
-            dsp.sourcepackagename.name, potemplate.sourcepackagename.name)
+            dsp.sourcepackagename.name, potemplate.sourcepackagename.name
+        )
         self.assertEqual(
             from_dsp.sourcepackagename.name,
-            potemplate.from_sourcepackagename.name)
+            potemplate.from_sourcepackagename.name,
+        )
 
 
 load_tests = load_tests_apply_scenarios
diff --git a/lib/lp/translations/browser/tests/test_product_view.py b/lib/lp/translations/browser/tests/test_product_view.py
index 83b69cc..79976da 100644
--- a/lib/lp/translations/browser/tests/test_product_view.py
+++ b/lib/lp/translations/browser/tests/test_product_view.py
@@ -1,34 +1,25 @@
 # Copyright 2009 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from soupmatchers import (
-    HTMLContains,
-    Tag,
-    )
+from soupmatchers import HTMLContains, Tag
 from testtools.matchers import Not
 
 from lp.app.enums import (
-    InformationType,
     PILLAR_INFORMATION_TYPES,
+    InformationType,
     ServiceUsage,
-    )
+)
 from lp.registry.interfaces.series import SeriesStatus
 from lp.services.webapp import canonical_url
 from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.testing import (
+    TestCaseWithFactory,
     celebrity_logged_in,
     login_person,
     person_logged_in,
-    TestCaseWithFactory,
-    )
-from lp.testing.layers import (
-    DatabaseFunctionalLayer,
-    LaunchpadZopelessLayer,
-    )
-from lp.testing.views import (
-    create_initialized_view,
-    create_view,
-    )
+)
+from lp.testing.layers import DatabaseFunctionalLayer, LaunchpadZopelessLayer
+from lp.testing.views import create_initialized_view, create_view
 from lp.translations.browser.product import ProductView
 
 
@@ -51,10 +42,12 @@ class TestProduct(TestCaseWithFactory):
         sourcepackage = self.factory.makeSourcePackage()
         sourcepackage.setPackaging(series, None)
         sourcepackage.distroseries.distribution.translations_usage = (
-            ServiceUsage.LAUNCHPAD)
+            ServiceUsage.LAUNCHPAD
+        )
         self.factory.makePOTemplate(
             distroseries=sourcepackage.distroseries,
-            sourcepackagename=sourcepackage.sourcepackagename)
+            sourcepackagename=sourcepackage.sourcepackagename,
+        )
         self.assertIsNone(view.primary_translatable)
 
     def test_untranslatable_series(self):
@@ -65,44 +58,55 @@ class TestProduct(TestCaseWithFactory):
 
         # New series are added, one for each type of status
         series_experimental = self.factory.makeProductSeries(
-            product=product, name='evo-experimental')
+            product=product, name="evo-experimental"
+        )
         series_experimental.status = SeriesStatus.EXPERIMENTAL
 
         series_development = self.factory.makeProductSeries(
-            product=product, name='evo-development')
+            product=product, name="evo-development"
+        )
         series_development.status = SeriesStatus.DEVELOPMENT
 
         series_frozen = self.factory.makeProductSeries(
-            product=product, name='evo-frozen')
+            product=product, name="evo-frozen"
+        )
         series_frozen.status = SeriesStatus.FROZEN
 
         series_current = self.factory.makeProductSeries(
-            product=product, name='evo-current')
+            product=product, name="evo-current"
+        )
         series_current.status = SeriesStatus.CURRENT
 
         series_supported = self.factory.makeProductSeries(
-            product=product, name='evo-supported')
+            product=product, name="evo-supported"
+        )
         series_supported.status = SeriesStatus.SUPPORTED
 
         series_obsolete = self.factory.makeProductSeries(
-            product=product, name='evo-obsolete')
+            product=product, name="evo-obsolete"
+        )
         series_obsolete.status = SeriesStatus.OBSOLETE
 
         series_future = self.factory.makeProductSeries(
-            product=product, name='evo-future')
+            product=product, name="evo-future"
+        )
         series_future.status = SeriesStatus.FUTURE
 
         # The series are returned in alphabetical order and do not
         # include obsolete series.
         series_names = [series.name for series in view.untranslatable_series]
-        self.assertEqual([
-            'evo-current',
-            'evo-development',
-            'evo-experimental',
-            'evo-frozen',
-            'evo-future',
-            'evo-supported',
-            'trunk'], series_names)
+        self.assertEqual(
+            [
+                "evo-current",
+                "evo-development",
+                "evo-experimental",
+                "evo-frozen",
+                "evo-future",
+                "evo-supported",
+                "trunk",
+            ],
+            series_names,
+        )
 
 
 class TestCanConfigureTranslations(TestCaseWithFactory):
@@ -111,19 +115,19 @@ class TestCanConfigureTranslations(TestCaseWithFactory):
 
     def test_cannot_configure_translations_product_no_edit_permission(self):
         product = self.factory.makeProduct()
-        view = create_view(product, '+translations')
+        view = create_view(product, "+translations")
         self.assertEqual(False, view.can_configure_translations())
 
     def test_can_configure_translations_product_with_edit_permission(self):
         product = self.factory.makeProduct()
         login_person(product.owner)
-        view = create_view(product, '+translations')
+        view = create_view(product, "+translations")
         self.assertEqual(True, view.can_configure_translations())
 
     def test_rosetta_expert_can_configure_translations(self):
         product = self.factory.makeProduct()
-        with celebrity_logged_in('rosetta_experts'):
-            view = create_view(product, '+translations')
+        with celebrity_logged_in("rosetta_experts"):
+            view = create_view(product, "+translations")
             self.assertEqual(True, view.can_configure_translations())
 
     def test_launchpad_not_listed_for_proprietary(self):
@@ -132,15 +136,18 @@ class TestCanConfigureTranslations(TestCaseWithFactory):
             for info_type in PILLAR_INFORMATION_TYPES:
                 product.information_type = info_type
                 view = create_initialized_view(
-                    product, '+configure-translations')
+                    product, "+configure-translations"
+                )
                 if product.private:
                     self.assertNotIn(
                         ServiceUsage.LAUNCHPAD,
-                        view.widgets['translations_usage'].vocabulary)
+                        view.widgets["translations_usage"].vocabulary,
+                    )
                 else:
                     self.assertIn(
                         ServiceUsage.LAUNCHPAD,
-                        view.widgets['translations_usage'].vocabulary)
+                        view.widgets["translations_usage"].vocabulary,
+                    )
 
     @staticmethod
     def getViewContent(view):
@@ -149,12 +156,13 @@ class TestCanConfigureTranslations(TestCaseWithFactory):
 
     @staticmethod
     def hasLink(url):
-        return HTMLContains(Tag('link', 'a', attrs={'href': url}))
+        return HTMLContains(Tag("link", "a", attrs={"href": url}))
 
     @classmethod
     def getTranslationsContent(cls, product):
         view = create_initialized_view(
-            product, '+translations', principal=product.owner)
+            product, "+translations", principal=product.owner
+        )
         return cls.getViewContent(view)
 
     def test_no_sync_links_for_proprietary(self):
@@ -163,14 +171,20 @@ class TestCanConfigureTranslations(TestCaseWithFactory):
         product = self.factory.makeProduct()
         content = self.getTranslationsContent(product)
         series_url = canonical_url(
-            product.development_focus, view_name='+translations',
-            rootsite='translations')
+            product.development_focus,
+            view_name="+translations",
+            rootsite="translations",
+        )
         manual_url = canonical_url(
-            product.development_focus, view_name='+translations-upload',
-            rootsite='translations')
+            product.development_focus,
+            view_name="+translations-upload",
+            rootsite="translations",
+        )
         automatic_url = canonical_url(
-            product.development_focus, view_name='+translations-settings',
-            rootsite='translations')
+            product.development_focus,
+            view_name="+translations-settings",
+            rootsite="translations",
+        )
         self.assertThat(content, self.hasLink(series_url))
         self.assertThat(content, self.hasLink(manual_url))
         self.assertThat(content, self.hasLink(automatic_url))
diff --git a/lib/lp/translations/browser/tests/test_productseries.py b/lib/lp/translations/browser/tests/test_productseries.py
index 9abdb45..035a5fa 100644
--- a/lib/lp/translations/browser/tests/test_productseries.py
+++ b/lib/lp/translations/browser/tests/test_productseries.py
@@ -1,10 +1,7 @@
 # Copyright 2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from soupmatchers import (
-    HTMLContains,
-    Tag,
-    )
+from soupmatchers import HTMLContains, Tag
 from testtools.matchers import Not
 
 from lp.app.enums import InformationType
@@ -18,20 +15,32 @@ class TestProductSeries(BrowserTestCase):
 
     @staticmethod
     def hasAutoImport(value):
-        tag = Tag('importall', 'input',
-                  attrs={'name': 'field.translations_autoimport_mode',
-                         'value': value})
+        tag = Tag(
+            "importall",
+            "input",
+            attrs={
+                "name": "field.translations_autoimport_mode",
+                "value": value,
+            },
+        )
         return HTMLContains(tag)
 
     def test_private_disables_imports(self):
         # Proprietary products disable import options.
         owner = self.factory.makePerson()
         product = self.factory.makeProduct(
-            owner=owner, information_type=InformationType.PROPRIETARY)
+            owner=owner, information_type=InformationType.PROPRIETARY
+        )
         series = self.factory.makeProductSeries(product=product)
-        browser = self.getViewBrowser(series, '+translations-settings',
-                                      user=owner, rootsite='translations')
-        self.assertThat(browser.contents,
-                        Not(self.hasAutoImport('IMPORT_TRANSLATIONS')))
-        self.assertThat(browser.contents,
-                        Not(self.hasAutoImport('IMPORT_TEMPLATES')))
+        browser = self.getViewBrowser(
+            series,
+            "+translations-settings",
+            user=owner,
+            rootsite="translations",
+        )
+        self.assertThat(
+            browser.contents, Not(self.hasAutoImport("IMPORT_TRANSLATIONS"))
+        )
+        self.assertThat(
+            browser.contents, Not(self.hasAutoImport("IMPORT_TEMPLATES"))
+        )
diff --git a/lib/lp/translations/browser/tests/test_productserieslanguage_views.py b/lib/lp/translations/browser/tests/test_productserieslanguage_views.py
index 319f05c..2954757 100644
--- a/lib/lp/translations/browser/tests/test_productserieslanguage_views.py
+++ b/lib/lp/translations/browser/tests/test_productserieslanguage_views.py
@@ -5,20 +5,13 @@ from zope.security.proxy import removeSecurityProxy
 
 from lp.app.enums import InformationType
 from lp.services.webapp.servers import LaunchpadTestRequest
-from lp.testing import (
-    login_person,
-    person_logged_in,
-    TestCaseWithFactory,
-    )
-from lp.testing.layers import (
-    DatabaseFunctionalLayer,
-    ZopelessDatabaseLayer,
-    )
+from lp.testing import TestCaseWithFactory, login_person, person_logged_in
+from lp.testing.layers import DatabaseFunctionalLayer, ZopelessDatabaseLayer
 from lp.translations.browser.productseries import ProductSeriesView
 from lp.translations.browser.serieslanguage import ProductSeriesLanguageView
 from lp.translations.interfaces.translations import (
     TranslationsBranchImportMode,
-    )
+)
 
 
 class TestProductSeriesView(TestCaseWithFactory):
@@ -59,7 +52,8 @@ class TestProductSeriesView(TestCaseWithFactory):
         # Adding a translation group with no documentation keeps
         # `has_translation_documentation` at False.
         self.product.translationgroup = self.factory.makeTranslationGroup(
-            self.productseries.product.owner, url=None)
+            self.productseries.product.owner, url=None
+        )
         view = self._createView()
         self.assertFalse(view.has_translation_documentation)
 
@@ -67,7 +61,8 @@ class TestProductSeriesView(TestCaseWithFactory):
         # After adding a translation group with a documentation URL lets
         # `has_translation_documentation` be True.
         self.product.translationgroup = self.factory.makeTranslationGroup(
-            self.productseries.product.owner, url='http://something')
+            self.productseries.product.owner, url="http://something";
+        )
         view = self._createView()
         self.assertTrue(view.has_translation_documentation)
 
@@ -90,11 +85,13 @@ class TestProductSeriesView(TestCaseWithFactory):
         # The `productserieslanguages` properperty has a list of the
         # languages of the po files for the templates in this seris.
         potemplate = self.factory.makePOTemplate(
-            productseries=self.productseries)
+            productseries=self.productseries
+        )
         pofile = self.factory.makePOFile(potemplate=potemplate)
         view = self._createView()
         self.assertEqual(
-            [pofile.language], self._getProductserieslanguages(view))
+            [pofile.language], self._getProductserieslanguages(view)
+        )
 
     def _makePersonWithLanguage(self):
         user = self.factory.makePerson()
@@ -105,8 +102,7 @@ class TestProductSeriesView(TestCaseWithFactory):
     def test_productserieslanguages_preferred_language_without_pofile(self):
         # If the user has a preferred language, that language always in
         # the list.
-        self.factory.makePOTemplate(
-            productseries=self.productseries)
+        self.factory.makePOTemplate(productseries=self.productseries)
         user, language = self._makePersonWithLanguage()
         login_person(user)
         view = self._createView()
@@ -116,35 +112,41 @@ class TestProductSeriesView(TestCaseWithFactory):
         # If the user has a preferred language, that language always in
         # the list.
         potemplate = self.factory.makePOTemplate(
-            productseries=self.productseries)
+            productseries=self.productseries
+        )
         pofile = self.factory.makePOFile(potemplate=potemplate)
         user, language = self._makePersonWithLanguage()
         login_person(user)
         view = self._createView()
         self.assertContentEqual(
-            [pofile.language, language],
-            self._getProductserieslanguages(view))
+            [pofile.language, language], self._getProductserieslanguages(view)
+        )
 
     def test_productserieslanguages_ordered_by_englishname(self):
         # Returned languages are ordered by their name in English.
         language1 = self.factory.makeLanguage(
-            language_code='lang-aa', name='Zz')
+            language_code="lang-aa", name="Zz"
+        )
         language2 = self.factory.makeLanguage(
-            language_code='lang-zz', name='Aa')
+            language_code="lang-zz", name="Aa"
+        )
         potemplate = self.factory.makePOTemplate(
-            productseries=self.productseries)
+            productseries=self.productseries
+        )
         self.factory.makePOFile(language=language1, potemplate=potemplate)
         self.factory.makePOFile(language=language2, potemplate=potemplate)
         view = self._createView()
         self.assertEqual(
-            [language2, language1], self._getProductserieslanguages(view))
+            [language2, language1], self._getProductserieslanguages(view)
+        )
 
     def test_productserieslanguages_english(self):
         # English is not listed among translated languages, even if there's
         # an English POFile
         potemplate = self.factory.makePOTemplate(
-            productseries=self.productseries)
-        self.factory.makePOFile('en', potemplate)
+            productseries=self.productseries
+        )
+        self.factory.makePOFile("en", potemplate)
         view = self._createView()
         self.assertEqual([], self._getProductserieslanguages(view))
 
@@ -169,7 +171,8 @@ class TestProductSeriesViewBzrUsage(TestCaseWithFactory):
     def _createView(self):
         # The view operates on the secured product series!
         view = ProductSeriesView(
-            self.secured_productseries, LaunchpadTestRequest())
+            self.secured_productseries, LaunchpadTestRequest()
+        )
         view.initialize()
         return view
 
@@ -184,21 +187,24 @@ class TestProductSeriesViewBzrUsage(TestCaseWithFactory):
     def test_has_imports_enabled_with_branch_imports_disabled(self):
         self.productseries.branch = self.factory.makeBranch()
         self.productseries.translations_autoimport_mode = (
-                TranslationsBranchImportMode.NO_IMPORT)
+            TranslationsBranchImportMode.NO_IMPORT
+        )
         view = self._createView()
         self.assertFalse(view.has_imports_enabled)
 
     def test_has_imports_enabled_with_branch_template_imports_enabled(self):
         self.productseries.branch = self.factory.makeBranch()
         self.productseries.translations_autoimport_mode = (
-            TranslationsBranchImportMode.IMPORT_TEMPLATES)
+            TranslationsBranchImportMode.IMPORT_TEMPLATES
+        )
         view = self._createView()
         self.assertTrue(view.has_imports_enabled)
 
     def test_has_imports_enabled_with_branch_trans_imports_enabled(self):
         self.productseries.branch = self.factory.makeBranch()
         self.productseries.translations_autoimport_mode = (
-            TranslationsBranchImportMode.IMPORT_TRANSLATIONS)
+            TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+        )
         view = self._createView()
         self.assertTrue(view.has_imports_enabled)
 
@@ -206,18 +212,22 @@ class TestProductSeriesViewBzrUsage(TestCaseWithFactory):
         # Private branches are hidden from non-privileged users. The view
         # pretends that it is not used for imports.
         self.productseries.branch = self.factory.makeBranch(
-            information_type=InformationType.USERDATA)
+            information_type=InformationType.USERDATA
+        )
         self.productseries.translations_autoimport_mode = (
-            TranslationsBranchImportMode.IMPORT_TRANSLATIONS)
+            TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+        )
         view = self._createView()
         self.assertFalse(view.has_imports_enabled)
 
     def test_has_imports_enabled_private_branch_privileged(self):
         # Private branches are visible for privileged users.
         self.productseries.branch = self.factory.makeBranch(
-            information_type=InformationType.USERDATA)
+            information_type=InformationType.USERDATA
+        )
         self.productseries.translations_autoimport_mode = (
-            TranslationsBranchImportMode.IMPORT_TRANSLATIONS)
+            TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+        )
         with person_logged_in(self.productseries.branch.owner):
             view = self._createView()
             self.assertTrue(view.has_imports_enabled)
@@ -231,14 +241,16 @@ class TestProductSeriesViewBzrUsage(TestCaseWithFactory):
         # Private branches are hidden from non-privileged users. The view
         # pretends that it is not used for exports.
         self.productseries.translations_branch = self.factory.makeBranch(
-            information_type=InformationType.USERDATA)
+            information_type=InformationType.USERDATA
+        )
         view = self._createView()
         self.assertFalse(view.has_exports_enabled)
 
     def test_has_exports_enabled_private_branch_privileged(self):
         # Private branches are visible for privileged users.
         self.productseries.translations_branch = self.factory.makeBranch(
-            information_type=InformationType.USERDATA)
+            information_type=InformationType.USERDATA
+        )
         with person_logged_in(self.productseries.translations_branch.owner):
             view = self._createView()
             self.assertTrue(view.has_exports_enabled)
@@ -255,7 +267,8 @@ class TestProductSeriesLanguageView(TestCaseWithFactory):
         self.productseries = self.factory.makeProductSeries()
         self.language = self.factory.makeLanguage()
         potemplate = self.factory.makePOTemplate(
-            productseries=self.productseries)
+            productseries=self.productseries
+        )
         self.factory.makePOFile(language=self.language, potemplate=potemplate)
         self.psl = self.productseries.productserieslanguages[0]
 
@@ -274,7 +287,8 @@ class TestProductSeriesLanguageView(TestCaseWithFactory):
 
     def _makeTranslationGroup(self):
         group = self.factory.makeTranslationGroup(
-            self.productseries.product.owner, url=None)
+            self.productseries.product.owner, url=None
+        )
         self.productseries.product.translationgroup = group
         return group
 
@@ -295,6 +309,7 @@ class TestProductSeriesLanguageView(TestCaseWithFactory):
         # appear as the translation_team.
         group = self._makeTranslationGroup()
         translator = self.factory.makeTranslator(
-            group=group, language=self.language)
+            group=group, language=self.language
+        )
         view = self._createView()
         self.assertEqual(translator, view.translation_team)
diff --git a/lib/lp/translations/browser/tests/test_seriestemplatesview.py b/lib/lp/translations/browser/tests/test_seriestemplatesview.py
index b0d1483..49c390e 100644
--- a/lib/lp/translations/browser/tests/test_seriestemplatesview.py
+++ b/lib/lp/translations/browser/tests/test_seriestemplatesview.py
@@ -11,11 +11,7 @@ from lp.registry.model.distroseries import DistroSeries
 from lp.registry.model.productseries import ProductSeries
 from lp.services.webapp.publisher import canonical_url
 from lp.services.webapp.servers import LaunchpadTestRequest
-from lp.testing import (
-    login,
-    login_person,
-    TestCaseWithFactory,
-    )
+from lp.testing import TestCaseWithFactory, login, login_person
 from lp.testing.layers import DatabaseFunctionalLayer
 from lp.testing.sampledata import ADMIN_EMAIL
 from lp.translations.browser.distroseries import DistroSeriesTemplatesView
@@ -64,29 +60,29 @@ class SeriesTemplatesViewScenario:
         """
         regex = '<%s [^>]*class="([^"]*)"' % tag
         return [
-            sorted(css_class.split())
-            for css_class in re.findall(regex, html)]
+            sorted(css_class.split()) for css_class in re.findall(regex, html)
+        ]
 
     def _findActions(self, html):
         """Find the available actions in an HTML actions column."""
-        return re.findall('<[^>]*>([^<]*)</[^>]*', html)
+        return re.findall("<[^>]*>([^<]*)</[^>]*", html)
 
     def test_has_the_right_columns(self):
         # Test the column headers against the expected list.
         view = self._makeView()
         header = view.renderTemplatesHeader()
-        self.assertEqual(self.columns, self._findTagClasses(header, 'th'))
+        self.assertEqual(self.columns, self._findTagClasses(header, "th"))
 
     def test_logging_in_adds_actions_column(self):
         # A logged-in user gets to see an extra "actions" column.
         template = self._makeTemplate()
         login_person(self.factory.makePerson())
         view = self._makeView(template)
-        columns = self.columns + [['actions_column']]
+        columns = self.columns + [["actions_column"]]
         header = view.renderTemplatesHeader()
-        self.assertEqual(columns, self._findTagClasses(header, 'th'))
+        self.assertEqual(columns, self._findTagClasses(header, "th"))
         row = view.renderTemplateRow(template)
-        self.assertEqual(columns, self._findTagClasses(row, 'td'))
+        self.assertEqual(columns, self._findTagClasses(row, "td"))
 
     def test_user_actions(self):
         # The only action offered to regular users is Download.
@@ -96,8 +92,9 @@ class SeriesTemplatesViewScenario:
         view = self._makeView(template)
 
         self.assertEqual(
-            ['Download'],
-            self._findActions(view._renderActionsColumn(template, url)))
+            ["Download"],
+            self._findActions(view._renderActionsColumn(template, url)),
+        )
 
     def test_admin_actions(self):
         # An administrator gets to see all actions on a template.
@@ -107,8 +104,9 @@ class SeriesTemplatesViewScenario:
         view = self._makeView(template)
 
         self.assertEqual(
-            ['Edit', 'Upload', 'Download', 'Administer'],
-            self._findActions(view._renderActionsColumn(template, url)))
+            ["Edit", "Upload", "Download", "Administer"],
+            self._findActions(view._renderActionsColumn(template, url)),
+        )
 
     def test_edit_actions(self):
         # A non-admin user with edit rights gets the Edit, Upload, and
@@ -120,8 +118,9 @@ class SeriesTemplatesViewScenario:
         view.can_edit = True
 
         self.assertEqual(
-            ['Edit', 'Upload', 'Download'],
-            self._findActions(view._renderActionsColumn(template, url)))
+            ["Edit", "Upload", "Download"],
+            self._findActions(view._renderActionsColumn(template, url)),
+        )
 
     def test_constructs_correct_urls(self):
         # The view classes can override constructTemplateURL with
@@ -132,12 +131,14 @@ class SeriesTemplatesViewScenario:
         view = self._makeView(template)
 
         series_url = canonical_url(
-            self._getSeries(template), rootsite='translations')
+            self._getSeries(template), rootsite="translations"
+        )
         constructed_url = view.constructTemplateURL(template)
 
         self.assertIn(
             canonical_url(template),
-            (constructed_url, '/'.join([series_url, constructed_url])))
+            (constructed_url, "/".join([series_url, constructed_url])),
+        )
 
     def test_renderTemplateLink(self):
         # _renderTemplateLink renders a link to the template.
@@ -147,9 +148,9 @@ class SeriesTemplatesViewScenario:
         url = view.constructTemplateURL(template)
         link = view._renderTemplateLink(template, url)
 
-        self.assertIn('<a ', link)
+        self.assertIn("<a ", link)
         self.assertIn('href="%s"' % url, link)
-        self.assertIn('>%s<' % template.name, link)
+        self.assertIn(">%s<" % template.name, link)
 
     def test_renderTemplateLink_marks_disabled(self):
         # _renderTemplateLinks marks disabled templates as "(inactive)."
@@ -158,10 +159,9 @@ class SeriesTemplatesViewScenario:
         url = canonical_url(template)
 
         removeSecurityProxy(template).iscurrent = True
-        self.assertNotIn(
-            '(inactive)', view._renderTemplateLink(template, url))
+        self.assertNotIn("(inactive)", view._renderTemplateLink(template, url))
         removeSecurityProxy(template).iscurrent = False
-        self.assertIn('(inactive)', view._renderTemplateLink(template, url))
+        self.assertIn("(inactive)", view._renderTemplateLink(template, url))
 
     def test_renderLastUpdateDate_sets_sortkey(self):
         # _renderLastUpdateDate sets the full date as the column's sort
@@ -175,7 +175,8 @@ class SeriesTemplatesViewScenario:
 
         # The sort key is set in a span of class "sortkey."
         sortkey_match = re.findall(
-            '<span class="sortkey">([^<]*)</span>', date_field)
+            '<span class="sortkey">([^<]*)</span>', date_field
+        )
         self.assertIsNot(None, sortkey_match)
         self.assertEqual(1, len(sortkey_match))
 
@@ -186,8 +187,8 @@ class SeriesTemplatesViewScenario:
     def test_renderAction_returns_empty_string_if_not_enabled(self):
         view = self._makeView()
         self.assertEqual(
-            '',
-            view._renderAction('url', 'name', 'path', 'sprite', False))
+            "", view._renderAction("url", "name", "path", "sprite", False)
+        )
 
     def test_renderAction(self):
         # If enabled, _renderAction produces a link to an action form
@@ -201,19 +202,19 @@ class SeriesTemplatesViewScenario:
 
         action = view._renderAction(url, name, path, sprite, True)
 
-        self.assertIn('<a ', action)
+        self.assertIn("<a ", action)
         self.assertIn('href="%s/%s"' % (url, path), action)
         self.assertIn(name, action)
         self.assertIn('class="sprite %s"' % sprite, action)
 
     def test_renderField_returns_empty_string_if_no_content(self):
         view = self._makeView()
-        self.assertEqual('', view._renderField('x', None, tag='y'))
+        self.assertEqual("", view._renderField("x", None, tag="y"))
 
     def test_renderField_returns_empty_field_for_empty_content(self):
-        field = self._makeView()._renderField('class', '', tag='tag')
+        field = self._makeView()._renderField("class", "", tag="tag")
         self.assertIn('<tag class="class">', field)
-        self.assertIn('</tag>', field)
+        self.assertIn("</tag>", field)
 
     def test_renderField(self):
         column_class = self.factory.getUniqueString()
@@ -224,7 +225,7 @@ class SeriesTemplatesViewScenario:
 
         self.assertIn('<%s class="%s">' % (tag, column_class), field)
         self.assertIn(content, field)
-        self.assertIn('</%s>' % tag, field)
+        self.assertIn("</%s>" % tag, field)
 
     def test_renderTemplateRow(self):
         template = self._makeTemplate()
@@ -233,14 +234,16 @@ class SeriesTemplatesViewScenario:
         row = view.renderTemplateRow(template)
 
         self.assertEqual(
-            [sorted(['template_row', view.rowCSSClass(template)])],
-            self._findTagClasses(row, 'tr'))
+            [sorted(["template_row", view.rowCSSClass(template)])],
+            self._findTagClasses(row, "tr"),
+        )
 
-        self.assertEqual(self.columns, self._findTagClasses(row, 'td'))
+        self.assertEqual(self.columns, self._findTagClasses(row, "td"))
 
 
-class TestDistroSeriesTemplatesView(SeriesTemplatesViewScenario,
-                                    TestCaseWithFactory):
+class TestDistroSeriesTemplatesView(
+    SeriesTemplatesViewScenario, TestCaseWithFactory
+):
     """Run the test scenario against `DistroSeriesTemplatesView`."""
 
     layer = DatabaseFunctionalLayer
@@ -248,19 +251,20 @@ class TestDistroSeriesTemplatesView(SeriesTemplatesViewScenario,
     view_class = DistroSeriesTemplatesView
 
     columns = [
-        ['priority_column'],
-        ['sourcepackage_column'],
-        ['template_column'],
-        ['sharing'],
-        ['length_column'],
-        ['lastupdate_column'],
+        ["priority_column"],
+        ["sourcepackage_column"],
+        ["template_column"],
+        ["sharing"],
+        ["length_column"],
+        ["lastupdate_column"],
     ]
 
     def makeTemplateContext(self):
         """See `SeriesTemplatesViewScenario`."""
         return dict(
             sourcepackagename=self.factory.makeSourcePackageName(),
-            distroseries=self.factory.makeDistroSeries())
+            distroseries=self.factory.makeDistroSeries(),
+        )
 
     def test_makeTemplate(self):
         # In this test case, _makeTemplate produces a distroseries
@@ -273,13 +277,14 @@ class TestDistroSeriesTemplatesView(SeriesTemplatesViewScenario,
         # Tested here arbitrarily (no need to repeat it): the
         # _findTagClasses helper.
         self.assertEqual(
-            [['b', 'c'], ['a']],
-            self._findTagClasses('<x class="c b" /><x class="a">', 'x'))
+            [["b", "c"], ["a"]],
+            self._findTagClasses('<x class="c b" /><x class="a">', "x"),
+        )
 
     def test_findActions(self):
         # Tested here arbitrarily (no need to repeat it): the
         # _findActions helper.
-        self.assertEqual(['Foo'], self._findActions('<a class="bar">Foo</a>'))
+        self.assertEqual(["Foo"], self._findActions('<a class="bar">Foo</a>'))
 
     def test_is_distroseries(self):
         self.assertTrue(self._makeView().is_distroseries)
@@ -292,34 +297,38 @@ class TestDistroSeriesTemplatesView(SeriesTemplatesViewScenario,
 
         self.assertEqual(
             template.sourcepackagename.name,
-            view._renderSourcePackage(template))
+            view._renderSourcePackage(template),
+        )
 
 
 class FauxSharedTemplate:
     """A stand-in for a template."""
-    name = 'TEMPLATE_NAME'
+
+    name = "TEMPLATE_NAME"
 
 
 class FauxSourcePackageName:
     """A stand-in for a SourcePackageName."""
-    name = 'SOURCE_PACKAGE_NAME'
+
+    name = "SOURCE_PACKAGE_NAME"
 
 
 class FauxProductSeries:
     """A stand-in for a ProductSeries."""
-    name = 'PRODUCT_SERIES_NAME'
+
+    name = "PRODUCT_SERIES_NAME"
 
 
 class TestSharingColumn(TestDistroSeriesTemplatesView):
     """Test the _renderSharing method of BaseSeriesTemplatesView."""
 
     columns = [
-        ['priority_column'],
-        ['sourcepackage_column'],
-        ['template_column'],
-        ['sharing'],
-        ['length_column'],
-        ['lastupdate_column'],
+        ["priority_column"],
+        ["sourcepackage_column"],
+        ["template_column"],
+        ["sharing"],
+        ["length_column"],
+        ["lastupdate_column"],
     ]
 
     def test_unshared(self):
@@ -327,27 +336,36 @@ class TestSharingColumn(TestDistroSeriesTemplatesView):
         template = self._makeTemplate()
         view = self._makeView(template)
         rendered = view._renderSharing(template, None, None, None, None, None)
-        self.assertTrue('not shared' in rendered)
-        edit_link_segment = ('+source/%s/+sharing-details' %
-            template.sourcepackagename.name)
+        self.assertTrue("not shared" in rendered)
+        edit_link_segment = (
+            "+source/%s/+sharing-details" % template.sourcepackagename.name
+        )
         self.assertTrue(edit_link_segment in rendered)
 
     def test_shared(self):
         view = self._makeView()
-        rendered = view._renderSharing(FauxSharedTemplate, object(),
-            FauxProductSeries, object(), object(), FauxSourcePackageName)
+        rendered = view._renderSharing(
+            FauxSharedTemplate,
+            object(),
+            FauxProductSeries,
+            object(),
+            object(),
+            FauxSourcePackageName,
+        )
         # Shared templates are displayed with an edit link that leads to the
         # +sharing-details page...
-        edit_link_segment = ('+source/%s/+sharing-details' %
-            FauxSourcePackageName.name)
+        edit_link_segment = (
+            "+source/%s/+sharing-details" % FauxSourcePackageName.name
+        )
         self.assertTrue(edit_link_segment in rendered)
         # ...and a link to the shared template.
-        template_link_segment = ('/+pots/%s' % FauxSharedTemplate.name)
+        template_link_segment = "/+pots/%s" % FauxSharedTemplate.name
         self.assertTrue(template_link_segment in rendered)
 
 
-class TestProductSeriesTemplatesView(SeriesTemplatesViewScenario,
-                                     TestCaseWithFactory):
+class TestProductSeriesTemplatesView(
+    SeriesTemplatesViewScenario, TestCaseWithFactory
+):
     """Run the test scenario against `ProductSeriesTemplatesView`."""
 
     layer = DatabaseFunctionalLayer
@@ -355,10 +373,10 @@ class TestProductSeriesTemplatesView(SeriesTemplatesViewScenario,
     view_class = ProductSeriesTemplatesView
 
     columns = [
-        ['priority_column'],
-        ['template_column'],
-        ['length_column'],
-        ['lastupdate_column'],
+        ["priority_column"],
+        ["template_column"],
+        ["length_column"],
+        ["lastupdate_column"],
     ]
 
     def makeTemplateContext(self):
diff --git a/lib/lp/translations/browser/tests/test_sharing_details.py b/lib/lp/translations/browser/tests/test_sharing_details.py
index b2c068c..fecbe12 100644
--- a/lib/lp/translations/browser/tests/test_sharing_details.py
+++ b/lib/lp/translations/browser/tests/test_sharing_details.py
@@ -4,10 +4,7 @@
 import re
 
 from lazr.restful.interfaces import IJSONRequestCache
-from soupmatchers import (
-    HTMLContains,
-    Tag,
-    )
+from soupmatchers import HTMLContains, Tag
 
 from lp.app.enums import ServiceUsage
 from lp.services.webapp import canonical_url
@@ -15,27 +12,25 @@ from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.testing import (
     BrowserTestCase,
     EventRecorder,
+    TestCaseWithFactory,
     extract_lp_cache,
     person_logged_in,
-    TestCaseWithFactory,
-    )
+)
 from lp.testing.layers import DatabaseFunctionalLayer
-from lp.testing.pages import (
-    extract_text,
-    find_tag_by_id,
-    )
+from lp.testing.pages import extract_text, find_tag_by_id
 from lp.translations.browser.sourcepackage import (
     SourcePackageTranslationSharingDetailsView,
-    )
+)
 from lp.translations.interfaces.translations import (
     TranslationsBranchImportMode,
-    )
+)
 from lp.translations.model.translationpackagingjob import TranslationMergeJob
 
 
 def make_initialized_view(sourcepackage):
     view = SourcePackageTranslationSharingDetailsView(
-        sourcepackage, LaunchpadTestRequest())
+        sourcepackage, LaunchpadTestRequest()
+    )
     view.initialize()
     return view
 
@@ -43,19 +38,23 @@ def make_initialized_view(sourcepackage):
 class ConfigureScenarioMixin:
     """Provide a method for project configuration."""
 
-    def configureUpstreamProject(self, productseries,
-            set_upstream_branch=False,
-            translations_usage=ServiceUsage.UNKNOWN,
-            translation_import_mode=TranslationsBranchImportMode.NO_IMPORT):
-        """Configure the productseries and its product as an upstream project.
-        """
+    def configureUpstreamProject(
+        self,
+        productseries,
+        set_upstream_branch=False,
+        translations_usage=ServiceUsage.UNKNOWN,
+        translation_import_mode=TranslationsBranchImportMode.NO_IMPORT,
+    ):
+        """Configure the productseries and its product as an upstream project."""  # noqa: E501
         with person_logged_in(productseries.product.owner):
             if set_upstream_branch:
                 productseries.branch = self.factory.makeBranch(
-                    product=productseries.product)
+                    product=productseries.product
+                )
             productseries.product.translations_usage = translations_usage
             productseries.translations_autoimport_mode = (
-                translation_import_mode)
+                translation_import_mode
+            )
 
     def makeFullyConfiguredSharing(self, suppress_merge_job=True):
         """Setup a fully configured sharing scenario."""
@@ -72,7 +71,9 @@ class ConfigureScenarioMixin:
             set_upstream_branch=True,
             translations_usage=ServiceUsage.LAUNCHPAD,
             translation_import_mode=(
-                TranslationsBranchImportMode.IMPORT_TRANSLATIONS))
+                TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+            ),
+        )
         return (sourcepackage, productseries)
 
     def endMergeJob(self, sourcepackage):
@@ -83,8 +84,9 @@ class ConfigureScenarioMixin:
                 job.complete()
 
 
-class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
-                                                     ConfigureScenarioMixin):
+class TestSourcePackageTranslationSharingDetailsView(
+    TestCaseWithFactory, ConfigureScenarioMixin
+):
     """Tests for SourcePackageTranslationSharingStatus."""
 
     layer = DatabaseFunctionalLayer
@@ -93,24 +95,31 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         super().setUp()
         distroseries = self.factory.makeUbuntuDistroSeries()
         self.sourcepackage = self.factory.makeSourcePackage(
-            distroseries=distroseries)
+            distroseries=distroseries
+        )
         self.ubuntu_only_template = self.factory.makePOTemplate(
-            sourcepackage=self.sourcepackage, name='ubuntu-only')
+            sourcepackage=self.sourcepackage, name="ubuntu-only"
+        )
         self.shared_template_ubuntu_side = self.factory.makePOTemplate(
-            sourcepackage=self.sourcepackage, name='shared-template')
+            sourcepackage=self.sourcepackage, name="shared-template"
+        )
         self.privileged_user = self.factory.makePerson(karma=200)
         product = self.factory.makeProduct(owner=self.privileged_user)
         self.productseries = self.factory.makeProductSeries(product=product)
         self.shared_template_upstream_side = self.factory.makePOTemplate(
-            productseries=self.productseries, name='shared-template')
+            productseries=self.productseries, name="shared-template"
+        )
         self.upstream_only_template = self.factory.makePOTemplate(
-            productseries=self.productseries, name='upstream-only')
+            productseries=self.productseries, name="upstream-only"
+        )
         self.view = make_initialized_view(self.sourcepackage)
 
-    def configureSharing(self,
-            set_upstream_branch=False,
-            translations_usage=ServiceUsage.UNKNOWN,
-            translation_import_mode=TranslationsBranchImportMode.NO_IMPORT):
+    def configureSharing(
+        self,
+        set_upstream_branch=False,
+        translations_usage=ServiceUsage.UNKNOWN,
+        translation_import_mode=TranslationsBranchImportMode.NO_IMPORT,
+    ):
         """Configure translation sharing, at least partially.
 
         A packaging link is always set; the remaining configuration is
@@ -119,10 +128,14 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # Suppress merge job creation.
         with EventRecorder():
             self.sourcepackage.setPackaging(
-                self.productseries, self.productseries.owner)
+                self.productseries, self.productseries.owner
+            )
         self.configureUpstreamProject(
-            self.productseries, set_upstream_branch, translations_usage,
-            translation_import_mode)
+            self.productseries,
+            set_upstream_branch,
+            translations_usage,
+            translation_import_mode,
+        )
 
     def test_is_packaging_configured__not_configured(self):
         # If a sourcepackage is not linked to a product series,
@@ -161,7 +174,7 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
 
     def test_branch_link_text(self):
         self.configureSharing(set_upstream_branch=True)
-        expected_text = '>lp:%s</a>' % self.view.upstream_branch.unique_name
+        expected_text = ">lp:%s</a>" % self.view.upstream_branch.unique_name
         self.assertIn(expected_text, self.view.branch_link.escapedtext)
 
     def test_is_upstream_translations_enabled__no_packaging_link(self):
@@ -202,7 +215,8 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # If no synchronization is enabled on the upstream series,
         # is_upstream_synchronization_enabled returns False.
         self.configureSharing(
-            translation_import_mode=TranslationsBranchImportMode.NO_IMPORT)
+            translation_import_mode=TranslationsBranchImportMode.NO_IMPORT
+        )
         self.assertFalse(self.view.is_upstream_synchronization_enabled)
 
     def test_is_upstream_synchronization_enabled__import_templates(self):
@@ -210,7 +224,9 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # is_upstream_synchronization_enabled returns False.
         self.configureSharing(
             translation_import_mode=(
-                TranslationsBranchImportMode.IMPORT_TEMPLATES))
+                TranslationsBranchImportMode.IMPORT_TEMPLATES
+            )
+        )
         self.assertFalse(self.view.is_upstream_synchronization_enabled)
 
     def test_is_upstream_synchronization_enabled__import_translations(self):
@@ -218,7 +234,9 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # series, is_upstream_synchronization_enabled returns False.
         self.configureSharing(
             translation_import_mode=(
-                TranslationsBranchImportMode.IMPORT_TRANSLATIONS))
+                TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+            )
+        )
         self.assertTrue(self.view.is_upstream_synchronization_enabled)
 
     def test_is_configuration_complete__nothing_configured(self):
@@ -256,8 +274,8 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # but if the upstream series does not synchronize translations
         # then is_configuration_complete is False.
         self.configureSharing(
-            set_upstream_branch=True,
-            translations_usage=ServiceUsage.LAUNCHPAD)
+            set_upstream_branch=True, translations_usage=ServiceUsage.LAUNCHPAD
+        )
         self.assertFalse(self.view.is_configuration_complete)
 
     def test_is_configuration_complete__all_conditions_fulfilled(self):
@@ -271,7 +289,9 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
             set_upstream_branch=True,
             translations_usage=ServiceUsage.LAUNCHPAD,
             translation_import_mode=(
-                TranslationsBranchImportMode.IMPORT_TRANSLATIONS))
+                TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+            ),
+        )
         self.assertTrue(self.view.is_configuration_complete)
 
     def test_template_info__no_sharing(self):
@@ -280,18 +300,18 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # only data about templates in Ubuntu.
         expected = [
             {
-                'name': 'shared-template',
-                'status': 'only in Ubuntu',
-                'package_template': self.shared_template_ubuntu_side,
-                'upstream_template': None,
-                },
+                "name": "shared-template",
+                "status": "only in Ubuntu",
+                "package_template": self.shared_template_ubuntu_side,
+                "upstream_template": None,
+            },
             {
-                'name': 'ubuntu-only',
-                'status': 'only in Ubuntu',
-                'package_template': self.ubuntu_only_template,
-                'upstream_template': None,
-                },
-            ]
+                "name": "ubuntu-only",
+                "status": "only in Ubuntu",
+                "package_template": self.ubuntu_only_template,
+                "upstream_template": None,
+            },
+        ]
         self.assertEqual(expected, self.view.template_info())
 
     def test_template_info___sharing(self):
@@ -303,27 +323,29 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
             set_upstream_branch=True,
             translations_usage=ServiceUsage.LAUNCHPAD,
             translation_import_mode=(
-                TranslationsBranchImportMode.IMPORT_TRANSLATIONS))
+                TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+            ),
+        )
         expected = [
             {
-                'name': 'shared-template',
-                'status': 'shared',
-                'package_template': self.shared_template_ubuntu_side,
-                'upstream_template': self.shared_template_upstream_side,
-                },
+                "name": "shared-template",
+                "status": "shared",
+                "package_template": self.shared_template_ubuntu_side,
+                "upstream_template": self.shared_template_upstream_side,
+            },
             {
-                'name': 'ubuntu-only',
-                'status': 'only in Ubuntu',
-                'package_template': self.ubuntu_only_template,
-                'upstream_template': None,
-                },
+                "name": "ubuntu-only",
+                "status": "only in Ubuntu",
+                "package_template": self.ubuntu_only_template,
+                "upstream_template": None,
+            },
             {
-                'name': 'upstream-only',
-                'status': 'only in upstream',
-                'package_template': None,
-                'upstream_template': self.upstream_only_template,
-                },
-            ]
+                "name": "upstream-only",
+                "status": "only in upstream",
+                "package_template": None,
+                "upstream_template": self.upstream_only_template,
+            },
+        ]
         self.assertEqual(expected, self.view.template_info())
 
     def getCacheObjects(self):
@@ -334,38 +356,38 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
 
     def test_cache_contents_no_productseries(self):
         objects = self.getCacheObjects()
-        self.assertIs(None, objects['productseries'])
-        self.assertIn('user_can_change_product_series', objects)
-        self.assertIn('user_can_change_branch', objects)
-        self.assertIn('user_can_change_translation_usage', objects)
-        self.assertIn('user_can_change_translations_autoimport_mode', objects)
+        self.assertIs(None, objects["productseries"])
+        self.assertIn("user_can_change_product_series", objects)
+        self.assertIn("user_can_change_branch", objects)
+        self.assertIn("user_can_change_translation_usage", objects)
+        self.assertIn("user_can_change_translations_autoimport_mode", objects)
 
     def test_cache_contents_no_branch(self):
         self.configureSharing()
         objects = self.getCacheObjects()
-        self.assertEqual(self.productseries, objects['productseries'])
-        self.assertEqual(self.productseries.product, objects['product'])
-        self.assertIs(None, objects['upstream_branch'])
+        self.assertEqual(self.productseries, objects["productseries"])
+        self.assertEqual(self.productseries.product, objects["product"])
+        self.assertIs(None, objects["upstream_branch"])
 
     def test_cache_contents_branch(self):
         self.configureSharing(set_upstream_branch=True)
         objects = self.getCacheObjects()
-        self.assertEqual(
-            self.productseries.branch, objects['upstream_branch'])
+        self.assertEqual(self.productseries.branch, objects["upstream_branch"])
 
     def _getExpectedTranslationSettingsLink(self, id, series, visible):
         if series is None:
-            url = '#'
+            url = "#"
         else:
-            url = '%s/+configure-translations' % canonical_url(series.product)
+            url = "%s/+configure-translations" % canonical_url(series.product)
         return (
             '<a id="upstream-translations-%(id)s" class="sprite '
             'edit action-icon%(seen)s" href="%(url)s">'
-            'Configure Upstream Translations</a>') % {
-            'id': id,
-            'url': url,
-            'seen': '' if visible else ' hidden',
-            }
+            "Configure Upstream Translations</a>"
+        ) % {
+            "id": id,
+            "url": url,
+            "seen": "" if visible else " hidden",
+        }
 
     def test_configure_translations_link__no_packaging_link(self):
         # If no packaging link exists,
@@ -373,15 +395,19 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # configure_translations_link_configured return hidden dummy
         # links.
         expected = self._getExpectedTranslationSettingsLink(
-            id='incomplete', series=None, visible=False)
+            id="incomplete", series=None, visible=False
+        )
         self.assertEqual(
             expected,
-            self.view.configure_translations_link_unconfigured.escapedtext)
+            self.view.configure_translations_link_unconfigured.escapedtext,
+        )
         expected = self._getExpectedTranslationSettingsLink(
-            id='complete', series=None, visible=False)
+            id="complete", series=None, visible=False
+        )
         self.assertEqual(
             expected,
-            self.view.configure_translations_link_configured.escapedtext)
+            self.view.configure_translations_link_configured.escapedtext,
+        )
 
     def test_configure_translations_link__packaging_link__anon_user(self):
         # If a packaging link exists,
@@ -390,18 +416,23 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # pointing to the configuration page for anonymous users.
         self.configureSharing()
         expected = self._getExpectedTranslationSettingsLink(
-            id='incomplete', series=self.productseries, visible=False)
+            id="incomplete", series=self.productseries, visible=False
+        )
         self.assertEqual(
             expected,
-            self.view.configure_translations_link_unconfigured.escapedtext)
+            self.view.configure_translations_link_unconfigured.escapedtext,
+        )
         expected = self._getExpectedTranslationSettingsLink(
-            id='complete', series=self.productseries, visible=False)
+            id="complete", series=self.productseries, visible=False
+        )
         self.assertEqual(
             expected,
-            self.view.configure_translations_link_configured.escapedtext)
+            self.view.configure_translations_link_configured.escapedtext,
+        )
 
     def test_configure_translations_link__packaging_link__unprivileged_user(
-        self):
+        self,
+    ):
         # If a packaging link exists,
         # configure_translations_link_unconfigured and
         # configure_translations_link_configured return hidden links
@@ -410,21 +441,27 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         self.configureSharing()
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             expected = self._getExpectedTranslationSettingsLink(
-                id='incomplete', series=self.productseries, visible=False)
+                id="incomplete", series=self.productseries, visible=False
+            )
             self.assertEqual(
                 expected,
-                view.configure_translations_link_unconfigured.escapedtext)
+                view.configure_translations_link_unconfigured.escapedtext,
+            )
             expected = self._getExpectedTranslationSettingsLink(
-                id='complete', series=self.productseries, visible=False)
+                id="complete", series=self.productseries, visible=False
+            )
             self.assertEqual(
                 expected,
-                view.configure_translations_link_configured.escapedtext)
+                view.configure_translations_link_configured.escapedtext,
+            )
 
     def test_configure_translations_link__packaging_link__privileged_user(
-        self):
+        self,
+    ):
         # If a packaging link exists,
         # configure_translations_link_unconfigured and
         # configure_translations_link_configured return visible links
@@ -433,46 +470,54 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         self.configureSharing()
         with person_logged_in(self.productseries.owner):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             expected = self._getExpectedTranslationSettingsLink(
-                id='incomplete', series=self.productseries, visible=True)
+                id="incomplete", series=self.productseries, visible=True
+            )
             self.assertEqual(
                 expected,
-                view.configure_translations_link_unconfigured.escapedtext)
+                view.configure_translations_link_unconfigured.escapedtext,
+            )
             expected = self._getExpectedTranslationSettingsLink(
-                id='complete', series=self.productseries, visible=True)
+                id="complete", series=self.productseries, visible=True
+            )
             self.assertEqual(
                 expected,
-                view.configure_translations_link_configured.escapedtext)
+                view.configure_translations_link_configured.escapedtext,
+            )
 
     def _getExpectedTranslationSyncLink(self, id, series, visible):
         if series is None:
-            url = '#'
+            url = "#"
         else:
-            url = '%s/+translations-settings' % canonical_url(series)
+            url = "%s/+translations-settings" % canonical_url(series)
         return (
-        '<a id="translation-synchronisation-%(id)s" class="sprite '
-        'edit action-icon%(seen)s" href="%(url)s">'
-        'Configure Translation Synchronisation</a>') % {
-            'id': id,
-            'url': url,
-            'seen': '' if visible else ' hidden',
-            }
+            '<a id="translation-synchronisation-%(id)s" class="sprite '
+            'edit action-icon%(seen)s" href="%(url)s">'
+            "Configure Translation Synchronisation</a>"
+        ) % {
+            "id": id,
+            "url": url,
+            "seen": "" if visible else " hidden",
+        }
 
     def test_upstream_sync_link__no_packaging_link(self):
         # If no packaging link exists, translation_sync_link_unconfigured
         # and translation_sync_link_configured return hidden dummy links.
         expected = self._getExpectedTranslationSyncLink(
-            id='incomplete', series=None, visible=False)
+            id="incomplete", series=None, visible=False
+        )
         self.assertEqual(
-            expected,
-            self.view.translation_sync_link_unconfigured.escapedtext)
+            expected, self.view.translation_sync_link_unconfigured.escapedtext
+        )
         expected = self._getExpectedTranslationSyncLink(
-            id='complete', series=None, visible=False)
+            id="complete", series=None, visible=False
+        )
         self.assertEqual(
-            expected,
-            self.view.translation_sync_link_configured.escapedtext)
+            expected, self.view.translation_sync_link_configured.escapedtext
+        )
 
     def test_upstream_sync_link__packaging_link__anon_user(self):
         # If a packaging link exists, translation_sync_link_unconfigured
@@ -480,15 +525,17 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # for anonymous users.
         self.configureSharing()
         expected = self._getExpectedTranslationSyncLink(
-            id='incomplete', series=self.productseries, visible=False)
+            id="incomplete", series=self.productseries, visible=False
+        )
         self.assertEqual(
-            expected,
-            self.view.translation_sync_link_unconfigured.escapedtext)
+            expected, self.view.translation_sync_link_unconfigured.escapedtext
+        )
         expected = self._getExpectedTranslationSyncLink(
-            id='complete', series=self.productseries, visible=False)
+            id="complete", series=self.productseries, visible=False
+        )
         self.assertEqual(
-            expected,
-            self.view.translation_sync_link_configured.escapedtext)
+            expected, self.view.translation_sync_link_configured.escapedtext
+        )
 
     def test_upstream_sync_link__packaging_link__unprivileged_user(self):
         # If a packaging link exists, translation_sync_link_unconfigured
@@ -498,18 +545,21 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         self.configureSharing()
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             expected = self._getExpectedTranslationSyncLink(
-                id='incomplete', series=self.productseries, visible=False)
+                id="incomplete", series=self.productseries, visible=False
+            )
             self.assertEqual(
-                expected,
-                view.translation_sync_link_unconfigured.escapedtext)
+                expected, view.translation_sync_link_unconfigured.escapedtext
+            )
             expected = self._getExpectedTranslationSyncLink(
-                id='complete', series=self.productseries, visible=False)
+                id="complete", series=self.productseries, visible=False
+            )
             self.assertEqual(
-                expected,
-                view.translation_sync_link_configured.escapedtext)
+                expected, view.translation_sync_link_configured.escapedtext
+            )
 
     def test_upstream_sync_link__packaging_link__privileged_user(self):
         # If a packaging link exists, translation_sync_link_unconfigured
@@ -519,65 +569,85 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         self.configureSharing()
         with person_logged_in(self.productseries.owner):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             expected = self._getExpectedTranslationSyncLink(
-                id='incomplete', series=self.productseries, visible=True)
+                id="incomplete", series=self.productseries, visible=True
+            )
             self.assertEqual(
-                expected,
-                view.translation_sync_link_unconfigured.escapedtext)
+                expected, view.translation_sync_link_unconfigured.escapedtext
+            )
             expected = self._getExpectedTranslationSyncLink(
-                id='complete', series=self.productseries, visible=True)
+                id="complete", series=self.productseries, visible=True
+            )
             self.assertEqual(
-                expected,
-                view.translation_sync_link_configured.escapedtext)
+                expected, view.translation_sync_link_configured.escapedtext
+            )
 
     def _getExpectedPackagingLink(self, id, url, icon, text, visible):
-        url = '%s/%s' % (canonical_url(self.sourcepackage), url)
+        url = "%s/%s" % (canonical_url(self.sourcepackage), url)
         return (
             '<a id="%(id)s" class="sprite %(icon)s action-icon%(seen)s"'
-            ' href="%(url)s">%(text)s</a>') % {
-            'id': id,
-            'url': url,
-            'icon': icon,
-            'seen': '' if visible else ' hidden',
-            'text': text,
-            }
+            ' href="%(url)s">%(text)s</a>'
+        ) % {
+            "id": id,
+            "url": url,
+            "icon": icon,
+            "seen": "" if visible else " hidden",
+            "text": text,
+        }
 
     def test_set_packaging_link__anonymous(self):
         # The "set packaging" link is hidden for anonymous users.
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='set-packaging', url='+edit-packaging', icon='add',
-            text='Set upstream link', visible=False)
+            id="set-packaging",
+            url="+edit-packaging",
+            icon="add",
+            text="Set upstream link",
+            visible=False,
+        )
         self.assertEqual(expected, self.view.set_packaging_link.escapedtext)
 
     def test_set_packaging_link__no_packaging_any_user(self):
         # If packaging is not configured, any user sees the "set packaging"
         # link.
         expected = self._getExpectedPackagingLink(
-            id='set-packaging', url='+edit-packaging', icon='add',
-            text='Set upstream link', visible=True)
+            id="set-packaging",
+            url="+edit-packaging",
+            icon="add",
+            text="Set upstream link",
+            visible=True,
+        )
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.set_packaging_link.escapedtext)
+                expected, self.view.set_packaging_link.escapedtext
+            )
 
     def test_set_packaging_link__with_packaging_probationary_user(self):
         # If packaging is configured, probationary users do no see
         # the "set packaging" link.
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='set-packaging', url='+edit-packaging', icon='add',
-            text='Set upstream link', visible=False)
+            id="set-packaging",
+            url="+edit-packaging",
+            icon="add",
+            text="Set upstream link",
+            visible=False,
+        )
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.set_packaging_link.escapedtext)
+                expected, self.view.set_packaging_link.escapedtext
+            )
 
     def test_set_packaging_link__with_packaging_privileged_user(self):
         # If packaging is configured, privileged users see the
@@ -585,50 +655,71 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # details about which people are "privileged".)
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='set-packaging', url='+edit-packaging', icon='add',
-            text='Set upstream link', visible=True)
+            id="set-packaging",
+            url="+edit-packaging",
+            icon="add",
+            text="Set upstream link",
+            visible=True,
+        )
         with person_logged_in(self.privileged_user):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.set_packaging_link.escapedtext)
+                expected, self.view.set_packaging_link.escapedtext
+            )
 
     def test_change_packaging_link__anonymous(self):
         # The "change packaging" link is hidden for anonymous users.
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='change-packaging', url='+edit-packaging', icon='edit',
-            text='Change upstream link', visible=False)
-        self.assertEqual(
-            expected, self.view.change_packaging_link.escapedtext)
+            id="change-packaging",
+            url="+edit-packaging",
+            icon="edit",
+            text="Change upstream link",
+            visible=False,
+        )
+        self.assertEqual(expected, self.view.change_packaging_link.escapedtext)
 
     def test_change_packaging_link__no_packaging_any_user(self):
         # If packaging is not configured, any user sees the "change packaging"
         # link.
         expected = self._getExpectedPackagingLink(
-            id='change-packaging', url='+edit-packaging', icon='edit',
-            text='Change upstream link', visible=True)
+            id="change-packaging",
+            url="+edit-packaging",
+            icon="edit",
+            text="Change upstream link",
+            visible=True,
+        )
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.change_packaging_link.escapedtext)
+                expected, self.view.change_packaging_link.escapedtext
+            )
 
     def test_change_packaging_link__with_packaging_probationary_user(self):
         # If packaging is configured, probationary users do no see
         # the "change packaging" link.
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='change-packaging', url='+edit-packaging', icon='edit',
-            text='Change upstream link', visible=False)
+            id="change-packaging",
+            url="+edit-packaging",
+            icon="edit",
+            text="Change upstream link",
+            visible=False,
+        )
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.change_packaging_link.escapedtext)
+                expected, self.view.change_packaging_link.escapedtext
+            )
 
     def test_change_packaging_link__with_packaging_privileged_user(self):
         # If packaging is configured, privileged users see the
@@ -636,50 +727,71 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # details about which people are "privileged".)
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='change-packaging', url='+edit-packaging', icon='edit',
-            text='Change upstream link', visible=True)
+            id="change-packaging",
+            url="+edit-packaging",
+            icon="edit",
+            text="Change upstream link",
+            visible=True,
+        )
         with person_logged_in(self.privileged_user):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.change_packaging_link.escapedtext)
+                expected, self.view.change_packaging_link.escapedtext
+            )
 
     def test_remove_packaging_link__anonymous(self):
         # The "remove packaging" link is hidden for anonymous users.
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='remove-packaging', url='+remove-packaging', icon='remove',
-            text='Remove upstream link', visible=False)
-        self.assertEqual(
-            expected, self.view.remove_packaging_link.escapedtext)
+            id="remove-packaging",
+            url="+remove-packaging",
+            icon="remove",
+            text="Remove upstream link",
+            visible=False,
+        )
+        self.assertEqual(expected, self.view.remove_packaging_link.escapedtext)
 
     def test_remove_packaging_link__no_packaging_any_user(self):
         # If packaging is not configured, any user sees the "remove packaging"
         # link.
         expected = self._getExpectedPackagingLink(
-            id='remove-packaging', url='+remove-packaging', icon='remove',
-            text='Remove upstream link', visible=True)
+            id="remove-packaging",
+            url="+remove-packaging",
+            icon="remove",
+            text="Remove upstream link",
+            visible=True,
+        )
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.remove_packaging_link.escapedtext)
+                expected, self.view.remove_packaging_link.escapedtext
+            )
 
     def test_remove_packaging_link__with_packaging_probationary_user(self):
         # If packaging is configured, probationary users do no see
         # the "remove packaging" link.
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='remove-packaging', url='+remove-packaging', icon='remove',
-            text='Remove upstream link', visible=False)
+            id="remove-packaging",
+            url="+remove-packaging",
+            icon="remove",
+            text="Remove upstream link",
+            visible=False,
+        )
         with person_logged_in(self.factory.makePerson()):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.remove_packaging_link.escapedtext)
+                expected, self.view.remove_packaging_link.escapedtext
+            )
 
     def test_remove_packaging_link__with_packaging_privileged_user(self):
         # If packaging is configured, privileged users see the
@@ -687,18 +799,25 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
         # details about which people are "privileged".)
         self.configureSharing()
         expected = self._getExpectedPackagingLink(
-            id='remove-packaging', url='+remove-packaging', icon='remove',
-            text='Remove upstream link', visible=True)
+            id="remove-packaging",
+            url="+remove-packaging",
+            icon="remove",
+            text="Remove upstream link",
+            visible=True,
+        )
         with person_logged_in(self.privileged_user):
             view = SourcePackageTranslationSharingDetailsView(
-                self.sourcepackage, LaunchpadTestRequest())
+                self.sourcepackage, LaunchpadTestRequest()
+            )
             view.initialize()
             self.assertEqual(
-                expected, self.view.remove_packaging_link.escapedtext)
+                expected, self.view.remove_packaging_link.escapedtext
+            )
 
 
-class TestSourcePackageSharingDetailsPage(BrowserTestCase,
-                                          ConfigureScenarioMixin):
+class TestSourcePackageSharingDetailsPage(
+    BrowserTestCase, ConfigureScenarioMixin
+):
     """Test for the sharing details page of a source package."""
 
     layer = DatabaseFunctionalLayer
@@ -714,72 +833,106 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         else:
             no_login = False
         return self.getViewBrowser(
-            sourcepackage, no_login=no_login, rootsite="translations",
-            view_name="+sharing-details", user=user)
+            sourcepackage,
+            no_login=no_login,
+            rootsite="translations",
+            view_name="+sharing-details",
+            user=user,
+        )
 
     def asserthidden(self, browser, html_id):
-        hidden_matcher = Tag(html_id, 'li', attrs={
-            'id': html_id,
-            'class': lambda v: v and 'hidden' in v.split(' ')})
+        hidden_matcher = Tag(
+            html_id,
+            "li",
+            attrs={
+                "id": html_id,
+                "class": lambda v: v and "hidden" in v.split(" "),
+            },
+        )
         self.assertThat(browser.contents, HTMLContains(hidden_matcher))
 
     def assertSeen(self, browser, html_id, dimmed=False):
-        seen_matcher = Tag(html_id, 'li', attrs={
-            'id': html_id,
-            'class': lambda v: v and 'hidden' not in v.split(' ')})
+        seen_matcher = Tag(
+            html_id,
+            "li",
+            attrs={
+                "id": html_id,
+                "class": lambda v: v and "hidden" not in v.split(" "),
+            },
+        )
         self.assertThat(browser.contents, HTMLContains(seen_matcher))
         if dimmed:
-            dimmed_matcher = Tag(html_id, 'li', attrs={
-            'id': html_id,
-            'class': lambda v: v and 'lowlight' in v.split(' ')})
+            dimmed_matcher = Tag(
+                html_id,
+                "li",
+                attrs={
+                    "id": html_id,
+                    "class": lambda v: v and "lowlight" in v.split(" "),
+                },
+            )
         else:
-            dimmed_matcher = Tag(html_id, 'li', attrs={
-            'id': html_id,
-            'class': lambda v: v and 'lowlight' not in v.split(' ')})
+            dimmed_matcher = Tag(
+                html_id,
+                "li",
+                attrs={
+                    "id": html_id,
+                    "class": lambda v: v and "lowlight" not in v.split(" "),
+                },
+            )
         self.assertThat(browser.contents, HTMLContains(dimmed_matcher))
 
     def assertStatusDisplayShowsIncomplete(self, browser):
         seen_matcher = Tag(
-            'configuration-incomplete', 'span',
+            "configuration-incomplete",
+            "span",
             attrs={
-                'id': 'configuration-incomplete',
-                'class': '',
-                })
+                "id": "configuration-incomplete",
+                "class": "",
+            },
+        )
         self.assertThat(browser.contents, HTMLContains(seen_matcher))
         hidden_matcher = Tag(
-            'configuration-complete', 'span',
+            "configuration-complete",
+            "span",
             attrs={
-                'id': 'configuration-complete',
-                'class': 'hidden',
-                })
+                "id": "configuration-complete",
+                "class": "hidden",
+            },
+        )
         self.assertThat(browser.contents, HTMLContains(hidden_matcher))
 
     def assertStatusDisplayShowsCompleted(self, browser):
         seen_matcher = Tag(
-            'configuration-complete', 'span',
+            "configuration-complete",
+            "span",
             attrs={
-                'id': 'configuration-complete',
-                'class': '',
-                })
+                "id": "configuration-complete",
+                "class": "",
+            },
+        )
         self.assertThat(browser.contents, HTMLContains(seen_matcher))
         hidden_matcher = Tag(
-            'configuration-incomplete', 'span',
+            "configuration-incomplete",
+            "span",
             attrs={
-                'id': 'configuration-incomplete',
-                'class': 'hidden',
-                })
+                "id": "configuration-incomplete",
+                "class": "hidden",
+            },
+        )
         self.assertThat(browser.contents, HTMLContains(hidden_matcher))
 
     def assertElementText(self, browser, id, expected):
         node = find_tag_by_id(browser.contents, id)
         self.assertTextMatchesExpressionIgnoreWhitespace(
-            expected, extract_text(node))
+            expected, extract_text(node)
+        )
 
     def assertContentComplete(self, browser):
         # The HTML data contains always all text variants.
-        checklist = find_tag_by_id(browser.contents, 'sharing-checklist')
+        checklist = find_tag_by_id(browser.contents, "sharing-checklist")
         self.assertIsNot(None, checklist)
-        self.assertTextMatchesExpressionIgnoreWhitespace("""
+        self.assertTextMatchesExpressionIgnoreWhitespace(
+            """
             Translation sharing configuration is incomplete.
             Translation sharing with upstream is active.
             No upstream project series has been linked.
@@ -799,25 +952,37 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
             Configure Translation Synchronisation
             Automatic synchronization of translations is enabled.
             Configure Translation Synchronisation""",
-            extract_text(checklist))
+            extract_text(checklist),
+        )
         self.assertElementText(
-            browser, 'packaging-incomplete',
-            'No upstream project series has been linked.')
+            browser,
+            "packaging-incomplete",
+            "No upstream project series has been linked.",
+        )
         self.assertElementText(
-            browser, 'packaging-complete', 'Linked upstream series is .*')
+            browser, "packaging-complete", "Linked upstream series is .*"
+        )
         self.assertElementText(
-            browser, 'packaging-complete', 'Linked upstream series is .*')
+            browser, "packaging-complete", "Linked upstream series is .*"
+        )
         self.assertElementText(
-            browser, 'branch-incomplete',
-            'No source branch exists for the upstream series.')
+            browser,
+            "branch-incomplete",
+            "No source branch exists for the upstream series.",
+        )
         self.assertElementText(
-            browser, 'branch-complete', 'Upstream source branch is .*')
+            browser, "branch-complete", "Upstream source branch is .*"
+        )
         self.assertElementText(
-            browser, 'translation-incomplete',
-            'Translations are not enabled on the upstream project.')
+            browser,
+            "translation-incomplete",
+            "Translations are not enabled on the upstream project.",
+        )
         self.assertElementText(
-            browser, 'translation-complete',
-            'Translations are enabled on the upstream project.')
+            browser,
+            "translation-complete",
+            "Translations are enabled on the upstream project.",
+        )
 
     def test_checklist_unconfigured(self):
         # Without a packaging link, sharing is completely unconfigured
@@ -825,13 +990,13 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
         self.assertContentComplete(browser)
         self.assertStatusDisplayShowsIncomplete(browser)
-        self.asserthidden(browser, 'packaging-complete')
-        self.assertSeen(browser, 'branch-incomplete', dimmed=True)
-        self.asserthidden(browser, 'branch-complete')
-        self.assertSeen(browser, 'translation-incomplete', dimmed=True)
-        self.asserthidden(browser, 'translation-complete')
-        self.assertSeen(browser, 'upstream-sync-incomplete', dimmed=True)
-        self.asserthidden(browser, 'upstream-sync-complete')
+        self.asserthidden(browser, "packaging-complete")
+        self.assertSeen(browser, "branch-incomplete", dimmed=True)
+        self.asserthidden(browser, "branch-complete")
+        self.assertSeen(browser, "translation-incomplete", dimmed=True)
+        self.asserthidden(browser, "translation-complete")
+        self.assertSeen(browser, "upstream-sync-incomplete", dimmed=True)
+        self.asserthidden(browser, "upstream-sync-complete")
 
     def test_checklist_packaging_configured(self):
         # Linking a source package takes care of one item.
@@ -840,32 +1005,33 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         browser = self._getSharingDetailsViewBrowser(packaging.sourcepackage)
         self.assertContentComplete(browser)
         self.assertStatusDisplayShowsIncomplete(browser)
-        self.asserthidden(browser, 'packaging-incomplete')
-        self.assertSeen(browser, 'packaging-complete')
-        self.assertSeen(browser, 'branch-incomplete')
-        self.asserthidden(browser, 'branch-complete')
-        self.assertSeen(browser, 'translation-incomplete')
-        self.asserthidden(browser, 'translation-complete')
-        self.assertSeen(browser, 'upstream-sync-incomplete')
-        self.asserthidden(browser, 'upstream-sync-complete')
+        self.asserthidden(browser, "packaging-incomplete")
+        self.assertSeen(browser, "packaging-complete")
+        self.assertSeen(browser, "branch-incomplete")
+        self.asserthidden(browser, "branch-complete")
+        self.assertSeen(browser, "translation-incomplete")
+        self.asserthidden(browser, "translation-complete")
+        self.assertSeen(browser, "upstream-sync-incomplete")
+        self.asserthidden(browser, "upstream-sync-complete")
 
     def test_checklist_packaging_and_branch_configured(self):
         # Linking a source package and and setting an upstream branch
         # changes the text displayed for the branch configuration.
         packaging = self.factory.makePackagingLink(in_ubuntu=True)
         self.configureUpstreamProject(
-            productseries=packaging.productseries, set_upstream_branch=True)
+            productseries=packaging.productseries, set_upstream_branch=True
+        )
         browser = self._getSharingDetailsViewBrowser(packaging.sourcepackage)
         self.assertContentComplete(browser)
         self.assertStatusDisplayShowsIncomplete(browser)
-        self.asserthidden(browser, 'packaging-incomplete')
-        self.assertSeen(browser, 'packaging-complete')
-        self.asserthidden(browser, 'branch-incomplete')
-        self.assertSeen(browser, 'branch-complete')
-        self.assertSeen(browser, 'translation-incomplete')
-        self.asserthidden(browser, 'translation-complete')
-        self.assertSeen(browser, 'upstream-sync-incomplete')
-        self.asserthidden(browser, 'upstream-sync-complete')
+        self.asserthidden(browser, "packaging-incomplete")
+        self.assertSeen(browser, "packaging-complete")
+        self.asserthidden(browser, "branch-incomplete")
+        self.assertSeen(browser, "branch-complete")
+        self.assertSeen(browser, "translation-incomplete")
+        self.asserthidden(browser, "translation-complete")
+        self.assertSeen(browser, "upstream-sync-incomplete")
+        self.asserthidden(browser, "upstream-sync-complete")
 
     def test_checklist_packaging_and_translations_enabled(self):
         # Linking a source package and and setting an upstream branch
@@ -873,18 +1039,19 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         packaging = self.factory.makePackagingLink(in_ubuntu=True)
         self.configureUpstreamProject(
             productseries=packaging.productseries,
-            translations_usage=ServiceUsage.LAUNCHPAD)
+            translations_usage=ServiceUsage.LAUNCHPAD,
+        )
         browser = self._getSharingDetailsViewBrowser(packaging.sourcepackage)
         self.assertContentComplete(browser)
         self.assertStatusDisplayShowsIncomplete(browser)
-        self.asserthidden(browser, 'packaging-incomplete')
-        self.assertSeen(browser, 'packaging-complete')
-        self.assertSeen(browser, 'branch-incomplete')
-        self.asserthidden(browser, 'branch-complete')
-        self.asserthidden(browser, 'translation-incomplete')
-        self.assertSeen(browser, 'translation-complete')
-        self.assertSeen(browser, 'upstream-sync-incomplete')
-        self.asserthidden(browser, 'upstream-sync-complete')
+        self.asserthidden(browser, "packaging-incomplete")
+        self.assertSeen(browser, "packaging-complete")
+        self.assertSeen(browser, "branch-incomplete")
+        self.asserthidden(browser, "branch-complete")
+        self.asserthidden(browser, "translation-incomplete")
+        self.assertSeen(browser, "translation-complete")
+        self.assertSeen(browser, "upstream-sync-incomplete")
+        self.asserthidden(browser, "upstream-sync-complete")
 
     def test_checklist_packaging_and_upstream_sync_enabled(self):
         # Linking a source package and enabling upstream translation
@@ -894,18 +1061,20 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         self.configureUpstreamProject(
             productseries=packaging.productseries,
             translation_import_mode=(
-                TranslationsBranchImportMode.IMPORT_TRANSLATIONS))
+                TranslationsBranchImportMode.IMPORT_TRANSLATIONS
+            ),
+        )
         browser = self._getSharingDetailsViewBrowser(packaging.sourcepackage)
         self.assertContentComplete(browser)
         self.assertStatusDisplayShowsIncomplete(browser)
-        self.asserthidden(browser, 'packaging-incomplete')
-        self.assertSeen(browser, 'packaging-complete')
-        self.assertSeen(browser, 'branch-incomplete')
-        self.asserthidden(browser, 'branch-complete')
-        self.assertSeen(browser, 'translation-incomplete')
-        self.asserthidden(browser, 'translation-complete')
-        self.asserthidden(browser, 'upstream-sync-incomplete')
-        self.assertSeen(browser, 'upstream-sync-complete')
+        self.asserthidden(browser, "packaging-incomplete")
+        self.assertSeen(browser, "packaging-complete")
+        self.assertSeen(browser, "branch-incomplete")
+        self.asserthidden(browser, "branch-complete")
+        self.assertSeen(browser, "translation-incomplete")
+        self.asserthidden(browser, "translation-complete")
+        self.asserthidden(browser, "upstream-sync-incomplete")
+        self.assertSeen(browser, "upstream-sync-complete")
 
     def test_checklist_fully_configured(self):
         # A fully configured sharing setup.
@@ -913,111 +1082,139 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
         self.assertContentComplete(browser)
         self.assertStatusDisplayShowsCompleted(browser)
-        self.asserthidden(browser, 'packaging-incomplete')
-        self.assertSeen(browser, 'packaging-complete')
-        self.asserthidden(browser, 'branch-incomplete')
-        self.assertSeen(browser, 'branch-complete')
-        self.asserthidden(browser, 'translation-incomplete')
-        self.assertSeen(browser, 'translation-complete')
-        self.asserthidden(browser, 'upstream-sync-incomplete')
-        self.assertSeen(browser, 'upstream-sync-complete')
+        self.asserthidden(browser, "packaging-incomplete")
+        self.assertSeen(browser, "packaging-complete")
+        self.asserthidden(browser, "branch-incomplete")
+        self.assertSeen(browser, "branch-complete")
+        self.asserthidden(browser, "translation-incomplete")
+        self.assertSeen(browser, "translation-complete")
+        self.asserthidden(browser, "upstream-sync-incomplete")
+        self.assertSeen(browser, "upstream-sync-complete")
 
     def test_cache_javascript(self):
         # Cache object entries propagate into the javascript.
         sourcepackage = self.makeFullyConfiguredSharing()[0]
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
-        self.assertIn(
-            'productseries', extract_lp_cache(browser.contents))
+        self.assertIn("productseries", extract_lp_cache(browser.contents))
 
     def test_potlist_only_ubuntu(self):
         # Without a packaging link, only Ubuntu templates are listed.
         sourcepackage = self._makeSourcePackage()
         self.factory.makePOTemplate(
-            name='foo-template', sourcepackage=sourcepackage)
+            name="foo-template", sourcepackage=sourcepackage
+        )
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
-        tbody = find_tag_by_id(
-            browser.contents, 'template-table').find('tbody')
+        tbody = find_tag_by_id(browser.contents, "template-table").find(
+            "tbody"
+        )
         self.assertIsNot(None, tbody)
         self.assertEqual(
             "foo-template\nonly in Ubuntu\n0\na moment ago",
-            extract_text(tbody))
+            extract_text(tbody),
+        )
 
     def test_potlist_sharing(self):
         # With sharing configured, templates on both sides are listed.
         sourcepackage, productseries = self.makeFullyConfiguredSharing()
-        template_name = 'foo-template'
+        template_name = "foo-template"
         self.factory.makePOTemplate(
-            name=template_name, sourcepackage=sourcepackage)
+            name=template_name, sourcepackage=sourcepackage
+        )
         self.factory.makePOTemplate(
-            name=template_name, productseries=productseries)
+            name=template_name, productseries=productseries
+        )
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
-        tbody = find_tag_by_id(
-            browser.contents, 'template-table').find('tbody')
+        tbody = find_tag_by_id(browser.contents, "template-table").find(
+            "tbody"
+        )
         self.assertIsNot(None, tbody)
         self.assertEqual(
             "foo-template\nshared\n0\na moment ago\n0\na moment ago\n"
-            "View upstream", extract_text(tbody))
+            "View upstream",
+            extract_text(tbody),
+        )
 
     def test_potlist_only_upstream(self):
         # A template that is only present in upstream is called
         # "only in upstream".
         sourcepackage, productseries = self.makeFullyConfiguredSharing()
-        template_name = 'foo-template'
+        template_name = "foo-template"
         self.factory.makePOTemplate(
-            name=template_name, productseries=productseries)
+            name=template_name, productseries=productseries
+        )
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
-        tbody = find_tag_by_id(
-            browser.contents, 'template-table').find('tbody')
+        tbody = find_tag_by_id(browser.contents, "template-table").find(
+            "tbody"
+        )
         self.assertIsNot(None, tbody)
         self.assertEqual(
             "foo-template\nonly in upstream\n0\na moment ago\nView upstream",
-            extract_text(tbody))
+            extract_text(tbody),
+        )
 
     def test_potlist_linking(self):
         # When a merge job is running, the state is "linking".
         sourcepackage, productseries = self.makeFullyConfiguredSharing(
-            suppress_merge_job=False)
-        template_name = 'foo-template'
+            suppress_merge_job=False
+        )
+        template_name = "foo-template"
         self.factory.makePOTemplate(
-            name=template_name, sourcepackage=sourcepackage)
+            name=template_name, sourcepackage=sourcepackage
+        )
         self.factory.makePOTemplate(
-            name=template_name, productseries=productseries)
+            name=template_name, productseries=productseries
+        )
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
-        tbody = find_tag_by_id(
-            browser.contents, 'template-table').find('tbody')
+        tbody = find_tag_by_id(browser.contents, "template-table").find(
+            "tbody"
+        )
         self.assertIsNot(None, tbody)
-        self.assertTextMatchesExpressionIgnoreWhitespace("""
+        self.assertTextMatchesExpressionIgnoreWhitespace(
+            """
             foo-template  linking""",
-            extract_text(tbody))
+            extract_text(tbody),
+        )
 
     def assertBranchLinks(self, contents, real_links, enabled):
         if real_links:
             match = (
-                r'^http://translations.launchpad.test/.*/trunk/\+setbranch$')
+                r"^http://translations.launchpad.test/.*/trunk/\+setbranch$";
+            )
 
             def link_matcher(url):
                 if url is None:
                     return False
                 return re.search(match, url)
+
         else:
-            link_matcher = '#'
+            link_matcher = "#"
         if enabled:
-            css_class = 'sprite add action-icon'
+            css_class = "sprite add action-icon"
         else:
-            css_class = 'sprite add action-icon hidden'
-        matcher = Tag('add-branch', 'a', attrs={
-            'id': 'add-branch',
-            'href': link_matcher,
-            'class': css_class})
+            css_class = "sprite add action-icon hidden"
+        matcher = Tag(
+            "add-branch",
+            "a",
+            attrs={
+                "id": "add-branch",
+                "href": link_matcher,
+                "class": css_class,
+            },
+        )
         self.assertThat(contents, HTMLContains(matcher))
         if enabled:
-            css_class = 'sprite edit action-icon'
+            css_class = "sprite edit action-icon"
         else:
-            css_class = 'sprite edit action-icon hidden'
-        matcher = Tag('change-branch', 'a', attrs={
-            'id': 'change-branch',
-            'href': link_matcher,
-            'class': css_class})
+            css_class = "sprite edit action-icon hidden"
+        matcher = Tag(
+            "change-branch",
+            "a",
+            attrs={
+                "id": "change-branch",
+                "href": link_matcher,
+                "class": css_class,
+            },
+        )
         self.assertThat(contents, HTMLContains(matcher))
 
     def test_edit_branch_links__no_packaging_link(self):
@@ -1026,18 +1223,19 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         sourcepackage = self._makeSourcePackage()
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
         self.assertBranchLinks(
-            browser.contents, real_links=False, enabled=False)
+            browser.contents, real_links=False, enabled=False
+        )
 
     def test_edit_branch_links__with_packaging_link__anon_user(self):
         # If a packaging link exists, new_branch_link and edit_branch_link
         # return hidden links which point to the product series
         # branch configuration page for anonymous users.
         packaging = self.factory.makePackagingLink(in_ubuntu=True)
-        self.configureUpstreamProject(
-            productseries=packaging.productseries)
+        self.configureUpstreamProject(productseries=packaging.productseries)
         browser = self._getSharingDetailsViewBrowser(packaging.sourcepackage)
         self.assertBranchLinks(
-            browser.contents, real_links=True, enabled=False)
+            browser.contents, real_links=True, enabled=False
+        )
 
     def test_edit_branch_links__with_packaging_link__unprivileged_user(self):
         # If a packaging link exists, new_branch_link and edit_branch_link
@@ -1045,12 +1243,13 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         # branch configuration page for users which cannot change the
         # branch of the product series.
         packaging = self.factory.makePackagingLink(in_ubuntu=True)
-        self.configureUpstreamProject(
-            productseries=packaging.productseries)
+        self.configureUpstreamProject(productseries=packaging.productseries)
         browser = self._getSharingDetailsViewBrowser(
-            packaging.sourcepackage, user=self.factory.makePerson())
+            packaging.sourcepackage, user=self.factory.makePerson()
+        )
         self.assertBranchLinks(
-            browser.contents, real_links=True, enabled=False)
+            browser.contents, real_links=True, enabled=False
+        )
 
     def test_edit_branch_links__with_packaging_link__privileged_user(self):
         # If a packaging link exists, new_branch_link and edit_branch_link
@@ -1058,12 +1257,11 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         # branch configuration page for users which can change the
         # branch of the product series.
         packaging = self.factory.makePackagingLink(in_ubuntu=True)
-        self.configureUpstreamProject(
-            productseries=packaging.productseries)
+        self.configureUpstreamProject(productseries=packaging.productseries)
         browser = self._getSharingDetailsViewBrowser(
-            packaging.sourcepackage, user=packaging.productseries.owner)
-        self.assertBranchLinks(
-            browser.contents, real_links=True, enabled=True)
+            packaging.sourcepackage, user=packaging.productseries.owner
+        )
+        self.assertBranchLinks(browser.contents, real_links=True, enabled=True)
 
     def test_configure_translations(self):
         # The link to the translation configuration page of the
@@ -1071,21 +1269,23 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         sourcepackage = self._makeSourcePackage()
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
         matcher = Tag(
-            'upstream-translations-incomplete', 'a',
+            "upstream-translations-incomplete",
+            "a",
             attrs={
-                'id': 'upstream-translations-incomplete',
-                'href': '#',
-                'class': 'sprite edit action-icon hidden',
-                },
+                "id": "upstream-translations-incomplete",
+                "href": "#",
+                "class": "sprite edit action-icon hidden",
+            },
         )
         self.assertThat(browser.contents, HTMLContains(matcher))
         matcher = Tag(
-            'upstream-translations-complete', 'a',
+            "upstream-translations-complete",
+            "a",
             attrs={
-                'id': 'upstream-translations-complete',
-                'href': '#',
-                'class': 'sprite edit action-icon hidden',
-                },
+                "id": "upstream-translations-complete",
+                "href": "#",
+                "class": "sprite edit action-icon hidden",
+            },
         )
         self.assertThat(browser.contents, HTMLContains(matcher))
 
@@ -1095,48 +1295,53 @@ class TestSourcePackageSharingDetailsPage(BrowserTestCase,
         sourcepackage = self._makeSourcePackage()
         browser = self._getSharingDetailsViewBrowser(sourcepackage)
         matcher = Tag(
-            'translation-synchronisation-incomplete', 'a',
+            "translation-synchronisation-incomplete",
+            "a",
             attrs={
-                'id': 'translation-synchronisation-incomplete',
-                'href': '#',
-                'class': 'sprite edit action-icon hidden',
-                },
+                "id": "translation-synchronisation-incomplete",
+                "href": "#",
+                "class": "sprite edit action-icon hidden",
+            },
         )
         self.assertThat(browser.contents, HTMLContains(matcher))
         matcher = Tag(
-            'translation-synchronisation-complete', 'a',
+            "translation-synchronisation-complete",
+            "a",
             attrs={
-                'id': 'translation-synchronisation-complete',
-                'href': '#',
-                'class': 'sprite edit action-icon hidden',
-                },
+                "id": "translation-synchronisation-complete",
+                "href": "#",
+                "class": "sprite edit action-icon hidden",
+            },
         )
         self.assertThat(browser.contents, HTMLContains(matcher))
 
 
-class TestTranslationSharingDetailsViewNotifications(TestCaseWithFactory,
-                                                     ConfigureScenarioMixin):
+class TestTranslationSharingDetailsViewNotifications(
+    TestCaseWithFactory, ConfigureScenarioMixin
+):
     """Tests for Notifications in SourcePackageTranslationSharingView."""
 
     layer = DatabaseFunctionalLayer
 
     def _getNotifications(self, view):
         notifications = view.request.response.notifications
-        return [extract_text(notification.message)
-                for notification in notifications]
+        return [
+            extract_text(notification.message)
+            for notification in notifications
+        ]
 
     no_templates_message = (
         "No upstream templates have been found yet. Please follow "
         "the import process by going to the Translation Import Queue "
-        "of the upstream project series.")
+        "of the upstream project series."
+    )
 
     def test_message_no_templates(self):
         # When sharing is fully configured but no upstream templates are
         # found, a message is displayed.
         sourcepackage = self.makeFullyConfiguredSharing()[0]
         view = make_initialized_view(sourcepackage)
-        self.assertIn(
-            self.no_templates_message, self._getNotifications(view))
+        self.assertIn(self.no_templates_message, self._getNotifications(view))
 
     def test_no_message_with_templates(self):
         # When sharing is fully configured and templates are found, no
@@ -1145,7 +1350,8 @@ class TestTranslationSharingDetailsViewNotifications(TestCaseWithFactory,
         self.factory.makePOTemplate(productseries=productseries)
         view = make_initialized_view(sourcepackage)
         self.assertNotIn(
-            self.no_templates_message, self._getNotifications(view))
+            self.no_templates_message, self._getNotifications(view)
+        )
 
     def test_no_message_with_incomplate_sharing(self):
         # When sharing is not fully configured and templates are found, no
@@ -1156,26 +1362,30 @@ class TestTranslationSharingDetailsViewNotifications(TestCaseWithFactory,
         self.factory.makePOTemplate(productseries=productseries)
         view = make_initialized_view(sourcepackage)
         self.assertNotIn(
-            self.no_templates_message, self._getNotifications(view))
+            self.no_templates_message, self._getNotifications(view)
+        )
 
     job_running_message = (
         "Translations are currently being linked by a background "
         "job. When that job has finished, translations will be "
-        "shared with the upstream project.")
+        "shared with the upstream project."
+    )
 
     def test_message_job_running(self):
         # When a merge job is running, a message is displayed.
         sourcepackage = self.makeFullyConfiguredSharing(
-            suppress_merge_job=False)[0]
+            suppress_merge_job=False
+        )[0]
         view = make_initialized_view(sourcepackage)
-        self.assertIn(
-            self.job_running_message, self._getNotifications(view))
+        self.assertIn(self.job_running_message, self._getNotifications(view))
 
     def test_no_message_job_not_running(self):
         # Without a merge job running, no such message is displayed.
         sourcepackage = self.makeFullyConfiguredSharing(
-            suppress_merge_job=False)[0]
+            suppress_merge_job=False
+        )[0]
         self.endMergeJob(sourcepackage)
         view = make_initialized_view(sourcepackage)
         self.assertNotIn(
-            self.job_running_message, self._getNotifications(view))
+            self.job_running_message, self._getNotifications(view)
+        )
diff --git a/lib/lp/translations/browser/tests/test_sharing_information.py b/lib/lp/translations/browser/tests/test_sharing_information.py
index a9d69b3..bfaed87 100644
--- a/lib/lp/translations/browser/tests/test_sharing_information.py
+++ b/lib/lp/translations/browser/tests/test_sharing_information.py
@@ -4,26 +4,20 @@
 """Tests for the POTemplate recipe view classes and templates."""
 
 from lp.app.enums import ServiceUsage
-from lp.testing import (
-    BrowserTestCase,
-    celebrity_logged_in,
-    )
+from lp.testing import BrowserTestCase, celebrity_logged_in
 from lp.testing.layers import DatabaseFunctionalLayer
-from lp.testing.pages import (
-    extract_text,
-    find_tag_by_id,
-    )
+from lp.testing.pages import extract_text, find_tag_by_id
 from lp.translations.interfaces.side import TranslationSide
 
 
 def set_translations_usage(obj):
     """Set the translations_usage to LAUNCHPAD."""
-    with celebrity_logged_in('admin'):
+    with celebrity_logged_in("admin"):
         obj.translations_usage = ServiceUsage.LAUNCHPAD
 
 
 def enable_translations_on_distroseries(distroseries):
-    with celebrity_logged_in('admin'):
+    with celebrity_logged_in("admin"):
         distroseries.hide_all_translations = False
 
 
@@ -37,11 +31,13 @@ class TestSharingInfoMixin:
         """
         upstream_template = self.factory.makePOTemplate()
         packaging = self.factory.makePackagingLink(
-            productseries=upstream_template.productseries, in_ubuntu=True)
+            productseries=upstream_template.productseries, in_ubuntu=True
+        )
         ubuntu_template = self.factory.makePOTemplate(
             distroseries=packaging.distroseries,
             sourcepackagename=packaging.sourcepackagename,
-            name=upstream_template.name)
+            name=upstream_template.name,
+        )
         if side == TranslationSide.UPSTREAM:
             return upstream_template
         else:
@@ -71,20 +67,20 @@ class TestSharingInfoMixin:
         """
         logged_in_user = self.factory.makePerson()
         if productseries is not None:
-            with celebrity_logged_in('admin'):
+            with celebrity_logged_in("admin"):
                 productseries.product.owner = logged_in_user
         return logged_in_user
 
-    def _test_sharing_information(self, obj,
-                                  id_under_test, expected_text,
-                                  authorized=False):
+    def _test_sharing_information(
+        self, obj, id_under_test, expected_text, authorized=False
+    ):
         if authorized:
             user = self.getAuthorizedUser(obj)
         else:
             user = None
         browser = self.getViewBrowser(
-                obj, user=user, no_login=(not authorized),
-                rootsite="translations")
+            obj, user=user, no_login=(not authorized), rootsite="translations"
+        )
 
         sharing_info = find_tag_by_id(browser.contents, id_under_test)
         if expected_text is None:
@@ -92,17 +88,20 @@ class TestSharingInfoMixin:
         else:
             self.assertIsNot(None, sharing_info)
             self.assertTextMatchesExpressionIgnoreWhitespace(
-                expected_text, extract_text(sharing_info))
+                expected_text, extract_text(sharing_info)
+            )
 
     def test_not_sharing_info(self):
         self._test_sharing_information(
             self.makeNotSharingObject(),
-            'sharing-information', self.NOT_SHARING_TEXT)
+            "sharing-information",
+            self.NOT_SHARING_TEXT,
+        )
 
     def test_sharing_info(self):
         self._test_sharing_information(
-            self.makeSharingObject(),
-            'sharing-information', self.SHARING_TEXT)
+            self.makeSharingObject(), "sharing-information", self.SHARING_TEXT
+        )
 
 
 class TestSharingDetailsLinkMixin:
@@ -120,28 +119,34 @@ class TestSharingDetailsLinkMixin:
         # informational.
         self._test_sharing_information(
             self.makeSharingObject(),
-            'sharing-details', self.SHARING_DETAILS_INFO)
+            "sharing-details",
+            self.SHARING_DETAILS_INFO,
+        )
 
     def test_sharing_details_setup(self):
         # For authorized users of not sharing objects, the link to the
         # sharing details page encourages action.
         self._test_sharing_information(
             self.makeNotSharingObject(),
-            'sharing-details', self.SHARING_DETAILS_SETUP,
-            authorized=True)
+            "sharing-details",
+            self.SHARING_DETAILS_SETUP,
+            authorized=True,
+        )
 
     def test_sharing_details_edit(self):
         # For authorized users, the link to the sharing details page is for
         # editing
         self._test_sharing_information(
             self.makeSharingObject(),
-            'sharing-details', self.SHARING_DETAILS_EDIT,
-            authorized=True)
+            "sharing-details",
+            self.SHARING_DETAILS_EDIT,
+            authorized=True,
+        )
 
 
-class TestUpstreamPOTemplateSharingInfo(BrowserTestCase,
-                                        TestSharingInfoMixin,
-                                        TestSharingDetailsLinkMixin):
+class TestUpstreamPOTemplateSharingInfo(
+    BrowserTestCase, TestSharingInfoMixin, TestSharingDetailsLinkMixin
+):
     """Test display of template sharing info."""
 
     layer = DatabaseFunctionalLayer
@@ -181,7 +186,8 @@ class TestPOFileSharingInfo(BrowserTestCase, TestSharingInfoMixin):
         template = self._makePackagingAndTemplates(TranslationSide.UPSTREAM)
         # This will also create a copy of pofile in the sharing template.
         pofile = self.factory.makePOFile(
-            potemplate=template, create_sharing=True)
+            potemplate=template, create_sharing=True
+        )
         return pofile
 
     SHARING_TEXT = """
@@ -211,9 +217,9 @@ class TestPlaceholderPOFileSharingInfo(BrowserTestCase, TestSharingInfoMixin):
         These translations are shared with .*"""
 
 
-class TestUpstreamSharingInfo(BrowserTestCase,
-                              TestSharingInfoMixin,
-                              TestSharingDetailsLinkMixin):
+class TestUpstreamSharingInfo(
+    BrowserTestCase, TestSharingInfoMixin, TestSharingDetailsLinkMixin
+):
     """Test display of product series sharing info."""
 
     layer = DatabaseFunctionalLayer
@@ -241,9 +247,9 @@ class TestUpstreamSharingInfo(BrowserTestCase,
         return self.getAuthorizedUserForProductseries(productseries)
 
 
-class TestUbuntuPOTemplateSharingInfo(BrowserTestCase,
-                                      TestSharingInfoMixin,
-                                      TestSharingDetailsLinkMixin):
+class TestUbuntuPOTemplateSharingInfo(
+    BrowserTestCase, TestSharingInfoMixin, TestSharingDetailsLinkMixin
+):
     """Test display of template sharing info in an Ubuntu source package."""
 
     layer = DatabaseFunctionalLayer
@@ -270,16 +276,17 @@ class TestUbuntuPOTemplateSharingInfo(BrowserTestCase,
         return self.getAuthorizedUserForProductseries(productseries)
 
 
-class TestUbuntuSharingInfo(BrowserTestCase,
-                            TestSharingInfoMixin,
-                            TestSharingDetailsLinkMixin):
+class TestUbuntuSharingInfo(
+    BrowserTestCase, TestSharingInfoMixin, TestSharingDetailsLinkMixin
+):
     """Test display of source package sharing info."""
 
     layer = DatabaseFunctionalLayer
 
     def makeNotSharingObject(self):
         sourcepackage = self.factory.makeSourcePackage(
-            distroseries=self.factory.makeUbuntuDistroSeries())
+            distroseries=self.factory.makeUbuntuDistroSeries()
+        )
         enable_translations_on_distroseries(sourcepackage.distroseries)
         return sourcepackage
 
diff --git a/lib/lp/translations/browser/tests/test_translationgroup.py b/lib/lp/translations/browser/tests/test_translationgroup.py
index 2b642d6..412105a 100644
--- a/lib/lp/translations/browser/tests/test_translationgroup.py
+++ b/lib/lp/translations/browser/tests/test_translationgroup.py
@@ -8,14 +8,8 @@ from zope.component import getUtility
 
 from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.services.worlddata.interfaces.language import ILanguageSet
-from lp.testing import (
-    BrowserTestCase,
-    TestCaseWithFactory,
-    )
-from lp.testing.layers import (
-    DatabaseFunctionalLayer,
-    LaunchpadZopelessLayer,
-    )
+from lp.testing import BrowserTestCase, TestCaseWithFactory
+from lp.testing.layers import DatabaseFunctionalLayer, LaunchpadZopelessLayer
 from lp.translations.browser.translationgroup import TranslationGroupView
 
 
@@ -38,30 +32,33 @@ class TestTranslationGroupView(TestCaseWithFactory):
     def test_translator_list(self):
         # translator_list composes dicts using _makeTranslatorDict.
         group = self.factory.makeTranslationGroup()
-        tr_translator = self.factory.makeTranslator('tr', group)
+        tr_translator = self.factory.makeTranslator("tr", group)
         transaction.commit()
         view = self._makeView(group)
         translator_dict = view._makeTranslatorDict(
-            tr_translator, tr_translator.language, tr_translator.translator)
+            tr_translator, tr_translator.language, tr_translator.translator
+        )
         self.assertEqual([translator_dict], list(view.translator_list))
 
     def test_makeTranslatorDict(self):
         # _makeTranslatorDict describes a Translator entry to the UI.
         group = self.factory.makeTranslationGroup()
-        xhosa = self.factory.makeTranslator('xh', group)
-        xhosa.style_guide_url = 'http://xh.example.com/'
+        xhosa = self.factory.makeTranslator("xh", group)
+        xhosa.style_guide_url = "http://xh.example.com/";
         view = self._makeView(group)
         output = view._makeTranslatorDict(
-            xhosa, xhosa.language, xhosa.translator)
+            xhosa, xhosa.language, xhosa.translator
+        )
 
-        self.assertEqual(xhosa.translator, output['person'])
-        self.assertEqual('xh', output['code'])
+        self.assertEqual(xhosa.translator, output["person"])
+        self.assertEqual("xh", output["code"])
         self.assertEqual(
-            getUtility(ILanguageSet).getLanguageByCode('xh'),
-            output['language'])
-        self.assertEqual(xhosa.datecreated, output['datecreated'])
-        self.assertEqual(xhosa.style_guide_url, output['style_guide_url'])
-        self.assertEqual(xhosa, output['context'])
+            getUtility(ILanguageSet).getLanguageByCode("xh"),
+            output["language"],
+        )
+        self.assertEqual(xhosa.datecreated, output["datecreated"])
+        self.assertEqual(xhosa.style_guide_url, output["style_guide_url"])
+        self.assertEqual(xhosa, output["context"])
 
 
 class TestTranslationGroupViewPermissions(BrowserTestCase):
@@ -69,7 +66,7 @@ class TestTranslationGroupViewPermissions(BrowserTestCase):
     layer = DatabaseFunctionalLayer
 
     def _assertLinksFound(self, contents, links_found):
-        for link in ['+edit', '+appoint']:
+        for link in ["+edit", "+appoint"]:
             if links_found:
                 self.assertTrue(link in contents)
             else:
diff --git a/lib/lp/translations/browser/tests/test_translationimportqueueentry.py b/lib/lp/translations/browser/tests/test_translationimportqueueentry.py
index ac7c9ab..fd2d81e 100644
--- a/lib/lp/translations/browser/tests/test_translationimportqueueentry.py
+++ b/lib/lp/translations/browser/tests/test_translationimportqueueentry.py
@@ -6,27 +6,20 @@
 from datetime import datetime
 
 from pytz import timezone
-from testscenarios import (
-    load_tests_apply_scenarios,
-    WithScenarios,
-    )
+from testscenarios import WithScenarios, load_tests_apply_scenarios
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
 from lp.app.enums import ServiceUsage
 from lp.services.features.testing import FeatureFixture
 from lp.services.webapp import canonical_url
-from lp.testing import (
-    celebrity_logged_in,
-    TestCase,
-    TestCaseWithFactory,
-    )
+from lp.testing import TestCase, TestCaseWithFactory, celebrity_logged_in
 from lp.testing.layers import LaunchpadFunctionalLayer
 from lp.testing.views import create_initialized_view
 from lp.translations.browser.translationimportqueue import escape_js_string
 from lp.translations.interfaces.translationimportqueue import (
     ITranslationImportQueue,
-    )
+)
 
 
 class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
@@ -37,10 +30,10 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
     scenarios = [
         ("spn_picker", {"features": {}}),
         ("dsp_picker", {"features": {"disclosure.dsp_picker.enabled": "on"}}),
-        ]
+    ]
 
     def setUp(self):
-        super().setUp('foo.bar@xxxxxxxxxxxxx')
+        super().setUp("foo.bar@xxxxxxxxxxxxx")
         if self.features:
             self.useFixture(FeatureFixture(self.features))
         self.queue = getUtility(ITranslationImportQueue)
@@ -50,17 +43,29 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         """Set up a product series for a translatable product."""
         product = self.factory.makeProduct()
         product.translations_usage = ServiceUsage.LAUNCHPAD
-        return product.getSeries('trunk')
-
-    def _makeEntry(self, productseries=None, distroseries=None,
-                   sourcepackagename=None, filename=None, potemplate=None):
+        return product.getSeries("trunk")
+
+    def _makeEntry(
+        self,
+        productseries=None,
+        distroseries=None,
+        sourcepackagename=None,
+        filename=None,
+        potemplate=None,
+    ):
         if filename is None:
-            filename = self.factory.getUniqueUnicode() + '.pot'
+            filename = self.factory.getUniqueUnicode() + ".pot"
         contents = self.factory.getUniqueBytes()
         entry = self.queue.addOrUpdateEntry(
-            filename, contents, False, self.uploader,
-            productseries=productseries, distroseries=distroseries,
-            sourcepackagename=sourcepackagename, potemplate=potemplate)
+            filename,
+            contents,
+            False,
+            self.uploader,
+            productseries=productseries,
+            distroseries=distroseries,
+            sourcepackagename=sourcepackagename,
+            potemplate=potemplate,
+        )
         return removeSecurityProxy(entry)
 
     def test_import_target_productseries(self):
@@ -68,7 +73,7 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         # import_target returns.
         series = self._makeProductSeries()
         entry = self._makeEntry(productseries=series)
-        view = create_initialized_view(entry, '+index')
+        view = create_initialized_view(entry, "+index")
 
         self.assertEqual(series, view.import_target)
 
@@ -79,8 +84,9 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         packagename = self.factory.makeSourcePackageName()
         package = self.factory.makeSourcePackage(packagename, series)
         entry = self._makeEntry(
-            distroseries=series, sourcepackagename=packagename)
-        view = create_initialized_view(entry, '+index')
+            distroseries=series, sourcepackagename=packagename
+        )
+        view = create_initialized_view(entry, "+index")
 
         self.assertEqual(package, view.import_target)
 
@@ -89,7 +95,7 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         # to, the series' templates.
         series = self._makeProductSeries()
         entry = self._makeEntry(productseries=series)
-        view = create_initialized_view(entry, '+index')
+        view = create_initialized_view(entry, "+index")
 
         # If there are no templates, there is no link.
         self.assertEqual("no templates", view.productseries_templates_link)
@@ -97,9 +103,9 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         # For one template, there is a link.  Its text uses the
         # singular.
         self.factory.makePOTemplate(productseries=series)
-        self.assertIn('1 template', view.productseries_templates_link)
-        self.assertNotIn('1 templates', view.productseries_templates_link)
-        url = canonical_url(series, rootsite='translations') + '/+templates'
+        self.assertIn("1 template", view.productseries_templates_link)
+        self.assertNotIn("1 templates", view.productseries_templates_link)
+        url = canonical_url(series, rootsite="translations") + "/+templates"
         self.assertIn(url, view.productseries_templates_link)
 
     def test_product_translatable_series(self):
@@ -108,7 +114,7 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         series = self._makeProductSeries()
         product = series.product
         entry = self._makeEntry(productseries=series)
-        view = create_initialized_view(entry, '+index')
+        view = create_initialized_view(entry, "+index")
 
         # No translatable series.
         series_text = view.product_translatable_series
@@ -120,7 +126,7 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         series_text = view.product_translatable_series
         self.assertIn("Project has translatable series:", series_text)
         # A link follows, and the sentence ends in a period.
-        self.assertEqual('</a>.', series_text[-5:])
+        self.assertEqual("</a>.", series_text[-5:])
 
         # Two translatable series.
         extra_series = self.factory.makeProductSeries(product=product)
@@ -129,7 +135,7 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         # The links to the series are separated by a comma.
         self.assertIn("</a>, <a ", series_text)
         # The sentence ends in a period.
-        self.assertEqual('</a>.', series_text[-5:])
+        self.assertEqual("</a>.", series_text[-5:])
 
         # Many translatable series.  The list is cut short; there's an
         # ellipsis to indicate this.
@@ -139,43 +145,46 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
             self.factory.makePOTemplate(productseries=extra_series)
         series_text = view.product_translatable_series
         # The list is cut short.
-        displayed_series_count = series_text.count('</a>')
+        displayed_series_count = series_text.count("</a>")
         self.assertNotEqual(
-            len(product.translatable_series), displayed_series_count)
+            len(product.translatable_series), displayed_series_count
+        )
         self.assertEqual(view.max_series_to_display, displayed_series_count)
         # The list of links ends with an ellipsis.
-        self.assertEqual('</a>, ...', series_text[-9:])
+        self.assertEqual("</a>, ...", series_text[-9:])
 
     def test_status_change_date(self):
         # status_change_date describes the date of the entry's last
         # status change.
         series = self._makeProductSeries()
         entry = self._makeEntry(productseries=series)
-        view = create_initialized_view(entry, '+index')
+        view = create_initialized_view(entry, "+index")
 
         # If the date equals the upload date, there's no need to show
         # anything.
-        self.assertEqual('', view.status_change_date)
+        self.assertEqual("", view.status_change_date)
 
         # If there is a difference, there's a human-readable
         # description.
-        UTC = timezone('UTC')
+        UTC = timezone("UTC")
         entry.dateimported = datetime(year=2005, month=11, day=29, tzinfo=UTC)
         entry.date_status_changed = datetime(
-            year=2007, month=8, day=14, tzinfo=UTC)
+            year=2007, month=8, day=14, tzinfo=UTC
+        )
         self.assertEqual(
-            "Last changed on 2007-08-14.", view.status_change_date)
+            "Last changed on 2007-08-14.", view.status_change_date
+        )
 
     def test_initial_values_domain(self):
         # Without a given potemplate, a translation domain will be suggested
         # from the file name.
         series = self._makeProductSeries()
-        entry = self._makeEntry(
-            productseries=series, filename="My_Domain.pot")
-        view = create_initialized_view(entry, '+index')
+        entry = self._makeEntry(productseries=series, filename="My_Domain.pot")
+        view = create_initialized_view(entry, "+index")
 
         self.assertEqual(
-            "My_Domain", view.initial_values['translation_domain'])
+            "My_Domain", view.initial_values["translation_domain"]
+        )
 
     def test_initial_values_existing_domain(self):
         # With a given potemplate, its translation domain will be presented
@@ -183,22 +192,21 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         domain = self.factory.getUniqueString()
         series = self._makeProductSeries()
         potemplate = self.factory.makePOTemplate(
-            productseries=series, translation_domain=domain)
-        entry = self._makeEntry(
-            productseries=series, potemplate=potemplate)
-        view = create_initialized_view(entry, '+index')
+            productseries=series, translation_domain=domain
+        )
+        entry = self._makeEntry(productseries=series, potemplate=potemplate)
+        view = create_initialized_view(entry, "+index")
 
-        self.assertEqual(domain, view.initial_values['translation_domain'])
+        self.assertEqual(domain, view.initial_values["translation_domain"])
 
     def test_initial_values_potemplate(self):
         # Without a given potemplate, a name will be suggested from the file
         # name. The name is converted to be suitable as a template name.
         series = self._makeProductSeries()
-        entry = self._makeEntry(
-            productseries=series, filename="My_Domain.pot")
-        view = create_initialized_view(entry, '+index')
+        entry = self._makeEntry(productseries=series, filename="My_Domain.pot")
+        view = create_initialized_view(entry, "+index")
 
-        self.assertEqual("my-domain", view.initial_values['name'])
+        self.assertEqual("my-domain", view.initial_values["name"])
 
     def test_initial_values_existing_potemplate(self):
         # With a given potemplate, its name will be presented
@@ -206,48 +214,51 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
         name = self.factory.getUniqueString()
         series = self._makeProductSeries()
         potemplate = self.factory.makePOTemplate(
-            productseries=series, name=name)
-        entry = self._makeEntry(
-            productseries=series, potemplate=potemplate)
-        view = create_initialized_view(entry, '+index')
+            productseries=series, name=name
+        )
+        entry = self._makeEntry(productseries=series, potemplate=potemplate)
+        view = create_initialized_view(entry, "+index")
 
-        self.assertEqual(name, view.initial_values['name'])
+        self.assertEqual(name, view.initial_values["name"])
 
     def test_change_sourcepackage(self):
         # Changing the source package is honoured.
         series = self.factory.makeDistroSeries()
         packagename = self.factory.makeSourcePackageName()
         potemplate = self.factory.makePOTemplate(
-            distroseries=series, sourcepackagename=packagename)
+            distroseries=series, sourcepackagename=packagename
+        )
         entry = self._makeEntry(
-            distroseries=series, sourcepackagename=packagename,
-            potemplate=potemplate)
+            distroseries=series,
+            sourcepackagename=packagename,
+            potemplate=potemplate,
+        )
         dsp = self.factory.makeDSPCache(distroseries=series)
         form = {
-            'field.file_type': 'POT',
-            'field.path': entry.path,
-            'field.sourcepackagename': dsp.sourcepackagename.name,
-            'field.name': potemplate.name,
-            'field.translation_domain': potemplate.translation_domain,
-            'field.languagepack': '',
-            'field.actions.approve': 'Approve',
-            }
-        with celebrity_logged_in('rosetta_experts'):
-            view = create_initialized_view(entry, '+index', form=form)
+            "field.file_type": "POT",
+            "field.path": entry.path,
+            "field.sourcepackagename": dsp.sourcepackagename.name,
+            "field.name": potemplate.name,
+            "field.translation_domain": potemplate.translation_domain,
+            "field.languagepack": "",
+            "field.actions.approve": "Approve",
+        }
+        with celebrity_logged_in("rosetta_experts"):
+            view = create_initialized_view(entry, "+index", form=form)
         self.assertEqual([], view.errors)
         self.assertEqual(
-            dsp.sourcepackagename.name,
-            entry.potemplate.sourcepackagename.name)
+            dsp.sourcepackagename.name, entry.potemplate.sourcepackagename.name
+        )
 
 
 class TestEscapeJSString(TestCase):
     """Test `escape_js_string`."""
 
     def test_escape_js_string_empty(self):
-        self.assertEqual('', escape_js_string(''))
+        self.assertEqual("", escape_js_string(""))
 
     def test_escape_js_string_plain(self):
-        self.assertEqual('foo', escape_js_string('foo'))
+        self.assertEqual("foo", escape_js_string("foo"))
 
     def test_escape_js_string_singlequote(self):
         self.assertEqual("\\'", escape_js_string("'"))
@@ -256,10 +267,10 @@ class TestEscapeJSString(TestCase):
         self.assertEqual('\\"', escape_js_string('"'))
 
     def test_escape_js_string_backslash(self):
-        self.assertEqual('\\\\', escape_js_string('\\'))
+        self.assertEqual("\\\\", escape_js_string("\\"))
 
     def test_escape_js_string_ampersand(self):
-        self.assertEqual('&', escape_js_string('&'))
+        self.assertEqual("&", escape_js_string("&"))
 
 
 load_tests = load_tests_apply_scenarios
diff --git a/lib/lp/translations/browser/tests/test_translationlinksaggregator.py b/lib/lp/translations/browser/tests/test_translationlinksaggregator.py
index 1106ff1..4558b37 100644
--- a/lib/lp/translations/browser/tests/test_translationlinksaggregator.py
+++ b/lib/lp/translations/browser/tests/test_translationlinksaggregator.py
@@ -9,7 +9,7 @@ from lp.testing import TestCaseWithFactory
 from lp.testing.layers import LaunchpadZopelessLayer
 from lp.translations.browser.translationlinksaggregator import (
     TranslationLinksAggregator,
-    )
+)
 from lp.translations.model.productserieslanguage import ProductSeriesLanguage
 
 
@@ -54,7 +54,7 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
     def test_circumscribe_single_pofile(self):
         # If passed a single POFile, _circumscribe returns a list of
         # just that POFile.
-        pofile = self.factory.makePOFile(language_code='lua')
+        pofile = self.factory.makePOFile(language_code="lua")
 
         links = self.aggregator._circumscribe([pofile])
 
@@ -63,12 +63,13 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
     def test_circumscribe_product_wild_mix(self):
         # A combination of wildly different POFiles in the same product
         # yields links to the individual POFiles.
-        pofile1 = self.factory.makePOFile(language_code='sux')
+        pofile1 = self.factory.makePOFile(language_code="sux")
         product = pofile1.potemplate.productseries.product
         series2 = self.factory.makeProductSeries(product)
         template2 = self.factory.makePOTemplate(productseries=series2)
         pofile2 = self.factory.makePOFile(
-            potemplate=template2, language_code='la')
+            potemplate=template2, language_code="la"
+        )
 
         links = self.aggregator._circumscribe([pofile1, pofile2])
 
@@ -80,11 +81,12 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
         # A combination of POFiles in the same language but different
         # templates of the same productseries is represented as a link
         # to the ProductSeriesLanguage.
-        pofile1 = self.factory.makePOFile(language_code='nl')
+        pofile1 = self.factory.makePOFile(language_code="nl")
         series = pofile1.potemplate.productseries
         template2 = self.factory.makePOTemplate(productseries=series)
         pofile2 = self.factory.makePOFile(
-            potemplate=template2, language_code='nl')
+            potemplate=template2, language_code="nl"
+        )
 
         links = self.aggregator._circumscribe([pofile1, pofile2])
 
@@ -94,10 +96,11 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
     def test_circumscribe_different_languages(self):
         # If the POFiles differ only in language, we get a link to the
         # overview for the template.
-        pofile1 = self.factory.makePOFile(language_code='nl')
+        pofile1 = self.factory.makePOFile(language_code="nl")
         template = pofile1.potemplate
         pofile2 = self.factory.makePOFile(
-            potemplate=template, language_code='lo')
+            potemplate=template, language_code="lo"
+        )
 
         pofiles = [pofile1, pofile2]
         links = self.aggregator._circumscribe(pofiles)
@@ -108,14 +111,16 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
         # In a Product, two POFiles may share their translations.  For
         # now, we link to each individually.  We may want to make this
         # more clever in the future.
-        pofile1 = self.factory.makePOFile(language_code='nl')
+        pofile1 = self.factory.makePOFile(language_code="nl")
         template1 = pofile1.potemplate
         series1 = template1.productseries
         series2 = self.factory.makeProductSeries(product=series1.product)
         template2 = self.factory.makePOTemplate(
-            productseries=series2, name=template1.name,
-            translation_domain=template1.translation_domain)
-        pofile2 = template2.getPOFileByLang('nl')
+            productseries=series2,
+            name=template1.name,
+            translation_domain=template1.translation_domain,
+        )
+        pofile2 = template2.getPOFileByLang("nl")
 
         pofiles = [pofile1, pofile2]
         links = self.aggregator._circumscribe(pofiles)
@@ -129,14 +134,18 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
         # languages, we link to the template.
         package = self.factory.makeSourcePackage()
         package.distroseries.distribution.translations_usage = (
-            ServiceUsage.LAUNCHPAD)
+            ServiceUsage.LAUNCHPAD
+        )
         template = self.factory.makePOTemplate(
             distroseries=package.distroseries,
-            sourcepackagename=package.sourcepackagename)
+            sourcepackagename=package.sourcepackagename,
+        )
         pofile1 = self.factory.makePOFile(
-            potemplate=template, language_code='nl')
+            potemplate=template, language_code="nl"
+        )
         pofile2 = self.factory.makePOFile(
-            potemplate=template, language_code='ka')
+            potemplate=template, language_code="ka"
+        )
 
         pofiles = [pofile1, pofile2]
         links = self.aggregator._circumscribe(pofiles)
@@ -148,17 +157,22 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
         # language" page.
         package = self.factory.makeSourcePackage()
         package.distroseries.distribution.translations_usage = (
-            ServiceUsage.LAUNCHPAD)
+            ServiceUsage.LAUNCHPAD
+        )
         template1 = self.factory.makePOTemplate(
             distroseries=package.distroseries,
-            sourcepackagename=package.sourcepackagename)
+            sourcepackagename=package.sourcepackagename,
+        )
         template2 = self.factory.makePOTemplate(
             distroseries=package.distroseries,
-            sourcepackagename=package.sourcepackagename)
+            sourcepackagename=package.sourcepackagename,
+        )
         pofile1 = self.factory.makePOFile(
-            potemplate=template1, language_code='nl')
+            potemplate=template1, language_code="nl"
+        )
         pofile2 = self.factory.makePOFile(
-            potemplate=template2, language_code='nl')
+            potemplate=template2, language_code="nl"
+        )
 
         pofiles = [pofile1, pofile2]
         links = self.aggregator._circumscribe(pofiles)
@@ -168,7 +182,7 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
     def test_circumscribe_pofile_plus_template(self):
         # A template circumscribes both itself and any of its
         # translations.
-        pofile = self.factory.makePOFile(language_code='uga')
+        pofile = self.factory.makePOFile(language_code="uga")
         template = pofile.potemplate
 
         sheets = [pofile, template]
@@ -184,7 +198,7 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
         self.assertEqual([], self.aggregator.aggregate([]))
 
         # Basic case: one POFile yields its product or package.
-        pofile = self.factory.makePOFile(language_code='ca')
+        pofile = self.factory.makePOFile(language_code="ca")
         product = pofile.potemplate.productseries.product
 
         descriptions = self.aggregator.aggregate([pofile])
@@ -204,61 +218,72 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
 
     def test_aggregate_product_and_package(self):
         # The aggregator keeps a product and a package separate.
-        product_pofile = self.factory.makePOFile(language_code='th')
+        product_pofile = self.factory.makePOFile(language_code="th")
         product = product_pofile.potemplate.productseries.product
         removeSecurityProxy(product_pofile).unreviewed_count = 1
 
         package = self.factory.makeSourcePackage()
         package.distroseries.distribution.translations_usage = (
-            ServiceUsage.LAUNCHPAD)
+            ServiceUsage.LAUNCHPAD
+        )
         package_template = self.factory.makePOTemplate(
             distroseries=package.distroseries,
-            sourcepackagename=package.sourcepackagename)
+            sourcepackagename=package.sourcepackagename,
+        )
         package_pofile = self.factory.makePOFile(
-            potemplate=package_template, language_code='th')
+            potemplate=package_template, language_code="th"
+        )
         removeSecurityProxy(package_pofile).unreviewed_count = 2
 
         descriptions = self.aggregator.aggregate(
-            [product_pofile, package_pofile])
+            [product_pofile, package_pofile]
+        )
 
         expected = [
             (product, canonical_url(product_pofile), [product_pofile]),
             (package, canonical_url(package_pofile), [package_pofile]),
-            ]
+        ]
         self.assertContentEqual(expected, descriptions)
 
     def test_aggregate_bundles_productseries(self):
         # _aggregateTranslationTargets describes POFiles for the same
         # ProductSeries together.
-        pofile1 = self.factory.makePOFile(language_code='es')
+        pofile1 = self.factory.makePOFile(language_code="es")
         series = pofile1.potemplate.productseries
         template2 = self.factory.makePOTemplate(productseries=series)
         pofile2 = self.factory.makePOFile(
-            language_code='br', potemplate=template2)
+            language_code="br", potemplate=template2
+        )
 
         pofiles = [pofile1, pofile2]
         descriptions = self.aggregator.aggregate(pofiles)
 
         self.assertEqual(1, len(descriptions))
         self.assertEqual(
-            [(series.product, canonical_url(series), pofiles)], descriptions)
+            [(series.product, canonical_url(series), pofiles)], descriptions
+        )
 
     def test_aggregate_bundles_package(self):
         # _aggregateTranslationTargets describes POFiles for the same
         # ProductSeries together.
         package = self.factory.makeSourcePackage()
         package.distroseries.distribution.translations_usage = (
-            ServiceUsage.LAUNCHPAD)
+            ServiceUsage.LAUNCHPAD
+        )
         template1 = self.factory.makePOTemplate(
             distroseries=package.distroseries,
-            sourcepackagename=package.sourcepackagename)
+            sourcepackagename=package.sourcepackagename,
+        )
         pofile1 = self.factory.makePOFile(
-            language_code='es', potemplate=template1)
+            language_code="es", potemplate=template1
+        )
         template2 = self.factory.makePOTemplate(
             distroseries=package.distroseries,
-            sourcepackagename=package.sourcepackagename)
+            sourcepackagename=package.sourcepackagename,
+        )
         pofile2 = self.factory.makePOFile(
-            language_code='br', potemplate=template2)
+            language_code="br", potemplate=template2
+        )
 
         pofiles = [pofile1, pofile2]
         descriptions = self.aggregator.aggregate(pofiles)
diff --git a/lib/lp/translations/browser/tests/test_translationmessage_view.py b/lib/lp/translations/browser/tests/test_translationmessage_view.py
index 0c84403..eff116c 100644
--- a/lib/lp/translations/browser/tests/test_translationmessage_view.py
+++ b/lib/lp/translations/browser/tests/test_translationmessage_view.py
@@ -1,10 +1,7 @@
 # Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from datetime import (
-    datetime,
-    timedelta,
-    )
+from datetime import datetime, timedelta
 from functools import partial
 
 import pytz
@@ -15,22 +12,19 @@ from lp.app.errors import UnexpectedFormData
 from lp.services.webapp.publisher import canonical_url
 from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.testing import (
+    TestCaseWithFactory,
     anonymous_logged_in,
     person_logged_in,
-    TestCaseWithFactory,
-    )
-from lp.testing.layers import (
-    DatabaseFunctionalLayer,
-    ZopelessDatabaseLayer,
-    )
+)
+from lp.testing.layers import DatabaseFunctionalLayer, ZopelessDatabaseLayer
 from lp.testing.views import create_view
 from lp.translations.browser.translationmessage import (
-    contains_translations,
-    convert_translationmessage_to_submission,
     CurrentTranslationMessagePageView,
     CurrentTranslationMessageView,
+    contains_translations,
+    convert_translationmessage_to_submission,
     revert_unselected_translations,
-    )
+)
 from lp.translations.enums import TranslationPermission
 from lp.translations.interfaces.side import ITranslationSideTraitsSet
 from lp.translations.interfaces.translations import TranslationConstants
@@ -59,13 +53,23 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
 
     def _createView(self, message):
         self.view = CurrentTranslationMessageView(
-            message, LaunchpadTestRequest(),
-            {}, dict(enumerate(message.translations)),
-            False, False, None, None, True, pofile=self.pofile, can_edit=True)
+            message,
+            LaunchpadTestRequest(),
+            {},
+            dict(enumerate(message.translations)),
+            False,
+            False,
+            None,
+            None,
+            True,
+            pofile=self.pofile,
+            can_edit=True,
+        )
         self.view.initialize()
 
-    def _makeTranslation(self, translation=None,
-                         suggestion=False, is_other=False):
+    def _makeTranslation(
+        self, translation=None, suggestion=False, is_other=False
+    ):
         if translation is None:
             translations = None
         elif isinstance(translation, list):
@@ -76,33 +80,40 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
         date_reviewed = date_created
         if suggestion or is_other:
             message = self.factory.makeSuggestion(
-                self.pofile, self.potmsgset,
+                self.pofile,
+                self.potmsgset,
                 translations=translations,
                 translator=self.owner,
-                date_created=date_created)
+                date_created=date_created,
+            )
             if is_other:
                 # Activate and review on the other side.
                 side_traits = getUtility(
-                    ITranslationSideTraitsSet).getForTemplate(
-                        self.pofile.potemplate)
+                    ITranslationSideTraitsSet
+                ).getForTemplate(self.pofile.potemplate)
                 side_traits.other_side_traits.setFlag(message, True)
-                message.markReviewed(
-                    self.factory.makePerson(), date_reviewed)
+                message.markReviewed(self.factory.makePerson(), date_reviewed)
         else:
             message = self.factory.makeCurrentTranslationMessage(
-                self.pofile, self.potmsgset, translator=self.owner,
+                self.pofile,
+                self.potmsgset,
+                translator=self.owner,
                 translations=translations,
-                date_created=date_created, date_reviewed=date_reviewed)
+                date_created=date_created,
+                date_reviewed=date_reviewed,
+            )
 
         message.browser_pofile = self.pofile
         return message
 
-    def _assertConfirmEmptyPluralOther(self,
-                                          can_confirm_and_dismiss,
-                                          can_dismiss_on_empty,
-                                          can_dismiss_on_plural,
-                                          can_dismiss_other):
-        """ Test the state of all four flags.
+    def _assertConfirmEmptyPluralOther(
+        self,
+        can_confirm_and_dismiss,
+        can_dismiss_on_empty,
+        can_dismiss_on_plural,
+        can_dismiss_other,
+    ):
+        """Test the state of all four flags.
 
         In the view and the template the flags are used to determine if and
         where the "dismiss suggestion" checkbox is displayed. There are
@@ -120,14 +131,19 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
         """
         assert self.view is not None
         self.assertEqual(
-            [can_confirm_and_dismiss,
-               can_dismiss_on_empty,
-               can_dismiss_on_plural,
-               can_dismiss_other],
-            [self.view.can_confirm_and_dismiss,
-               self.view.can_dismiss_on_empty,
-               self.view.can_dismiss_on_plural,
-               self.view.can_dismiss_other])
+            [
+                can_confirm_and_dismiss,
+                can_dismiss_on_empty,
+                can_dismiss_on_plural,
+                can_dismiss_other,
+            ],
+            [
+                self.view.can_confirm_and_dismiss,
+                self.view.can_dismiss_on_empty,
+                self.view.can_dismiss_on_plural,
+                self.view.can_dismiss_other,
+            ],
+        )
 
     def test_no_suggestion(self):
         # If there is no suggestion, nothing can be dismissed.
@@ -154,11 +170,12 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
         # If there is a suggestion on a plural message, it is dismissed
         # in yet a different place.
         self.potmsgset = self.factory.makePOTMsgSet(
-            self.potemplate,
-            singular="msgid_singular", plural="msgid_plural")
+            self.potemplate, singular="msgid_singular", plural="msgid_plural"
+        )
         message = self._makeTranslation(["singular_trans", "plural_trans"])
         self._makeTranslation(
-            ["singular_sugg", "plural_sugg"], suggestion=True)
+            ["singular_sugg", "plural_sugg"], suggestion=True
+        )
         self._createView(message)
         self._assertConfirmEmptyPluralOther(False, False, True, False)
 
@@ -181,8 +198,8 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
         # If there is a suggestion on a plural message, it is dismissed
         # in yet a different place.
         self.potmsgset = self.factory.makePOTMsgSet(
-            self.potemplate,
-            singular="msgid_singular", plural="msgid_plural")
+            self.potemplate, singular="msgid_singular", plural="msgid_plural"
+        )
         message = self._makeTranslation(["singular_trans", "plural_trans"])
         self._makeTranslation(["singular_new", "plural_new"], is_other=True)
         self._createView(message)
@@ -215,6 +232,7 @@ class TestResetTranslations(TestCaseWithFactory):
     :ivar current_translation: A current `TranslationMessage` in `POFile`,
         submitted and reviewed sometime in the past.
     """
+
     layer = DatabaseFunctionalLayer
 
     def setUp(self):
@@ -222,10 +240,12 @@ class TestResetTranslations(TestCaseWithFactory):
         package = self.factory.makeSourcePackage()
         template = self.factory.makePOTemplate(
             distroseries=package.distroseries,
-            sourcepackagename=package.sourcepackagename)
+            sourcepackagename=package.sourcepackagename,
+        )
         self.pofile = self.factory.makePOFile(potemplate=template)
         self.current_translation = self.factory.makeCurrentTranslationMessage(
-            pofile=self.pofile)
+            pofile=self.pofile
+        )
         self.current_translation.setPOFile(self.pofile)
 
         naked_tm = removeSecurityProxy(self.current_translation)
@@ -235,37 +255,41 @@ class TestResetTranslations(TestCaseWithFactory):
     def closeTranslations(self):
         """Disallow editing of `self.pofile` translations by regular users."""
         policy = removeSecurityProxy(
-            self.pofile.potemplate.getTranslationPolicy())
+            self.pofile.potemplate.getTranslationPolicy()
+        )
         policy.translationpermission = TranslationPermission.CLOSED
 
     def getLocalSuggestions(self):
         """Get local suggestions for `self.current_translation`."""
         return list(
             self.current_translation.potmsgset.getLocalTranslationMessages(
-                self.pofile.potemplate, self.pofile.language))
+                self.pofile.potemplate, self.pofile.language
+            )
+        )
 
     def submitForcedEmptySuggestion(self):
         """Submit an empty suggestion for `self.current_translation`."""
-        empty_translation = ''
+        empty_translation = ""
 
-        msgset_id = 'msgset_' + str(self.current_translation.potmsgset.id)
-        msgset_id_lang = msgset_id + '_' + self.pofile.language.code
-        widget_id_base = msgset_id_lang + '_translation_0_'
+        msgset_id = "msgset_" + str(self.current_translation.potmsgset.id)
+        msgset_id_lang = msgset_id + "_" + self.pofile.language.code
+        widget_id_base = msgset_id_lang + "_translation_0_"
 
         form = {
-            'lock_timestamp': datetime.now(pytz.utc).isoformat(),
-            'alt': None,
+            "lock_timestamp": datetime.now(pytz.utc).isoformat(),
+            "alt": None,
             msgset_id: None,
-            widget_id_base + 'radiobutton': widget_id_base + 'new',
-            widget_id_base + 'new': empty_translation,
-            'submit_translations': 'Save &amp; Continue',
-            msgset_id_lang + '_needsreview': 'force_suggestion',
+            widget_id_base + "radiobutton": widget_id_base + "new",
+            widget_id_base + "new": empty_translation,
+            "submit_translations": "Save &amp; Continue",
+            msgset_id_lang + "_needsreview": "force_suggestion",
         }
 
-        url = canonical_url(self.current_translation) + '/+translate'
+        url = canonical_url(self.current_translation) + "/+translate"
         view = create_view(
-            self.current_translation, '+translate', form=form, server_url=url)
-        view.request.method = 'POST'
+            self.current_translation, "+translate", form=form, server_url=url
+        )
+        view.request.method = "POST"
         view.initialize()
 
     def test_disables_current_translation(self):
@@ -282,7 +306,8 @@ class TestResetTranslations(TestCaseWithFactory):
         with person_logged_in(self.factory.makePerson()):
             self.submitForcedEmptySuggestion()
         self.assertEqual(
-            [self.current_translation], self.getLocalSuggestions())
+            [self.current_translation], self.getLocalSuggestions()
+        )
 
     def test_unprivileged_user_cannot_reset(self):
         # When a user without editing privileges on the translation
@@ -305,20 +330,26 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
         pofile = self.factory.makePOFile(potemplate=potemplate)
         potmsgset = self.factory.makePOTMsgSet(potemplate)
         message = self.factory.makeCurrentTranslationMessage(
-            pofile=pofile, potmsgset=potmsgset)
+            pofile=pofile, potmsgset=potmsgset
+        )
         message.browser_pofile = pofile
         form = {}
         if with_form:
-            msgset_id_field = 'msgset_%d' % potmsgset.id
-            form[msgset_id_field] = 'poit'
-            base_field_name = 'msgset_%d_%s_translation_' % (
-                message.potmsgset.id, pofile.language.code)
+            msgset_id_field = "msgset_%d" % potmsgset.id
+            form[msgset_id_field] = "poit"
+            base_field_name = "msgset_%d_%s_translation_" % (
+                message.potmsgset.id,
+                pofile.language.code,
+            )
             # Add the expected plural forms fields.
             for plural_form in range(TranslationConstants.MAX_PLURAL_FORMS):
-                field_name = '%s%d_new' % (base_field_name, plural_form)
-                form[field_name] = 'snarf'
-        url = '/%s/%s/%s/+translate' % (
-            canonical_url(potemplate), pofile.language.code, 1)
+                field_name = "%s%d_new" % (base_field_name, plural_form)
+                form[field_name] = "snarf"
+        url = "/%s/%s/%s/+translate" % (
+            canonical_url(potemplate),
+            pofile.language.code,
+            1,
+        )
         request = LaunchpadTestRequest(SERVER_URL=url, form=form)
         view = CurrentTranslationMessagePageView(message, request)
         view.lock_timestamp = datetime.now(pytz.utc)
@@ -326,10 +357,10 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
 
     def test_extractLockTimestamp(self):
         view = self._makeView()
-        view.request.form['lock_timestamp'] = '2010-01-01 00:00:00 UTC'
+        view.request.form["lock_timestamp"] = "2010-01-01 00:00:00 UTC"
         self.assertEqual(
-            datetime(2010, 1, 1, tzinfo=pytz.utc),
-            view._extractLockTimestamp())
+            datetime(2010, 1, 1, tzinfo=pytz.utc), view._extractLockTimestamp()
+        )
 
     def test_extractLockTimestamp_returns_None_by_default(self):
         view = self._makeView()
@@ -337,7 +368,7 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
 
     def test_extractLockTimestamp_returns_None_for_bogus_timestamp(self):
         view = self._makeView()
-        view.request.form['lock_timestamp'] = 'Hi mom!'
+        view.request.form["lock_timestamp"] = "Hi mom!"
         self.assertIs(None, view._extractLockTimestamp())
 
     def test_checkSubmitConditions_passes(self):
@@ -360,8 +391,9 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
         # Users who have declined the relicensing agreement can't post
         # translations.
         decliner = self.factory.makePerson()
-        ITranslationsPerson(decliner).translations_relicensing_agreement = (
-            False)
+        ITranslationsPerson(
+            decliner
+        ).translations_relicensing_agreement = False
         with person_logged_in(decliner):
             view = self._makeView()
             self.assertRaises(UnexpectedFormData, view._checkSubmitConditions)
@@ -372,7 +404,8 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
         view = self._makeView(with_form=True)
         view.initialize()
         self.assertEqual(
-            None, view._extractFormPostedTranslations(view.context.potmsgset))
+            None, view._extractFormPostedTranslations(view.context.potmsgset)
+        )
 
     def test_max_plural_forms_fields_greater_error(self):
         # An AssertionError is raised if the number of plural forms
@@ -380,12 +413,17 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
         view = self._makeView(with_form=True)
         view.initialize()
         # Add a field that is greater than the expected MAX_PLURAL_FORMS.
-        field_name = 'msgset_%d_%s_translation_%d_new' % (
-            view.context.potmsgset.id, view.pofile.language.code,
-            TranslationConstants.MAX_PLURAL_FORMS)
-        view.request.form[field_name] = 'snarf'
-        self.assertRaises(AssertionError,
-            view._extractFormPostedTranslations, view.context.potmsgset)
+        field_name = "msgset_%d_%s_translation_%d_new" % (
+            view.context.potmsgset.id,
+            view.pofile.language.code,
+            TranslationConstants.MAX_PLURAL_FORMS,
+        )
+        view.request.form[field_name] = "snarf"
+        self.assertRaises(
+            AssertionError,
+            view._extractFormPostedTranslations,
+            view.context.potmsgset,
+        )
 
 
 class TestHelpers(TestCaseWithFactory):
@@ -398,10 +436,11 @@ class TestHelpers(TestCaseWithFactory):
     def test_contains_translations_finds_any_translations(self):
         for plural_form in range(TranslationConstants.MAX_PLURAL_FORMS):
             self.assertTrue(
-                contains_translations({plural_form: self.getUniqueString()}))
+                contains_translations({plural_form: self.getUniqueString()})
+            )
 
     def test_contains_translations_ignores_empty_strings(self):
-        self.assertFalse(contains_translations({0: ''}))
+        self.assertFalse(contains_translations({0: ""}))
 
     def test_contains_translations_ignores_nones(self):
         self.assertFalse(contains_translations({0: None}))
@@ -412,17 +451,21 @@ class TestHelpers(TestCaseWithFactory):
         translations = {0: self.getUniqueString()}
         self.assertEqual(
             translations,
-            revert_unselected_translations(translations, None, [0]))
+            revert_unselected_translations(translations, None, [0]),
+        )
 
     def test_revert_unselected_translations_handles_plurals(self):
         translated_forms = list(range(3))
         translations = {
-            form: self.getUniqueString() for form in translated_forms}
+            form: self.getUniqueString() for form in translated_forms
+        }
 
         self.assertEqual(
             translations,
             revert_unselected_translations(
-                translations, None, translated_forms))
+                translations, None, translated_forms
+            ),
+        )
 
     def test_revert_unselected_translations_selects_forms_separately(self):
         # If some of the translated forms are accepted and some aren't,
@@ -433,15 +476,17 @@ class TestHelpers(TestCaseWithFactory):
             1: self.getUniqueString(),
         }
         resulting_translations = revert_unselected_translations(
-            translations, None, [0])
+            translations, None, [0]
+        )
         self.assertEqual(translations[0], resulting_translations[0])
         self.assertNotEqual(translations[1], resulting_translations[1])
-        self.assertEqual('', resulting_translations[1])
+        self.assertEqual("", resulting_translations[1])
 
     def test_revert_unselected_translations_ignores_untranslated_form(self):
         translations = {0: self.getUniqueString()}
         self.assertNotIn(
-            1, revert_unselected_translations(translations, None, [1]))
+            1, revert_unselected_translations(translations, None, [1])
+        )
 
     def test_revert_unselected_translations_reverts_to_existing(self):
         # Translations for plural forms not in plural_indices_to_store
@@ -450,18 +495,22 @@ class TestHelpers(TestCaseWithFactory):
         new_translations = {0: self.getUniqueString()}
         original_translations = {0: self.getUniqueString()}
         current_message = self.factory.makeCurrentTranslationMessage(
-            translations=original_translations)
+            translations=original_translations
+        )
         self.assertEqual(
             original_translations,
             revert_unselected_translations(
-                new_translations, current_message, []))
+                new_translations, current_message, []
+            ),
+        )
 
     def test_revert_unselected_translations_reverts_to_empty_string(self):
         # If there is no current message, any translation not in
         # plural_indices_to_store is set to the empty string.
         translations = {0: self.getUniqueString()}
         self.assertEqual(
-            {0: ''}, revert_unselected_translations(translations, None, []))
+            {0: ""}, revert_unselected_translations(translations, None, [])
+        )
 
     def test_revert_unselected_translations_handles_missing_plurals(self):
         # When reverting based on a current message that does not
@@ -470,11 +519,14 @@ class TestHelpers(TestCaseWithFactory):
         new_translations = {1: self.getUniqueString()}
         original_translations = {0: self.getUniqueString()}
         current_message = self.factory.makeCurrentTranslationMessage(
-            translations=original_translations)
+            translations=original_translations
+        )
         self.assertEqual(
-            {1: ''},
+            {1: ""},
             revert_unselected_translations(
-                new_translations, current_message, []))
+                new_translations, current_message, []
+            ),
+