launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #28876
[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(' ', ' ')
+ return self.context.title.replace(" ", " ")
@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(
- "<blink>X</blink>", view.documentation_link_bubble)
+ "<blink>X</blink>", 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(
- "<blink>Y</blink>", view.documentation_link_bubble)
+ "<blink>Y</blink>", 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(
- "<blink>Z</blink>", view.documentation_link_bubble)
+ "<blink>Z</blink>", 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 & Continue',
- msgset_id_lang + '_needsreview': 'force_suggestion',
+ widget_id_base + "radiobutton": widget_id_base + "new",
+ widget_id_base + "new": empty_translation,
+ "submit_translations": "Save & 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, []
+ ),
+