launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #27950
[Merge] ~cjwatson/launchpad:pyupgrade-py3-translations-1 into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:pyupgrade-py3-translations-1 into launchpad:master.
Commit message:
lp.translations.browser: Apply "pyupgrade --py3-plus"
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/414052
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:pyupgrade-py3-translations-1 into launchpad:master.
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 83958cd..e01ae37 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -46,3 +46,5 @@ f3f15787ebabe305fbf3e3ae6c0fd8ca7dfb4465
21fb5364d9371c0ad2edf41fa6920c4e16ead2b0
# apply pyupgrade --py3-plus to lp.{testing,testopenid,tests}
9621eff0fd58287b254fb228c11948fca85d547c
+# apply pyupgrade --py3-plus to lp.translations
+d61c2ad002c2997a132a1580ce6ee82bb03de11d
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index cc22ee7..ba49e44 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -60,6 +60,7 @@ repos:
|testing
|testopenid
|tests
+ |translations/browser
)/
- repo: https://github.com/PyCQA/isort
rev: 5.9.2
diff --git a/lib/lp/translations/browser/browser_helpers.py b/lib/lp/translations/browser/browser_helpers.py
index 48a57b1..a4894a6 100644
--- a/lib/lp/translations/browser/browser_helpers.py
+++ b/lib/lp/translations/browser/browser_helpers.py
@@ -15,8 +15,6 @@ __all__ = [
from math import ceil
import re
-import six
-
from lp.services import helpers
from lp.services.webapp.escaping import html_escape
from lp.translations.interfaces.translations import TranslationConstants
@@ -30,20 +28,20 @@ def contract_rosetta_escapes(text):
"""Replace Rosetta escape sequences with the real characters."""
return helpers.text_replaced(text, {'[tab]': '\t',
r'\[tab]': '[tab]',
- '[nbsp]': u'\u00a0',
+ '[nbsp]': '\u00a0',
r'\[nbsp]': '[nbsp]',
- '[nnbsp]': u'\u202f',
+ '[nnbsp]': '\u202f',
r'\[nnbsp]': '[nnbsp]'})
def expand_rosetta_escapes(unicode_text):
"""Replace characters needing a Rosetta escape sequences."""
- escapes = {u'\t': TranslationConstants.TAB_CHAR,
- u'[tab]': TranslationConstants.TAB_CHAR_ESCAPED,
- u'\u00a0': TranslationConstants.NO_BREAK_SPACE_CHAR,
- u'[nbsp]': TranslationConstants.NO_BREAK_SPACE_CHAR_ESCAPED,
- u'\u202f': TranslationConstants.NARROW_NO_BREAK_SPACE_CHAR,
- u'[nnbsp]':
+ 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)
@@ -56,12 +54,12 @@ def text_to_html(text, flags, space=TranslationConstants.SPACE_CHAR,
markup_lines = []
# Replace leading and trailing spaces on each line with special markup.
- if u'\r\n' in text:
- newline_chars = u'\r\n'
- elif u'\r' in text:
- newline_chars = u'\r'
+ if '\r\n' in text:
+ newline_chars = '\r\n'
+ elif '\r' in text:
+ newline_chars = '\r'
else:
- newline_chars = u'\n'
+ newline_chars = '\n'
for line in text.split(newline_chars):
# Pattern:
# - group 1: zero or more spaces: leading whitespace
@@ -69,7 +67,7 @@ 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(u'^( *)((?: *[^ ]+)*)( *)$', line)
+ match = re.match('^( *)((?: *[^ ]+)*)( *)$', line)
if match:
format_segments = None
@@ -84,7 +82,7 @@ def text_to_html(text, flags, space=TranslationConstants.SPACE_CHAR,
type, content = segment
if type == 'interpolation':
- markup += (u'<code>%s</code>' % html_escape(content))
+ markup += ('<code>%s</code>' % html_escape(content))
elif type == 'string':
markup += html_escape(content)
else:
@@ -109,18 +107,18 @@ def convert_newlines_to_web_form(unicode_text):
if unicode_text is None:
return None
- assert isinstance(unicode_text, six.text_type), (
+ 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 u'\r\n' in unicode_text:
+ elif '\r\n' in unicode_text:
# The text is already using the windows newline chars
return unicode_text
- elif u'\n' in unicode_text:
- return helpers.text_replaced(unicode_text, {u'\n': u'\r\n'})
+ elif '\n' in unicode_text:
+ return helpers.text_replaced(unicode_text, {'\n': '\r\n'})
else:
- return helpers.text_replaced(unicode_text, {u'\r': u'\r\n'})
+ return helpers.text_replaced(unicode_text, {'\r': '\r\n'})
def count_lines(text):
@@ -135,7 +133,7 @@ def count_lines(text):
CHARACTERS_PER_LINE = 60
count = 0
- for line in text.split(u'\n'):
+ for line in text.split('\n'):
if len(line) == 0:
count += 1
else:
diff --git a/lib/lp/translations/browser/distroseries.py b/lib/lp/translations/browser/distroseries.py
index 02a4292..8191792 100644
--- a/lib/lp/translations/browser/distroseries.py
+++ b/lib/lp/translations/browser/distroseries.py
@@ -102,7 +102,7 @@ class DistroSeriesLanguagePackView(LaunchpadEditFormView):
self.field_names = ['language_pack_full_export_requested']
else:
self.field_names = []
- super(DistroSeriesLanguagePackView, self).initialize()
+ super().initialize()
self.displayname = '%s %s' % (
self.context.distribution.displayname,
self.context.version)
@@ -194,8 +194,7 @@ class DistroSeriesTemplatesView(BaseSeriesTemplatesView):
"""Show a list of all templates for the DistroSeries."""
def initialize(self):
- super(DistroSeriesTemplatesView, self).initialize(
- series=self.context, is_distroseries=True)
+ super().initialize(series=self.context, is_distroseries=True)
def constructTemplateURL(self, template):
"""See `BaseSeriesTemplatesView`."""
diff --git a/lib/lp/translations/browser/language.py b/lib/lp/translations/browser/language.py
index adc5612..918b7ed 100644
--- a/lib/lp/translations/browser/language.py
+++ b/lib/lp/translations/browser/language.py
@@ -75,7 +75,7 @@ class LanguageSetNavigation(GetitemNavigation):
class LanguageSetBreadcrumb(Breadcrumb):
"""`Breadcrumb` for `ILanguageSet`."""
- text = u"Languages"
+ text = "Languages"
class LanguageSetContextMenu(ContextMenu):
@@ -108,7 +108,7 @@ class ILanguageSetSearch(Interface):
"""The collection of languages."""
search_lang = TextLine(
- title=u'Name of the language to search for.',
+ title='Name of the language to search for.',
required=True)
diff --git a/lib/lp/translations/browser/person.py b/lib/lp/translations/browser/person.py
index 3b416da..2dd8d81 100644
--- a/lib/lp/translations/browser/person.py
+++ b/lib/lp/translations/browser/person.py
@@ -204,7 +204,7 @@ class PersonTranslationView(LaunchpadView):
reviews_to_show = 10
def __init__(self, *args, **kwargs):
- super(PersonTranslationView, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
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).
diff --git a/lib/lp/translations/browser/pofile.py b/lib/lp/translations/browser/pofile.py
index c01f046..1e85b3e 100644
--- a/lib/lp/translations/browser/pofile.py
+++ b/lib/lp/translations/browser/pofile.py
@@ -582,7 +582,7 @@ class POFileTranslateView(BaseTranslationView, POFileMetadataViewMixin):
self.start_offset = 0
self._initializeShowOption()
- super(POFileTranslateView, self).initialize()
+ super().initialize()
#
# BaseTranslationView API
diff --git a/lib/lp/translations/browser/potemplate.py b/lib/lp/translations/browser/potemplate.py
index 12cb580..aa3d5f2 100644
--- a/lib/lp/translations/browser/potemplate.py
+++ b/lib/lp/translations/browser/potemplate.py
@@ -183,8 +183,7 @@ class POTemplateMenu(NavigationMenu):
class POTemplateSubsetView(RedirectionView):
def __init__(self, context, request):
- super(POTemplateSubsetView, self).__init__(
- '../+translations', request)
+ super().__init__('../+translations', request)
class POTemplateView(LaunchpadView,
diff --git a/lib/lp/translations/browser/productseries.py b/lib/lp/translations/browser/productseries.py
index 0b9b00a..e17dafc 100644
--- a/lib/lp/translations/browser/productseries.py
+++ b/lib/lp/translations/browser/productseries.py
@@ -467,7 +467,7 @@ class SettingsRadioWidget(LaunchpadRadioWidgetWithDescription):
"""Remove the confusing hint under the widget."""
def __init__(self, field, vocabulary, request):
- super(SettingsRadioWidget, self).__init__(field, vocabulary, request)
+ super().__init__(field, vocabulary, request)
self.hint = None
@@ -485,7 +485,7 @@ class ProductSeriesTranslationsSettingsView(ReturnToReferrerMixin,
field_names = ['translations_autoimport_mode']
custom_widget_translations_autoimport_mode = SettingsRadioWidget
- @action(u"Save settings", name="save_settings")
+ @action("Save settings", name="save_settings")
def change_settings_action(self, action, data):
"""Change the translation settings."""
if (self.context.translations_autoimport_mode !=
@@ -522,7 +522,7 @@ class ProductSeriesTranslationsBzrImportView(LaunchpadFormView,
self.addError(
"Please set the official Bazaar branch first.")
- @action(u"Request one-time import", name="request_import")
+ @action("Request one-time import", name="request_import")
def request_import_action(self, action, data):
""" Request an upload of translation files. """
job = getUtility(IRosettaUploadJobSource).create(
@@ -539,8 +539,7 @@ class ProductSeriesTemplatesView(BaseSeriesTemplatesView):
"""Show a list of all templates for the ProductSeries."""
def initialize(self):
- super(ProductSeriesTemplatesView, self).initialize(
- series=self.context, is_distroseries=False)
+ super().initialize(series=self.context, is_distroseries=False)
def constructTemplateURL(self, template):
"""See `BaseSeriesTemplatesView`."""
diff --git a/lib/lp/translations/browser/serieslanguage.py b/lib/lp/translations/browser/serieslanguage.py
index d0eeca3..6004a18 100644
--- a/lib/lp/translations/browser/serieslanguage.py
+++ b/lib/lp/translations/browser/serieslanguage.py
@@ -144,7 +144,7 @@ class DistroSeriesLanguageView(BaseSeriesLanguageView):
def initialize(self):
series = self.context.distroseries
- super(DistroSeriesLanguageView, self).initialize(
+ super().initialize(
series=series,
translationgroup=series.distribution.translationgroup)
self.parent = self.series.distribution
@@ -155,7 +155,7 @@ class ProductSeriesLanguageView(BaseSeriesLanguageView):
def initialize(self):
series = self.context.productseries
- super(ProductSeriesLanguageView, self).initialize(
+ super().initialize(
series=series,
translationgroup=series.product.translationgroup)
self.context.recalculateCounts()
diff --git a/lib/lp/translations/browser/sourcepackage.py b/lib/lp/translations/browser/sourcepackage.py
index 37c5c25..1cf947a 100644
--- a/lib/lp/translations/browser/sourcepackage.py
+++ b/lib/lp/translations/browser/sourcepackage.py
@@ -116,7 +116,7 @@ class SourcePackageTranslationSharingDetailsView(LaunchpadView):
return check_permission('launchpad.Edit', self.context.productseries)
def initialize(self):
- super(SourcePackageTranslationSharingDetailsView, self).initialize()
+ super().initialize()
if self.is_configuration_complete and not self.is_sharing():
self.request.response.addInfoNotification(
structured(
diff --git a/lib/lp/translations/browser/tests/test_baseexportview.py b/lib/lp/translations/browser/tests/test_baseexportview.py
index 7e62dd0..d4f3488 100644
--- a/lib/lp/translations/browser/tests/test_baseexportview.py
+++ b/lib/lp/translations/browser/tests/test_baseexportview.py
@@ -35,7 +35,7 @@ class BaseExportViewMixin(TestCaseWithFactory):
def setUp(self):
# Create a product with two series and a shared POTemplate
# in different series ('devel' and 'stable').
- super(BaseExportViewMixin, self).setUp()
+ super().setUp()
def createTranslationTemplate(self, name, priority=0):
"""Attaches a template to appropriate container."""
@@ -142,7 +142,7 @@ class TestProductSeries(BaseExportViewMixin):
return potemplate
def setUp(self):
- super(TestProductSeries, self).setUp()
+ super().setUp()
self.container = self.factory.makeProductSeries()
self.view = ProductSeriesTranslationsExportView(
self.container, LaunchpadTestRequest())
@@ -159,7 +159,7 @@ class TestSourcePackage(BaseExportViewMixin):
return potemplate
def setUp(self):
- super(TestSourcePackage, self).setUp()
+ super().setUp()
self.container = self.factory.makeSourcePackage()
self.view = SourcePackageTranslationsExportView(
self.container, LaunchpadTestRequest())
@@ -170,7 +170,7 @@ class TestPOExportQueueStatusDescriptions(TestCaseWithFactory):
layer = ZopelessDatabaseLayer
def setUp(self):
- super(TestPOExportQueueStatusDescriptions, self).setUp()
+ super().setUp()
self.container = self.factory.makeProductSeries()
self.view = ProductSeriesTranslationsExportView(
self.container, LaunchpadTestRequest())
diff --git a/lib/lp/translations/browser/tests/test_breadcrumbs.py b/lib/lp/translations/browser/tests/test_breadcrumbs.py
index 2033298..75be521 100644
--- a/lib/lp/translations/browser/tests/test_breadcrumbs.py
+++ b/lib/lp/translations/browser/tests/test_breadcrumbs.py
@@ -104,7 +104,7 @@ class TestTranslationGroupsBreadcrumbs(BaseBreadcrumbTestCase):
class TestSeriesLanguageBreadcrumbs(BaseBreadcrumbTestCase):
def setUp(self):
- super(TestSeriesLanguageBreadcrumbs, self).setUp()
+ super().setUp()
self.language = getUtility(ILanguageSet)['sr']
def test_distroserieslanguage(self):
@@ -175,7 +175,7 @@ class TestPOTemplateBreadcrumbs(BaseBreadcrumbTestCase):
class TestPOFileBreadcrumbs(BaseBreadcrumbTestCase):
def setUp(self):
- super(TestPOFileBreadcrumbs, self).setUp()
+ super().setUp()
def test_pofiletranslate(self):
product = self.factory.makeProduct(
diff --git a/lib/lp/translations/browser/tests/test_noindex.py b/lib/lp/translations/browser/tests/test_noindex.py
index a1bc130..5383319 100644
--- a/lib/lp/translations/browser/tests/test_noindex.py
+++ b/lib/lp/translations/browser/tests/test_noindex.py
@@ -86,7 +86,7 @@ class TestRobotsProduct(BrowserTestCase, TestRobotsMixin):
"""Test noindex,nofollow for products."""
def setUp(self):
- super(TestRobotsProduct, self).setUp()
+ super().setUp()
self.target = self.factory.makeProduct()
self.factory.makePOTemplate(
productseries=self.target.development_focus)
@@ -97,7 +97,7 @@ class TestRobotsProjectGroup(BrowserTestCase, TestRobotsMixin):
"""Test noindex,nofollow for project groups."""
def setUp(self):
- super(TestRobotsProjectGroup, self).setUp()
+ super().setUp()
self.target = self.factory.makeProject()
self.product = self.factory.makeProduct()
self.factory.makePOTemplate(
@@ -110,7 +110,7 @@ class TestRobotsProductSeries(BrowserTestCase, TestRobotsMixin):
"""Test noindex,nofollow for product series."""
def setUp(self):
- super(TestRobotsProductSeries, self).setUp()
+ super().setUp()
self.product = self.factory.makeProduct()
self.target = self.product.development_focus
self.factory.makePOTemplate(
@@ -122,7 +122,7 @@ class TestRobotsDistroSeries(BrowserTestCase, TestRobotsMixin):
"""Test noindex,nofollow for distro series."""
def setUp(self):
- super(TestRobotsDistroSeries, self).setUp()
+ super().setUp()
login_person(self.user)
self.distro = self.factory.makeDistribution(
name="whobuntu", owner=self.user)
@@ -140,7 +140,7 @@ class TestRobotsDistro(BrowserTestCase, TestRobotsMixin):
"""Test noindex,nofollow for distro."""
def setUp(self):
- super(TestRobotsDistro, self).setUp()
+ super().setUp()
login_person(self.user)
self.target = self.factory.makeDistribution(
name="whobuntu", owner=self.user)
diff --git a/lib/lp/translations/browser/tests/test_persontranslationview.py b/lib/lp/translations/browser/tests/test_persontranslationview.py
index 98ff0ba..e3c1251 100644
--- a/lib/lp/translations/browser/tests/test_persontranslationview.py
+++ b/lib/lp/translations/browser/tests/test_persontranslationview.py
@@ -26,7 +26,7 @@ class TestPersonTranslationView(TestCaseWithFactory):
layer = LaunchpadZopelessLayer
def setUp(self):
- super(TestPersonTranslationView, self).setUp()
+ super().setUp()
person = removeSecurityProxy(self.factory.makePerson())
self.view = PersonTranslationView(person, LaunchpadTestRequest())
self.translationgroup = None
@@ -388,7 +388,7 @@ class TestPersonTranslationViewPermissions(BrowserTestCase):
layer = DatabaseFunctionalLayer
def setUp(self):
- super(TestPersonTranslationViewPermissions, self).setUp()
+ super().setUp()
self.context = self.factory.makePerson()
self.language = self.factory.makeLanguage()
with person_logged_in(self.context):
diff --git a/lib/lp/translations/browser/tests/test_poexportrequest_views.py b/lib/lp/translations/browser/tests/test_poexportrequest_views.py
index fdcd704..cda3a05 100644
--- a/lib/lp/translations/browser/tests/test_poexportrequest_views.py
+++ b/lib/lp/translations/browser/tests/test_poexportrequest_views.py
@@ -42,7 +42,7 @@ class TestPOTEmplateExportView(TestCaseWithFactory):
layer = DatabaseFunctionalLayer
def setUp(self):
- super(TestPOTEmplateExportView, self).setUp()
+ super().setUp()
self.potemplate = self.factory.makePOTemplate()
# All exports can be requested by an unprivileged user.
self.translator = self.factory.makePerson()
diff --git a/lib/lp/translations/browser/tests/test_pofile_view.py b/lib/lp/translations/browser/tests/test_pofile_view.py
index 2a45878..3c50614 100644
--- a/lib/lp/translations/browser/tests/test_pofile_view.py
+++ b/lib/lp/translations/browser/tests/test_pofile_view.py
@@ -92,7 +92,7 @@ class TestPOFileTranslateViewInvalidFiltering(TestCaseWithFactory):
view_class = POFileTranslateView
def setUp(self):
- super(TestPOFileTranslateViewInvalidFiltering, self).setUp()
+ super().setUp()
self.pofile = self.factory.makePOFile('eo')
def _test_parameter_list(self, parameter_name):
@@ -366,7 +366,7 @@ class TestBrowser(BrowserTestCase):
product.translationpermission = TranslationPermission.CLOSED
# Add credits so that they show in the UI
self.factory.makePOTMsgSet(
- potemplate=pofile.potemplate, singular=u'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)
@@ -376,7 +376,7 @@ class TestBrowser(BrowserTestCase):
pofile = self.factory.makePOFile()
# Add credits so that they show in the UI
self.factory.makePOTMsgSet(
- potemplate=pofile.potemplate, singular=u'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'
diff --git a/lib/lp/translations/browser/tests/test_potemplate_views.py b/lib/lp/translations/browser/tests/test_potemplate_views.py
index 78dc73b..4a85ac4 100644
--- a/lib/lp/translations/browser/tests/test_potemplate_views.py
+++ b/lib/lp/translations/browser/tests/test_potemplate_views.py
@@ -29,13 +29,11 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
scenarios = [
("spn_picker", {"features": {}}),
- ("dsp_picker", {
- "features": {u"disclosure.dsp_picker.enabled": u"on"},
- }),
+ ("dsp_picker", {"features": {"disclosure.dsp_picker.enabled": "on"}}),
]
def setUp(self):
- super(TestPOTemplateEditViewValidation, self).setUp()
+ super().setUp()
if self.features:
self.useFixture(FeatureFixture(self.features))
@@ -84,9 +82,9 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
view.validate(data)
self.assertEqual(
[html_escape(
- u'Template name can only start with lowercase letters a-z '
- u'or digits 0-9, and other than those characters, can only '
- u'contain "-", "+" and "." characters.')],
+ '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):
@@ -99,7 +97,7 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
view = POTemplateEditView(potemplate, LaunchpadTestRequest())
data = self._makeData(potemplate, name=existing_name)
view.validate(data)
- self.assertEqual([u'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.
@@ -112,7 +110,7 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
view = POTemplateEditView(potemplate, LaunchpadTestRequest())
data = self._makeData(potemplate, translation_domain=existing_domain)
view.validate(data)
- self.assertEqual([u'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
@@ -129,7 +127,7 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
potemplate, sourcepackagename=sourcepackage.sourcepackagename)
view.validate(data)
self.assertEqual(
- [u'Source package already has a template with that same name.'],
+ ['Source package already has a template with that same name.'],
view.errors)
def test_detects_domain_clash_on_sourcepackage_change(self):
@@ -147,7 +145,7 @@ class TestPOTemplateEditViewValidation(WithScenarios, TestCaseWithFactory):
potemplate, sourcepackagename=sourcepackage.sourcepackagename)
view.validate(data)
self.assertEqual(
- [u'Source package already has a template with that same domain.'],
+ ['Source package already has a template with that same domain.'],
view.errors)
def test_change_sourcepackage(self):
@@ -182,7 +180,7 @@ class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
data = self._makeData(potemplate, productseries=new_series)
view.validate(data)
self.assertEqual(
- [u'Series already has a template with that same name.'],
+ ['Series already has a template with that same name.'],
view.errors)
def test_detects_domain_clash_on_productseries_change(self):
@@ -199,7 +197,7 @@ class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
data = self._makeData(potemplate, productseries=new_series)
view.validate(data)
self.assertEqual(
- [u'Series already has a template with that same domain.'],
+ ['Series already has a template with that same domain.'],
view.errors)
def test_detects_no_sourcepackage_or_productseries(self):
@@ -212,8 +210,8 @@ class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
distroseries=None, sourcepackagename=None, productseries=None)
view.validate(data)
self.assertEqual(
- [u'Choose either a distribution release series or a project '
- u'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.
@@ -228,8 +226,8 @@ class TestPOTemplateAdminViewValidation(TestPOTemplateEditViewValidation):
productseries=potemplate.productseries)
view.validate(data)
self.assertEqual(
- [u'Choose a distribution release series or a project '
- u'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.
diff --git a/lib/lp/translations/browser/tests/test_product_view.py b/lib/lp/translations/browser/tests/test_product_view.py
index 1b380c5..83b69cc 100644
--- a/lib/lp/translations/browser/tests/test_product_view.py
+++ b/lib/lp/translations/browser/tests/test_product_view.py
@@ -96,13 +96,13 @@ class TestProduct(TestCaseWithFactory):
# include obsolete series.
series_names = [series.name for series in view.untranslatable_series]
self.assertEqual([
- u'evo-current',
- u'evo-development',
- u'evo-experimental',
- u'evo-frozen',
- u'evo-future',
- u'evo-supported',
- u'trunk'], series_names)
+ 'evo-current',
+ 'evo-development',
+ 'evo-experimental',
+ 'evo-frozen',
+ 'evo-future',
+ 'evo-supported',
+ 'trunk'], series_names)
class TestCanConfigureTranslations(TestCaseWithFactory):
diff --git a/lib/lp/translations/browser/tests/test_productserieslanguage_views.py b/lib/lp/translations/browser/tests/test_productserieslanguage_views.py
index d62bfbf..319f05c 100644
--- a/lib/lp/translations/browser/tests/test_productserieslanguage_views.py
+++ b/lib/lp/translations/browser/tests/test_productserieslanguage_views.py
@@ -28,7 +28,7 @@ class TestProductSeriesView(TestCaseWithFactory):
def setUp(self):
# Create a productseries that uses translations.
- super(TestProductSeriesView, self).setUp()
+ super().setUp()
self.productseries = self.factory.makeProductSeries()
self.product = self.productseries.product
@@ -67,7 +67,7 @@ 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=u'http://something')
+ self.productseries.product.owner, url='http://something')
view = self._createView()
self.assertTrue(view.has_translation_documentation)
@@ -162,7 +162,7 @@ class TestProductSeriesViewBzrUsage(TestCaseWithFactory):
def setUp(self):
# Create a productseries that uses translations.
# Strip off the security proxy to allow customization.
- super(TestProductSeriesViewBzrUsage, self).setUp()
+ super().setUp()
self.secured_productseries = self.factory.makeProductSeries()
self.productseries = removeSecurityProxy(self.secured_productseries)
@@ -251,7 +251,7 @@ class TestProductSeriesLanguageView(TestCaseWithFactory):
def setUp(self):
# Create a productseries that uses translations.
- super(TestProductSeriesLanguageView, self).setUp()
+ super().setUp()
self.productseries = self.factory.makeProductSeries()
self.language = self.factory.makeLanguage()
potemplate = self.factory.makePOTemplate(
diff --git a/lib/lp/translations/browser/tests/test_sharing_details.py b/lib/lp/translations/browser/tests/test_sharing_details.py
index ee6f04d..b2c068c 100644
--- a/lib/lp/translations/browser/tests/test_sharing_details.py
+++ b/lib/lp/translations/browser/tests/test_sharing_details.py
@@ -90,7 +90,7 @@ class TestSourcePackageTranslationSharingDetailsView(TestCaseWithFactory,
layer = DatabaseFunctionalLayer
def setUp(self):
- super(TestSourcePackageTranslationSharingDetailsView, self).setUp()
+ super().setUp()
distroseries = self.factory.makeUbuntuDistroSeries()
self.sourcepackage = self.factory.makeSourcePackage(
distroseries=distroseries)
diff --git a/lib/lp/translations/browser/tests/test_translationgroup.py b/lib/lp/translations/browser/tests/test_translationgroup.py
index 0f3fc46..2b642d6 100644
--- a/lib/lp/translations/browser/tests/test_translationgroup.py
+++ b/lib/lp/translations/browser/tests/test_translationgroup.py
@@ -23,7 +23,7 @@ class TestTranslationGroupView(TestCaseWithFactory):
layer = LaunchpadZopelessLayer
def setUp(self):
- super(TestTranslationGroupView, self).setUp()
+ super().setUp()
def _makeView(self, group, name=None):
"""Create a view for self.group."""
diff --git a/lib/lp/translations/browser/tests/test_translationimportqueueentry.py b/lib/lp/translations/browser/tests/test_translationimportqueueentry.py
index 8f5347d..ac7c9ab 100644
--- a/lib/lp/translations/browser/tests/test_translationimportqueueentry.py
+++ b/lib/lp/translations/browser/tests/test_translationimportqueueentry.py
@@ -36,14 +36,11 @@ class TestTranslationImportQueueEntryView(WithScenarios, TestCaseWithFactory):
scenarios = [
("spn_picker", {"features": {}}),
- ("dsp_picker", {
- "features": {u"disclosure.dsp_picker.enabled": u"on"},
- }),
+ ("dsp_picker", {"features": {"disclosure.dsp_picker.enabled": "on"}}),
]
def setUp(self):
- super(TestTranslationImportQueueEntryView, self).setUp(
- 'foo.bar@xxxxxxxxxxxxx')
+ super().setUp('foo.bar@xxxxxxxxxxxxx')
if self.features:
self.useFixture(FeatureFixture(self.features))
self.queue = getUtility(ITranslationImportQueue)
diff --git a/lib/lp/translations/browser/tests/test_translationlinksaggregator.py b/lib/lp/translations/browser/tests/test_translationlinksaggregator.py
index 2bab92a..1106ff1 100644
--- a/lib/lp/translations/browser/tests/test_translationlinksaggregator.py
+++ b/lib/lp/translations/browser/tests/test_translationlinksaggregator.py
@@ -48,7 +48,7 @@ class TestTranslationLinksAggregator(TestCaseWithFactory):
layer = LaunchpadZopelessLayer
def setUp(self):
- super(TestTranslationLinksAggregator, self).setUp()
+ super().setUp()
self.aggregator = DumbAggregator()
def test_circumscribe_single_pofile(self):
diff --git a/lib/lp/translations/browser/tests/test_translationmessage_view.py b/lib/lp/translations/browser/tests/test_translationmessage_view.py
index 3b7ecc0..0c84403 100644
--- a/lib/lp/translations/browser/tests/test_translationmessage_view.py
+++ b/lib/lp/translations/browser/tests/test_translationmessage_view.py
@@ -49,7 +49,7 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
now += timedelta(milliseconds=1)
def setUp(self):
- super(TestCurrentTranslationMessage_can_dismiss, self).setUp()
+ super().setUp()
self.owner = self.factory.makePerson()
self.potemplate = self.factory.makePOTemplate(owner=self.owner)
self.pofile = self.factory.makePOFile(potemplate=self.potemplate)
@@ -155,7 +155,7 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
# in yet a different place.
self.potmsgset = self.factory.makePOTMsgSet(
self.potemplate,
- singular=u"msgid_singular", plural=u"msgid_plural")
+ singular="msgid_singular", plural="msgid_plural")
message = self._makeTranslation(["singular_trans", "plural_trans"])
self._makeTranslation(
["singular_sugg", "plural_sugg"], suggestion=True)
@@ -182,7 +182,7 @@ class TestCurrentTranslationMessage_can_dismiss(TestCaseWithFactory):
# in yet a different place.
self.potmsgset = self.factory.makePOTMsgSet(
self.potemplate,
- singular=u"msgid_singular", plural=u"msgid_plural")
+ 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)
@@ -218,7 +218,7 @@ class TestResetTranslations(TestCaseWithFactory):
layer = DatabaseFunctionalLayer
def setUp(self):
- super(TestResetTranslations, self).setUp()
+ super().setUp()
package = self.factory.makeSourcePackage()
template = self.factory.makePOTemplate(
distroseries=package.distroseries,
@@ -246,7 +246,7 @@ class TestResetTranslations(TestCaseWithFactory):
def submitForcedEmptySuggestion(self):
"""Submit an empty suggestion for `self.current_translation`."""
- empty_translation = u''
+ empty_translation = ''
msgset_id = 'msgset_' + str(self.current_translation.potmsgset.id)
msgset_id_lang = msgset_id + '_' + self.pofile.language.code
@@ -310,13 +310,13 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
form = {}
if with_form:
msgset_id_field = 'msgset_%d' % potmsgset.id
- form[msgset_id_field] = u'poit'
+ 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] = u'snarf'
+ form[field_name] = 'snarf'
url = '/%s/%s/%s/+translate' % (
canonical_url(potemplate), pofile.language.code, 1)
request = LaunchpadTestRequest(SERVER_URL=url, form=form)
@@ -326,7 +326,7 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
def test_extractLockTimestamp(self):
view = self._makeView()
- view.request.form['lock_timestamp'] = u'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())
@@ -337,7 +337,7 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
def test_extractLockTimestamp_returns_None_for_bogus_timestamp(self):
view = self._makeView()
- view.request.form['lock_timestamp'] = u'Hi mom!'
+ view.request.form['lock_timestamp'] = 'Hi mom!'
self.assertIs(None, view._extractLockTimestamp())
def test_checkSubmitConditions_passes(self):
@@ -383,7 +383,7 @@ class TestCurrentTranslationMessagePageView(TestCaseWithFactory):
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] = u'snarf'
+ view.request.form[field_name] = 'snarf'
self.assertRaises(AssertionError,
view._extractFormPostedTranslations, view.context.potmsgset)
@@ -401,7 +401,7 @@ class TestHelpers(TestCaseWithFactory):
contains_translations({plural_form: self.getUniqueString()}))
def test_contains_translations_ignores_empty_strings(self):
- self.assertFalse(contains_translations({0: u''}))
+ self.assertFalse(contains_translations({0: ''}))
def test_contains_translations_ignores_nones(self):
self.assertFalse(contains_translations({0: None}))
@@ -436,7 +436,7 @@ class TestHelpers(TestCaseWithFactory):
translations, None, [0])
self.assertEqual(translations[0], resulting_translations[0])
self.assertNotEqual(translations[1], resulting_translations[1])
- self.assertEqual(u'', resulting_translations[1])
+ self.assertEqual('', resulting_translations[1])
def test_revert_unselected_translations_ignores_untranslated_form(self):
translations = {0: self.getUniqueString()}
@@ -461,7 +461,7 @@ class TestHelpers(TestCaseWithFactory):
# plural_indices_to_store is set to the empty string.
translations = {0: self.getUniqueString()}
self.assertEqual(
- {0: u''}, 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
@@ -472,7 +472,7 @@ class TestHelpers(TestCaseWithFactory):
current_message = self.factory.makeCurrentTranslationMessage(
translations=original_translations)
self.assertEqual(
- {1: u''},
+ {1: ''},
revert_unselected_translations(
new_translations, current_message, []))
diff --git a/lib/lp/translations/browser/translationgroup.py b/lib/lp/translations/browser/translationgroup.py
index c93538c..eb64a92 100644
--- a/lib/lp/translations/browser/translationgroup.py
+++ b/lib/lp/translations/browser/translationgroup.py
@@ -53,7 +53,7 @@ class TranslationGroupSetNavigation(GetitemNavigation):
class TranslationGroupSetBreadcrumb(Breadcrumb):
"""Builds a breadcrumb for an `ITranslationGroupSet`."""
- text = u"Translation groups"
+ text = "Translation groups"
class TranslationGroupSetView(LaunchpadView):
@@ -65,7 +65,7 @@ class TranslationGroupSetView(LaunchpadView):
class TranslationGroupView(LaunchpadView):
def __init__(self, context, request):
- super(TranslationGroupView, self).__init__(context, request)
+ super().__init__(context, request)
self.context = context
self.request = request
self.translation_groups = getUtility(ITranslationGroupSet)
diff --git a/lib/lp/translations/browser/translationimportqueue.py b/lib/lp/translations/browser/translationimportqueue.py
index 556b3a5..a3790c3 100644
--- a/lib/lp/translations/browser/translationimportqueue.py
+++ b/lib/lp/translations/browser/translationimportqueue.py
@@ -167,7 +167,7 @@ class TranslationImportQueueEntryView(LaunchpadFormView):
# as its filename. We try to get it to use as a suggestion.
language_set = getUtility(ILanguageSet)
filename = os.path.basename(self.context.path)
- guessed_language, file_ext = filename.split(u'.', 1)
+ guessed_language, file_ext = filename.split('.', 1)
language = language_set.getLanguageByCode(guessed_language)
if language is not None:
field_values['language'] = language
@@ -596,7 +596,7 @@ class TranslationImportQueueView(HasTranslationImportsView):
def initialize(self):
"""Useful initialization for this view class."""
- super(TranslationImportQueueView, self).initialize()
+ super().initialize()
target_filter = self.widgets['filter_target']
if target_filter.hasInput() and not target_filter.hasValidInput():
raise UnexpectedFormData("Unknown target.")
diff --git a/lib/lp/translations/browser/translationlinksaggregator.py b/lib/lp/translations/browser/translationlinksaggregator.py
index d22ed82..7d250b2 100644
--- a/lib/lp/translations/browser/translationlinksaggregator.py
+++ b/lib/lp/translations/browser/translationlinksaggregator.py
@@ -5,8 +5,6 @@ __all__ = [
'TranslationLinksAggregator',
]
-import six
-
from lp.services.webapp import canonical_url
from lp.translations.interfaces.pofile import IPOFile
from lp.translations.model.productserieslanguage import ProductSeriesLanguage
@@ -177,10 +175,10 @@ class TranslationLinksAggregator:
returns for the sensible chunks.
"""
links = []
- for target, sheets in six.iteritems(self._bundle(sheets)):
+ for target, sheets in self._bundle(sheets).items():
assert sheets, "Translation target has no POFiles or templates."
links_and_sheets = self._circumscribe(sheets)
- for link, covered_sheets in six.iteritems(links_and_sheets):
+ for link, covered_sheets in links_and_sheets.items():
links.append(self.describe(target, link, covered_sheets))
return links
diff --git a/lib/lp/translations/browser/translationmessage.py b/lib/lp/translations/browser/translationmessage.py
index 5087c92..4f904d9 100644
--- a/lib/lp/translations/browser/translationmessage.py
+++ b/lib/lp/translations/browser/translationmessage.py
@@ -21,7 +21,6 @@ import operator
import re
import pytz
-import six
from six.moves.urllib.parse import (
parse_qsl,
urlencode,
@@ -95,11 +94,11 @@ def revert_unselected_translations(translations, current_message,
original_translations = dict(enumerate(current_message.translations))
output = {}
- for plural_form, translation in six.iteritems(translations):
+ for plural_form, translation in translations.items():
if plural_form in plural_indices_to_store:
output[plural_form] = translation
elif original_translations.get(plural_form) is None:
- output[plural_form] = u''
+ output[plural_form] = ''
else:
output[plural_form] = original_translations[plural_form]
@@ -112,7 +111,7 @@ def contains_translations(translations):
:param translations: a dict mapping plural forms to their respective
translation strings.
"""
- for text in six.itervalues(translations):
+ for text in translations.values():
if text is not None and len(text) != 0:
return True
return False
@@ -219,8 +218,7 @@ class CurrentTranslationMessageIndexView(RedirectionView):
def __init__(self, context, request):
target = canonical_url(context, view_name='+translate')
- super(CurrentTranslationMessageIndexView, self).__init__(
- target, request)
+ super().__init__(target, request)
def _getSuggestionFromFormId(form_id):
@@ -358,7 +356,7 @@ class BaseTranslationView(LaunchpadView):
"""
try:
return zope_datetime.parseDatetimetz(
- self.request.form.get('lock_timestamp', u''))
+ self.request.form.get('lock_timestamp', ''))
except zope_datetime.DateTimeError:
# invalid format. Either we don't have the timestamp in the
# submitted form or it has the wrong format.
@@ -439,7 +437,7 @@ class BaseTranslationView(LaunchpadView):
try:
self._storeTranslations(potmsgset)
except GettextValidationError as e:
- return six.text_type(e)
+ return str(e)
except TranslationConflict:
# The translations are demoted to suggestions, but they may
# still affect the "messages with new suggestions" filter.
@@ -644,7 +642,7 @@ class BaseTranslationView(LaunchpadView):
editlanguages_url = canonical_url(
self.user, view_name="+editlanguages")
self.request.response.addInfoNotification(structured(
- u"Not showing suggestions from selected alternative "
+ "Not showing suggestions from selected alternative "
"language %(alternative)s. If you wish to see "
"suggestions from this language, "
'<a href="%(editlanguages_url)s">'
@@ -791,7 +789,7 @@ class BaseTranslationView(LaunchpadView):
else:
# Current translation is None, this code expects u''
# when there is no translation.
- value = u''
+ value = ''
# Current user is an official translator and the radio button
# for 'New translation' is selected, so we are sure we want to
# store this submission.
@@ -1167,7 +1165,7 @@ class CurrentTranslationMessageView(LaunchpadView):
if self.message_must_be_hidden:
# We must hide the translation because it may have private
# info that we don't want to show to anonymous users.
- translation_entry['current_translation'] = u'''
+ translation_entry['current_translation'] = '''
To prevent privacy issues, this translation is not
available to anonymous users,<br />
if you want to see it, please, <a href="+login">log in</a>
@@ -1668,7 +1666,7 @@ def convert_translationmessage_to_submission(
submission.legal_warning = legal_warning_needed and (
message.origin == RosettaTranslationOrigin.SCM)
submission.suggestion_html_id = (
- current_message.potmsgset.makeHTMLID(u'%s_suggestion_%s_%s' % (
+ current_message.potmsgset.makeHTMLID('%s_suggestion_%s_%s' % (
message.language.code, message.id,
plural_form)))
if other_side:
@@ -1679,14 +1677,13 @@ def convert_translationmessage_to_submission(
submission.row_html_id = ''
submission.origin_html_id = submission.suggestion_html_id + '_origin'
submission.translation_html_id = (
- current_message.makeHTMLID(
- u'translation_%s' % (plural_form)))
+ current_message.makeHTMLID('translation_%s' % (plural_form)))
suggestion_dismissable_class = message.potmsgset.makeHTMLID(
- u'dismissable_button')
+ 'dismissable_button')
if submission.is_local_to_pofile:
- suggestion_dismissable_class += u' ' + message.potmsgset.makeHTMLID(
- u'dismissable')
+ suggestion_dismissable_class += ' ' + message.potmsgset.makeHTMLID(
+ 'dismissable')
submission.suggestion_dismissable_class = suggestion_dismissable_class
return submission
diff --git a/lib/lp/translations/browser/translations.py b/lib/lp/translations/browser/translations.py
index be77832..61b99b1 100644
--- a/lib/lp/translations/browser/translations.py
+++ b/lib/lp/translations/browser/translations.py
@@ -153,8 +153,7 @@ class TranslationsRedirectView(RedirectionView):
def __init__(self, context, request):
target = canonical_url(
context, rootsite='translations', view_name='+translations')
- super(TranslationsRedirectView, self).__init__(
- target, request, status=301)
+ super().__init__(target, request, status=301)
class TranslationsLanguageBreadcrumb(Breadcrumb):
diff --git a/lib/lp/translations/browser/widgets/tests/test_potemplate.py b/lib/lp/translations/browser/widgets/tests/test_potemplate.py
index 8763ebe..e52ece0 100644
--- a/lib/lp/translations/browser/widgets/tests/test_potemplate.py
+++ b/lib/lp/translations/browser/widgets/tests/test_potemplate.py
@@ -32,13 +32,13 @@ class TestPOTemplateEditSourcePackageNameWidget(
"interface": IPOTemplate,
}),
("dsp_picker", {
- "features": {u"disclosure.dsp_picker.enabled": u"on"},
+ "features": {"disclosure.dsp_picker.enabled": "on"},
"interface": IPOTemplateEditForm,
}),
]
def setUp(self):
- super(TestPOTemplateEditSourcePackageNameWidget, self).setUp()
+ super().setUp()
if self.features:
self.useFixture(FeatureFixture(self.features))
@@ -75,13 +75,13 @@ class TestPOTemplateAdminSourcePackageNameWidget(
"interface": IPOTemplate,
}),
("dsp_picker", {
- "features": {u"disclosure.dsp_picker.enabled": u"on"},
+ "features": {"disclosure.dsp_picker.enabled": "on"},
"interface": IPOTemplateEditForm,
}),
]
def setUp(self):
- super(TestPOTemplateAdminSourcePackageNameWidget, self).setUp()
+ super().setUp()
if self.features:
self.useFixture(FeatureFixture(self.features))
diff --git a/lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py b/lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py
index e7dcf3c..8729a03 100644
--- a/lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py
+++ b/lib/lp/translations/browser/widgets/tests/test_translationimportqueue.py
@@ -34,15 +34,13 @@ class TestTranslationImportQueueEntrySourcePackageNameWidget(
"interface": IEditTranslationImportQueueEntry,
}),
("dsp_picker", {
- "features": {u"disclosure.dsp_picker.enabled": u"on"},
+ "features": {"disclosure.dsp_picker.enabled": "on"},
"interface": IEditTranslationImportQueueEntryDSP,
}),
]
def setUp(self):
- super(
- TestTranslationImportQueueEntrySourcePackageNameWidget,
- self).setUp()
+ super().setUp()
if self.features:
self.useFixture(FeatureFixture(self.features))