← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:py3-dict-views into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:py3-dict-views into launchpad:master.

Commit message:
Don't assume that dict.keys() or dict.values() return lists

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/396832
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-dict-views into launchpad:master.
diff --git a/lib/lp/archivepublisher/tests/test_dominator.py b/lib/lp/archivepublisher/tests/test_dominator.py
index b35596e..c19f8b9 100755
--- a/lib/lp/archivepublisher/tests/test_dominator.py
+++ b/lib/lp/archivepublisher/tests/test_dominator.py
@@ -914,7 +914,7 @@ class TestDominatorMethods(TestCaseWithFactory):
                 pocket=pocket, status=status))
             for status in PackagePublishingStatus.items)
         published_spph = spphs[PackagePublishingStatus.PUBLISHED]
-        dominator = self.makeDominator(spphs.values())
+        dominator = self.makeDominator(list(spphs.values()))
         self.assertContentEqual(
             [(published_spph.sourcepackagerelease.sourcepackagename.name, 1)],
             dominator.findPublishedSourcePackageNames(series, pocket))
@@ -999,7 +999,7 @@ class TestDominatorMethods(TestCaseWithFactory):
                 sourcepackagerelease=self.factory.makeSourcePackageRelease(
                     sourcepackagename=package)))
             for status in PackagePublishingStatus.items)
-        dominator = self.makeDominator(spphs.values())
+        dominator = self.makeDominator(list(spphs.values()))
         self.assertContentEqual(
             [spphs[PackagePublishingStatus.PUBLISHED]],
             dominator.findPublishedSPPHs(series, pocket, package.name))
diff --git a/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py b/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
index 9339459..c8077b5 100644
--- a/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
+++ b/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
@@ -258,7 +258,7 @@ class TestPublishFTPMasterScript(
         distro = self.makeDistroWithPublishDirectory()
         script = self.makeScript(distro)
         script.setUp()
-        self.assertEqual([distro], script.getConfigs().keys())
+        self.assertEqual([distro], list(script.getConfigs()))
 
     def test_getConfigs_skips_configless_distros(self):
         distro = self.factory.makeDistribution(no_pubconf=True)
diff --git a/lib/lp/archiveuploader/nascentuploadfile.py b/lib/lp/archiveuploader/nascentuploadfile.py
index a5b9090..9e48cc3 100644
--- a/lib/lp/archiveuploader/nascentuploadfile.py
+++ b/lib/lp/archiveuploader/nascentuploadfile.py
@@ -745,7 +745,7 @@ class BaseBinaryUploadFile(PackageUploadFile):
         try:
             deb_file.control.go(tar_checker.callback)
             deb_file.data.go(tar_checker.callback)
-            future_files = tar_checker.future_files.keys()
+            future_files = list(tar_checker.future_files)
             if future_files:
                 first_file = future_files[0]
                 timestamp = time.ctime(tar_checker.future_files[first_file])
@@ -755,7 +755,7 @@ class BaseBinaryUploadFile(PackageUploadFile):
                      % (self.filename, len(future_files), first_file,
                         timestamp))
 
-            ancient_files = tar_checker.ancient_files.keys()
+            ancient_files = list(tar_checker.ancient_files)
             if ancient_files:
                 first_file = ancient_files[0]
                 timestamp = time.ctime(tar_checker.ancient_files[first_file])
diff --git a/lib/lp/blueprints/browser/tests/test_person_upcomingwork.py b/lib/lp/blueprints/browser/tests/test_person_upcomingwork.py
index 5f6673c..8aa2365 100644
--- a/lib/lp/blueprints/browser/tests/test_person_upcomingwork.py
+++ b/lib/lp/blueprints/browser/tests/test_person_upcomingwork.py
@@ -64,7 +64,7 @@ class Test_getWorkItemsDueBefore(TestCaseWithFactory):
             self.team, self.current_milestone.dateexpected, user=None)
 
         self.assertEqual(
-            [self.current_milestone.dateexpected], workitems.keys())
+            [self.current_milestone.dateexpected], list(workitems))
         containers = workitems[self.current_milestone.dateexpected]
         # We have one container for the work item from the spec and another
         # one for the bugtask.
@@ -96,7 +96,7 @@ class Test_getWorkItemsDueBefore(TestCaseWithFactory):
             self.team, self.current_milestone.dateexpected, user=None)
 
         self.assertEqual(
-            [self.current_milestone.dateexpected], workitems.keys())
+            [self.current_milestone.dateexpected], list(workitems))
         containers = workitems[self.current_milestone.dateexpected]
         self.assertEqual(1, len(containers))
         [container] = containers
@@ -120,7 +120,7 @@ class Test_getWorkItemsDueBefore(TestCaseWithFactory):
             self.team, self.current_milestone.dateexpected, user=None)
 
         self.assertEqual(
-            [self.current_milestone.dateexpected], workitems.keys())
+            [self.current_milestone.dateexpected], list(workitems))
         containers = workitems[self.current_milestone.dateexpected]
         self.assertEqual(1, len(containers))
         [container] = containers
diff --git a/lib/lp/bugs/browser/bugtask.py b/lib/lp/bugs/browser/bugtask.py
index 308f52b..f21c742 100644
--- a/lib/lp/bugs/browser/bugtask.py
+++ b/lib/lp/bugs/browser/bugtask.py
@@ -1390,7 +1390,7 @@ class BugTaskEditView(LaunchpadEditFormView, BugTaskBugWatchMixin,
         # Save the field names we extract from the form in a separate
         # list, because we modify this list of names later if the
         # bugtask is reassigned to a different product.
-        field_names = data.keys()
+        field_names = list(data)
         new_values = data.copy()
         data_to_apply = data.copy()
 
diff --git a/lib/lp/bugs/browser/structuralsubscription.py b/lib/lp/bugs/browser/structuralsubscription.py
index b250906..f8b7eb1 100644
--- a/lib/lp/bugs/browser/structuralsubscription.py
+++ b/lib/lp/bugs/browser/structuralsubscription.py
@@ -527,8 +527,7 @@ def expose_user_subscriptions_to_js(user, subscriptions, request):
                 can_mute=filter.isMuteAllowed(user),
                 is_muted=filter.muted(user) is not None,
                 target_title=target.title))
-    info = info.values()
-    info.sort(key=itemgetter('target_url'))
+    info = sorted(info.values(), key=itemgetter('target_url'))
     IJSONRequestCache(request).objects['subscription_info'] = info
 
 
diff --git a/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py b/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py
index 81c4f0e..4faa851 100644
--- a/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py
+++ b/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py
@@ -174,7 +174,7 @@ class TestWebserviceAccessToBugAttachmentFiles(TestCaseWithFactory):
         mo = re.search(r'^/\d+/foo\.txt$', parsed_url.path)
         self.assertIsNot(None, mo)
         params = parse_qs(parsed_url.query)
-        self.assertEqual(['token'], params.keys())
+        self.assertEqual(['token'], list(params))
 
         # Our test environment does not support wildcard DNS.  Work around
         # this.
diff --git a/lib/lp/bugs/doc/externalbugtracker-rt.txt b/lib/lp/bugs/doc/externalbugtracker-rt.txt
index 0e06d00..94771cb 100644
--- a/lib/lp/bugs/doc/externalbugtracker-rt.txt
+++ b/lib/lp/bugs/doc/externalbugtracker-rt.txt
@@ -132,7 +132,7 @@ the bugs will be fetched one-at-a-time:
     ...     rt.initializeRemoteBugDB([1585])
     GET http://example.com/REST/1.0/ticket/1585/show
 
-    >>> rt.bugs.keys()
+    >>> list(rt.bugs)
     [1585]
 
 If there are more than batch_query_threshold bugs to update then they are
diff --git a/lib/lp/bugs/model/bugwatch.py b/lib/lp/bugs/model/bugwatch.py
index fca7a1c..1cc3a16 100644
--- a/lib/lp/bugs/model/bugwatch.py
+++ b/lib/lp/bugs/model/bugwatch.py
@@ -626,9 +626,9 @@ class BugWatchSet:
         # or that have an item_id parameter containing the bug ID.
         if path not in ('/bugs/', '/bugs/index.php'):
             return None
-        if len(query) == 1 and query.values()[0] is None:
+        if len(query) == 1 and list(query.values())[0] is None:
             # The query string is just a bare ID.
-            remote_bug = query.keys()[0]
+            remote_bug = list(query)[0]
         elif 'item_id' in query:
             remote_bug = query['item_id']
         else:
diff --git a/lib/lp/buildmaster/doc/builder.txt b/lib/lp/buildmaster/doc/builder.txt
index 7fe82f7..85414de 100644
--- a/lib/lp/buildmaster/doc/builder.txt
+++ b/lib/lp/buildmaster/doc/builder.txt
@@ -108,7 +108,7 @@ There are no 'amd64' build queue entries.
 
 The virtualized build queue for 386 is also empty.
 
-    >>> queue_sizes['virt'].keys()
+    >>> list(queue_sizes['virt'])
     []
 
 The queue size is not affect by builds target to disabled
@@ -128,7 +128,7 @@ We will temporarily disable the ubuntu primary archive.
 That done, the non-virtualized queue for i386 becomes empty.
 
     >>> queue_sizes = builderset.getBuildQueueSizes()
-    >>> queue_sizes['nonvirt'].keys()
+    >>> list(queue_sizes['nonvirt'])
     []
 
 Let's re-enable the ubuntu primary archive.
diff --git a/lib/lp/buildmaster/tests/mock_slaves.py b/lib/lp/buildmaster/tests/mock_slaves.py
index 2e935e4..f2cf744 100644
--- a/lib/lp/buildmaster/tests/mock_slaves.py
+++ b/lib/lp/buildmaster/tests/mock_slaves.py
@@ -111,7 +111,7 @@ class OkSlave:
 
     def build(self, buildid, buildtype, chroot, filemap, args):
         self.call_log.append(
-            ('build', buildid, buildtype, chroot, filemap.keys(), args))
+            ('build', buildid, buildtype, chroot, list(filemap), args))
         return defer.succeed(('BuildStatus.BUILDING', buildid))
 
     def echo(self, *args):
diff --git a/lib/lp/code/adapters/branch.py b/lib/lp/code/adapters/branch.py
index 285424d..34cb1a7 100644
--- a/lib/lp/code/adapters/branch.py
+++ b/lib/lp/code/adapters/branch.py
@@ -131,7 +131,7 @@ class BranchMergeProposalDelta:
         if merge_proposal_delta is not None:
             merge_proposal_event = ObjectModifiedEvent(
                 merge_proposal, merge_proposal_snapshot,
-                vars(merge_proposal_delta).keys())
+                list(vars(merge_proposal_delta)))
             notify(merge_proposal_event)
 
 
diff --git a/lib/lp/code/doc/branch-xmlrpc.txt b/lib/lp/code/doc/branch-xmlrpc.txt
index e7da5ad..ba2981b 100644
--- a/lib/lp/code/doc/branch-xmlrpc.txt
+++ b/lib/lp/code/doc/branch-xmlrpc.txt
@@ -27,7 +27,7 @@ On success, resolve_lp_path returns a dict containing a single key,
 
     >>> results = public_codehosting_api.resolve_lp_path(
     ...     '~vcs-imports/evolution/main')
-    >>> print(results.keys())
+    >>> print(list(results))
     ['urls']
 
 
diff --git a/lib/lp/code/model/branchcollection.py b/lib/lp/code/model/branchcollection.py
index 0ab5fd8..98a43b7 100644
--- a/lib/lp/code/model/branchcollection.py
+++ b/lib/lp/code/model/branchcollection.py
@@ -438,7 +438,7 @@ class GenericBranchCollection:
             "candidate_branches",
             Select(
                 Branch.id,
-                tables=[Branch] + self._tables.values(),
+                tables=[Branch] + list(self._tables.values()),
                 where=And(*expressions) if expressions else True))
         expressions = [SQL("""
             source_branch IN (SELECT id FROM candidate_branches) AND
diff --git a/lib/lp/code/model/gitcollection.py b/lib/lp/code/model/gitcollection.py
index f9466a9..37cf78d 100644
--- a/lib/lp/code/model/gitcollection.py
+++ b/lib/lp/code/model/gitcollection.py
@@ -364,7 +364,7 @@ class GenericGitCollection:
             "candidate_repositories",
             Select(
                 GitRepository.id,
-                tables=[GitRepository] + self._tables.values(),
+                tables=[GitRepository] + list(self._tables.values()),
                 where=And(*expressions) if expressions else True))
         expressions = [SQL("""
             source_git_repository IN
diff --git a/lib/lp/code/model/gitjob.py b/lib/lp/code/model/gitjob.py
index 1eb87da..2bec89f 100644
--- a/lib/lp/code/model/gitjob.py
+++ b/lib/lp/code/model/gitjob.py
@@ -222,7 +222,7 @@ class GitRefScanJob(GitJobDerived):
     def composeWebhookPayload(repository, old_refs_commits, refs_to_upsert,
                               refs_to_remove):
         ref_changes = {}
-        for ref in refs_to_upsert.keys() + list(refs_to_remove):
+        for ref in list(refs_to_upsert) + list(refs_to_remove):
             old = (
                 {"commit_sha1": old_refs_commits[ref]}
                 if ref in old_refs_commits else None)
diff --git a/lib/lp/codehosting/inmemory.py b/lib/lp/codehosting/inmemory.py
index 19aca1e..4de60fd 100644
--- a/lib/lp/codehosting/inmemory.py
+++ b/lib/lp/codehosting/inmemory.py
@@ -88,7 +88,7 @@ class FakeStore:
         branch_id = kwargs.pop('id')
         assert len(kwargs) == 1, (
             'Expected only id and one other. Got %r' % kwargs)
-        attribute = kwargs.keys()[0]
+        attribute = list(kwargs)[0]
         expected_value = kwargs[attribute]
         branch = self._object_set.get(branch_id)
         if branch is None:
diff --git a/lib/lp/registry/scripts/tests/test_populate_distroseriesdiff.py b/lib/lp/registry/scripts/tests/test_populate_distroseriesdiff.py
index 3825fa0..6882c96 100644
--- a/lib/lp/registry/scripts/tests/test_populate_distroseriesdiff.py
+++ b/lib/lp/registry/scripts/tests/test_populate_distroseriesdiff.py
@@ -565,8 +565,7 @@ class TestPopulateDistroSeriesDiffScript(TestCaseWithFactory, FactoryHelper):
             '--distribution', spph.distroseries.distribution.name,
             '--series', spph.distroseries.name,
             ])
-        self.assertEqual(
-            [spph.distroseries], script.getDistroSeries().keys())
+        self.assertEqual([spph.distroseries], list(script.getDistroSeries()))
 
     def test_finds_all_distroseries(self):
         spphs = []
diff --git a/lib/lp/registry/stories/webservice/xx-source-package.txt b/lib/lp/registry/stories/webservice/xx-source-package.txt
index 79b2402..b920169 100644
--- a/lib/lp/registry/stories/webservice/xx-source-package.txt
+++ b/lib/lp/registry/stories/webservice/xx-source-package.txt
@@ -92,8 +92,9 @@ we'll get the new branch.
 
     >>> linked_branches = webservice.named_get(
     ...     evolution['self_link'], 'linkedBranches').jsonBody()
-    >>> print(linked_branches.keys())
-    [u'RELEASE']
+    >>> for pocket in linked_branches:
+    ...     print(pocket)
+    RELEASE
     >>> branch = linked_branches[u'RELEASE']
     >>> print(branch['unique_name'])
     ~devo/my-distro/.../branch
diff --git a/lib/lp/registry/tests/test_mailinglist.py b/lib/lp/registry/tests/test_mailinglist.py
index 837d79f..f5416f4 100644
--- a/lib/lp/registry/tests/test_mailinglist.py
+++ b/lib/lp/registry/tests/test_mailinglist.py
@@ -572,7 +572,7 @@ class MailingListSetTestCase(TestCaseWithFactory):
             team2.mailing_list.transitionToStatus(MailingListStatus.INACTIVE)
         team_names = [team1.name, team2.name]
         result = self.mailing_list_set.getSenderAddresses(team_names)
-        self.assertEqual([team1.name], result.keys())
+        self.assertEqual([team1.name], list(result))
 
     def test_getSubscribedAddresses_dict_keys(self):
         # getSubscribedAddresses() returns a dict of team names.
@@ -693,7 +693,7 @@ class MailingListSetTestCase(TestCaseWithFactory):
             team2.mailing_list.transitionToStatus(MailingListStatus.INACTIVE)
         team_names = [team1.name, team2.name]
         result = self.mailing_list_set.getSubscribedAddresses(team_names)
-        self.assertEqual([team1.name], result.keys())
+        self.assertEqual([team1.name], list(result))
 
     def test_getSubscribedAddresses_after_rejoin(self):
         # A users subscription is preserved when a user leaved a team, then
diff --git a/lib/lp/registry/tests/test_mailinglistapi.py b/lib/lp/registry/tests/test_mailinglistapi.py
index d0f768b..52ac452 100644
--- a/lib/lp/registry/tests/test_mailinglistapi.py
+++ b/lib/lp/registry/tests/test_mailinglistapi.py
@@ -95,7 +95,7 @@ class MailingListAPITestCase(TestCaseWithFactory):
         with person_logged_in(self.member):
             self.member.hide_email_addresses = True
         all_info = self.api.getMembershipInformation([self.team.name])
-        self.assertEqual(['team-a'], all_info.keys())
+        self.assertEqual(['team-a'], list(all_info))
         self.assertEqual(self.team_expected, sorted(all_info[self.team.name]))
 
     def test_getMembershipInformation_remote_public_archive(self):
diff --git a/lib/lp/scripts/tests/test_garbo.py b/lib/lp/scripts/tests/test_garbo.py
index ffc5bbf..abbfe97 100644
--- a/lib/lp/scripts/tests/test_garbo.py
+++ b/lib/lp/scripts/tests/test_garbo.py
@@ -1251,7 +1251,7 @@ class TestGarbo(FakeAdapterMixin, TestCaseWithFactory):
             potmsgset_pofile[translation_message.potmsgset.id] = pofile.id
         transaction.commit()
         store = IMasterStore(POTMsgSet)
-        test_ids = potmsgset_pofile.keys()
+        test_ids = list(potmsgset_pofile)
         obsolete_msgsets = store.find(
             POTMsgSet,
             In(TranslationTemplateItem.potmsgsetID, test_ids),
diff --git a/lib/lp/services/job/tests/test_runner.py b/lib/lp/services/job/tests/test_runner.py
index ec8dd11..8981b66 100644
--- a/lib/lp/services/job/tests/test_runner.py
+++ b/lib/lp/services/job/tests/test_runner.py
@@ -229,7 +229,7 @@ class TestJobRunner(StatsMixin, TestCaseWithFactory):
         self.assertEqual(JobStatus.COMPLETED, job_2.job.status)
         oops = self.oopses[-1]
         self.assertIn('Fake exception.  Foobar, I say!', oops['tb_text'])
-        self.assertEqual(["{'foo': 'bar'}"], oops['req_vars'].values())
+        self.assertEqual(["{'foo': 'bar'}"], list(oops['req_vars'].values()))
         self.assertEqual(
             self.stats_client.incr.call_args_list[0][0],
             ('job.start_count,type=NullJob,env=test',))
@@ -251,7 +251,7 @@ class TestJobRunner(StatsMixin, TestCaseWithFactory):
         runner = JobRunner([job_1, job_2])
         runner.runAll()
         oops = self.oopses[-1]
-        self.assertEqual(["{'foo': 'bar'}"], oops['req_vars'].values())
+        self.assertEqual(["{'foo': 'bar'}"], list(oops['req_vars'].values()))
 
     def test_runAll_aborts_transaction_on_error(self):
         """runAll should abort the transaction on oops."""
diff --git a/lib/lp/services/testing/tests/test_customresult.py b/lib/lp/services/testing/tests/test_customresult.py
index 0c5c8c3..31ee6d7 100644
--- a/lib/lp/services/testing/tests/test_customresult.py
+++ b/lib/lp/services/testing/tests/test_customresult.py
@@ -9,9 +9,8 @@ import string
 import tempfile
 import unittest
 
-from testtools import TestCase
-
 from lp.services.testing.customresult import filter_tests
+from lp.testing import TestCase
 from lp.testing.layers import BaseLayer
 
 
@@ -155,6 +154,6 @@ class TestFilterTests(TestCase):
             results = do_filter({'layer1': suite1,
                                  None: suite2})
         self.assertEqual(2, len(results))
-        self.assertEqual([None, 'layer1'], sorted(results.keys()))
+        self.assertContentEqual([None, 'layer1'], results.keys())
         self.assertEqual(['a', 'b'], [t.id() for t in results['layer1']])
         self.assertEqual(['y', 'z'], [t.id() for t in results[None]])
diff --git a/lib/lp/services/webapp/tests/test_menu.py b/lib/lp/services/webapp/tests/test_menu.py
index 8545adb..c30d5a3 100644
--- a/lib/lp/services/webapp/tests/test_menu.py
+++ b/lib/lp/services/webapp/tests/test_menu.py
@@ -69,7 +69,7 @@ class TestMenuBaseLinkCaching(TestCase):
         link = menu._get_link('test_link')
         request = get_current_browser_request()
         cache = request.annotations.get(MENU_ANNOTATION_KEY)
-        self.assertEqual([link], cache.values())
+        self.assertEqual([link], list(cache.values()))
 
     def test_cache_key_is_unique(self):
         # The cache key must include the link name, the context of the link
@@ -82,4 +82,4 @@ class TestMenuBaseLinkCaching(TestCase):
             MENU_ANNOTATION_KEY)
         self.assertEqual(len(cache.keys()), 1)
         self.assertContentEqual(
-            cache.keys()[0], (menu.__class__, context, 'test_link'))
+            list(cache.keys())[0], (menu.__class__, context, 'test_link'))
diff --git a/lib/lp/services/webapp/tests/test_pgsession.py b/lib/lp/services/webapp/tests/test_pgsession.py
index 4cfa50a..971ad4c 100644
--- a/lib/lp/services/webapp/tests/test_pgsession.py
+++ b/lib/lp/services/webapp/tests/test_pgsession.py
@@ -6,7 +6,6 @@
 __metaclass__ = type
 
 import hashlib
-from unittest import TestCase
 
 from zope.publisher.browser import TestRequest
 from zope.security.management import (
@@ -22,6 +21,7 @@ from lp.services.webapp.pgsession import (
     PGSessionData,
     PGSessionDataContainer,
     )
+from lp.testing import TestCase
 from lp.testing.layers import (
     LaunchpadFunctionalLayer,
     LaunchpadLayer,
@@ -42,15 +42,14 @@ class TestPgSession(TestCase):
     layer = LaunchpadFunctionalLayer
 
     def setUp(self):
+        super(TestPgSession, self).setUp()
         self.sdc = PGSessionDataContainer()
+        self.addCleanup(delattr, self, 'sdc')
         LaunchpadLayer.resetSessionDb()
         self.request = TestRequest()
+        self.addCleanup(delattr, self, 'request')
         newInteraction(self.request)
-
-    def tearDown(self):
-        endInteraction()
-        del self.request
-        del self.sdc
+        self.addCleanup(endInteraction)
 
     def test_sdc_basics(self):
         # Make sure we have the correct class and it provides the required
@@ -111,15 +110,15 @@ class TestPgSession(TestCase):
         self.assertIsNot(session1a['key2'], session1a_dupe['key2'])
 
         # Ensure the keys method works as it is suppsed to
-        self.assertEqual(sorted(session1a.keys()), ['key1', 'key2'])
-        self.assertEqual(session2a.keys(), [])
+        self.assertContentEqual(session1a.keys(), ['key1', 'key2'])
+        self.assertContentEqual(session2a.keys(), [])
 
         # Ensure we can delete and alter things from the session
         del session1a['key1']
         session1a['key2'] = 'new value2'
         self.assertRaises(KeyError, session1a.__getitem__, 'key1')
         self.assertEqual(session1a['key2'], 'new value2')
-        self.assertEqual(session1a.keys(), ['key2'])
+        self.assertContentEqual(session1a.keys(), ['key2'])
 
         # Note that deleting will not raise a KeyError
         del session1a['key1']
@@ -130,7 +129,7 @@ class TestPgSession(TestCase):
         session1a_dupe = self.sdc[client_id1][product_id1]
         self.assertRaises(KeyError, session1a_dupe.__getitem__, 'key1')
         self.assertEqual(session1a_dupe['key2'], 'new value2')
-        self.assertEqual(session1a_dupe.keys(), ['key2'])
+        self.assertContentEqual(session1a_dupe.keys(), ['key2'])
 
     def test_session_only_stored_when_changed(self):
         # A record of the session is only stored in the database when
diff --git a/lib/lp/services/webapp/tests/test_view_model.py b/lib/lp/services/webapp/tests/test_view_model.py
index 913d15d..e8e4478 100644
--- a/lib/lp/services/webapp/tests/test_view_model.py
+++ b/lib/lp/services/webapp/tests/test_view_model.py
@@ -123,7 +123,7 @@ class TestJsonModelView(BrowserTestCase):
         self.configZCML()
         browser = self.getUserBrowser(self.url)
         cache = loads(browser.contents)
-        self.assertEqual(['related_features', 'context'], cache.keys())
+        self.assertEqual(['related_features', 'context'], list(cache))
 
     def test_JsonModel_custom_cache(self):
         # Adding an item to the cache in the initialize method results in it
diff --git a/lib/lp/services/xref/tests/test_model.py b/lib/lp/services/xref/tests/test_model.py
index e086e15..fd1c455 100644
--- a/lib/lp/services/xref/tests/test_model.py
+++ b/lib/lp/services/xref/tests/test_model.py
@@ -199,4 +199,4 @@ class TestXRefSet(TestCaseWithFactory):
         self.assertThat(recorder, HasQueryCount(Equals(1)))
         self.assertEqual(
             [('a', 'baz')],
-            getUtility(IXRefSet).findFrom(('b', 'foo')).keys())
+            list(getUtility(IXRefSet).findFrom(('b', 'foo'))))
diff --git a/lib/lp/soyuz/browser/tests/test_queue.py b/lib/lp/soyuz/browser/tests/test_queue.py
index 7c26c09..d8be2f6 100644
--- a/lib/lp/soyuz/browser/tests/test_queue.py
+++ b/lib/lp/soyuz/browser/tests/test_queue.py
@@ -500,7 +500,7 @@ class TestCompletePackageUpload(TestCaseWithFactory):
         complete_upload = self.makeCompletePackageUpload(
             upload, package_sets=package_sets)
         self.assertEqual(
-            package_sets.values()[0][0].name,
+            list(package_sets.values())[0][0].name,
             complete_upload.display_package_sets)
 
     def test_display_package_sets_returns_empty_for_other_upload(self):
diff --git a/lib/lp/soyuz/model/binarypackagebuild.py b/lib/lp/soyuz/model/binarypackagebuild.py
index 8561e70..238221c 100644
--- a/lib/lp/soyuz/model/binarypackagebuild.py
+++ b/lib/lp/soyuz/model/binarypackagebuild.py
@@ -1326,8 +1326,8 @@ class BinaryPackageBuildSet(SpecificBuildFarmJobSourceMixin):
         # Exclude any architectures which already have built or copied
         # binaries. A new build with the same archtag could never
         # succeed; its files would conflict during upload.
-        relevant_builds = self.findBuiltOrPublishedBySourceAndArchive(
-            sourcepackagerelease, archive).values()
+        relevant_builds = list(self.findBuiltOrPublishedBySourceAndArchive(
+            sourcepackagerelease, archive).values())
 
         # Find any architectures that already have a build that exactly
         # matches, regardless of status. We can't create a second build
diff --git a/lib/lp/soyuz/scripts/custom_uploads_copier.py b/lib/lp/soyuz/scripts/custom_uploads_copier.py
index b7d47e7..09f6fa4 100644
--- a/lib/lp/soyuz/scripts/custom_uploads_copier.py
+++ b/lib/lp/soyuz/scripts/custom_uploads_copier.py
@@ -78,7 +78,7 @@ class CustomUploadsCopier:
                             source_pocket=PackagePublishingPocket.RELEASE):
         """Find custom uploads that may need copying."""
         uploads = source_series.getPackageUploads(
-            pocket=source_pocket, custom_type=self.copyable_types.keys())
+            pocket=source_pocket, custom_type=list(self.copyable_types))
         load_referencing(PackageUploadCustom, uploads, ['packageuploadID'])
         customs = sum([list(upload.customfiles) for upload in uploads], [])
         return sorted(
diff --git a/lib/lp/testing/tests/test_html5browser.py b/lib/lp/testing/tests/test_html5browser.py
index 48db456..bdece29 100644
--- a/lib/lp/testing/tests/test_html5browser.py
+++ b/lib/lp/testing/tests/test_html5browser.py
@@ -89,7 +89,7 @@ class BrowserTestCase(TestCase):
         self.assertIsNone(browser.command)
         self.assertIsNone(browser.script)
         self.assertIsNone(browser.browser_window)
-        self.assertEqual(['console-message'], browser.listeners.keys())
+        self.assertEqual(['console-message'], list(browser.listeners))
 
     def test_init_show_browser(self):
         # The Browser can be set to show the window.
diff --git a/lib/lp/translations/model/approver.py b/lib/lp/translations/model/approver.py
index b77dc30..d7c55ab 100644
--- a/lib/lp/translations/model/approver.py
+++ b/lib/lp/translations/model/approver.py
@@ -96,7 +96,7 @@ class TranslationBranchApprover(object):
         # The simplest case of exactly one file and one POTemplate object is
         # always approved.
         if len(self._potemplateset) == len(self._potemplates) == 1:
-            self._potemplates[self._potemplates.keys()[0]] = (
+            self._potemplates[list(self._potemplates)[0]] = (
                 list(self._potemplateset)[0])
             self.is_approval_possible = True
 
diff --git a/lib/lp/translations/tests/test_exportresult.py b/lib/lp/translations/tests/test_exportresult.py
index de3f17b..fc02dc8 100644
--- a/lib/lp/translations/tests/test_exportresult.py
+++ b/lib/lp/translations/tests/test_exportresult.py
@@ -64,7 +64,8 @@ class TestExportResult(TestCaseWithFactory):
 
         self.assertStartsWith(export_result.url, "https://";)
         sha256 = hashlib.sha256(export.content).hexdigest()
-        self.assertEqual(sha256, librarian.aliases.values()[0].content.sha256)
+        self.assertEqual(
+            sha256, list(librarian.aliases.values())[0].content.sha256)
         alias = librarian.findBySHA256(sha256)
         self.assertEqual(export.path, alias.filename)
 
diff --git a/lib/lp/translations/tests/test_translationimportqueue.py b/lib/lp/translations/tests/test_translationimportqueue.py
index 67a05e1..a87fbc3 100644
--- a/lib/lp/translations/tests/test_translationimportqueue.py
+++ b/lib/lp/translations/tests/test_translationimportqueue.py
@@ -437,7 +437,7 @@ class TestTranslationImportQueue(TestCaseWithFactory):
         self.import_queue.addOrUpdateEntriesFromTarball(
             tarfile_content, True, self.importer,
             productseries=self.productseries)
-        self.assertEqual(files.keys(), self._getQueuePaths())
+        self.assertEqual(list(files), self._getQueuePaths())
 
     def test_addOrUpdateEntriesFromTarball_path_leading_slash(self):
         # Leading slashes are stripped from path names.