Merge ~cjwatson/launchpad:py3only-version-detection into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: f20f13a3d5fa1ee1104b1ae141f33747b302f3f2
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:py3only-version-detection
Merge into: launchpad:master
Diff against target: 983 lines (+83/-258)
36 files modified
lib/lp/app/security.py (+0/-4)
lib/lp/bugs/externalbugtracker/bugzilla.py (+1/-3)
lib/lp/bugs/mail/handler.py (+0/-7)
lib/lp/bugs/scripts/bugexport.py (+2/-8)
lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py (+1/-5)
lib/lp/code/browser/tests/test_branchmergeproposal.py (+14/-21)
lib/lp/registry/browser/person.py (+0/-3)
lib/lp/registry/interfaces/sourcepackagename.py (+0/-5)
lib/lp/registry/model/productrelease.py (+1/-5)
lib/lp/registry/tests/test_nickname.py (+3/-14)
lib/lp/registry/tests/test_ssh.py (+1/-7)
lib/lp/scripts/utilities/importpedant.py (+1/-3)
lib/lp/scripts/utilities/test.py (+1/-1)
lib/lp/services/compat.py (+10/-16)
lib/lp/services/encoding.py (+1/-1)
lib/lp/services/limitedlist.py (+0/-11)
lib/lp/services/mail/interfaces.py (+0/-4)
lib/lp/services/mail/notificationrecipientset.py (+0/-3)
lib/lp/services/scripts/base.py (+1/-5)
lib/lp/services/tests/test_encoding.py (+2/-12)
lib/lp/services/twistedsupport/tests/test_xmlrpc.py (+0/-10)
lib/lp/services/twistedsupport/xmlrpc.py (+1/-6)
lib/lp/services/webapp/pgsession.py (+21/-24)
lib/lp/services/webapp/publisher.py (+0/-5)
lib/lp/services/webapp/servers.py (+3/-17)
lib/lp/services/webapp/tests/test_servers.py (+6/-10)
lib/lp/services/webapp/url.py (+1/-4)
lib/lp/services/webhooks/payload.py (+0/-6)
lib/lp/soyuz/adapters/archivesourcepublication.py (+0/-4)
lib/lp/soyuz/interfaces/binarypackagename.py (+0/-5)
lib/lp/testing/factory.py (+2/-6)
lib/lp/testing/systemdocs.py (+4/-7)
lib/lp/translations/doc/poexport-queue.txt (+5/-7)
lib/lp/translations/model/translatedlanguage.py (+0/-4)
lib/sqlobject/__init__.py (+0/-2)
scripts/process-one-mail.py (+1/-3)
Reviewer Review Type Date Requested Status
Cristian Gonzalez (community) Approve
Review via email: mp+406806@code.launchpad.net

Commit message

Remove simple cases of Python 2 version detection

To post a comment you must log in.
Revision history for this message
Cristian Gonzalez (cristiangsp) wrote :

Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/app/security.py b/lib/lp/app/security.py
2index 6fae684..08fe1e5 100644
3--- a/lib/lp/app/security.py
4+++ b/lib/lp/app/security.py
5@@ -13,7 +13,6 @@ __all__ = [
6
7 from itertools import repeat
8
9-import six
10 from six.moves import zip as izip
11 from zope.component import queryAdapter
12 from zope.interface import implementer
13@@ -128,9 +127,6 @@ class non_boolean_izip(izip):
14 "DelegatedAuthorization results can't be used in boolean "
15 "expressions.")
16
17- if six.PY2:
18- __nonzero__ = __bool__
19-
20
21 class DelegatedAuthorization(AuthorizationBase):
22
23diff --git a/lib/lp/bugs/externalbugtracker/bugzilla.py b/lib/lp/bugs/externalbugtracker/bugzilla.py
24index 830f680..2f941e8 100644
25--- a/lib/lp/bugs/externalbugtracker/bugzilla.py
26+++ b/lib/lp/bugs/externalbugtracker/bugzilla.py
27@@ -13,7 +13,6 @@ __all__ = [
28
29 from email.utils import parseaddr
30 import re
31-import string
32 import xml.parsers.expat
33
34 from defusedxml import minidom
35@@ -190,8 +189,7 @@ class Bugzilla(ExternalBugTracker):
36 bad_chars = b''.join(six.int2byte(i) for i in range(0, 32))
37 for char in b'\n', b'\r', b'\t':
38 bad_chars = bad_chars.replace(char, b'')
39- maketrans = bytes.maketrans if six.PY3 else string.maketrans
40- trans_map = maketrans(bad_chars, b' ' * len(bad_chars))
41+ trans_map = bytes.maketrans(bad_chars, b' ' * len(bad_chars))
42 contents = contents.translate(trans_map)
43 # Don't use forbid_dtd=True here; Bugzilla XML responses seem to
44 # include DOCTYPE declarations.
45diff --git a/lib/lp/bugs/mail/handler.py b/lib/lp/bugs/mail/handler.py
46index 3a151e2..fdf9a31 100644
47--- a/lib/lp/bugs/mail/handler.py
48+++ b/lib/lp/bugs/mail/handler.py
49@@ -13,7 +13,6 @@ import os
50
51 from lazr.lifecycle.event import ObjectCreatedEvent
52 from lazr.lifecycle.interfaces import IObjectCreatedEvent
53-import six
54 import transaction
55 from zope.component import getUtility
56 from zope.event import notify
57@@ -69,9 +68,6 @@ class BugTaskCommandGroup:
58 def __bool__(self):
59 return len(self._commands) > 0
60
61- if six.PY2:
62- __nonzero__ = __bool__
63-
64 def __str__(self):
65 text_commands = [str(cmd) for cmd in self.commands]
66 return '\n'.join(text_commands).strip()
67@@ -98,9 +94,6 @@ class BugCommandGroup(BugTaskCommandGroup):
68 else:
69 return super(BugCommandGroup, self).__bool__()
70
71- if six.PY2:
72- __nonzero__ = __bool__
73-
74 def __str__(self):
75 text_commands = [super(BugCommandGroup, self).__str__()]
76 for group in self.groups:
77diff --git a/lib/lp/bugs/scripts/bugexport.py b/lib/lp/bugs/scripts/bugexport.py
78index 70e340c..b607f40 100644
79--- a/lib/lp/bugs/scripts/bugexport.py
80+++ b/lib/lp/bugs/scripts/bugexport.py
81@@ -8,7 +8,6 @@ __all__ = [
82 ]
83
84 import base64
85-import sys
86
87
88 try:
89@@ -28,12 +27,6 @@ from lp.services.librarian.browser import ProxiedLibraryFileAlias
90 BUGS_XMLNS = 'https://launchpad.net/xmlns/2006/bugs'
91
92
93-if sys.version_info[0] >= 3:
94- encodebytes = base64.encodebytes
95-else:
96- encodebytes = base64.encodestring
97-
98-
99 def addnode(parent, elementname, content, **attrs):
100 node = ET.SubElement(parent, elementname, attrs)
101 node.text = content
102@@ -104,7 +97,8 @@ def serialise_bugtask(bugtask):
103 attachment.libraryfile.mimetype)
104 # Attach the attachment file contents, base 64 encoded.
105 addnode(attachment_node, 'contents',
106- encodebytes(attachment.libraryfile.read()).decode('ASCII'))
107+ base64.encodebytes(
108+ attachment.libraryfile.read()).decode('ASCII'))
109
110 return bug_node
111
112diff --git a/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py b/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py
113index 70ae789..f7530e2 100644
114--- a/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py
115+++ b/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py
116@@ -3,8 +3,6 @@
117
118 __metaclass__ = type
119
120-import sys
121-
122 from testtools.content import text_content
123 from testtools.matchers import MatchesRegex
124 import transaction
125@@ -153,12 +151,10 @@ class TestBugSummaryRebuild(TestCaseWithFactory):
126 rebuild_bugsummary_for_target(product, log)
127 self.assertEqual(1, get_bugsummary_rows(product).count())
128 self.assertEqual(0, get_bugsummaryjournal_rows(product).count())
129- long_type = int if sys.version_info[0] >= 3 else long
130 self.assertThat(
131 log.getLogBufferAndClear(),
132 MatchesRegex(
133- 'DEBUG Rebuilding %s\nDEBUG Added {.*: %r}' %
134- (product.name, long_type(1))))
135+ 'DEBUG Rebuilding %s\nDEBUG Added {.*: 1}' % product.name))
136
137 def test_script(self):
138 product = self.factory.makeProduct()
139diff --git a/lib/lp/code/browser/tests/test_branchmergeproposal.py b/lib/lp/code/browser/tests/test_branchmergeproposal.py
140index c4a776d..5f21254 100644
141--- a/lib/lp/code/browser/tests/test_branchmergeproposal.py
142+++ b/lib/lp/code/browser/tests/test_branchmergeproposal.py
143@@ -13,9 +13,11 @@ from datetime import (
144 datetime,
145 timedelta,
146 )
147-from difflib import unified_diff
148+from difflib import (
149+ diff_bytes,
150+ unified_diff,
151+ )
152 import doctest
153-from functools import partial
154 import hashlib
155 import re
156
157@@ -144,14 +146,6 @@ from lp.testing.views import (
158 )
159
160
161-if six.PY3:
162- from difflib import diff_bytes
163-
164- unified_diff_bytes = partial(diff_bytes, unified_diff)
165-else:
166- unified_diff_bytes = unified_diff
167-
168-
169 class GitHostingClientMixin:
170
171 def setUp(self):
172@@ -1427,22 +1421,21 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
173 def test_preview_diff_utf8(self):
174 """A preview_diff in utf-8 should be decoded as utf-8."""
175 text = ''.join(six.unichr(x) for x in range(255))
176- diff_bytes = ''.join(unified_diff([''], [text])).encode('utf-8')
177- self.setPreviewDiff(diff_bytes)
178+ diff = ''.join(unified_diff([''], [text])).encode('utf-8')
179+ self.setPreviewDiff(diff)
180 transaction.commit()
181 view = create_initialized_view(self.bmp, '+index')
182- self.assertEqual(diff_bytes.decode('utf-8'),
183- view.preview_diff_text)
184+ self.assertEqual(diff.decode('utf-8'), view.preview_diff_text)
185 self.assertTrue(view.diff_available)
186
187 def test_preview_diff_all_chars(self):
188 """preview_diff should work on diffs containing all possible bytes."""
189 text = b''.join(six.int2byte(x) for x in range(255))
190- diff_bytes = b''.join(unified_diff_bytes([b''], [text]))
191- self.setPreviewDiff(diff_bytes)
192+ diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
193+ self.setPreviewDiff(diff)
194 transaction.commit()
195 view = create_initialized_view(self.bmp, '+index')
196- self.assertEqual(diff_bytes.decode('windows-1252', 'replace'),
197+ self.assertEqual(diff.decode('windows-1252', 'replace'),
198 view.preview_diff_text)
199 self.assertTrue(view.diff_available)
200
201@@ -1450,8 +1443,8 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
202 # The preview_diff will recover from a timeout set to get the
203 # librarian content.
204 text = b''.join(six.int2byte(x) for x in range(255))
205- diff_bytes = b''.join(unified_diff_bytes([b''], [text]))
206- preview_diff = self.setPreviewDiff(diff_bytes)
207+ diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
208+ preview_diff = self.setPreviewDiff(diff)
209 transaction.commit()
210
211 def fake_open(*args):
212@@ -1470,8 +1463,8 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
213 # librarian content. (This can happen e.g. on staging replicas of
214 # the production database.)
215 text = b''.join(six.int2byte(x) for x in range(255))
216- diff_bytes = b''.join(unified_diff_bytes([b''], [text]))
217- preview_diff = self.setPreviewDiff(diff_bytes)
218+ diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
219+ preview_diff = self.setPreviewDiff(diff)
220 transaction.commit()
221
222 def fake_open(*args):
223diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
224index 28239d7..2cb78bc 100644
225--- a/lib/lp/registry/browser/person.py
226+++ b/lib/lp/registry/browser/person.py
227@@ -4296,9 +4296,6 @@ class ContactViaWebNotificationRecipientSet:
228 """See `INotificationRecipientSet`."""
229 return len(self) > 0
230
231- if six.PY2:
232- __nonzero__ = __bool__
233-
234 def getReason(self, person_or_email):
235 """See `INotificationRecipientSet`."""
236 if person_or_email not in self:
237diff --git a/lib/lp/registry/interfaces/sourcepackagename.py b/lib/lp/registry/interfaces/sourcepackagename.py
238index 89c0a8c..1d07542 100644
239--- a/lib/lp/registry/interfaces/sourcepackagename.py
240+++ b/lib/lp/registry/interfaces/sourcepackagename.py
241@@ -10,7 +10,6 @@ __all__ = [
242 'ISourcePackageNameSet',
243 ]
244
245-import six
246 from zope.interface import (
247 Attribute,
248 Interface,
249@@ -40,10 +39,6 @@ class ISourcePackageName(Interface):
250 def __str__():
251 """Return the name"""
252
253- if six.PY2:
254- def __unicode__():
255- """Return the name"""
256-
257
258 class ISourcePackageNameSet(Interface):
259 """A set of SourcePackageName."""
260diff --git a/lib/lp/registry/model/productrelease.py b/lib/lp/registry/model/productrelease.py
261index 7ae8b4b..6dfc8b3 100644
262--- a/lib/lp/registry/model/productrelease.py
263+++ b/lib/lp/registry/model/productrelease.py
264@@ -14,7 +14,6 @@ from io import (
265 BytesIO,
266 )
267 import os
268-import sys
269
270 from sqlobject import (
271 ForeignKey,
272@@ -137,10 +136,7 @@ class ProductRelease(SQLBase):
273 file_size = len(file_or_data)
274 file_obj = BytesIO(file_or_data)
275 else:
276- file_types = [BufferedIOBase]
277- if sys.version_info[0] < 3:
278- file_types.append(file)
279- assert isinstance(file_or_data, tuple(file_types)), (
280+ assert isinstance(file_or_data, BufferedIOBase), (
281 "file_or_data is not an expected type")
282 file_obj = file_or_data
283 start = file_obj.tell()
284diff --git a/lib/lp/registry/tests/test_nickname.py b/lib/lp/registry/tests/test_nickname.py
285index dbe5c45..6ca86bb 100644
286--- a/lib/lp/registry/tests/test_nickname.py
287+++ b/lib/lp/registry/tests/test_nickname.py
288@@ -5,8 +5,6 @@
289
290 __metaclass__ = type
291
292-import sys
293-
294 from zope.component import getUtility
295
296 from lp.registry.interfaces.person import IPersonSet
297@@ -45,26 +43,17 @@ class TestNicknameGeneration(TestCaseWithFactory):
298 # adding random suffixes to the required length.
299 self.assertIs(None, getUtility(IPersonSet).getByName('i'))
300 nick = generate_nick('i@example.com')
301- if sys.version_info[0] >= 3:
302- self.assertEqual('i-d', nick)
303- else:
304- self.assertEqual('i-b', nick)
305+ self.assertEqual('i-d', nick)
306
307 def test_can_create_noncolliding_nicknames(self):
308 # Given the same email address, generate_nick doesn't recreate the
309 # same nick once that nick is used.
310 self.factory.makePerson(name='bar')
311 nick = generate_nick('bar@example.com')
312- if sys.version_info[0] >= 3:
313- self.assertEqual('bar-1', nick)
314- else:
315- self.assertEqual('bar-3', nick)
316+ self.assertEqual('bar-1', nick)
317
318 # If we used the previously created nick and get another bar@ email
319 # address, another new nick is generated.
320 self.factory.makePerson(name=nick)
321 nick = generate_nick('bar@example.com')
322- if sys.version_info[0] >= 3:
323- self.assertEqual('3-bar', nick)
324- else:
325- self.assertEqual('5-bar', nick)
326+ self.assertEqual('3-bar', nick)
327diff --git a/lib/lp/registry/tests/test_ssh.py b/lib/lp/registry/tests/test_ssh.py
328index 2f3e700..006e185 100644
329--- a/lib/lp/registry/tests/test_ssh.py
330+++ b/lib/lp/registry/tests/test_ssh.py
331@@ -5,8 +5,6 @@
332
333 __metaclass__ = type
334
335-import sys
336-
337 from testtools.matchers import StartsWith
338 from zope.component import getUtility
339 from zope.security.proxy import removeSecurityProxy
340@@ -205,14 +203,10 @@ class TestSSHKeySet(TestCaseWithFactory):
341 keyset.new,
342 person, 'ssh-rsa badkeytext comment'
343 )
344- if sys.version_info[0] >= 3:
345- expected_message = "unknown blob type: b'\\xc7_'"
346- else:
347- expected_message = "unknown blob type: \\xc7_"
348 self.assertRaisesWithContent(
349 SSHKeyAdditionError,
350 "Invalid SSH key data: 'ssh-rsa asdfasdf comment' "
351- "(%s)" % expected_message,
352+ "(unknown blob type: b'\\xc7_')",
353 keyset.new,
354 person, 'ssh-rsa asdfasdf comment'
355 )
356diff --git a/lib/lp/scripts/utilities/importpedant.py b/lib/lp/scripts/utilities/importpedant.py
357index 5bf143e..93e7da9 100644
358--- a/lib/lp/scripts/utilities/importpedant.py
359+++ b/lib/lp/scripts/utilities/importpedant.py
360@@ -7,7 +7,6 @@ from operator import attrgetter
361 import types
362 import warnings
363
364-import six
365 from six.moves import builtins
366
367
368@@ -174,8 +173,7 @@ class NotFoundPolicyViolation(PedantDisagreesError):
369 # The names of the arguments form part of the interface of __import__(...),
370 # and must not be changed, as code may choose to invoke __import__ using
371 # keyword arguments - e.g. the encodings module in Python 2.6.
372-def import_pedant(name, globals={}, locals={}, fromlist=[],
373- level=(0 if six.PY3 else -1)):
374+def import_pedant(name, globals={}, locals={}, fromlist=[], level=0):
375 global naughty_imports
376
377 module = original_import(name, globals, locals, fromlist, level)
378diff --git a/lib/lp/scripts/utilities/test.py b/lib/lp/scripts/utilities/test.py
379index 375d70c..00795c2 100755
380--- a/lib/lp/scripts/utilities/test.py
381+++ b/lib/lp/scripts/utilities/test.py
382@@ -91,7 +91,7 @@ def configure_environment():
383 # Suppress accessibility warning because the test runner does not have UI.
384 os.environ['GTK_MODULES'] = ''
385
386- if six.PY3 and distro.linux_distribution()[:2] == ('Ubuntu', '18.04'):
387+ if distro.linux_distribution()[:2] == ('Ubuntu', '18.04'):
388 # XXX cjwatson 2020-10-09: Certain versions of Python crash when
389 # importing readline into a process that has libedit loaded
390 # (https://bugs.python.org/issue38634,
391diff --git a/lib/lp/services/compat.py b/lib/lp/services/compat.py
392index 4d8ee9d..3673a45 100644
393--- a/lib/lp/services/compat.py
394+++ b/lib/lp/services/compat.py
395@@ -32,19 +32,13 @@ try:
396 except ImportError:
397 from unittest import mock
398
399-import six
400-
401-
402-if six.PY3:
403- def message_as_bytes(message):
404- from email.generator import BytesGenerator
405- from email.policy import compat32
406-
407- fp = io.BytesIO()
408- g = BytesGenerator(
409- fp, mangle_from_=False, maxheaderlen=0, policy=compat32)
410- g.flatten(message)
411- return fp.getvalue()
412-else:
413- def message_as_bytes(message):
414- return message.as_string()
415+
416+def message_as_bytes(message):
417+ from email.generator import BytesGenerator
418+ from email.policy import compat32
419+
420+ fp = io.BytesIO()
421+ g = BytesGenerator(
422+ fp, mangle_from_=False, maxheaderlen=0, policy=compat32)
423+ g.flatten(message)
424+ return fp.getvalue()
425diff --git a/lib/lp/services/encoding.py b/lib/lp/services/encoding.py
426index 3c1728b..aa5f74e 100644
427--- a/lib/lp/services/encoding.py
428+++ b/lib/lp/services/encoding.py
429@@ -228,7 +228,7 @@ def wsgi_native_string(s):
430 Python 2, we enforce this here.
431 """
432 result = six.ensure_str(s, encoding='ISO-8859-1')
433- if six.PY3 and isinstance(s, six.text_type):
434+ if isinstance(s, six.text_type):
435 # Ensure we're limited to ISO-8859-1.
436 result.encode('ISO-8859-1')
437 return result
438diff --git a/lib/lp/services/limitedlist.py b/lib/lp/services/limitedlist.py
439index 9c9ca8b..1cb0db5 100644
440--- a/lib/lp/services/limitedlist.py
441+++ b/lib/lp/services/limitedlist.py
442@@ -6,8 +6,6 @@ __all__ = [
443 'LimitedList',
444 ]
445
446-import sys
447-
448
449 class LimitedList(list):
450 """A mutable sequence that takes a limited number of elements."""
451@@ -64,15 +62,6 @@ class LimitedList(list):
452 self._ensureLength()
453 return result
454
455- if sys.version_info[0] < 3:
456- # list.__setslice__ exists on Python 2, so we must override it in
457- # this subclass. (If it didn't exist, as is the case on Python 3,
458- # then __setitem__ above would be good enough.)
459- def __setslice__(self, i, j, sequence):
460- result = super(LimitedList, self).__setslice__(i, j, sequence)
461- self._ensureLength()
462- return result
463-
464 def append(self, value):
465 result = super(LimitedList, self).append(value)
466 self._ensureLength()
467diff --git a/lib/lp/services/mail/interfaces.py b/lib/lp/services/mail/interfaces.py
468index 41818a4..59fdfec 100644
469--- a/lib/lp/services/mail/interfaces.py
470+++ b/lib/lp/services/mail/interfaces.py
471@@ -19,7 +19,6 @@ __all__ = [
472 'UnknownRecipientError',
473 ]
474
475-import six
476 from zope.interface import (
477 Attribute,
478 Interface,
479@@ -156,9 +155,6 @@ class INotificationRecipientSet(Interface):
480 def __bool__():
481 """Return False when the set is empty, True when it's not."""
482
483- if six.PY2:
484- __nonzero__ = __bool__
485-
486 def getReason(person_or_email):
487 """Return a reason tuple containing (text, header) for an address.
488
489diff --git a/lib/lp/services/mail/notificationrecipientset.py b/lib/lp/services/mail/notificationrecipientset.py
490index 6004399..68f9014 100644
491--- a/lib/lp/services/mail/notificationrecipientset.py
492+++ b/lib/lp/services/mail/notificationrecipientset.py
493@@ -88,9 +88,6 @@ class NotificationRecipientSet:
494 """See `INotificationRecipientSet`."""
495 return bool(self._personToRationale)
496
497- if six.PY2:
498- __nonzero__ = __bool__
499-
500 def getReason(self, person_or_email):
501 """See `INotificationRecipientSet`."""
502 if zope_isinstance(person_or_email, six.string_types):
503diff --git a/lib/lp/services/scripts/base.py b/lib/lp/services/scripts/base.py
504index cd3f19b..989eab6 100644
505--- a/lib/lp/services/scripts/base.py
506+++ b/lib/lp/services/scripts/base.py
507@@ -468,11 +468,7 @@ def cronscript_enabled(control_url, name, log):
508 # traceback and continue on using the defaults.
509 try:
510 with response:
511- if sys.version_info[:2] >= (3, 2):
512- read_file = cron_config.read_file
513- else:
514- read_file = cron_config.readfp
515- read_file(io.StringIO(response.text))
516+ cron_config.read_file(io.StringIO(response.text))
517 except Exception:
518 log.exception("Error parsing %s", control_url)
519
520diff --git a/lib/lp/services/tests/test_encoding.py b/lib/lp/services/tests/test_encoding.py
521index 4a0e235..ed44acc 100644
522--- a/lib/lp/services/tests/test_encoding.py
523+++ b/lib/lp/services/tests/test_encoding.py
524@@ -7,8 +7,6 @@ from doctest import (
525 )
526 import unittest
527
528-import six
529-
530 import lp.services.encoding
531 from lp.services.encoding import wsgi_native_string
532 from lp.testing import TestCase
533@@ -16,22 +14,14 @@ from lp.testing import TestCase
534
535 class TestWSGINativeString(TestCase):
536
537- def _toNative(self, s):
538- if six.PY3:
539- return s
540- else:
541- return s.encode('ISO-8859-1')
542-
543 def test_not_bytes_or_unicode(self):
544 self.assertRaises(TypeError, wsgi_native_string, object())
545
546 def test_bytes_iso_8859_1(self):
547- self.assertEqual(
548- self._toNative(u'foo\xfe'), wsgi_native_string(b'foo\xfe'))
549+ self.assertEqual(u'foo\xfe', wsgi_native_string(b'foo\xfe'))
550
551 def test_unicode_iso_8859_1(self):
552- self.assertEqual(
553- self._toNative(u'foo\xfe'), wsgi_native_string(u'foo\xfe'))
554+ self.assertEqual(u'foo\xfe', wsgi_native_string(u'foo\xfe'))
555
556 def test_unicode_not_iso_8859_1(self):
557 self.assertRaises(UnicodeEncodeError, wsgi_native_string, u'foo\u2014')
558diff --git a/lib/lp/services/twistedsupport/tests/test_xmlrpc.py b/lib/lp/services/twistedsupport/tests/test_xmlrpc.py
559index 126d275..59e45fc 100644
560--- a/lib/lp/services/twistedsupport/tests/test_xmlrpc.py
561+++ b/lib/lp/services/twistedsupport/tests/test_xmlrpc.py
562@@ -5,12 +5,6 @@
563
564 __metaclass__ = type
565
566-import sys
567-
568-from testtools.matchers import (
569- LessThan,
570- Not,
571- )
572 from twisted.python.failure import Failure
573
574 from lp.services.twistedsupport import extract_result
575@@ -58,11 +52,7 @@ class TestTrapFault(TestCase):
576 def assertRaisesFailure(self, failure, function, *args, **kwargs):
577 try:
578 function(*args, **kwargs)
579- except Failure as raised_failure:
580- self.assertThat(sys.version_info, LessThan((3, 0)))
581- self.assertEqual(failure, raised_failure)
582 except Exception as raised_exception:
583- self.assertThat(sys.version_info, Not(LessThan((3, 0))))
584 self.assertEqual(failure.value, raised_exception)
585
586 def test_raises_non_faults(self):
587diff --git a/lib/lp/services/twistedsupport/xmlrpc.py b/lib/lp/services/twistedsupport/xmlrpc.py
588index 3521641..70f5598 100644
589--- a/lib/lp/services/twistedsupport/xmlrpc.py
590+++ b/lib/lp/services/twistedsupport/xmlrpc.py
591@@ -10,8 +10,6 @@ __all__ = [
592 'trap_fault',
593 ]
594
595-import sys
596-
597 from twisted.internet import defer
598 from twisted.web import xmlrpc
599
600@@ -68,7 +66,4 @@ def trap_fault(failure, *fault_classes):
601 fault = failure.value
602 if fault.faultCode in [cls.error_code for cls in fault_classes]:
603 return fault
604- if sys.version_info >= (3, 0):
605- failure.raiseException()
606- else:
607- raise failure
608+ failure.raiseException()
609diff --git a/lib/lp/services/webapp/pgsession.py b/lib/lp/services/webapp/pgsession.py
610index 0a5c664..de05da4 100644
611--- a/lib/lp/services/webapp/pgsession.py
612+++ b/lib/lp/services/webapp/pgsession.py
613@@ -32,33 +32,30 @@ HOURS = 60 * MINUTES
614 DAYS = 24 * HOURS
615
616
617-if six.PY3:
618- class Python2FriendlyUnpickler(pickle._Unpickler):
619- """An unpickler that handles Python 2 datetime objects.
620-
621- Python 3 versions before 3.6 fail to unpickle Python 2 datetime
622- objects (https://bugs.python.org/issue22005); even in Python >= 3.6
623- they require passing a different encoding to pickle.loads, which may
624- have undesirable effects on other objects being unpickled. Work
625- around this by instead patching in a different encoding just for the
626- argument to datetime.datetime.
627- """
628+class Python2FriendlyUnpickler(pickle._Unpickler):
629+ """An unpickler that handles Python 2 datetime objects.
630+
631+ Python 3 versions before 3.6 fail to unpickle Python 2 datetime objects
632+ (https://bugs.python.org/issue22005); even in Python >= 3.6 they require
633+ passing a different encoding to pickle.loads, which may have undesirable
634+ effects on other objects being unpickled. Work around this by instead
635+ patching in a different encoding just for the argument to
636+ datetime.datetime.
637+ """
638
639- def find_class(self, module, name):
640- if module == 'datetime' and name == 'datetime':
641- original_encoding = self.encoding
642- self.encoding = 'bytes'
643+ def find_class(self, module, name):
644+ if module == 'datetime' and name == 'datetime':
645+ original_encoding = self.encoding
646+ self.encoding = 'bytes'
647
648- def datetime_factory(pickle_data):
649- self.encoding = original_encoding
650- return datetime(pickle_data)
651+ def datetime_factory(pickle_data):
652+ self.encoding = original_encoding
653+ return datetime(pickle_data)
654
655- return datetime_factory
656- else:
657- return super(Python2FriendlyUnpickler, self).find_class(
658- module, name)
659-else:
660- Python2FriendlyUnpickler = pickle.Unpickler
661+ return datetime_factory
662+ else:
663+ return super(Python2FriendlyUnpickler, self).find_class(
664+ module, name)
665
666
667 class PGSessionBase:
668diff --git a/lib/lp/services/webapp/publisher.py b/lib/lp/services/webapp/publisher.py
669index 168b22e..f4d42cd 100644
670--- a/lib/lp/services/webapp/publisher.py
671+++ b/lib/lp/services/webapp/publisher.py
672@@ -632,11 +632,6 @@ class CanonicalAbsoluteURL:
673 self.context = context
674 self.request = request
675
676- if six.PY2:
677- def __unicode__(self):
678- """Returns the URL as a unicode string."""
679- raise NotImplementedError()
680-
681 def __str__(self):
682 """Returns an ASCII string with all unicode characters url quoted."""
683 return canonical_url(self.context, self.request)
684diff --git a/lib/lp/services/webapp/servers.py b/lib/lp/services/webapp/servers.py
685index d637916..a2ef356 100644
686--- a/lib/lp/services/webapp/servers.py
687+++ b/lib/lp/services/webapp/servers.py
688@@ -211,9 +211,6 @@ class StepsToGo(six.Iterator):
689 def __bool__(self):
690 return bool(self._stack)
691
692- if six.PY2:
693- __nonzero__ = __bool__
694-
695
696 class ApplicationServerSettingRequestFactory:
697 """Create a request and call its setApplicationServer method.
698@@ -527,20 +524,9 @@ def get_query_string_params(request):
699 if query_string is None:
700 query_string = ''
701
702- kwargs = {}
703- if not six.PY2:
704- kwargs['encoding'] = 'UTF-8'
705- kwargs['errors'] = 'replace'
706- parsed_qs = parse_qs(query_string, keep_blank_values=True, **kwargs)
707- if six.PY2:
708- decoded_qs = {}
709- for key, values in six.iteritems(parsed_qs):
710- decoded_qs[key] = [
711- (value.decode('UTF-8', 'replace') if isinstance(value, bytes)
712- else value)
713- for value in values]
714- parsed_qs = decoded_qs
715- return parsed_qs
716+ return parse_qs(
717+ query_string, keep_blank_values=True,
718+ encoding='UTF-8', errors='replace')
719
720
721 class LaunchpadBrowserRequestMixin:
722diff --git a/lib/lp/services/webapp/tests/test_servers.py b/lib/lp/services/webapp/tests/test_servers.py
723index ed66bfa..1b09775 100644
724--- a/lib/lp/services/webapp/tests/test_servers.py
725+++ b/lib/lp/services/webapp/tests/test_servers.py
726@@ -21,7 +21,6 @@ from lazr.restful.testing.webservice import (
727 IGenericEntry,
728 WebServiceTestCase,
729 )
730-import six
731 from talisker.context import Context
732 from talisker.logs import logging_context
733 from zope.component import (
734@@ -441,15 +440,12 @@ class TestBasicLaunchpadRequest(TestCase):
735 def test_request_with_invalid_query_string_recovers(self):
736 # When the query string has invalid utf-8, it is decoded with
737 # replacement.
738- if six.PY2:
739- env = {'QUERY_STRING': 'field.title=subproc\xe9s '}
740- else:
741- # PEP 3333 requires environment variables to be native strings,
742- # so we can't actually get a bytes object in here on Python 3
743- # (both because the WSGI runner will never put it there, and
744- # because parse_qs would crash if we did). Test the next best
745- # thing, namely percent-encoded invalid UTF-8.
746- env = {'QUERY_STRING': 'field.title=subproc%E9s '}
747+ # PEP 3333 requires environment variables to be native strings, so
748+ # we can't actually get a bytes object in here on Python 3 (both
749+ # because the WSGI runner will never put it there, and because
750+ # parse_qs would crash if we did). Test the next best thing, namely
751+ # percent-encoded invalid UTF-8.
752+ env = {'QUERY_STRING': 'field.title=subproc%E9s '}
753 request = LaunchpadBrowserRequest(io.BytesIO(b''), env)
754 self.assertEqual(
755 [u'subproc\ufffds '], request.query_string_params['field.title'])
756diff --git a/lib/lp/services/webapp/url.py b/lib/lp/services/webapp/url.py
757index e438fd9..3a05c33 100644
758--- a/lib/lp/services/webapp/url.py
759+++ b/lib/lp/services/webapp/url.py
760@@ -6,7 +6,6 @@
761 __metaclass__ = type
762 __all__ = ['urlappend', 'urlparse', 'urlsplit']
763
764-import six
765 import six.moves.urllib.parse as urlparse_module
766 from six.moves.urllib.parse import (
767 urljoin,
768@@ -81,9 +80,7 @@ def urlappend(baseurl, path):
769
770 def _ensure_ascii_str(url):
771 """Ensure that `url` only contains ASCII, and convert it to a `str`."""
772- if six.PY2:
773- url = url.encode('ascii')
774- elif isinstance(url, bytes):
775+ if isinstance(url, bytes):
776 url = url.decode('ascii')
777 else:
778 # Ignore the result; just check that `url` is pure ASCII.
779diff --git a/lib/lp/services/webhooks/payload.py b/lib/lp/services/webhooks/payload.py
780index f7c7e3d..d73cd1b 100644
781--- a/lib/lp/services/webhooks/payload.py
782+++ b/lib/lp/services/webhooks/payload.py
783@@ -12,7 +12,6 @@ __all__ = [
784 from io import BytesIO
785
786 from lazr.restful.interfaces import IFieldMarshaller
787-import six
788 from zope.component import getMultiAdapter
789 from zope.interface import implementer
790 from zope.traversing.browser.interfaces import IAbsoluteURL
791@@ -43,11 +42,6 @@ class WebhookAbsoluteURL:
792 self.context = context
793 self.request = request
794
795- if six.PY2:
796- def __unicode__(self):
797- """Returns the URL as a unicode string."""
798- raise NotImplementedError()
799-
800 def __str__(self):
801 """Returns an ASCII string with all unicode characters url quoted."""
802 return canonical_url(self.context, force_local_path=True)
803diff --git a/lib/lp/soyuz/adapters/archivesourcepublication.py b/lib/lp/soyuz/adapters/archivesourcepublication.py
804index 34e4919..f04807d 100644
805--- a/lib/lp/soyuz/adapters/archivesourcepublication.py
806+++ b/lib/lp/soyuz/adapters/archivesourcepublication.py
807@@ -17,7 +17,6 @@ __all__ = [
808 from collections import defaultdict
809
810 from lazr.delegates import delegate_to
811-import six
812 from zope.component import getUtility
813
814 from lp.registry.model.distroseries import DistroSeries
815@@ -104,9 +103,6 @@ class ArchiveSourcePublications:
816 """Are there any sources to iterate?"""
817 return self.has_sources
818
819- if six.PY2:
820- __nonzero__ = __bool__
821-
822 def __iter__(self):
823 """`ArchiveSourcePublication` iterator."""
824 results = []
825diff --git a/lib/lp/soyuz/interfaces/binarypackagename.py b/lib/lp/soyuz/interfaces/binarypackagename.py
826index bfef027..69973c6 100644
827--- a/lib/lp/soyuz/interfaces/binarypackagename.py
828+++ b/lib/lp/soyuz/interfaces/binarypackagename.py
829@@ -11,7 +11,6 @@ __all__ = [
830 'IBinaryPackageNameSet',
831 ]
832
833-import six
834 from zope.interface import Interface
835 from zope.schema import (
836 Int,
837@@ -31,10 +30,6 @@ class IBinaryPackageName(Interface):
838 def __str__():
839 """Return the name"""
840
841- if six.PY2:
842- def __unicode__():
843- """Return the name"""
844-
845
846 class IBinaryPackageNameSet(Interface):
847
848diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
849index 32c9923..084cee1 100644
850--- a/lib/lp/testing/factory.py
851+++ b/lib/lp/testing/factory.py
852@@ -38,7 +38,6 @@ from itertools import count
853 import os
854 import sys
855 from textwrap import dedent
856-import types
857 import uuid
858 import warnings
859
860@@ -5210,7 +5209,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
861 # Some factory methods return simple Python types. We don't add
862 # security wrappers for them, as well as for objects created by
863 # other Python libraries.
864-unwrapped_types = {
865+unwrapped_types = frozenset({
866 BaseRecipeBranch,
867 DSCFile,
868 Message,
869@@ -5218,10 +5217,7 @@ unwrapped_types = {
870 int,
871 str,
872 six.text_type,
873- }
874-if sys.version_info[0] < 3:
875- unwrapped_types.add(types.InstanceType)
876-unwrapped_types = frozenset(unwrapped_types)
877+ })
878
879
880 def is_security_proxied_or_harmless(obj):
881diff --git a/lib/lp/testing/systemdocs.py b/lib/lp/testing/systemdocs.py
882index 5e9bdac..29bb200 100644
883--- a/lib/lp/testing/systemdocs.py
884+++ b/lib/lp/testing/systemdocs.py
885@@ -232,19 +232,16 @@ class PrettyPrinter(pprint.PrettyPrinter, object):
886 return '"%s"' % obj, True, False
887 else:
888 return "'%s'" % obj.replace("'", "\\'"), True, False
889- elif sys.version_info[0] < 3 and isinstance(obj, long):
890- return repr(int(obj)), True, False
891 else:
892 return super(PrettyPrinter, self).format(
893 obj, contexts, maxlevels, level)
894
895 # Disable wrapping of long strings on Python >= 3.5, which is unhelpful
896 # in doctests. There seems to be no reasonable public API for this.
897- if sys.version_info[:2] >= (3, 5):
898- _dispatch = dict(pprint.PrettyPrinter._dispatch)
899- del _dispatch[six.text_type.__repr__]
900- del _dispatch[bytes.__repr__]
901- del _dispatch[bytearray.__repr__]
902+ _dispatch = dict(pprint.PrettyPrinter._dispatch)
903+ del _dispatch[six.text_type.__repr__]
904+ del _dispatch[bytes.__repr__]
905+ del _dispatch[bytearray.__repr__]
906
907
908 # XXX cjwatson 2018-05-13: Once all doctests are made safe for the standard
909diff --git a/lib/lp/translations/doc/poexport-queue.txt b/lib/lp/translations/doc/poexport-queue.txt
910index 7854639..562eb08 100644
911--- a/lib/lp/translations/doc/poexport-queue.txt
912+++ b/lib/lp/translations/doc/poexport-queue.txt
913@@ -139,14 +139,12 @@ It's not clear that it's possible to trigger this failure mode normally on
914 Python 3 at all, because bytes will just be formatted as b'...'. For now,
915 inject a mock exception in that case so that the test can pass.
916
917- >>> if six.PY3:
918- ... from lp.services.compat import mock
919- ... patcher = mock.patch.object(result, 'failure')
920- ... mock_failure = patcher.start()
921- ... mock_failure.__str__.side_effect = lambda: b'\xc3'.decode('UTF-8')
922+ >>> from lp.services.compat import mock
923+ >>> patcher = mock.patch.object(result, 'failure')
924+ >>> mock_failure = patcher.start()
925+ >>> mock_failure.__str__.side_effect = lambda: b'\xc3'.decode('UTF-8')
926 >>> result.notify()
927- >>> if six.PY3:
928- ... patcher.stop()
929+ >>> patcher.stop()
930
931 >>> test_emails = pop_notifications()
932 >>> len(test_emails)
933diff --git a/lib/lp/translations/model/translatedlanguage.py b/lib/lp/translations/model/translatedlanguage.py
934index e9d120a..7c7606c 100644
935--- a/lib/lp/translations/model/translatedlanguage.py
936+++ b/lib/lp/translations/model/translatedlanguage.py
937@@ -4,7 +4,6 @@
938 __all__ = ['TranslatedLanguageMixin']
939
940 import pytz
941-import six
942 from storm.expr import (
943 Coalesce,
944 Desc,
945@@ -75,9 +74,6 @@ class POFilesByPOTemplates(object):
946 def __bool__(self):
947 return bool(self.templates_collection.select(POTemplate).any())
948
949- if six.PY2:
950- __nonzero__ = __bool__
951-
952
953 @implementer(ITranslatedLanguage)
954 class TranslatedLanguageMixin(object):
955diff --git a/lib/sqlobject/__init__.py b/lib/sqlobject/__init__.py
956index 5450477..bc94046 100644
957--- a/lib/sqlobject/__init__.py
958+++ b/lib/sqlobject/__init__.py
959@@ -51,8 +51,6 @@ def sqlrepr(value, dbname=None):
960 return "'f'"
961 elif isinstance(value, int):
962 return repr(int(value))
963- elif six.PY2 and isinstance(value, long):
964- return str(value)
965 elif isinstance(value, float):
966 return repr(value)
967 elif value is None:
968diff --git a/scripts/process-one-mail.py b/scripts/process-one-mail.py
969index 0fa7484..3cb8598 100755
970--- a/scripts/process-one-mail.py
971+++ b/scripts/process-one-mail.py
972@@ -31,10 +31,8 @@ class ProcessMail(LaunchpadScript):
973 # with handling a mailbox, which we're avoiding here.
974 if len(self.args) >= 1:
975 from_file = open(self.args[0], 'rb')
976- elif sys.version_info[0] >= 3:
977- from_file = sys.stdin.buffer
978 else:
979- from_file = sys.stdin
980+ from_file = sys.stdin.buffer
981 self.logger.debug("reading message from %r" % (from_file,))
982 raw_mail = from_file.read()
983 if from_file != sys.stdin:

Subscribers

People subscribed via source and target branches

to status/vote changes: