← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/no-xrange into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/no-xrange into lp:launchpad with lp:~cjwatson/launchpad/range-iterator as a prerequisite.

Commit message:
Replace xrange with range, since xrange doesn't exist in Python 3.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/no-xrange/+merge/337044

Long, but doesn't really seem worth splitting up as it's almost all just s/xrange/range/g.  The only complication is that there are a couple of places that really do want an iterator rather than a list, and range returns a list in Python 2, so in those cases I went for iter(range(...)) which works in both versions of the language.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/no-xrange into lp:launchpad.
=== modified file 'lib/lp/archivepublisher/tests/test_dominator.py'
--- lib/lp/archivepublisher/tests/test_dominator.py	2014-10-31 10:34:51 +0000
+++ lib/lp/archivepublisher/tests/test_dominator.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for domination.py."""
@@ -526,7 +526,7 @@
             self.factory.makeSourcePackagePublishingHistory(
                 sourcepackagerelease=spr, distroseries=distroseries,
                 pocket=pocket)
-            for counter in xrange(len(ages))]
+            for counter in range(len(ages))]
         alter_creation_dates(spphs, ages)
 
         self.assertEqual(
@@ -550,7 +550,7 @@
                 distroseries=distroseries, pocket=pocket,
                 sourcepackagerelease=self.factory.makeSourcePackageRelease(
                     version=version))
-            for counter in xrange(len(ages))]
+            for counter in range(len(ages))]
         alter_creation_dates(spphs, ages)
 
         self.assertEqual(
@@ -666,7 +666,7 @@
                 archive=series.main_archive, distroseries=series,
                 pocket=pocket, status=PackagePublishingStatus.PUBLISHED,
                 sourcepackagerelease=spr)
-            for counter in xrange(3)]
+            for counter in range(3)]
         alter_creation_dates(pubs, [
             datetime.timedelta(3),
             datetime.timedelta(2),
@@ -688,7 +688,7 @@
     def test_dominatePackage_is_efficient(self):
         # dominatePackage avoids issuing too many queries.
         generalization = GeneralizedPublication(True)
-        versions = ["1.%s" % revision for revision in xrange(5)]
+        versions = ["1.%s" % revision for revision in range(5)]
         pubs = make_spphs_for_versions(self.factory, versions)
         with StormStatementRecorder() as recorder:
             self.makeDominator(pubs).dominatePackage(
@@ -709,7 +709,7 @@
         package = self.factory.makeSourcePackageName()
         pocket = PackagePublishingPocket.RELEASE
 
-        versions = ["1.%d" % number for number in xrange(4)]
+        versions = ["1.%d" % number for number in range(4)]
 
         # We have one package releases for each version.
         relevant_releases = dict(
@@ -737,7 +737,7 @@
             for version in jumble(versions))
 
         ages = jumble(
-            [datetime.timedelta(age) for age in xrange(len(versions))])
+            [datetime.timedelta(age) for age in range(len(versions))])
 
         # Actually the "oldest to newest" order on the publications only
         # applies to their creation dates.  Their creation orders are
@@ -887,7 +887,7 @@
             self.factory.makeSourcePackagePublishingHistory(
                 distroseries=series, sourcepackagerelease=spr, pocket=pocket,
                 status=PackagePublishingStatus.PUBLISHED)
-            for counter in xrange(2)]
+            for counter in range(2)]
         dominator = self.makeDominator(spphs)
         self.assertContentEqual(
             [(spr.sourcepackagename.name, len(spphs))],

=== modified file 'lib/lp/archivepublisher/tests/test_publish_ftpmaster.py'
--- lib/lp/archivepublisher/tests/test_publish_ftpmaster.py	2016-12-05 22:16:25 +0000
+++ lib/lp/archivepublisher/tests/test_publish_ftpmaster.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test publish-ftpmaster cron script."""
@@ -441,7 +441,7 @@
             self.factory.makeSourcePackagePublishingHistory(
                 distroseries=self.factory.makeDistroSeries(
                     distribution=distro))
-            for counter in xrange(2)]
+            for counter in range(2)]
 
         script = self.makeScript(distro)
         script.setUp()
@@ -472,7 +472,7 @@
                 distroseries=self.factory.makeDistroSeries(
                     distribution=distro),
                 pocket=PackagePublishingPocket.SECURITY)
-            for counter in xrange(2)]
+            for counter in range(2)]
 
         script = self.makeScript(distro)
         script.setUp()

=== modified file 'lib/lp/bugs/browser/tests/test_bugcomment.py'
--- lib/lp/bugs/browser/tests/test_bugcomment.py	2015-09-14 13:11:30 +0000
+++ lib/lp/bugs/browser/tests/test_bugcomment.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for the bugcomment module."""
@@ -108,7 +108,7 @@
         # have any common actors, no grouping is possible.
         comments = [
             BugCommentStub(*next(self.time_index))
-            for number in xrange(5)]
+            for number in range(5)]
         self.assertEqual(
             comments, self.group(comments=comments, activities=[]))
 
@@ -117,7 +117,7 @@
         # have any common actors, no grouping is possible.
         activities = [
             BugActivityStub(next(self.time_index)[0])
-            for number in xrange(5)]
+            for number in range(5)]
         self.assertEqual(
             [[activity] for activity in activities], self.group(
                 comments=[], activities=activities))
@@ -175,7 +175,7 @@
         actor = PersonStub()
         activities = [
             BugActivityStub(next(self.time_index)[0], owner=actor)
-            for count in xrange(8)]
+            for count in range(8)]
         grouped = self.group(comments=[], activities=activities)
         self.assertEqual(2, len(grouped))
         self.assertEqual(activities[:5], grouped[0])

=== modified file 'lib/lp/bugs/model/tests/test_bug.py'
--- lib/lp/bugs/model/tests/test_bug.py	2016-06-24 23:35:24 +0000
+++ lib/lp/bugs/model/tests/test_bug.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -202,7 +202,7 @@
     def test_get_direct_subscribers_query_count(self):
         bug = self.factory.makeBug()
         # Make lots of subscribers.
-        for i in xrange(10):
+        for i in range(10):
             subscriber = self.factory.makePerson()
             with person_logged_in(subscriber):
                 bug.subscribe(subscriber, subscriber)
@@ -216,10 +216,10 @@
         bug = self.factory.makeBug()
         # Make lots of duplicate bugs.
         previous_dup = None
-        for i in xrange(10):
+        for i in range(10):
             dup = self.factory.makeBug()
             # Make lots of subscribers.
-            for j in xrange(10):
+            for j in range(10):
                 subscriber = self.factory.makePerson()
                 with person_logged_in(subscriber):
                     dup.subscribe(subscriber, subscriber)
@@ -246,7 +246,7 @@
         return self._get_notifications(BugNotificationStatus.DEFERRED)
 
     def _add_subscribers(self, bug, number):
-        for i in xrange(number):
+        for i in range(number):
             subscriber = self.factory.makePerson()
             with person_logged_in(subscriber):
                 bug.subscribe(subscriber, subscriber)
@@ -259,7 +259,7 @@
         self.store = Store.of(bug)
         duplicates = []
         # Make a few duplicate bugs.
-        for i in xrange(3):
+        for i in range(3):
             duplicates.append(self.factory.makeBug(title="bug-%d" % (i + 1)))
 
         # Pending messages exist for the bug creation.

=== modified file 'lib/lp/bugs/scripts/checkwatches/core.py'
--- lib/lp/bugs/scripts/checkwatches/core.py	2015-10-15 14:09:50 +0000
+++ lib/lp/bugs/scripts/checkwatches/core.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Classes and logic for the checkwatches cronscript."""
@@ -529,7 +529,7 @@
                 # run out of bugs to ask about or we have batch_size
                 # bugs to check.
                 remote_old_ids_to_check = []
-                for index in xrange(0, len(remote_old_ids), batch_size):
+                for index in range(0, len(remote_old_ids), batch_size):
                     remote_old_ids_to_check.extend(
                         remotesystem.getModifiedRemoteBugs(
                             remote_old_ids[index:index + batch_size],

=== modified file 'lib/lp/bugs/scripts/tests/test_bugnotification.py'
--- lib/lp/bugs/scripts/tests/test_bugnotification.py	2018-01-02 16:10:26 +0000
+++ lib/lp/bugs/scripts/tests/test_bugnotification.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 """Tests for construction bug notification emails for sending."""
 
@@ -1305,7 +1305,7 @@
         # Create some deferred notifications and show that processing them
         # puts then in the state where they are ready to send.
         num = 5
-        for i in xrange(num):
+        for i in range(num):
             self._make_deferred_notification()
         deferred = self.notification_set.getDeferredNotifications()
         self.assertEqual(num, deferred.count())

=== modified file 'lib/lp/bugs/tests/test_bugnotification.py'
--- lib/lp/bugs/tests/test_bugnotification.py	2012-09-07 02:00:31 +0000
+++ lib/lp/bugs/tests/test_bugnotification.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests related to bug notifications."""
@@ -499,7 +499,7 @@
 
     def test_many_deferred_notification(self):
         num = 5
-        for i in xrange(num):
+        for i in range(num):
             self._make_deferred_notification()
         results = self.bns.getDeferredNotifications()
         self.assertEqual(num, results.count())

=== modified file 'lib/lp/buildmaster/browser/tests/test_builder_views.py'
--- lib/lp/buildmaster/browser/tests/test_builder_views.py	2015-10-21 09:37:08 +0000
+++ lib/lp/buildmaster/browser/tests/test_builder_views.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -56,7 +56,7 @@
 
     def createBuilds(self):
         builds = []
-        for i in xrange(2):
+        for i in range(2):
             builds.append(self.createBinaryPackageBuild())
             builds.append(self.createTranslationTemplateBuild())
             builds.append(self.createSourcePackageRecipeBuild())

=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposallisting.py'
--- lib/lp/code/browser/tests/test_branchmergeproposallisting.py	2017-10-04 01:16:22 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposallisting.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Unit tests for BranchMergeProposal listing views."""
@@ -915,7 +915,7 @@
         # view and a recorder of the queries generated by this page
         # rendering.
         user = self.factory.makePerson()
-        for i in xrange(number_of_bmps):
+        for i in range(number_of_bmps):
             # Create one of the two types of BMP which will be displayed
             # on a person's +activereviews page:
             # - A BMP for which the person is the reviewer.
@@ -956,7 +956,7 @@
         # view and a recorder of the queries generated by this page
         # rendering.
         product = self.factory.makeProduct()
-        for i in xrange(number_of_bmps):
+        for i in range(number_of_bmps):
             self.createProductBMP(product=product)
         login_person(product.owner)
         flush_database_caches()

=== modified file 'lib/lp/code/doc/branch-notifications.txt'
--- lib/lp/code/doc/branch-notifications.txt	2016-01-26 15:47:37 +0000
+++ lib/lp/code/doc/branch-notifications.txt	2018-02-02 10:39:33 +0000
@@ -209,7 +209,7 @@
 
 We need to create some sufficiently large diffs to compare against.
 
-    >>> diff = '\n'.join([str(value) for value in xrange(6000)])
+    >>> diff = '\n'.join([str(value) for value in range(6000)])
     >>> message = 'Test message.\n'
 
 Send the revision notifications.
@@ -287,7 +287,7 @@
 
 And just to be sure, lets create one with 800 lines.
 
-    >>> diff = '\n'.join([str(value) for value in xrange(800)])
+    >>> diff = '\n'.join([str(value) for value in range(800)])
     >>> BranchMailer.forRevision(
     ...     branch, 'no-reply@xxxxxxxxxxxxx', message, diff,
     ...     None, revno=1234).sendAll()

=== modified file 'lib/lp/code/model/tests/test_revisioncache.py'
--- lib/lp/code/model/tests/test_revisioncache.py	2017-10-04 01:53:48 +0000
+++ lib/lp/code/model/tests/test_revisioncache.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests relating to the revision cache."""
@@ -357,7 +357,7 @@
         # If there are multiple revisions with the same revision author text,
         # but not linked to a Launchpad person, then that revision_text is
         # counted as one author.
-        for counter in xrange(4):
+        for counter in range(4):
             self.makeCachedRevision(revision=self.factory.makeRevision(
                 author="Foo <foo@xxxxxxxxxxx>"))
         revision_cache = getUtility(IRevisionCache)

=== modified file 'lib/lp/hardwaredb/scripts/hwdbsubmissions.py'
--- lib/lp/hardwaredb/scripts/hwdbsubmissions.py	2015-09-28 17:38:45 +0000
+++ lib/lp/hardwaredb/scripts/hwdbsubmissions.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Parse Hardware Database submissions.
@@ -1103,7 +1103,7 @@
         """
         udi_device_map = {}
         duplicates = []
-        for index in xrange(len(devices)):
+        for index in range(len(devices)):
             device = devices[index]
             udi = device['udi']
             if udi in udi_device_map:

=== modified file 'lib/lp/registry/browser/tests/test_commercialsubscription.py'
--- lib/lp/registry/browser/tests/test_commercialsubscription.py	2012-12-07 15:48:29 +0000
+++ lib/lp/registry/browser/tests/test_commercialsubscription.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2012-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test views that manage commercial subscriptions."""
@@ -31,7 +31,7 @@
             voucher_proxy = TestSalesforceVoucherProxy()
         self.registerUtility(voucher_proxy, ISalesforceVoucherProxy)
         vouchers = []
-        for n in xrange(number):
+        for n in range(number):
             vouchers.append(voucher_proxy.grantVoucher(user, user, user, 12))
         return vouchers
 

=== modified file 'lib/lp/registry/browser/tests/test_distroseries.py'
--- lib/lp/registry/browser/tests/test_distroseries.py	2018-01-02 16:10:26 +0000
+++ lib/lp/registry/browser/tests/test_distroseries.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2013 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for `lp.registry.browser.distroseries`."""
@@ -913,7 +913,7 @@
         login_person(self.simple_user)
 
         def add_differences(num):
-            for index in xrange(num):
+            for index in range(num):
                 version = self.factory.getUniqueInteger()
                 versions = {
                     'base': u'1.%d' % version,
@@ -1514,7 +1514,7 @@
         self.assertThat(recorder1, HasQueryCount(LessThan(12)))
 
         # The query count does not increase with the number of upgrades.
-        for index in xrange(3):
+        for index in range(3):
             self.makePackageUpgrade(derived_series=derived_series)
         flush_database_caches()
         with StormStatementRecorder() as recorder2:

=== modified file 'lib/lp/registry/browser/tests/test_person_contact.py'
--- lib/lp/registry/browser/tests/test_person_contact.py	2012-11-29 16:17:01 +0000
+++ lib/lp/registry/browser/tests/test_person_contact.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2012-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 """Test views and helpers related to the contact person feature."""
 
@@ -256,7 +256,7 @@
         sender = self.factory.makePerson(email='me@xxxxxx')
         old_message = self.factory.makeSignedMessage(email_address='me@xxxxxx')
         authorization = IDirectEmailAuthorization(sender)
-        for action in xrange(authorization.message_quota):
+        for action in range(authorization.message_quota):
             authorization.record(old_message)
         return sender
 

=== modified file 'lib/lp/registry/scripts/tests/test_populate_distroseriesdiff.py'
--- lib/lp/registry/scripts/tests/test_populate_distroseriesdiff.py	2018-02-02 10:39:33 +0000
+++ lib/lp/registry/scripts/tests/test_populate_distroseriesdiff.py	2018-02-02 10:39:33 +0000
@@ -186,7 +186,7 @@
         spr = self.factory.makeSourcePackageRelease(distroseries=distroseries)
         spphs = [
             self.makeSPPH(distroseries=distroseries, sourcepackagerelease=spr)
-            for counter in xrange(5)]
+            for counter in range(5)]
         query = compose_sql_find_latest_source_package_releases(distroseries)
         self.assertContentEqual(
             [self.getExpectedResultFor(spphs[-1])],
@@ -198,7 +198,7 @@
         sprs = [
             self.factory.makeSourcePackageRelease(
                 sourcepackagename=spn, distroseries=distroseries)
-            for counter in xrange(5)]
+            for counter in range(5)]
         spphs = [
             self.makeSPPH(distroseries=distroseries, sourcepackagerelease=spr)
             for spr in reversed(sprs)]
@@ -568,7 +568,7 @@
 
     def test_finds_all_distroseries(self):
         spphs = []
-        for counter in xrange(2):
+        for counter in range(2):
             dsp = self.makeDerivedDistroSeries()
             spphs.append(self.makeSPPH(dsp.derived_series))
         script = self.makeScript(['--all'])

=== modified file 'lib/lp/registry/tests/test_distroseriesdifference.py'
--- lib/lp/registry/tests/test_distroseriesdifference.py	2018-01-02 16:10:26 +0000
+++ lib/lp/registry/tests/test_distroseriesdifference.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Model tests for the DistroSeriesDifference class."""
@@ -1133,7 +1133,7 @@
         names = [
             self.factory.makeDistroSeriesDifference(
                 series).source_package_name.name
-            for counter in xrange(10)]
+            for counter in range(10)]
 
         results = getUtility(
             IDistroSeriesDifferenceSource).getForDistroSeries(series)
@@ -1147,7 +1147,7 @@
         derived_series = self.factory.makeDistroSeries()
         dsps = [
             self.factory.makeDistroSeriesParent(derived_series=derived_series)
-            for counter in xrange(2)]
+            for counter in range(2)]
         dsds = [
             self.factory.makeDistroSeriesDifference(
                 parent_series=dsp.parent_series,
@@ -1174,7 +1174,7 @@
         dsd = self.factory.makeDistroSeriesDifference()
         packagesets = [
             self.factory.makePackageset(distroseries=dsd.derived_series)
-            for counter in xrange(2)]
+            for counter in range(2)]
         Store.of(dsd).add(PackagesetSources(
             packageset=packagesets[0],
             sourcepackagename=dsd.source_package_name))
@@ -1308,7 +1308,7 @@
         dsp = self.factory.makeDistroSeriesParent()
         dsds = set(
             self.factory.makeDistroSeriesDifference(
-                derived_series=dsp.derived_series) for index in xrange(5))
+                derived_series=dsp.derived_series) for index in range(5))
         expected_comments = set()
         for dsd in dsds:
             # Add a couple of comments.

=== modified file 'lib/lp/registry/tests/test_distroseriesdifferencecomment.py'
--- lib/lp/registry/tests/test_distroseriesdifferencecomment.py	2012-12-26 01:32:19 +0000
+++ lib/lp/registry/tests/test_distroseriesdifferencecomment.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Model tests for the DistroSeriesDifferenceComment class."""
@@ -151,7 +151,7 @@
         series = self.factory.makeDistroSeries()
         dsds = randomize_list([
             self.factory.makeDistroSeriesDifference(derived_series=series)
-            for counter in xrange(5)])
+            for counter in range(5)])
         comments = [
             self.factory.makeDistroSeriesDifferenceComment(dsd)
             for dsd in dsds]

=== modified file 'lib/lp/registry/tests/test_milestone.py'
--- lib/lp/registry/tests/test_milestone.py	2015-01-29 14:14:01 +0000
+++ lib/lp/registry/tests/test_milestone.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Milestone related test helper."""
@@ -469,7 +469,7 @@
     def _create_items(self, num, factory, **kwargs):
         items = []
         with person_logged_in(self.owner):
-            for n in xrange(num):
+            for n in range(num):
                 items.append(factory(**kwargs))
         return items
 

=== modified file 'lib/lp/registry/tests/test_milestonetag.py'
--- lib/lp/registry/tests/test_milestonetag.py	2018-01-02 16:10:26 +0000
+++ lib/lp/registry/tests/test_milestonetag.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Milestone related test helper."""
@@ -113,7 +113,7 @@
     def _create_bugtasks(self, num, milestone=None):
         bugtasks = []
         with person_logged_in(self.owner):
-            for n in xrange(num):
+            for n in range(num):
                 bugtask = self.factory.makeBugTask(
                     target=self.product,
                     owner=self.owner)
@@ -125,7 +125,7 @@
     def _create_specifications(self, num, milestone=None):
         specifications = []
         with person_logged_in(self.owner):
-            for n in xrange(num):
+            for n in range(num):
                 specification = self.factory.makeSpecification(
                     product=self.product,
                     owner=self.owner,

=== modified file 'lib/lp/registry/tests/test_notification.py'
--- lib/lp/registry/tests/test_notification.py	2015-09-11 12:20:23 +0000
+++ lib/lp/registry/tests/test_notification.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2012-2015 Canonical Ltd.  This software is licensed under the
+# Copyright 2012-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test notification classes and functions."""
@@ -59,7 +59,7 @@
         recipients_set = NotificationRecipientSet()
         old_message = self.factory.makeSignedMessage(email_address='me@xxxxxx')
         authorization = IDirectEmailAuthorization(user)
-        for action in xrange(authorization.message_quota):
+        for action in range(authorization.message_quota):
             authorization.record(old_message)
         self.assertRaises(
             QuotaReachedError, send_direct_contact_email,
@@ -73,7 +73,7 @@
         recipients_set = NotificationRecipientSet()
         old_message = self.factory.makeSignedMessage(email_address='me@xxxxxx')
         authorization = IDirectEmailAuthorization(user)
-        for action in xrange(authorization.message_quota - 1):
+        for action in range(authorization.message_quota - 1):
             authorization.record(old_message)
         pop_notifications()
         send_direct_contact_email(

=== modified file 'lib/lp/registry/tests/test_teammembership.py'
--- lib/lp/registry/tests/test_teammembership.py	2018-01-02 16:10:26 +0000
+++ lib/lp/registry/tests/test_teammembership.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -1320,7 +1320,7 @@
         """
         # Create a deeply nested team and member structure.
         team = self.factory.makeTeam()
-        for num in xrange(10):
+        for num in range(10):
             another_team = self.factory.makeTeam()
             another_person = self.factory.makePerson()
             with person_logged_in(team.teamowner):

=== modified file 'lib/lp/scripts/tests/test_garbo.py'
--- lib/lp/scripts/tests/test_garbo.py	2018-01-02 10:54:31 +0000
+++ lib/lp/scripts/tests/test_garbo.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test the database garbage collector."""
@@ -1189,7 +1189,7 @@
         # between calls.
         switch_dbuser('testadmin')
         potmsgset_pofile = {}
-        for n in xrange(4):
+        for n in range(4):
             pofile = self.factory.makePOFile()
             translation_message = self.factory.makeCurrentTranslationMessage(
                 pofile=pofile)

=== modified file 'lib/lp/services/doc/orderingcheck.txt'
--- lib/lp/services/doc/orderingcheck.txt	2011-12-20 20:40:15 +0000
+++ lib/lp/services/doc/orderingcheck.txt	2018-02-02 10:39:33 +0000
@@ -19,7 +19,7 @@
 
     >>> checker = OrderingCheck(key=sort_key)
 
-    >>> for number in xrange(3):
+    >>> for number in range(3):
     ...     checker.check(number)
 
 

=== modified file 'lib/lp/services/helpers.py'
--- lib/lp/services/helpers.py	2016-03-17 14:47:14 +0000
+++ lib/lp/services/helpers.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2014 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Various functions and classes that are useful across different parts of
@@ -146,12 +146,12 @@
 
     It works on iterable also which don't support the extended slice protocol.
 
-    >>> xrange(5)[:1] #doctest: +ELLIPSIS
+    >>> iter(range(5))[:1] #doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     TypeError: ...
 
-    >>> shortlist(xrange(10), 5, hardlimit=8) #doctest: +ELLIPSIS
+    >>> shortlist(iter(range(10)), 5, hardlimit=8) #doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     ShortListTooBigError: ...

=== modified file 'lib/lp/services/log/logger.py'
--- lib/lp/services/log/logger.py	2017-10-05 12:46:52 +0000
+++ lib/lp/services/log/logger.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Loggers."""
@@ -22,7 +22,7 @@
 
 LEVEL_PREFIXES = dict(
     (debug_level, "DEBUG%d" % (1 + debug_level - loglevels.DEBUG))
-    for debug_level in xrange(loglevels.DEBUG9, loglevels.DEBUG))
+    for debug_level in range(loglevels.DEBUG9, loglevels.DEBUG))
 
 LEVEL_PREFIXES.update({
     loglevels.DEBUG: 'DEBUG',

=== modified file 'lib/lp/services/tests/test_command_spawner.py'
--- lib/lp/services/tests/test_command_spawner.py	2012-04-16 23:02:44 +0000
+++ lib/lp/services/tests/test_command_spawner.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for `CommandSpawner`."""
@@ -287,7 +287,7 @@
 
         processes = 10
         seconds = 0.2
-        for counter in xrange(processes):
+        for counter in range(processes):
             spawner.start(["/bin/sleep", str(seconds)])
 
         before = datetime.now(utc)

=== modified file 'lib/lp/services/tests/test_helpers.py'
--- lib/lp/services/tests/test_helpers.py	2014-01-30 09:58:18 +0000
+++ lib/lp/services/tests/test_helpers.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 from doctest import DocTestSuite
@@ -104,7 +104,7 @@
     UserWarning: shortlist() should not...
     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 
-    >>> shortlist(xrange(10), longest_expected=5) #doctest: +ELLIPSIS
+    >>> shortlist(iter(range(10)), longest_expected=5) #doctest: +ELLIPSIS
     UserWarning: shortlist() should not...
     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 
@@ -145,7 +145,7 @@
         >>> english_list('12345')
         '1, 2, 3, 4, and 5'
 
-        >>> english_list(str(i) for i in xrange(5))
+        >>> english_list(str(i) for i in range(5))
         '0, 1, 2, 3, and 4'
 
     It does not convert non-string elements:

=== modified file 'lib/lp/services/webapp/tests/test_error.py'
--- lib/lp/services/webapp/tests/test_error.py	2018-01-02 16:10:26 +0000
+++ lib/lp/services/webapp/tests/test_error.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test error views."""
@@ -104,7 +104,7 @@
         Return the file-like object returned by *urllib2.urlopen(url)*.
         Raise a TimeoutException if the connection can not be established.
         """
-        for i in xrange(retries):
+        for i in range(retries):
             try:
                 return urllib2.urlopen(url)
             except urllib2.HTTPError as e:

=== modified file 'lib/lp/soyuz/adapters/tests/test_overrides.py'
--- lib/lp/soyuz/adapters/tests/test_overrides.py	2014-07-29 06:11:19 +0000
+++ lib/lp/soyuz/adapters/tests/test_overrides.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2013 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test generic override policy classes."""
@@ -144,7 +144,7 @@
         spns = []
         distroseries = self.factory.makeDistroSeries()
         pocket = self.factory.getAnyPocket()
-        for i in xrange(10):
+        for i in range(10):
             spph = self.factory.makeSourcePackagePublishingHistory(
                 distroseries=distroseries, archive=distroseries.main_archive,
                 pocket=pocket)
@@ -354,7 +354,7 @@
         distroseries = distroarchseries.distroseries
         distroseries.nominatedarchindep = distroarchseries
         pocket = self.factory.getAnyPocket()
-        for i in xrange(10):
+        for i in range(10):
             bpph = self.factory.makeBinaryPackagePublishingHistory(
                 distroarchseries=distroarchseries,
                 archive=distroseries.main_archive, pocket=pocket)
@@ -519,7 +519,7 @@
         expected = {spns[0]: SourceOverride(component=universe, new=True)}
         distroseries = self.factory.makeDistroSeries()
         pocket = self.factory.getAnyPocket()
-        for i in xrange(8):
+        for i in range(8):
             spph = self.factory.makeSourcePackagePublishingHistory(
                 distroseries=distroseries, archive=distroseries.main_archive,
                 pocket=pocket)
@@ -549,7 +549,7 @@
         bpn = self.factory.makeBinaryPackageName()
         bpns = []
         expected = {}
-        for i in xrange(3):
+        for i in range(3):
             distroarchseries = self.factory.makeDistroArchSeries(
                 distroseries=distroseries)
             bpb = self.factory.makeBinaryPackageBuild(
@@ -566,7 +566,7 @@
                     component=bpph.component, section=bpph.section,
                     priority=bpph.priority, new=False,
                     version=bpph.binarypackagerelease.version))
-        for i in xrange(2):
+        for i in range(2):
             distroarchseries = self.factory.makeDistroArchSeries(
                 distroseries=distroseries)
             bpns.append((bpn, distroarchseries.architecturetag))

=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
--- lib/lp/soyuz/scripts/tests/test_copypackage.py	2017-06-03 16:40:44 +0000
+++ lib/lp/soyuz/scripts/tests/test_copypackage.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -456,7 +456,7 @@
 
     def _setupSources(self, nb_of_sources):
         sources = []
-        for i in xrange(nb_of_sources):
+        for i in range(nb_of_sources):
             source = self.test_publisher.getPubSource(
                 version=u'%d' % self.factory.getUniqueInteger(),
                 sourcename=u'name-%d' % self.factory.getUniqueInteger())

=== modified file 'lib/lp/soyuz/scripts/tests/test_custom_uploads_copier.py'
--- lib/lp/soyuz/scripts/tests/test_custom_uploads_copier.py	2016-05-26 14:53:06 +0000
+++ lib/lp/soyuz/scripts/tests/test_custom_uploads_copier.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test copying of custom package uploads for a new `DistroSeries`."""
@@ -212,7 +212,7 @@
         # XXX JeroenVermeulen 2011-08-17, bug=827967: Should compare by
         # Debian version string, not id.
         source_series = self.factory.makeDistroSeries()
-        for counter in xrange(5):
+        for counter in range(5):
             self.makeUpload(source_series)
         copier = CustomUploadsCopier(FakeDistroSeries())
         candidate_ids = [
@@ -273,7 +273,7 @@
         uploads = [
             self.makeUpload(
                 source_series, version='1.0.%d' % counter, arch='ppc')
-            for counter in xrange(3)]
+            for counter in range(3)]
 
         copier = CustomUploadsCopier(FakeDistroSeries())
         self.assertContentEqual(
@@ -286,7 +286,7 @@
         source_series = self.factory.makeDistroSeries()
         uploads = [
             self.makeUpload(source_series, arch='i386')
-            for counter in xrange(2)]
+            for counter in range(2)]
         copier = CustomUploadsCopier(FakeDistroSeries())
         self.assertContentEqual(
             uploads[-1:], copier.getLatestUploads(source_series).values())

=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
--- lib/lp/soyuz/tests/test_binarypackagebuild.py	2016-01-06 12:24:47 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuild.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test Build features."""
@@ -423,7 +423,7 @@
                 sprb.build_farm_job))
 
     def test_getByBuildFarmJobs_works(self):
-        bpbs = [self.factory.makeBinaryPackageBuild() for i in xrange(10)]
+        bpbs = [self.factory.makeBinaryPackageBuild() for i in range(10)]
         self.assertContentEqual(
             bpbs,
             getUtility(IBinaryPackageBuildSet).getByBuildFarmJobs(

=== modified file 'lib/lp/soyuz/tests/test_distroseriesdifferencejob.py'
--- lib/lp/soyuz/tests/test_distroseriesdifferencejob.py	2018-02-02 10:39:33 +0000
+++ lib/lp/soyuz/tests/test_distroseriesdifferencejob.py	2018-02-02 10:39:33 +0000
@@ -155,7 +155,7 @@
 
     def createSPPHs(self, derived_series, nb_spph=10):
         res_spph = []
-        for i in xrange(nb_spph):
+        for i in range(nb_spph):
             packagename = self.factory.makeSourcePackageName()
             spph = self.factory.makeSourcePackagePublishingHistory(
                 sourcepackagename=packagename,
@@ -379,7 +379,7 @@
         spn = self.factory.makeSourcePackageName()
         series = [
             self.factory.makeDistroSeries(derived_distro)
-            for counter in xrange(2)]
+            for counter in range(2)]
         dsps = [
             self.factory.makeDistroSeriesParent(derived_series=distroseries)
             for distroseries in series]

=== modified file 'lib/lp/soyuz/tests/test_packagecopyjob.py'
--- lib/lp/soyuz/tests/test_packagecopyjob.py	2016-10-17 09:15:51 +0000
+++ lib/lp/soyuz/tests/test_packagecopyjob.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for sync package jobs."""
@@ -305,7 +305,7 @@
         # getActiveJobs returns the oldest available job first.
         dsd = self.factory.makeDistroSeriesDifference()
         target_archive = dsd.derived_series.main_archive
-        jobs = [self.makeJob(dsd) for counter in xrange(2)]
+        jobs = [self.makeJob(dsd) for counter in range(2)]
         source = getUtility(IPlainPackageCopyJobSource)
         self.assertEqual(jobs[0], source.getActiveJobs(target_archive)[0])
 
@@ -677,7 +677,7 @@
         dsds = [
             self.factory.makeDistroSeriesDifference(
                 derived_series=derived_series)
-            for counter in xrange(2)]
+            for counter in range(2)]
         jobs = map(self.makeJob, dsds)
         job_source = getUtility(IPlainPackageCopyJobSource)
         self.assertEqual(
@@ -688,7 +688,7 @@
         # If there are multiple jobs for one package,
         # getPendingJobsPerPackage picks the oldest.
         dsd = self.factory.makeDistroSeriesDifference()
-        jobs = [self.makeJob(dsd) for counter in xrange(2)]
+        jobs = [self.makeJob(dsd) for counter in range(2)]
         job_source = getUtility(IPlainPackageCopyJobSource)
         self.assertEqual(
             {dsd.source_package_name.name: jobs[0]},
@@ -710,7 +710,7 @@
         job_source = getUtility(IPlainPackageCopyJobSource)
         target1_jobs = [
             self.makePPAJob(target_archive=target1)
-            for counter in xrange(2)]
+            for counter in range(2)]
         self.makePPAJob(target2)
 
         pending_jobs = list(job_source.getIncompleteJobsForArchive(target1))

=== modified file 'lib/lp/soyuz/tests/test_packageset.py'
--- lib/lp/soyuz/tests/test_packageset.py	2018-01-02 10:54:31 +0000
+++ lib/lp/soyuz/tests/test_packageset.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2014 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test Packageset features."""
@@ -112,7 +112,7 @@
         # IPackagesetSet.getBySeries() will return those package sets
         # associated with the given distroseries.
         package_sets_for_current_ubuntu = [
-            self.factory.makePackageset() for counter in xrange(2)]
+            self.factory.makePackageset() for counter in range(2)]
         self.factory.makePackageset(
             distroseries=self.makeExperimentalSeries())
         self.assertContentEqual(

=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py	2017-04-25 11:36:10 +0000
+++ lib/lp/testing/factory.py	2018-02-02 10:39:33 +0000
@@ -2,7 +2,7 @@
 # NOTE: The first line above must stay first; do not move the copyright
 # notice to the top.  See http://www.python.org/dev/peps/pep-0263/.
 #
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Testing infrastructure for the Launchpad application.
@@ -1108,7 +1108,7 @@
 
     def makeStackedOnBranchChain(self, depth=5, **kwargs):
         branch = None
-        for i in xrange(depth):
+        for i in range(depth):
             branch = self.makeAnyBranch(stacked_on=branch, **kwargs)
         return branch
 

=== modified file 'lib/lp/testing/fixture.py'
--- lib/lp/testing/fixture.py	2017-09-02 13:29:14 +0000
+++ lib/lp/testing/fixture.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Launchpad test fixtures that have no better home."""
@@ -137,7 +137,7 @@
         """Start PGBouncer, waiting for it to accept connections if neccesary.
         """
         super(PGBouncerFixture, self).start()
-        for i in xrange(retries):
+        for i in range(retries):
             try:
                 socket.create_connection((self.host, self.port))
             except socket.error:

=== modified file 'lib/lp/testing/tests/test_fakemethod.py'
--- lib/lp/testing/tests/test_fakemethod.py	2011-08-12 11:37:08 +0000
+++ lib/lp/testing/tests/test_fakemethod.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 from unittest import TestCase
@@ -67,7 +67,7 @@
     def test_countCalls(self):
         # A FakeMethod counts the number of times it's been invoked.
         func = FakeMethod()
-        for count in xrange(3):
+        for count in range(3):
             self.assertEqual(count, func.call_count)
             func()
             self.assertEqual(count + 1, func.call_count)

=== modified file 'lib/lp/translations/browser/tests/test_persontranslationview.py'
--- lib/lp/translations/browser/tests/test_persontranslationview.py	2014-06-10 11:25:51 +0000
+++ lib/lp/translations/browser/tests/test_persontranslationview.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2014 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -57,7 +57,7 @@
         pofiles = []
         if languages is not None:
             potemplate = self.factory.makePOTemplate()
-        for counter in xrange(count):
+        for counter in range(count):
             if languages is None:
                 pofile = self.factory.makePOFile(language=self.language)
             else:

=== modified file 'lib/lp/translations/browser/tests/test_translationimportqueueentry.py'
--- lib/lp/translations/browser/tests/test_translationimportqueueentry.py	2016-09-12 17:41:21 +0000
+++ lib/lp/translations/browser/tests/test_translationimportqueueentry.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Unit tests for translation import queue views."""
@@ -137,7 +137,7 @@
         # Many translatable series.  The list is cut short; there's an
         # ellipsis to indicate this.
         series_count = len(product.translatable_series)
-        for counter in xrange(series_count, view.max_series_to_display + 1):
+        for counter in range(series_count, view.max_series_to_display + 1):
             extra_series = self.factory.makeProductSeries(product=product)
             self.factory.makePOTemplate(productseries=extra_series)
         series_text = view.product_translatable_series

=== modified file 'lib/lp/translations/browser/tests/test_translationmessage_view.py'
--- lib/lp/translations/browser/tests/test_translationmessage_view.py	2018-02-02 10:39:33 +0000
+++ lib/lp/translations/browser/tests/test_translationmessage_view.py	2018-02-02 10:39:33 +0000
@@ -315,7 +315,7 @@
             base_field_name = 'msgset_%d_%s_translation_' % (
                 message.potmsgset.id, pofile.language.code)
             # Add the expected plural forms fields.
-            for plural_form in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+            for plural_form in range(TranslationConstants.MAX_PLURAL_FORMS):
                 field_name = '%s%d_new' % (base_field_name, plural_form)
                 form[field_name] = u'snarf'
         url = '/%s/%s/%s/+translate' % (
@@ -397,7 +397,7 @@
         self.assertFalse(contains_translations({}))
 
     def test_contains_translations_finds_any_translations(self):
-        for plural_form in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+        for plural_form in range(TranslationConstants.MAX_PLURAL_FORMS):
             self.assertTrue(
                 contains_translations({plural_form: self.getUniqueString()}))
 

=== modified file 'lib/lp/translations/browser/translationmessage.py'
--- lib/lp/translations/browser/translationmessage.py	2018-02-02 10:39:33 +0000
+++ lib/lp/translations/browser/translationmessage.py	2018-02-02 10:39:33 +0000
@@ -741,7 +741,7 @@
         # Extract the translations from the form, and store them in
         # self.form_posted_translations. We try plural forms in turn,
         # starting at 0.
-        for pluralform in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+        for pluralform in range(TranslationConstants.MAX_PLURAL_FORMS):
             msgset_ID_LANGCODE_translation_PLURALFORM_new = '%s%d_new' % (
                 msgset_ID_LANGCODE_translation_, pluralform)
             if msgset_ID_LANGCODE_translation_PLURALFORM_new not in form:

=== modified file 'lib/lp/translations/model/pofile.py'
--- lib/lp/translations/model/pofile.py	2016-01-26 15:47:37 +0000
+++ lib/lp/translations/model/pofile.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """`SQLObject` implementation of `IPOFile` interface."""
@@ -624,7 +624,7 @@
         clauses = self._getStormClausesForPOFileMessages()
         msgstr_clause = Or(*(
             getattr(TranslationMessage, 'msgstr%d' % form) != None
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)))
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)))
         clauses.extend([
             TranslationTemplateItem.potmsgsetID == POTMsgSet.id,
             Not(getattr(TranslationMessage, flag_name)),
@@ -853,7 +853,7 @@
             self.potemplate).flag_name
         suggestion_nonempty = "COALESCE(%s) IS NOT NULL" % ', '.join([
             'Suggestion.msgstr%d' % form
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)])
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)])
         params = {
             'language': quote(self.language),
             'potemplate': quote(self.potemplate),
@@ -1198,7 +1198,7 @@
                 TranslationMessage.language = %(language)s
             """ % params
 
-        for form in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+        for form in range(TranslationConstants.MAX_PLURAL_FORMS):
             alias = "potranslation%d" % form
             field = "TranslationMessage.msgstr%d" % form
             query += "LEFT JOIN POTranslation AS %s ON %s.id = %s\n" % (
@@ -1729,7 +1729,7 @@
 
             forms = list(enumerate([
                 getattr(row, "translation%d" % form)
-                for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]))
+                for form in range(TranslationConstants.MAX_PLURAL_FORMS)]))
             max_forms = pofile.plural_forms
             for (pluralform, translation) in forms[:max_forms]:
                 if translation is not None:

=== modified file 'lib/lp/translations/model/potmsgset.py'
--- lib/lp/translations/model/potmsgset.py	2018-02-02 10:39:33 +0000
+++ lib/lp/translations/model/potmsgset.py	2018-02-02 10:39:33 +0000
@@ -426,7 +426,7 @@
         # distinct translations per form.
         msgstrs = ', '.join([
             'COALESCE(msgstr%d, -1)' % form
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)])
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)])
         ids_query_params = {
             'msgstrs': msgstrs,
             'where': '(' + ' OR '.join(lang_used) + ')',
@@ -518,7 +518,7 @@
         """Find all POTranslation records for passed `translations`."""
         potranslations = {}
         # Set all POTranslations we can have (up to MAX_PLURAL_FORMS)
-        for pluralform in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+        for pluralform in range(TranslationConstants.MAX_PLURAL_FORMS):
             translation = translations.get(pluralform)
             if translation is not None:
                 # Find or create a POTranslation for the specified text

=== modified file 'lib/lp/translations/model/translationmessage.py'
--- lib/lp/translations/model/translationmessage.py	2015-07-08 16:05:11 +0000
+++ lib/lp/translations/model/translationmessage.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -73,7 +73,7 @@
     """
     return separator.join([
         fragment % {'form': form}
-        for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)])
+        for form in range(TranslationConstants.MAX_PLURAL_FORMS)])
 
 
 def make_plurals_sql_fragment(fragment, separator="AND"):
@@ -169,7 +169,7 @@
         self.date_reviewed = None
         self.reviewer = None
 
-        for form in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+        for form in range(TranslationConstants.MAX_PLURAL_FORMS):
             setattr(self, 'msgstr%d' % form, None)
 
         self.comment = None
@@ -307,7 +307,7 @@
         """See `ITranslationMessage`."""
         return [
             getattr(self, 'msgstr%d' % form)
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)]
 
     @cachedproperty
     def translations(self):
@@ -498,7 +498,7 @@
         store = Store.of(self)
 
         forms_match = (TranslationMessage.msgstr0ID == self.msgstr0ID)
-        for form in xrange(1, TranslationConstants.MAX_PLURAL_FORMS):
+        for form in range(1, TranslationConstants.MAX_PLURAL_FORMS):
             form_name = 'msgstr%d' % form
             form_value = getattr(self, 'msgstr%dID' % form)
             forms_match = And(
@@ -571,7 +571,7 @@
             load_related(
                 POTranslation, tms,
                 ['msgstr%dID' % form
-                 for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)])
+                 for form in range(TranslationConstants.MAX_PLURAL_FORMS)])
         if need_potmsgset:
             load_related(POTMsgSet, tms, ['potmsgsetID'])
         if need_people:

=== modified file 'lib/lp/translations/scripts/fix_plural_forms.py'
--- lib/lp/translations/scripts/fix_plural_forms.py	2015-10-14 16:23:18 +0000
+++ lib/lp/translations/scripts/fix_plural_forms.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Functions for fixing mismatched plural form translations."""
@@ -58,7 +58,7 @@
             logger.debug("\tFixing translations for '%s'" % (
                 message.potmsgset.singular_text))
 
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS):
                 new_form = plural_forms_mapping[form]
                 assert new_form < TranslationConstants.MAX_PLURAL_FORMS, (
                     "Translation with plural form %d in plurals mapping." %

=== modified file 'lib/lp/translations/stories/standalone/xx-translations-to-review.txt'
--- lib/lp/translations/stories/standalone/xx-translations-to-review.txt	2017-10-21 18:14:14 +0000
+++ lib/lp/translations/stories/standalone/xx-translations-to-review.txt	2018-02-02 10:39:33 +0000
@@ -136,7 +136,7 @@
 at 10 entries.
 
     >>> login(ANONYMOUS)
-    >>> for count in xrange(9):
+    >>> for count in range(9):
     ...     pofile = add_unreviewed_pofile(translationgroup)
     ...     work_on(user, pofile)
     >>> logout()

=== modified file 'lib/lp/translations/tests/test_autoapproval.py'
--- lib/lp/translations/tests/test_autoapproval.py	2018-01-02 10:54:31 +0000
+++ lib/lp/translations/tests/test_autoapproval.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Unit tests for translation import queue auto-approval.
@@ -485,7 +485,7 @@
         series = self.factory.makeProductSeries()
         templates = [
             self.factory.makePOTemplate(productseries=series)
-            for counter in xrange(2)]
+            for counter in range(2)]
         entry = self.factory.makeTranslationImportQueueEntry(
             productseries=series)
         self.assertEqual(
@@ -501,7 +501,7 @@
             self.factory.makePOTemplate(
                 translation_domain=domain,
                 productseries=self.factory.makeProductSeries())
-            for counter in xrange(2)]
+            for counter in range(2)]
         entry = self.factory.makeTranslationImportQueueEntry(
             productseries=templates[0].productseries)
         self.assertEqual(
@@ -518,7 +518,7 @@
             self.factory.makePOTemplate(
                 translation_domain=domain, distroseries=distroseries,
                 sourcepackagename=self.factory.makeSourcePackageName())
-            for counter in xrange(2)]
+            for counter in range(2)]
         entry = self.factory.makeTranslationImportQueueEntry(
             distroseries=distroseries,
             sourcepackagename=templates[1].sourcepackagename)
@@ -557,7 +557,7 @@
         templates = [
             self.factory.makePOTemplate(
                 translation_domain=domain, productseries=series)
-            for counter in xrange(2)]
+            for counter in range(2)]
         entry = self.factory.makeTranslationImportQueueEntry(
             productseries=series)
 

=== modified file 'lib/lp/translations/tests/test_potmsgset.py'
--- lib/lp/translations/tests/test_potmsgset.py	2018-01-02 16:10:26 +0000
+++ lib/lp/translations/tests/test_potmsgset.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -1461,7 +1461,7 @@
         """Produce a POTranslations dict of random translations."""
         return dict(
             (form, self.factory.getUniqueString())
-            for form in xrange(forms))
+            for form in range(forms))
 
     def test_baseline(self):
         # setCurrentTranslation sets the current translation

=== modified file 'lib/lp/translations/tests/test_translationimportqueue.py'
--- lib/lp/translations/tests/test_translationimportqueue.py	2018-01-02 16:10:26 +0000
+++ lib/lp/translations/tests/test_translationimportqueue.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -474,7 +474,7 @@
         templates = [
             self.factory.makePOTemplate(
                 productseries=series, translation_domain=domain)
-            for counter in xrange(3)]
+            for counter in range(3)]
         entry = removeSecurityProxy(
             self.factory.makeTranslationImportQueueEntry())
 

=== modified file 'lib/lp/translations/tests/test_translationmessage.py'
--- lib/lp/translations/tests/test_translationmessage.py	2018-01-02 16:10:26 +0000
+++ lib/lp/translations/tests/test_translationmessage.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2014 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Unit tests for `TranslationMessage`."""
@@ -849,7 +849,7 @@
 
         self.translation_strings = [
             'foe%d' % form
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)]
 
         self.message = self.factory.makeCurrentTranslationMessage(
             pofile=self.pofile, potmsgset=self.potmsgset,

=== modified file 'lib/lp/translations/tests/test_translationpolicy.py'
--- lib/lp/translations/tests/test_translationpolicy.py	2015-07-08 16:05:11 +0000
+++ lib/lp/translations/tests/test_translationpolicy.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2014 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test `TranslationPolicyMixin`."""
@@ -48,8 +48,7 @@
 
     def _makeTranslationGroups(self, count):
         """Return a list of `count` freshly minted `TranslationGroup`s."""
-        return [
-            self.factory.makeTranslationGroup() for number in xrange(count)]
+        return [self.factory.makeTranslationGroup() for number in range(count)]
 
     def _makeTranslator(self, language, for_policy=None):
         """Create a translator for a policy object.

=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuild.py'
--- lib/lp/translations/tests/test_translationtemplatesbuild.py	2018-01-02 16:10:26 +0000
+++ lib/lp/translations/tests/test_translationtemplatesbuild.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """`TranslationTemplatesBuild` tests."""
@@ -233,7 +233,7 @@
         source = getUtility(ITranslationTemplatesBuildSource)
         build_farm_jobs = []
         builds = []
-        for i in xrange(10):
+        for i in range(10):
             branch = self.factory.makeBranch()
             build = source.create(branch)
             builds.append(build)

=== modified file 'lib/lp/translations/utilities/gettext_po_parser.py'
--- lib/lp/translations/utilities/gettext_po_parser.py	2016-09-14 11:13:06 +0000
+++ lib/lp/translations/utilities/gettext_po_parser.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 # Originally based on code from msgfmt.py (available from python source
@@ -662,7 +662,7 @@
                 # Octal escape.
                 position += 2
                 # Up to two more octal digits.
-                for i in xrange(2):
+                for i in range(2):
                     if string[position].isdigit():
                         position += 1
                     else:

=== modified file 'lib/lp/translations/utilities/kde_po_exporter.py'
--- lib/lp/translations/utilities/kde_po_exporter.py	2015-07-08 16:05:11 +0000
+++ lib/lp/translations/utilities/kde_po_exporter.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Export module for KDE legacy .po file format.
@@ -57,7 +57,7 @@
         elif translation_message.msgid_plural is not None:
             # Also, let's handle legacy KDE plural forms.
             translations = translation_message.translations
-            for pluralform_index in xrange(len(translations)):
+            for pluralform_index in range(len(translations)):
                 if translations[pluralform_index] is None:
                     translations[pluralform_index] = ''
             translation_message._translations = ["\n".join(translations)]

=== modified file 'lib/lp/translations/utilities/pluralforms.py'
--- lib/lp/translations/utilities/pluralforms.py	2018-02-02 10:39:33 +0000
+++ lib/lp/translations/utilities/pluralforms.py	2018-02-02 10:39:33 +0000
@@ -27,7 +27,7 @@
     # Maximum number of examples per plural form.
     MAX_EXAMPLES = 6
 
-    for number in xrange(200):
+    for number in range(200):
         try:
             form = function(number)
         except ZeroDivisionError:
@@ -82,7 +82,7 @@
 
 def make_plurals_identity_map():
     """Return a dict mapping each plural form number onto itself."""
-    return dict(enumerate(xrange(TranslationConstants.MAX_PLURAL_FORMS)))
+    return dict(enumerate(range(TranslationConstants.MAX_PLURAL_FORMS)))
 
 
 def plural_form_mapper(first_expression, second_expression):

=== modified file 'lib/lp/translations/utilities/translation_import.py'
--- lib/lp/translations/utilities/translation_import.py	2015-09-28 17:38:45 +0000
+++ lib/lp/translations/utilities/translation_import.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -99,14 +99,14 @@
         return False
     length_overlap = min(
         len(existing_msg.translations), len(new_msg.translations))
-    for pluralform_index in xrange(length_overlap):
+    for pluralform_index in range(length_overlap):
         # Plural forms that both messages have.  Translations for each
         # must match.
         existing_text = existing_msg.translations[pluralform_index]
         new_text = new_msg.translations[pluralform_index]
         if existing_text != new_text:
             return False
-    for pluralform_index in xrange(length_overlap, len(new_msg.translations)):
+    for pluralform_index in range(length_overlap, len(new_msg.translations)):
         # Plural forms that exist in new_translations but not in
         # existing_translations.  That's okay, as long as all of them are
         # None.
@@ -144,11 +144,11 @@
         msgstr_joins = [
             "LEFT OUTER JOIN POTranslation AS pt%d "
             "ON pt%d.id = TranslationMessage.msgstr%d" % (form, form, form)
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)]
 
         translations = [
             "pt%d.translation AS translation%d" % (form, form)
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)]
 
         substitutions = {
             'translation_columns': ', '.join(translations),
@@ -233,7 +233,7 @@
                 message.msgid_singular = msgid
                 message.msgid_plural = msgid_plural
 
-            for plural in xrange(TranslationConstants.MAX_PLURAL_FORMS):
+            for plural in range(TranslationConstants.MAX_PLURAL_FORMS):
                 msgstr = msgstrs.get(plural, None)
                 if (msgstr is not None and
                     ((len(message.translations) > plural and

=== modified file 'lib/lp/translations/utilities/translationmerger.py'
--- lib/lp/translations/utilities/translationmerger.py	2014-08-27 02:03:34 +0000
+++ lib/lp/translations/utilities/translationmerger.py	2018-02-02 10:39:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -600,7 +600,7 @@
         tm = removeSecurityProxy(tm)
         msgstr_ids = tuple([
             getattr(tm, 'msgstr%dID' % form)
-            for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)])
+            for form in range(TranslationConstants.MAX_PLURAL_FORMS)])
 
         return (tm.potemplateID, tm.languageID) + msgstr_ids
 


Follow ups