← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:pyupgrade-py3-code-1 into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:pyupgrade-py3-code-1 into launchpad:master.

Commit message:
lp.code.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/413302
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:pyupgrade-py3-code-1 into launchpad:master.
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index f2b6846..91cb020 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -20,3 +20,5 @@ c348b945c29c723201380d9aca0e0c0298037c8c
 b6725842a2470e3927bb73bf400c4476a06ee3ba
 # apply pyupgrade --py3-plus to lp.charms
 474f07ab7c3f28d8b6b8e4f1bd4c56832cec3fab
+# apply pyupgrade --py3-plus to lp.code.browser
+47ee1259461aa54ad7ee967e85f6131be2b74125
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 12d6018..47ab095 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -48,6 +48,7 @@ repos:
             |bugs
             |buildmaster
             |charms
+            |code/browser
           )/
 -   repo: https://github.com/PyCQA/isort
     rev: 5.9.2
diff --git a/lib/lp/code/browser/branch.py b/lib/lp/code/browser/branch.py
index f6e5d03..6f9dc1a 100644
--- a/lib/lp/code/browser/branch.py
+++ b/lib/lp/code/browser/branch.py
@@ -34,7 +34,6 @@ from lazr.restful.interface import (
 from lazr.uri import URI
 import pytz
 import simplejson
-import six
 from zope.component import getUtility
 from zope.event import notify
 from zope.formlib import form
@@ -418,7 +417,7 @@ class BranchView(InformationTypePortletMixin, FeedsMixin, BranchMirrorMixin,
     label = page_title
 
     def initialize(self):
-        super(BranchView, self).initialize()
+        super().initialize()
         self.branch = self.context
         self.notices = []
         # Cache permission so private team owner can be rendered.
@@ -953,8 +952,8 @@ class BranchDeletionView(LaunchpadFormView):
         :return: A list of tuples of (item, operation, reason, allowed)
         """
         reqs = []
-        for item, (operation, reason) in six.iteritems(
-                self.context.deletionRequirements(eager_load=True)):
+        for item, (operation, reason) in self.context.deletionRequirements(
+                eager_load=True).items():
             allowed = check_permission('launchpad.Edit', item)
             reqs.append((item, operation, reason, allowed))
         return reqs
@@ -1054,7 +1053,7 @@ class CodeEditOwnerMixin:
     """A mixin to adjust owner vocabularies for admins."""
 
     def setUpFields(self):
-        super(CodeEditOwnerMixin, self).setUpFields()
+        super().setUpFields()
         # If the user can administer the relevant object type, then they
         # should be able to assign the ownership of the object to any valid
         # person or team.
@@ -1114,7 +1113,7 @@ class BranchEditView(CodeEditOwnerMixin, BranchEditFormView):
         "person or team.")
 
     def setUpFields(self):
-        super(BranchEditView, self).setUpFields()
+        super().setUpFields()
         branch = self.context
         if branch.branch_type in (BranchType.HOSTED, BranchType.IMPORTED):
             self.form_fields = self.form_fields.omit('url')
@@ -1208,8 +1207,8 @@ class RegisterProposalSchema(Interface):
 
     review_type = copy_field(
         ICodeReviewVoteReference['review_type'],
-        description=u'Lowercase keywords describing the type of review you '
-                     'would like to be performed.')
+        description='Lowercase keywords describing the type of review you '
+                    'would like to be performed.')
 
     commit_message = IBranchMergeProposal['commit_message']
 
@@ -1331,15 +1330,15 @@ class BranchDiffView(DataDownloadView):
     content_type = "text/x-patch"
 
     def __init__(self, context, request, new, old=None):
-        super(BranchDiffView, self).__init__(context, request)
+        super().__init__(context, request)
         self.new = new
         self.old = old
 
     def __call__(self):
-        if getFeatureFlag(u"code.bzr.diff.disable_proxy"):
+        if getFeatureFlag("code.bzr.diff.disable_proxy"):
             self.request.response.setStatus(401)
             return "Proxying of branch diffs is disabled.\n"
-        return super(BranchDiffView, self).__call__()
+        return super().__call__()
 
     @property
     def filename(self):
diff --git a/lib/lp/code/browser/branchlisting.py b/lib/lp/code/browser/branchlisting.py
index d3ecb66..56e26b2 100644
--- a/lib/lp/code/browser/branchlisting.py
+++ b/lib/lp/code/browser/branchlisting.py
@@ -31,7 +31,6 @@ from lazr.enum import (
     EnumeratedType,
     Item,
     )
-import six
 from six.moves.urllib.parse import parse_qs
 from storm.expr import Desc
 from zope.browserpage import ViewPageTemplateFile
@@ -137,7 +136,7 @@ class BranchBadges(HasBadgeBase):
             return Badge('/@@/warning', '/@@/warning-large', '',
                          'Branch has errors')
         else:
-            return super(BranchBadges, self).getBadge(badge_name)
+            return super().getBadge(badge_name)
 
 
 @delegate_to(IBranch, context='context')
@@ -500,7 +499,7 @@ class BranchListingView(LaunchpadFormView, FeedsMixin):
         if render_table_only:
             return self.table_only_template
         else:
-            return super(BranchListingView, self).template
+            return super().template
 
     @property
     def initial_values(self):
@@ -658,7 +657,7 @@ class BranchListingView(LaunchpadFormView, FeedsMixin):
                 field = self.form_fields[field_name]
             fields.append(field)
         self.form_fields = form.Fields(*fields)
-        super(BranchListingView, self).setUpWidgets(context)
+        super().setUpWidgets(context)
 
     @cachedproperty
     def default_information_type(self):
@@ -814,7 +813,7 @@ class PersonBaseBranchListingView(BranchListingView):
 
     @property
     def initial_values(self):
-        values = super(PersonBaseBranchListingView, self).initial_values
+        values = super().initial_values
         values['sort_by'] = BranchListingSort.MOST_RECENTLY_CHANGED_FIRST
         return values
 
@@ -887,7 +886,7 @@ class PersonProductBranchesView(PersonBranchesView):
             self.context.product.displayname, self.context.person.displayname)
 
     def _getCollection(self):
-        coll = super(PersonProductBranchesView, self)._getCollection()
+        coll = super()._getCollection()
         return coll.inProduct(self.context.product)
 
 
@@ -1029,12 +1028,12 @@ class ProductBranchStatisticsView(BranchCountSummaryView,
 
     @property
     def branch_text(self):
-        text = super(ProductBranchStatisticsView, self).branch_text
+        text = super().branch_text
         return text.capitalize()
 
     @property
     def commit_text(self):
-        text = super(ProductBranchStatisticsView, self).commit_text
+        text = super().commit_text
         return text.capitalize()
 
 
@@ -1162,7 +1161,7 @@ class ProductBranchesView(ProductBranchListingView, SortSeriesMixin,
     def initial_branches(self):
         """Return the series branches, followed by most recently changed."""
         series_branches = self._getSeriesBranches()
-        branch_query = super(ProductBranchesView, self)._branches(
+        branch_query = super()._branches(
             self.selected_lifecycle_status,
             sort_by=BranchListingSort.MOST_RECENTLY_CHANGED_FIRST)
         # We don't want the initial branch listing to be batched, so only get
@@ -1182,7 +1181,7 @@ class ProductBranchesView(ProductBranchListingView, SortSeriesMixin,
         # The params are ignored, and only used by the listing view.
         if self.sort_by == BranchListingSort.DEFAULT:
             return self.initial_branches
-        return super(ProductBranchesView, self)._branches(lifecycle_status)
+        return super()._branches(lifecycle_status)
 
     @property
     def has_development_focus_branch(self):
@@ -1226,7 +1225,7 @@ class BaseSourcePackageBranchesView(BranchListingView):
 
     @property
     def initial_values(self):
-        values = super(BaseSourcePackageBranchesView, self).initial_values
+        values = super().initial_values
         values['sort_by'] = BranchListingSort.MOST_RECENTLY_CHANGED_FIRST
         return values
 
@@ -1305,7 +1304,7 @@ class GroupedDistributionSourcePackageBranchesView(LaunchpadView,
         # For each distro series, we only want the "best" pocket if one branch
         # is linked to more than one pocket.  Best here means smaller value.
         official_branches = {}
-        for key, value in six.iteritems(distro_links):
+        for key, value in distro_links.items():
             ordered = sorted(value, key=attrgetter('pocket'))
             seen_branches = set()
             branches = []
@@ -1362,7 +1361,7 @@ class GroupedDistributionSourcePackageBranchesView(LaunchpadView,
         and merge proposal links for badges.
         """
         visible_branches = []
-        for branches, count in six.itervalues(self.series_branches_map):
+        for branches, count in self.series_branches_map.values():
             visible_branches.extend(branches)
         return visible_branches
 
diff --git a/lib/lp/code/browser/branchmergeproposal.py b/lib/lp/code/browser/branchmergeproposal.py
index b7c157a..665e97c 100644
--- a/lib/lp/code/browser/branchmergeproposal.py
+++ b/lib/lp/code/browser/branchmergeproposal.py
@@ -34,7 +34,6 @@ from lazr.restful.interfaces import (
     IWebServiceClientRequest,
     )
 import simplejson
-import six
 from six.moves.urllib_parse import (
     urlsplit,
     urlunsplit,
@@ -157,7 +156,7 @@ def latest_proposals_for_each_branch(proposals):
             targets[target] = (proposal, date_created)
 
     return sorted(
-        (proposal for proposal, date_created in six.itervalues(targets)),
+        (proposal for proposal, date_created in targets.values()),
         key=operator.attrgetter('date_created'), reverse=True)
 
 
@@ -640,7 +639,7 @@ class BranchMergeProposalView(LaunchpadFormView, UnmergedRevisionsMixin,
     schema = ClaimButton
 
     def initialize(self):
-        super(BranchMergeProposalView, self).initialize()
+        super().initialize()
         cache = IJSONRequestCache(self.request)
         cache.objects['branch_name'] = self.context.merge_source.name
         if (IBranch.providedBy(self.context.merge_source) and
@@ -662,7 +661,7 @@ class BranchMergeProposalView(LaunchpadFormView, UnmergedRevisionsMixin,
             try:
                 request.claimReview(self.user)
             except ClaimReviewFailed as e:
-                self.request.response.addErrorNotification(six.text_type(e))
+                self.request.response.addErrorNotification(str(e))
         self.next_url = canonical_url(self.context)
 
     @property
@@ -1030,8 +1029,8 @@ class IReviewRequest(Interface):
 
     review_type = copy_field(
         ICodeReviewVoteReference['review_type'],
-        description=u'Lowercase keywords describing the type of review you '
-                     'would like to be performed.')
+        description='Lowercase keywords describing the type of review you '
+                    'would like to be performed.')
 
 
 class BranchMergeProposalRequestReviewView(LaunchpadEditFormView):
@@ -1091,15 +1090,15 @@ class MergeProposalEditView(LaunchpadEditFormView,
         # Record next_url and cancel url now
         self.next_url = canonical_url(self.context)
         self.cancel_url = self.next_url
-        super(MergeProposalEditView, self).initialize()
+        super().initialize()
 
 
 class ResubmitSchema(IBranchMergeProposal):
 
     break_link = Bool(
-        title=u'Start afresh',
+        title='Start afresh',
         description=(
-            u'Do not show old conversation and do not link to superseded'
+            'Do not show old conversation and do not link to superseded'
             ' proposal.'),
         default=False,)
 
@@ -1121,7 +1120,7 @@ class BranchMergeProposalResubmitView(LaunchpadFormView,
 
     def initialize(self):
         self.cancel_url = canonical_url(self.context)
-        super(BranchMergeProposalResubmitView, self).initialize()
+        super().initialize()
 
     @property
     def field_names(self):
@@ -1234,7 +1233,7 @@ class BranchMergeProposalDeleteView(MergeProposalEditView):
         # it is available in the situation where the merge proposal
         # is deleted.
         self.merge_source = self.context.merge_source
-        super(BranchMergeProposalDeleteView, self).initialize()
+        super().initialize()
 
     @action('Delete proposal', name='delete')
     def delete_action(self, action, data):
@@ -1401,7 +1400,7 @@ class IAddVote(Interface):
 
     review_type = copy_field(
         ICodeReviewVoteReference['review_type'],
-        description=u'Lowercase keywords describing the type of review you '
+        description='Lowercase keywords describing the type of review you '
                      'are performing.')
 
     comment = Text(title=_('Comment'), required=False)
@@ -1441,10 +1440,10 @@ class BranchMergeProposalAddVoteView(LaunchpadFormView):
         if self.user is None:
             # Anonymous users are not valid voters.
             raise AssertionError('Invalid voter')
-        super(BranchMergeProposalAddVoteView, self).initialize()
+        super().initialize()
 
     def setUpFields(self):
-        super(BranchMergeProposalAddVoteView, self).setUpFields()
+        super().setUpFields()
         self.reviewer = self.user.name
         # claim_review is set in situations where a user is reviewing on
         # behalf of a team.
diff --git a/lib/lp/code/browser/branchmergeproposallisting.py b/lib/lp/code/browser/branchmergeproposallisting.py
index 7d88ec0..5a219da 100644
--- a/lib/lp/code/browser/branchmergeproposallisting.py
+++ b/lib/lp/code/browser/branchmergeproposallisting.py
@@ -134,7 +134,7 @@ class BranchMergeProposalListingBatchNavigator(TableBatchNavigator):
     """Batch up the branch listings."""
 
     def __init__(self, view):
-        super(BranchMergeProposalListingBatchNavigator, self).__init__(
+        super().__init__(
             view.getVisibleProposalsForUser(), view.request,
             columns_to_show=view.extra_columns,
             size=config.launchpad.branchlisting_batch_size)
@@ -463,8 +463,7 @@ class PersonProductActiveReviewsView(PersonActiveReviewsView):
         return self.context.person
 
     def getProposals(self):
-        return super(PersonProductActiveReviewsView, self).getProposals(
-            project=self.context.product)
+        return super().getProposals(project=self.context.product)
 
     @property
     def no_proposal_message(self):
diff --git a/lib/lp/code/browser/branchsubscription.py b/lib/lp/code/browser/branchsubscription.py
index 8fcb708..b90a040 100644
--- a/lib/lp/code/browser/branchsubscription.py
+++ b/lib/lp/code/browser/branchsubscription.py
@@ -249,7 +249,7 @@ class BranchSubscriptionEditView(LaunchpadEditFormView):
     def initialize(self):
         self.branch = self.context.branch
         self.person = self.context.person
-        super(BranchSubscriptionEditView, self).initialize()
+        super().initialize()
 
     @action("Change", name="change")
     def change_action(self, action, data):
diff --git a/lib/lp/code/browser/codeimport.py b/lib/lp/code/browser/codeimport.py
index 394531c..5ecf7d4 100644
--- a/lib/lp/code/browser/codeimport.py
+++ b/lib/lp/code/browser/codeimport.py
@@ -112,7 +112,7 @@ class CodeImportSetNavigation(Navigation):
 
 class CodeImportSetBreadcrumb(Breadcrumb):
     """Builds a breadcrumb for an `ICodeImportSet`."""
-    text = u'Code Import System'
+    text = 'Code Import System'
 
 
 class DropdownWidgetWithAny(LaunchpadDropdownWidget):
@@ -381,7 +381,7 @@ class CodeImportNewView(CodeImportBaseView, CodeImportNameValidationMixin):
             self.form_fields = any_owner_field + self.form_fields
 
     def setUpWidgets(self):
-        super(CodeImportNewView, self).setUpWidgets()
+        super().setUpWidgets()
 
         # Extract the radio buttons from the rcs_type widget, so we can
         # display them separately in the form.
@@ -478,7 +478,7 @@ class CodeImportNewView(CodeImportBaseView, CodeImportNameValidationMixin):
         """See `LaunchpadFormView`."""
         self.widgets['git_target_rcs_type'].context.required = (
             data.get('rcs_type') == RevisionControlSystems.GIT)
-        super(CodeImportNewView, self).validate_widgets(data, names=names)
+        super().validate_widgets(data, names=names)
 
     def validate(self, data):
         """See `LaunchpadFormView`."""
@@ -615,7 +615,7 @@ class CodeImportEditView(CodeImportBaseView):
             raise Unauthorized
         # The next and cancel location is the target details page.
         self.cancel_url = self.next_url = canonical_url(self.context)
-        super(CodeImportEditView, self).initialize()
+        super().initialize()
 
     @property
     def adapters(self):
diff --git a/lib/lp/code/browser/codeimportmachine.py b/lib/lp/code/browser/codeimportmachine.py
index 6e4e868..428e422 100644
--- a/lib/lp/code/browser/codeimportmachine.py
+++ b/lib/lp/code/browser/codeimportmachine.py
@@ -58,7 +58,7 @@ class CodeImportMachineSetNavigation(Navigation):
 
 class CodeImportMachineSetBreadcrumb(Breadcrumb):
     """Builds a breadcrumb for an `ICodeImportMachineSet`."""
-    text = u'Machines'
+    text = 'Machines'
 
 
 class CodeImportMachineSetView(LaunchpadView):
diff --git a/lib/lp/code/browser/codereviewcomment.py b/lib/lp/code/browser/codereviewcomment.py
index 54d83aa..a8a480c 100644
--- a/lib/lp/code/browser/codereviewcomment.py
+++ b/lib/lp/code/browser/codereviewcomment.py
@@ -95,7 +95,7 @@ class CodeReviewDisplayComment(MessageComment):
             comment_limit = config.malone.max_comment_size
         else:
             comment_limit = None
-        super(CodeReviewDisplayComment, self).__init__(comment_limit)
+        super().__init__(comment_limit)
         self.comment = comment
         get_property_cache(self).has_body = bool(self.comment.message_body)
         self.has_footer = self.comment.vote is not None
@@ -109,8 +109,7 @@ class CodeReviewDisplayComment(MessageComment):
 
     @property
     def extra_css_class(self):
-        css_classes = (
-            super(CodeReviewDisplayComment, self).extra_css_class.split())
+        css_classes = super().extra_css_class.split()
         if self.from_superseded:
             css_classes.append('from-superseded')
         return ' '.join(css_classes)
@@ -230,7 +229,7 @@ class CodeReviewCommentIndexView(CodeReviewCommentView):
         """View redirects to +download if comment is too long to render."""
         if self.comment.too_long_to_render:
             return self.request.response.redirect(self.comment.download_url)
-        return super(CodeReviewCommentIndexView, self).__call__()
+        return super().__call__()
 
 
 class IEditCodeReviewComment(Interface):
@@ -240,8 +239,8 @@ class IEditCodeReviewComment(Interface):
 
     review_type = copy_field(
         ICodeReviewVoteReference['review_type'],
-        description=u'Lowercase keywords describing the type of review you '
-                     'are performing.')
+        description='Lowercase keywords describing the type of review you '
+                    'are performing.')
 
     comment = Text(title=_('Comment'), required=False)
 
diff --git a/lib/lp/code/browser/decorations.py b/lib/lp/code/browser/decorations.py
index 60bd781..d1110e5 100644
--- a/lib/lp/code/browser/decorations.py
+++ b/lib/lp/code/browser/decorations.py
@@ -47,7 +47,7 @@ class DecoratedBranch(BzrIdentityMixin):
         The property is defined in the bzrIdentityMixin class.  This uses the
         associatedProductSeries and associatedSuiteSourcePackages methods.
         """
-        return super(DecoratedBranch, self).bzr_identity
+        return super().bzr_identity
 
     @cachedproperty
     def is_series_branch(self):
diff --git a/lib/lp/code/browser/gitlisting.py b/lib/lp/code/browser/gitlisting.py
index e3ed8b6..5a9c092 100644
--- a/lib/lp/code/browser/gitlisting.py
+++ b/lib/lp/code/browser/gitlisting.py
@@ -47,7 +47,7 @@ class GitRepositoryBatchNavigator(TableBatchNavigator):
     variable_name_prefix = 'repo'
 
     def __init__(self, view, repo_collection):
-        super(GitRepositoryBatchNavigator, self).__init__(
+        super().__init__(
             repo_collection.getRepositories(
                 eager_load=True,
                 sort_by=GitListingSort.MOST_RECENTLY_CHANGED_FIRST),
diff --git a/lib/lp/code/browser/gitref.py b/lib/lp/code/browser/gitref.py
index b28f1d9..bdae8f2 100644
--- a/lib/lp/code/browser/gitref.py
+++ b/lib/lp/code/browser/gitref.py
@@ -302,8 +302,8 @@ class GitRefRegisterMergeProposalSchema(Interface):
 
     review_type = copy_field(
         ICodeReviewVoteReference['review_type'],
-        description=u'Lowercase keywords describing the type of review you '
-                     'would like to be performed.')
+        description='Lowercase keywords describing the type of review you '
+                    'would like to be performed.')
 
     commit_message = IBranchMergeProposal['commit_message']
 
@@ -338,11 +338,10 @@ class GitRefRegisterMergeProposalView(LaunchpadFormView):
         """Show a 404 if the repository namespace doesn't support proposals."""
         if not self.context.namespace.supports_merge_proposals:
             raise NotFound(self.context, '+register-merge')
-        super(GitRefRegisterMergeProposalView, self).initialize()
+        super().initialize()
 
     def setUpWidgets(self, context=None):
-        super(GitRefRegisterMergeProposalView, self).setUpWidgets(
-            context=context)
+        super().setUpWidgets(context=context)
 
         if not self.widgets['target_git_ref'].hasInput():
             if self.context.repository.namespace.has_defaults:
diff --git a/lib/lp/code/browser/gitrepository.py b/lib/lp/code/browser/gitrepository.py
index ddd79ca..cd35d5d 100644
--- a/lib/lp/code/browser/gitrepository.py
+++ b/lib/lp/code/browser/gitrepository.py
@@ -31,7 +31,6 @@ from lazr.restful.interface import (
     copy_field,
     use_template,
     )
-import six
 from six.moves.urllib_parse import (
     urlsplit,
     urlunsplit,
@@ -362,7 +361,7 @@ class GitRefBatchNavigator(TableBatchNavigator):
 
     def __init__(self, view, context):
         self.context = context
-        super(GitRefBatchNavigator, self).__init__(
+        super().__init__(
             self.context.branches_by_date, view.request,
             size=config.launchpad.branchlisting_batch_size)
         self.view = view
@@ -391,7 +390,7 @@ class GitRepositoryView(InformationTypePortletMixin, LaunchpadView,
     show_merge_links = True
 
     def initialize(self):
-        super(GitRepositoryView, self).initialize()
+        super().initialize()
         # Cache permission so that the private team owner can be rendered.  The
         # security adapter will do the job also but we don't want or need the
         # expense of running several complex SQL queries.
@@ -523,14 +522,14 @@ class GitRepositoryForkView(LaunchpadEditFormView):
     def initialize(self):
         if not getFeatureFlag(GIT_REPOSITORY_FORK_ENABLED):
             raise Unauthorized()
-        super(GitRepositoryForkView, self).initialize()
+        super().initialize()
 
     def setUpFields(self):
-        super(GitRepositoryForkView, self).setUpFields()
+        super().setUpFields()
         owner_field = Choice(
             vocabulary='AllUserTeamsParticipationPlusSelf',
-            title=u'Fork to the following owner', required=True,
-            __name__=u'owner')
+            title='Fork to the following owner', required=True,
+            __name__='owner')
         self.form_fields += FormFields(owner_field)
 
     @property
@@ -746,7 +745,7 @@ class GitRepositoryEditView(CodeEditOwnerMixin, GitRepositoryEditFormView):
         "person or team.")
 
     def setUpFields(self):
-        super(GitRepositoryEditView, self).setUpFields()
+        super().setUpFields()
         repository = self.context
         # If the user can administer repositories, then they should be able
         # to assign the ownership of the repository to any valid person or
@@ -794,7 +793,7 @@ class GitRepositoryEditView(CodeEditOwnerMixin, GitRepositoryEditFormView):
             target_field.custom_widget = GitRepositoryTargetWidget
 
     def setUpWidgets(self, context=None):
-        super(GitRepositoryEditView, self).setUpWidgets(context=context)
+        super().setUpWidgets(context=context)
         if self.context.target_default:
             self.widgets["target"].hint = (
                 "This is the default repository for this target, so it "
@@ -858,7 +857,7 @@ class GitRepositoryDiffView(DataDownloadView):
     charset = "UTF-8"
 
     def __init__(self, context, request, old, new):
-        super(GitRepositoryDiffView, self).__init__(context, request)
+        super().__init__(context, request)
         self.context = context
         self.request = request
         self.old = old
@@ -900,7 +899,7 @@ class GitRulePatternField(UniqueField):
     def __init__(self, ref_prefix, rule=None, *args, **kwargs):
         self.ref_prefix = ref_prefix
         self.rule = rule
-        super(GitRulePatternField, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
     def _getByAttribute(self, ref_pattern):
         """See `UniqueField`."""
@@ -919,14 +918,14 @@ class GitRulePatternField(UniqueField):
         """See `IField`."""
         if value is not None:
             value = value.strip()
-        super(GitRulePatternField, self).set(object, value)
+        super().set(object, value)
 
 
 class GitRepositoryPermissionsView(LaunchpadFormView):
     """A view to manage repository permissions."""
 
-    heads_prefix = u"refs/heads/"
-    tags_prefix = u"refs/tags/"
+    heads_prefix = "refs/heads/"
+    tags_prefix = "refs/tags/"
 
     @property
     def label(self):
@@ -975,7 +974,7 @@ class GitRepositoryPermissionsView(LaunchpadFormView):
         for prefix in (self.heads_prefix, self.tags_prefix):
             if ref_pattern.startswith(prefix):
                 return prefix, ref_pattern[len(prefix):]
-        return u"", ref_pattern
+        return "", ref_pattern
 
     def _getFieldName(self, name, ref_pattern, grantee=None):
         """Get the combined field name for a ref pattern and optional grantee.
@@ -1132,8 +1131,7 @@ class GitRepositoryPermissionsView(LaunchpadFormView):
 
     def setUpWidgets(self, context=None):
         """See `LaunchpadFormView`."""
-        super(GitRepositoryPermissionsView, self).setUpWidgets(
-            context=context)
+        super().setUpWidgets(context=context)
         for widget in self.widgets:
             widget.display_label = False
             widget.hint = None
@@ -1378,8 +1376,8 @@ class GitRepositoryDeletionView(LaunchpadFormView):
         :return: A list of tuples of (item, operation, reason, allowed)
         """
         reqs = []
-        for item, (operation, reason) in six.iteritems(
-                self.context.getDeletionRequirements(eager_load=True)):
+        for item, (operation, reason) in self.context.getDeletionRequirements(
+                eager_load=True).items():
             allowed = check_permission("launchpad.Edit", item)
             reqs.append((item, operation, reason, allowed))
         return reqs
diff --git a/lib/lp/code/browser/gitsubscription.py b/lib/lp/code/browser/gitsubscription.py
index 25a6ecc..e4af854 100644
--- a/lib/lp/code/browser/gitsubscription.py
+++ b/lib/lp/code/browser/gitsubscription.py
@@ -252,7 +252,7 @@ class GitSubscriptionEditView(LaunchpadEditFormView):
     def initialize(self):
         self.repository = self.context.repository
         self.person = self.context.person
-        super(GitSubscriptionEditView, self).initialize()
+        super().initialize()
 
     @action("Change", name="change")
     def change_action(self, action, data):
diff --git a/lib/lp/code/browser/sourcepackagerecipe.py b/lib/lp/code/browser/sourcepackagerecipe.py
index 1097ac7..eed6d6f 100644
--- a/lib/lp/code/browser/sourcepackagerecipe.py
+++ b/lib/lp/code/browser/sourcepackagerecipe.py
@@ -184,7 +184,7 @@ class SourcePackageRecipeView(LaunchpadView):
     """Default view of a SourcePackageRecipe."""
 
     def initialize(self):
-        super(SourcePackageRecipeView, self).initialize()
+        super().initialize()
         recipe = self.context
         if recipe.build_daily and recipe.daily_build_archive is None:
             self.request.response.addWarningNotification(
@@ -371,10 +371,10 @@ class SourcePackageRecipeRequestBuildsView(LaunchpadFormView):
     class schema(Interface):
         """Schema for requesting a build."""
         archive = Choice(
-            vocabulary='TargetPPAs', title=u'Archive', required=False)
+            vocabulary='TargetPPAs', title='Archive', required=False)
         distroseries = List(
             Choice(vocabulary='BuildableDistroSeries'),
-            title=u'Distribution series')
+            title='Distribution series')
 
     custom_widget_distroseries = LabeledMultiCheckBoxWidget
 
@@ -505,7 +505,7 @@ class SourcePackageRecipeRequestDailyBuildView(LaunchpadFormView):
     page_title = "Build now"
 
     def initialize(self):
-        super(SourcePackageRecipeRequestDailyBuildView, self).initialize()
+        super().initialize()
         if self.request.method == 'GET':
             self.request.response.redirect(canonical_url(self.context))
 
@@ -550,14 +550,14 @@ class ISourcePackageEditSchema(Interface):
         'distroseries',
         ])
     daily_build_archive = Choice(vocabulary='TargetPPAs',
-        title=u'Daily build archive',
+        title='Daily build archive',
         description=(
-            u'If built daily, this is the archive where the package '
-            u'will be uploaded.'))
+            'If built daily, this is the archive where the package '
+            'will be uploaded.'))
     recipe_text = has_structured_doc(
         Text(
-            title=u'Recipe text', required=True,
-            description=u"""The text of the recipe.
+            title='Recipe text', required=True,
+            description="""The text of the recipe.
                 <a href="/+help-code/recipe-syntax.html" target="help"
                   >Syntax help&nbsp;
                   <span class="sprite maybe action-icon">
@@ -580,10 +580,10 @@ USE_ARCHIVE_VOCABULARY = SimpleVocabulary((
 class ISourcePackageAddSchema(ISourcePackageEditSchema):
 
     daily_build_archive = Choice(vocabulary='TargetPPAs',
-        title=u'Daily build archive', required=False,
+        title='Daily build archive', required=False,
         description=(
-            u'If built daily, this is the archive where the package '
-            u'will be uploaded.'))
+            'If built daily, this is the archive where the package '
+            'will be uploaded.'))
 
     use_ppa = Choice(
         title=_('Which PPA'),
@@ -677,7 +677,7 @@ class RecipeRelatedBranchesMixin(LaunchpadFormView):
 
     def setUpWidgets(self, context=None):
         # Adds a new related branches widget.
-        super(RecipeRelatedBranchesMixin, self).setUpWidgets(context)
+        super().setUpWidgets(context)
         self.widgets['related_branches'].display_label = False
         self.widgets['related_branches'].setRenderedValue(dict(
             related_package_branch_info=self.related_package_branch_info,
@@ -712,7 +712,7 @@ class SourcePackageRecipeAddView(RecipeRelatedBranchesMixin,
     custom_widget_use_ppa = LaunchpadRadioWidget
 
     def initialize(self):
-        super(SourcePackageRecipeAddView, self).initialize()
+        super().initialize()
         widget = self.widgets['use_ppa']
         current_value = widget._getFormValue()
         self.use_ppa_existing = render_radio_widget_part(
@@ -730,7 +730,7 @@ class SourcePackageRecipeAddView(RecipeRelatedBranchesMixin,
         archive_widget._displayItemForMissingValue = False
 
     def setUpFields(self):
-        super(SourcePackageRecipeAddView, self).setUpFields()
+        super().setUpFields()
         # Ensure distro series widget allows input
         self.form_fields['distroseries'].for_input = True
 
@@ -820,7 +820,7 @@ class SourcePackageRecipeAddView(RecipeRelatedBranchesMixin,
         self.next_url = canonical_url(source_package_recipe)
 
     def validate(self, data):
-        super(SourcePackageRecipeAddView, self).validate(data)
+        super().validate(data)
         name = data.get('name', None)
         owner = data.get('owner', None)
         if name and owner:
@@ -860,7 +860,7 @@ class SourcePackageRecipeEditView(RecipeRelatedBranchesMixin,
     custom_widget_distroseries = LabeledMultiCheckBoxWidget
 
     def setUpFields(self):
-        super(SourcePackageRecipeEditView, self).setUpFields()
+        super().setUpFields()
 
         # Ensure distro series widget allows input
         self.form_fields['distroseries'].for_input = True
@@ -872,8 +872,8 @@ class SourcePackageRecipeEditView(RecipeRelatedBranchesMixin,
             owner_field = self.schema['owner']
             any_owner_choice = PersonChoice(
                 __name__='owner', title=owner_field.title,
-                description=(u"As an administrator you are able to assign"
-                             u" this recipe to any person or team."),
+                description=("As an administrator you are able to assign"
+                             " this recipe to any person or team."),
                 required=True, vocabulary='ValidPersonOrTeam')
             any_owner_field = form.Fields(
                 any_owner_choice, render_context=self.render_context)
@@ -932,7 +932,7 @@ class SourcePackageRecipeEditView(RecipeRelatedBranchesMixin,
         return {ISourcePackageEditSchema: self.context}
 
     def validate(self, data):
-        super(SourcePackageRecipeEditView, self).validate(data)
+        super().validate(data)
         name = data.get('name', None)
         owner = data.get('owner', None)
         if name and owner:
diff --git a/lib/lp/code/browser/sourcepackagerecipebuild.py b/lib/lp/code/browser/sourcepackagerecipebuild.py
index d92c092..8817d7e 100644
--- a/lib/lp/code/browser/sourcepackagerecipebuild.py
+++ b/lib/lp/code/browser/sourcepackagerecipebuild.py
@@ -148,14 +148,14 @@ class SourcePackageRecipeBuildRescoreView(LaunchpadFormView):
     class schema(Interface):
         """Schema for deleting a build."""
         score = Int(
-            title=u'Score', required=True,
-            description=u'The score of the recipe.')
+            title='Score', required=True,
+            description='The score of the recipe.')
 
     page_title = label = "Rescore build"
 
     def __call__(self):
         if self.context.buildqueue_record is not None:
-            return super(SourcePackageRecipeBuildRescoreView, self).__call__()
+            return super().__call__()
         self.request.response.addWarningNotification(
             'Cannot rescore this build because it is not queued.')
         self.request.response.redirect(canonical_url(self.context))
diff --git a/lib/lp/code/browser/sourcepackagerecipelisting.py b/lib/lp/code/browser/sourcepackagerecipelisting.py
index 319a49c..4b743cf 100644
--- a/lib/lp/code/browser/sourcepackagerecipelisting.py
+++ b/lib/lp/code/browser/sourcepackagerecipelisting.py
@@ -50,7 +50,7 @@ class BranchRecipeListingView(RecipeListingView):
     branch_enabled = False
 
     def initialize(self):
-        super(BranchRecipeListingView, self).initialize()
+        super().initialize()
         # Replace our context with a decorated branch, if it is not already
         # decorated.
         if (IBranch.providedBy(self.context) and
diff --git a/lib/lp/code/browser/tests/test_branch.py b/lib/lp/code/browser/tests/test_branch.py
index 6236544..ceaac7c 100644
--- a/lib/lp/code/browser/tests/test_branch.py
+++ b/lib/lp/code/browser/tests/test_branch.py
@@ -78,7 +78,7 @@ class TestBranchMirrorHidden(TestCaseWithFactory):
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
-        super(TestBranchMirrorHidden, self).setUp()
+        super().setUp()
         config.push(
             "test", dedent("""\
                 [codehosting]
@@ -87,7 +87,7 @@ class TestBranchMirrorHidden(TestCaseWithFactory):
 
     def tearDown(self):
         config.pop("test")
-        super(TestBranchMirrorHidden, self).tearDown()
+        super().tearDown()
 
     def testNormalBranch(self):
         # A branch from a normal location is fine.
diff --git a/lib/lp/code/browser/tests/test_branchlisting.py b/lib/lp/code/browser/tests/test_branchlisting.py
index 3f33640..47a187f 100644
--- a/lib/lp/code/browser/tests/test_branchlisting.py
+++ b/lib/lp/code/browser/tests/test_branchlisting.py
@@ -250,7 +250,7 @@ class TestSimplifiedPersonBranchesView(TestCaseWithFactory):
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
-        super(TestSimplifiedPersonBranchesView, self).setUp()
+        super().setUp()
         self.user = self.factory.makePerson()
         self.person = self.factory.makePerson(name='barney')
         self.team = self.factory.makeTeam(owner=self.person)
@@ -327,7 +327,7 @@ class TestSimplifiedPersonProductBranchesView(
     TestSimplifiedPersonBranchesView):
 
     def setUp(self):
-        super(TestSimplifiedPersonProductBranchesView, self).setUp()
+        super().setUp()
         self.person_product = getUtility(IPersonProductFactory).create(
             self.person, self.product)
         self.team_product = getUtility(IPersonProductFactory).create(
@@ -669,7 +669,7 @@ class TestProjectGroupBranches(TestCaseWithFactory,
     layer = DatabaseFunctionalLayer
 
     def setUp(self):
-        super(TestProjectGroupBranches, self).setUp()
+        super().setUp()
         self.projectgroup = self.factory.makeProject()
 
     def test_no_branches_gets_message_not_listing(self):
diff --git a/lib/lp/code/browser/tests/test_branchmergeproposal.py b/lib/lp/code/browser/tests/test_branchmergeproposal.py
index e722def..033b72e 100644
--- a/lib/lp/code/browser/tests/test_branchmergeproposal.py
+++ b/lib/lp/code/browser/tests/test_branchmergeproposal.py
@@ -143,7 +143,7 @@ from lp.testing.views import (
 class GitHostingClientMixin:
 
     def setUp(self):
-        super(GitHostingClientMixin, self).setUp()
+        super().setUp()
         self.git_hosting_fixture = self.useFixture(GitHostingFixture())
 
 
@@ -551,7 +551,7 @@ class TestRegisterBranchMergeProposalViewMixin:
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
-        super(TestRegisterBranchMergeProposalViewMixin, self).setUp()
+        super().setUp()
         self.source_branch = self._makeBranch()
         self.user = self.factory.makePerson()
         login_person(self.user)
@@ -1414,7 +1414,7 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
 
     def test_preview_diff_utf8(self):
         """A preview_diff in utf-8 should be decoded as utf-8."""
-        text = ''.join(six.unichr(x) for x in range(255))
+        text = ''.join(chr(x) for x in range(255))
         diff = ''.join(unified_diff([''], [text])).encode('utf-8')
         self.setPreviewDiff(diff)
         transaction.commit()
@@ -1424,7 +1424,7 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
 
     def test_preview_diff_all_chars(self):
         """preview_diff should work on diffs containing all possible bytes."""
-        text = b''.join(six.int2byte(x) for x in range(255))
+        text = b''.join(bytes((x,)) for x in range(255))
         diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
         self.setPreviewDiff(diff)
         transaction.commit()
@@ -1436,7 +1436,7 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
     def test_preview_diff_timeout(self):
         # The preview_diff will recover from a timeout set to get the
         # librarian content.
-        text = b''.join(six.int2byte(x) for x in range(255))
+        text = b''.join(bytes((x,)) for x in range(255))
         diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
         preview_diff = self.setPreviewDiff(diff)
         transaction.commit()
@@ -1456,7 +1456,7 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
         # The preview_diff will recover from a LookupError while getting the
         # librarian content.  (This can happen e.g. on staging replicas of
         # the production database.)
-        text = b''.join(six.int2byte(x) for x in range(255))
+        text = b''.join(bytes((x,)) for x in range(255))
         diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
         preview_diff = self.setPreviewDiff(diff)
         transaction.commit()
@@ -1675,7 +1675,7 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
         # contain a direct link to the Loggerhead diff rather than via the
         # webapp.  (This only works for public branches.)
         self.useFixture(
-            FeatureFixture({u'code.bzr.diff.disable_proxy': u'on'}))
+            FeatureFixture({'code.bzr.diff.disable_proxy': 'on'}))
         bmp = self.factory.makeBranchMergeProposal()
         view = create_initialized_view(bmp, '+index')
         cache = IJSONRequestCache(view.request)
@@ -1773,7 +1773,7 @@ class TestBranchMergeProposalBrowserView(BrowserTestCase):
     layer = DatabaseFunctionalLayer
 
     def setUp(self):
-        super(TestBranchMergeProposalBrowserView, self).setUp()
+        super().setUp()
         self.hosting_fixture = self.useFixture(GitHostingFixture())
 
     def test_prerequisite_bzr(self):
@@ -2551,7 +2551,7 @@ class TestBranchMergeProposalLinkBugViewMixin:
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
-        super(TestBranchMergeProposalLinkBugViewMixin, self).setUp()
+        super().setUp()
         self.bmp = self._makeBranchMergeProposal()
 
     def test_anonymous(self):
diff --git a/lib/lp/code/browser/tests/test_branchmergeproposallisting.py b/lib/lp/code/browser/tests/test_branchmergeproposallisting.py
index 7570612..7bc4b69 100644
--- a/lib/lp/code/browser/tests/test_branchmergeproposallisting.py
+++ b/lib/lp/code/browser/tests/test_branchmergeproposallisting.py
@@ -102,8 +102,7 @@ class TestProposalVoteSummaryMixin:
     def setUp(self):
         # Use an admin so we don't have to worry about launchpad.Edit
         # permissions on the merge proposals for adding comments.
-        super(TestProposalVoteSummaryMixin, self).setUp(
-            user="admin@xxxxxxxxxxxxx")
+        super().setUp(user="admin@xxxxxxxxxxxxx")
 
     def _createComment(self, proposal, reviewer=None, vote=None,
                        comment=_default):
@@ -437,7 +436,7 @@ class ProductContextMixin:
     label_describes_context = False
 
     def setUp(self):
-        super(ProductContextMixin, self).setUp()
+        super().setUp()
         self.git_target = self.bzr_target = self.context = (
             self.factory.makeProduct())
         self.user = self.git_target.owner
@@ -449,7 +448,7 @@ class ProjectGroupContextMixin:
     label_describes_context = False
 
     def setUp(self):
-        super(ProjectGroupContextMixin, self).setUp()
+        super().setUp()
         self.context = self.factory.makeProject()
         self.git_target = self.bzr_target = self.factory.makeProduct(
             projectgroup=self.context)
@@ -464,7 +463,7 @@ class DistributionSourcePackageContextMixin:
     label_describes_context = False
 
     def setUp(self):
-        super(DistributionSourcePackageContextMixin, self).setUp()
+        super().setUp()
         self.git_target = self.context = (
             self.factory.makeDistributionSourcePackage())
         with admin_logged_in():
@@ -487,7 +486,7 @@ class SourcePackageContextMixin:
     supports_git = False
 
     def setUp(self):
-        super(SourcePackageContextMixin, self).setUp()
+        super().setUp()
         self.bzr_target = self.context = self.factory.makeSourcePackage()
         self.user = self.context.distribution.owner
         self.owner = None
@@ -498,7 +497,7 @@ class PersonContextMixin:
     label_describes_context = False
 
     def setUp(self):
-        super(PersonContextMixin, self).setUp()
+        super().setUp()
         self.context = self.factory.makePerson()
         self.bzr_target = self.git_target = self.factory.makeProduct()
         self.user = self.bzr_target.owner
@@ -510,7 +509,7 @@ class PersonProductContextMixin:
     label_describes_context = False
 
     def setUp(self):
-        super(PersonProductContextMixin, self).setUp()
+        super().setUp()
         self.context = PersonProduct(
             self.factory.makePerson(), self.factory.makeProduct())
         self.bzr_target = self.git_target = self.context.product
@@ -523,7 +522,7 @@ class BranchContextMixin:
     supports_git = False
 
     def setUp(self):
-        super(BranchContextMixin, self).setUp()
+        super().setUp()
         self.bzr_target = self.factory.makeProduct()
         self.context = self.bzr_branch = self.factory.makeBranch(
             target=self.bzr_target)
@@ -536,7 +535,7 @@ class GitRefContextMixin:
     supports_bzr = False
 
     def setUp(self):
-        super(GitRefContextMixin, self).setUp()
+        super().setUp()
         self.git_target = self.factory.makeProduct()
         self.context = self.git_ref = self.factory.makeGitRefs(
             target=self.git_target)[0]
@@ -657,7 +656,7 @@ class ActiveReviewGroupsTestMixin:
     layer = DatabaseFunctionalLayer
 
     def setUp(self):
-        super(ActiveReviewGroupsTestMixin, self).setUp()
+        super().setUp()
         self.bmp = self._makeBranchMergeProposal(
             set_state=BranchMergeProposalStatus.NEEDS_REVIEW)
 
diff --git a/lib/lp/code/browser/tests/test_codereviewcomment.py b/lib/lp/code/browser/tests/test_codereviewcomment.py
index a70d0ad..458f67a 100644
--- a/lib/lp/code/browser/tests/test_codereviewcomment.py
+++ b/lib/lp/code/browser/tests/test_codereviewcomment.py
@@ -193,7 +193,7 @@ class TestCodeReviewCommentHtmlMixin:
         """The download view has the expected contents and header."""
         comment = self.makeCodeReviewComment(body='\u1234')
         browser = self.getViewBrowser(comment, view_name='+download')
-        contents = '\u1234'.encode('utf-8')
+        contents = '\u1234'.encode()
         self.assertEqual(contents, six.ensure_binary(browser.contents))
         self.assertEqual(
             'text/plain;charset=utf-8', browser.headers['Content-type'])
diff --git a/lib/lp/code/browser/tests/test_gitlisting.py b/lib/lp/code/browser/tests/test_gitlisting.py
index 49720de..409b535 100644
--- a/lib/lp/code/browser/tests/test_gitlisting.py
+++ b/lib/lp/code/browser/tests/test_gitlisting.py
@@ -323,7 +323,7 @@ class TestProductGitListingView(TestTargetGitListingView,
                                 TestCaseWithFactory):
 
     def setUp(self):
-        super(TestProductGitListingView, self).setUp()
+        super().setUp()
         self.owner = self.factory.makePerson(name="foowner")
         self.target = self.factory.makeProduct(name="foo", owner=self.owner,
                                                vcs=VCSType.GIT)
@@ -380,7 +380,7 @@ class TestPersonProductGitListingView(TestPersonTargetGitListingView,
                                       TestCaseWithFactory):
 
     def setUp(self):
-        super(TestPersonProductGitListingView, self).setUp()
+        super().setUp()
         self.owner = self.factory.makePerson(name="dev")
         self.target = self.factory.makeProduct(name="foo")
         self.target_path = "foo"
@@ -392,7 +392,7 @@ class TestDistributionSourcePackageGitListingView(TestTargetGitListingView,
                                                   TestCaseWithFactory):
 
     def setUp(self):
-        super(TestDistributionSourcePackageGitListingView, self).setUp()
+        super().setUp()
         self.owner = self.factory.makePerson(name="foowner")
         distro = self.factory.makeDistribution(name="foo", owner=self.owner)
         self.target = self.factory.makeDistributionSourcePackage(
@@ -406,7 +406,7 @@ class TestPersonDistributionSourcePackageGitListingView(
         TestPersonTargetGitListingView, TestCaseWithFactory):
 
     def setUp(self):
-        super(TestPersonDistributionSourcePackageGitListingView, self).setUp()
+        super().setUp()
         self.owner = self.factory.makePerson(name="dev")
         distro = self.factory.makeDistribution(name="foo", owner=self.owner)
         self.target = self.factory.makeDistributionSourcePackage(
@@ -433,7 +433,7 @@ class TestOCIProjectGitListingView(
         TestTargetGitListingView, TestCaseWithFactory):
 
     def setUp(self):
-        super(TestOCIProjectGitListingView, self).setUp()
+        super().setUp()
         self.owner = self.factory.makePerson(name="foowner")
         distro = self.factory.makeDistribution(name="foo", owner=self.owner)
         self.target = self.factory.makeOCIProject(
@@ -451,7 +451,7 @@ class TestPersonOCIProjectGitListingView(
         TestPersonTargetGitListingView, TestCaseWithFactory):
 
     def setUp(self):
-        super(TestPersonOCIProjectGitListingView, self).setUp()
+        super().setUp()
         self.owner = self.factory.makePerson(name="dev")
         distro = self.factory.makeDistribution(name="foo", owner=self.owner)
         self.target = self.factory.makeOCIProject(
@@ -548,7 +548,7 @@ class TestPlainGitListingView:
 class TestPersonGitListingView(TestPlainGitListingView, TestCaseWithFactory):
 
     def setUp(self):
-        super(TestPersonGitListingView, self).setUp()
+        super().setUp()
         self.context = self.user = self.owner = self.factory.makePerson()
         self.target = self.branch_target = None
 
@@ -570,7 +570,7 @@ class TestDistributionGitListingView(TestPlainGitListingView,
                                      TestCaseWithFactory):
 
     def setUp(self):
-        super(TestDistributionGitListingView, self).setUp()
+        super().setUp()
         self.target = self.factory.makeDistributionSourcePackage()
         self.factory.makeDistroSeries(distribution=self.target.distribution)
         self.branch_target = self.target.development_version
diff --git a/lib/lp/code/browser/tests/test_gitref.py b/lib/lp/code/browser/tests/test_gitref.py
index e8f5b25..3e3dd71 100644
--- a/lib/lp/code/browser/tests/test_gitref.py
+++ b/lib/lp/code/browser/tests/test_gitref.py
@@ -92,7 +92,7 @@ class TestGitRefNavigation(TestCaseWithFactory):
 class MissingCommitsNote(soupmatchers.Tag):
 
     def __init__(self):
-        super(MissingCommitsNote, self).__init__(
+        super().__init__(
             "missing commits note", "div",
             text="Some recent commit information could not be fetched.")
 
@@ -102,7 +102,7 @@ class TestGitRefView(BrowserTestCase):
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
-        super(TestGitRefView, self).setUp()
+        super().setUp()
         self.hosting_fixture = self.useFixture(GitHostingFixture())
 
     def _test_rendering(self, branch_name):
diff --git a/lib/lp/code/browser/tests/test_gitrepository.py b/lib/lp/code/browser/tests/test_gitrepository.py
index faca389..f065772 100644
--- a/lib/lp/code/browser/tests/test_gitrepository.py
+++ b/lib/lp/code/browser/tests/test_gitrepository.py
@@ -138,7 +138,7 @@ class TestGitRepositoryView(BrowserTestCase):
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
-        super(TestGitRepositoryView, self).setUp()
+        super().setUp()
         self.useFixture(FeatureFixture({GIT_REPOSITORY_FORK_ENABLED: 'on'}))
 
     def test_clone_instructions(self):
@@ -2153,7 +2153,7 @@ class TestGitRepositoryForkView(BrowserTestCase):
     layer = DatabaseFunctionalLayer
 
     def setUp(self):
-        super(TestGitRepositoryForkView, self).setUp()
+        super().setUp()
         self.useFixture(FeatureFixture({GIT_REPOSITORY_FORK_ENABLED: 'on'}))
 
     def getReposOwnedBy(self, user):
diff --git a/lib/lp/code/browser/tests/test_product.py b/lib/lp/code/browser/tests/test_product.py
index 4f9dfcc..cca51fc 100644
--- a/lib/lp/code/browser/tests/test_product.py
+++ b/lib/lp/code/browser/tests/test_product.py
@@ -431,7 +431,7 @@ class TestProductOverviewLinks(TestCaseWithFactory):
     layer = DatabaseFunctionalLayer
 
     def setUp(self, user=ANONYMOUS):
-        super(TestProductOverviewLinks, self).setUp(user)
+        super().setUp(user)
         self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: True}))
 
     def test_displays_create_and_list_snaps(self):
diff --git a/lib/lp/code/browser/tests/test_sourcepackagerecipe.py b/lib/lp/code/browser/tests/test_sourcepackagerecipe.py
index a54af33..281b225 100644
--- a/lib/lp/code/browser/tests/test_sourcepackagerecipe.py
+++ b/lib/lp/code/browser/tests/test_sourcepackagerecipe.py
@@ -239,7 +239,7 @@ class TestCaseForRecipe(BrowserTestCase):
 
     def setUp(self):
         """Provide useful defaults."""
-        super(TestCaseForRecipe, self).setUp()
+        super().setUp()
         self.chef = self.factory.makePerson(
             displayname='Master Chef', name='chef')
         self.user = self.chef
@@ -844,7 +844,7 @@ class TestSourcePackageRecipeAddViewGit(
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
-        super(TestSourcePackageRecipeAddViewGit, self).setUp()
+        super().setUp()
         self.useFixture(GitHostingFixture())
 
     def makeBranchAndPackage(self):
@@ -1699,7 +1699,7 @@ class TestSourcePackageRecipeBuildViewMixin:
 
     def setUp(self):
         """Provide useful defaults."""
-        super(TestSourcePackageRecipeBuildViewMixin, self).setUp()
+        super().setUp()
         self.user = self.factory.makePerson(
             displayname='Owner', name='build-owner')
 
diff --git a/lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py b/lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py
index 9e0bbd7..4e961fc 100644
--- a/lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py
+++ b/lib/lp/code/browser/tests/test_sourcepackagerecipebuild.py
@@ -55,7 +55,7 @@ class TestSourcePackageRecipeBuild(BrowserTestCase):
 
     def setUp(self):
         """Provide useful defaults."""
-        super(TestSourcePackageRecipeBuild, self).setUp()
+        super().setUp()
         self.admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
         self.chef = self.factory.makePerson(
             displayname='Master Chef', name='chef')
diff --git a/lib/lp/code/browser/widgets/branchtarget.py b/lib/lp/code/browser/widgets/branchtarget.py
index 55b5c95..8a5d36f 100644
--- a/lib/lp/code/browser/widgets/branchtarget.py
+++ b/lib/lp/code/browser/widgets/branchtarget.py
@@ -46,7 +46,7 @@ class BranchTargetWidget(BrowserWidget, InputWidget):
             return
         fields = [
             Choice(
-                __name__='product', title=u'Project',
+                __name__='product', title='Project',
                 required=True, vocabulary='Product'),
             ]
         for field in fields:
@@ -126,7 +126,7 @@ class BranchTargetWidget(BrowserWidget, InputWidget):
                 self.getInputValue()
         except InputErrors as error:
             self._error = error
-        return super(BranchTargetWidget, self).error()
+        return super().error()
 
     def __call__(self):
         """See zope.formlib.interfaces.IBrowserWidget."""
diff --git a/lib/lp/code/browser/widgets/gitgrantee.py b/lib/lp/code/browser/widgets/gitgrantee.py
index 0b1b8f4..ea49874 100644
--- a/lib/lp/code/browser/widgets/gitgrantee.py
+++ b/lib/lp/code/browser/widgets/gitgrantee.py
@@ -62,7 +62,7 @@ class GitGranteeField(Field):
     """A field that holds a Git access grantee."""
 
     def __init__(self, rule, *args, **kwargs):
-        super(GitGranteeField, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.rule = rule
 
     def constraint(self, value):
@@ -78,7 +78,7 @@ class GitGranteeField(Field):
 class GitGranteePersonDisplayWidget(BrowserWidget):
 
     def __init__(self, context, vocabulary, request):
-        super(GitGranteePersonDisplayWidget, self).__init__(context, request)
+        super().__init__(context, request)
 
     def __call__(self):
         if self._renderedValueSet():
@@ -99,7 +99,7 @@ class GitGranteeWidgetBase(BrowserWidget):
             return
         fields = [
             Choice(
-                __name__="person", title=u"Person",
+                __name__="person", title="Person",
                 required=False, vocabulary="ValidPersonOrTeam"),
             ]
         if self._read_only:
@@ -181,7 +181,7 @@ class GitGranteeWidget(GitGranteeWidgetBase, InputWidget):
 
     @property
     def show_options(self):
-        show_options = super(GitGranteeWidget, self).show_options
+        show_options = super().show_options
         # Hide options that indicate unique grantee_types (e.g.
         # repository_owner) if they already exist for the context rule.
         if (show_options["repository_owner"] and
@@ -241,4 +241,4 @@ class GitGranteeWidget(GitGranteeWidgetBase, InputWidget):
                 self.getInputValue()
         except InputErrors as error:
             self._error = error
-        return super(GitGranteeWidget, self).error()
+        return super().error()
diff --git a/lib/lp/code/browser/widgets/gitref.py b/lib/lp/code/browser/widgets/gitref.py
index 036f46b..9ffd54e 100644
--- a/lib/lp/code/browser/widgets/gitref.py
+++ b/lib/lp/code/browser/widgets/gitref.py
@@ -5,7 +5,6 @@ __all__ = [
     'GitRefWidget',
     ]
 
-import six
 from zope.browserpage import ViewPageTemplateFile
 from zope.formlib.interfaces import (
     ConversionError,
@@ -48,7 +47,7 @@ class GitRepositoryField(Choice):
     """
 
     def __init__(self, allow_external=False, **kwargs):
-        super(GitRepositoryField, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         if allow_external:
             self._uri_field = URIField(
                 __name__=self.__name__, title=self.title,
@@ -62,22 +61,22 @@ class GitRepositoryField(Choice):
             self._uri_field = None
 
     def set(self, object, value):
-        if self._uri_field is not None and isinstance(value, six.string_types):
+        if self._uri_field is not None and isinstance(value, str):
             try:
                 self._uri_field.set(object, value)
                 return
             except LaunchpadValidationError:
                 pass
-        super(GitRepositoryField, self).set(object, value)
+        super().set(object, value)
 
     def _validate(self, value):
-        if self._uri_field is not None and isinstance(value, six.string_types):
+        if self._uri_field is not None and isinstance(value, str):
             try:
                 self._uri_field._validate(value)
                 return
             except LaunchpadValidationError:
                 pass
-        super(GitRepositoryField, self)._validate(value)
+        super()._validate(value)
 
 
 class GitRepositoryPickerWidget(VocabularyPickerWidget):
@@ -89,8 +88,7 @@ class GitRepositoryPickerWidget(VocabularyPickerWidget):
                 return [tokens[0]]
             except LaunchpadValidationError:
                 pass
-        return super(GitRepositoryPickerWidget, self).convertTokensToValues(
-            tokens)
+        return super().convertTokensToValues(tokens)
 
 
 @implementer(IMultiLineWidgetLayout, IAlwaysSubmittedWidget, IInputWidget)
@@ -113,11 +111,11 @@ class GitRefWidget(BrowserWidget, InputWidget):
         path_vocabulary = "GitBranch" if self.require_branch else "GitRef"
         fields = [
             GitRepositoryField(
-                __name__="repository", title=u"Repository",
+                __name__="repository", title="Repository",
                 required=self.context.required, vocabulary="GitRepository",
                 allow_external=self.allow_external),
             Choice(
-                __name__="path", title=u"Branch",
+                __name__="path", title="Branch",
                 required=self.context.required,
                 vocabulary=path_vocabulary),
             ]
@@ -227,7 +225,7 @@ class GitRefWidget(BrowserWidget, InputWidget):
                 self.getInputValue()
         except InputErrors as error:
             self._error = error
-        return super(GitRefWidget, self).error()
+        return super().error()
 
     def __call__(self):
         """See `IBrowserWidget`."""
diff --git a/lib/lp/code/browser/widgets/gitrepositorytarget.py b/lib/lp/code/browser/widgets/gitrepositorytarget.py
index 50f964a..0e1028a 100644
--- a/lib/lp/code/browser/widgets/gitrepositorytarget.py
+++ b/lib/lp/code/browser/widgets/gitrepositorytarget.py
@@ -64,14 +64,14 @@ class GitRepositoryTargetWidgetBase(BrowserWidget):
             package_vocab = "BinaryAndSourcePackageName"
         fields = [
             Choice(
-                __name__="project", title=u"Project",
+                __name__="project", title="Project",
                 required=True, vocabulary="Product"),
             Choice(
-                __name__="distribution", title=u"Distribution",
+                __name__="distribution", title="Distribution",
                 required=True, vocabulary="Distribution",
                 default=getUtility(ILaunchpadCelebrities).ubuntu),
             Choice(
-                __name__="package", title=u"Package",
+                __name__="package", title="Package",
                 required=False, vocabulary=package_vocab),
             ]
         if not self._read_only:
@@ -227,4 +227,4 @@ class GitRepositoryTargetWidget(GitRepositoryTargetWidgetBase, InputWidget):
                 self.getInputValue()
         except InputErrors as error:
             self._error = error
-        return super(GitRepositoryTargetWidget, self).error()
+        return super().error()
diff --git a/lib/lp/code/browser/widgets/tests/test_branchtargetwidget.py b/lib/lp/code/browser/widgets/tests/test_branchtargetwidget.py
index 5c65934..75104b1 100644
--- a/lib/lp/code/browser/widgets/tests/test_branchtargetwidget.py
+++ b/lib/lp/code/browser/widgets/tests/test_branchtargetwidget.py
@@ -53,10 +53,10 @@ class LaunchpadTargetWidgetTestCase(TestCaseWithFactory):
         }
 
     def setUp(self):
-        super(LaunchpadTargetWidgetTestCase, self).setUp()
+        super().setUp()
         self.product = self.factory.makeProduct('pting')
         field = Reference(
-            __name__='target', schema=Interface, title=u'target')
+            __name__='target', schema=Interface, title='target')
         field = field.bind(Thing())
         request = LaunchpadTestRequest()
         self.widget = BranchTargetWidget(field, request)
diff --git a/lib/lp/code/browser/widgets/tests/test_gitgrantee.py b/lib/lp/code/browser/widgets/tests/test_gitgrantee.py
index 23553ea..7028550 100644
--- a/lib/lp/code/browser/widgets/tests/test_gitgrantee.py
+++ b/lib/lp/code/browser/widgets/tests/test_gitgrantee.py
@@ -34,7 +34,7 @@ class TestGitGranteeWidgetBase:
     layer = DatabaseFunctionalLayer
 
     def setUp(self):
-        super(TestGitGranteeWidgetBase, self).setUp()
+        super().setUp()
         [self.ref] = self.factory.makeGitRefs()
         self.rule = self.factory.makeGitRule(
             repository=self.ref.repository, ref_pattern=self.ref.path)
@@ -192,7 +192,7 @@ class TestGitGranteeWidget(TestGitGranteeWidgetBase, TestCaseWithFactory):
         ]
 
     def setUp(self):
-        super(TestGitGranteeWidget, self).setUp()
+        super().setUp()
         self.person = self.factory.makePerson()
 
     def test_show_options_repository_owner_grant_already_exists(self):
diff --git a/lib/lp/code/browser/widgets/tests/test_gitrefwidget.py b/lib/lp/code/browser/widgets/tests/test_gitrefwidget.py
index a238266..dbdd295 100644
--- a/lib/lp/code/browser/widgets/tests/test_gitrefwidget.py
+++ b/lib/lp/code/browser/widgets/tests/test_gitrefwidget.py
@@ -52,9 +52,9 @@ class TestGitRefWidget(WithScenarios, TestCaseWithFactory):
         ]
 
     def setUp(self):
-        super(TestGitRefWidget, self).setUp()
+        super().setUp()
         field = Reference(
-            __name__="git_ref", schema=Interface, title=u"Git reference")
+            __name__="git_ref", schema=Interface, title="Git reference")
         self.context = Thing()
         field = field.bind(self.context)
         request = LaunchpadTestRequest()
@@ -202,7 +202,7 @@ class TestGitRefWidget(WithScenarios, TestCaseWithFactory):
         [ref] = self.factory.makeGitRefs()
         form = {
             "field.git_ref.repository": ref.repository.unique_name,
-            "field.git_ref.path": u"non-existent",
+            "field.git_ref.path": "non-existent",
             }
         self.assertGetInputValueError(
             form,
diff --git a/lib/lp/code/browser/widgets/tests/test_gitrepositorytargetwidget.py b/lib/lp/code/browser/widgets/tests/test_gitrepositorytargetwidget.py
index 745b42f..aee909a 100644
--- a/lib/lp/code/browser/widgets/tests/test_gitrepositorytargetwidget.py
+++ b/lib/lp/code/browser/widgets/tests/test_gitrepositorytargetwidget.py
@@ -55,15 +55,14 @@ class TestGitRepositoryTargetWidgetBase:
     layer = DatabaseFunctionalLayer
 
     def setUp(self):
-        super(TestGitRepositoryTargetWidgetBase, self).setUp()
+        super().setUp()
         self.distribution = self.factory.makeDistribution(name="fnord")
         distroseries = self.factory.makeDistroSeries(
             distribution=self.distribution)
         self.package = self.factory.makeDSPCache(
             distroseries=distroseries, sourcepackagename="snarf")
         self.project = self.factory.makeProduct("pting")
-        field = Reference(
-            __name__="target", schema=Interface, title=u"target")
+        field = Reference(__name__="target", schema=Interface, title="target")
         self.context = Thing()
         field = field.bind(self.context)
         request = LaunchpadTestRequest()
@@ -110,7 +109,7 @@ class TestGitRepositoryTargetWidgetBase:
     def test_setUpSubWidgets_dsp_picker_feature_flag(self):
         # The DistributionSourcePackageVocabulary is used when the
         # disclosure.dsp_picker.enabled is true.
-        with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
+        with FeatureFixture({"disclosure.dsp_picker.enabled": "on"}):
             self.widget.setUpSubWidgets()
         self.assertIsInstance(
             self.widget.package_widget.context.vocabulary,
@@ -338,7 +337,7 @@ class TestGitRepositoryTargetWidget(
         form = self.form
         form["field.target"] = "package"
         self.widget.request = LaunchpadTestRequest(form=form)
-        with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
+        with FeatureFixture({"disclosure.dsp_picker.enabled": "on"}):
             self.widget.setUpSubWidgets()
             self.assertEqual(self.package, self.widget.getInputValue())