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
diff --git a/lib/lp/app/security.py b/lib/lp/app/security.py
index 6fae684..08fe1e5 100644
--- a/lib/lp/app/security.py
+++ b/lib/lp/app/security.py
@@ -13,7 +13,6 @@ __all__ = [
1313
14from itertools import repeat14from itertools import repeat
1515
16import six
17from six.moves import zip as izip16from six.moves import zip as izip
18from zope.component import queryAdapter17from zope.component import queryAdapter
19from zope.interface import implementer18from zope.interface import implementer
@@ -128,9 +127,6 @@ class non_boolean_izip(izip):
128 "DelegatedAuthorization results can't be used in boolean "127 "DelegatedAuthorization results can't be used in boolean "
129 "expressions.")128 "expressions.")
130129
131 if six.PY2:
132 __nonzero__ = __bool__
133
134130
135class DelegatedAuthorization(AuthorizationBase):131class DelegatedAuthorization(AuthorizationBase):
136132
diff --git a/lib/lp/bugs/externalbugtracker/bugzilla.py b/lib/lp/bugs/externalbugtracker/bugzilla.py
index 830f680..2f941e8 100644
--- a/lib/lp/bugs/externalbugtracker/bugzilla.py
+++ b/lib/lp/bugs/externalbugtracker/bugzilla.py
@@ -13,7 +13,6 @@ __all__ = [
1313
14from email.utils import parseaddr14from email.utils import parseaddr
15import re15import re
16import string
17import xml.parsers.expat16import xml.parsers.expat
1817
19from defusedxml import minidom18from defusedxml import minidom
@@ -190,8 +189,7 @@ class Bugzilla(ExternalBugTracker):
190 bad_chars = b''.join(six.int2byte(i) for i in range(0, 32))189 bad_chars = b''.join(six.int2byte(i) for i in range(0, 32))
191 for char in b'\n', b'\r', b'\t':190 for char in b'\n', b'\r', b'\t':
192 bad_chars = bad_chars.replace(char, b'')191 bad_chars = bad_chars.replace(char, b'')
193 maketrans = bytes.maketrans if six.PY3 else string.maketrans192 trans_map = bytes.maketrans(bad_chars, b' ' * len(bad_chars))
194 trans_map = maketrans(bad_chars, b' ' * len(bad_chars))
195 contents = contents.translate(trans_map)193 contents = contents.translate(trans_map)
196 # Don't use forbid_dtd=True here; Bugzilla XML responses seem to194 # Don't use forbid_dtd=True here; Bugzilla XML responses seem to
197 # include DOCTYPE declarations.195 # include DOCTYPE declarations.
diff --git a/lib/lp/bugs/mail/handler.py b/lib/lp/bugs/mail/handler.py
index 3a151e2..fdf9a31 100644
--- a/lib/lp/bugs/mail/handler.py
+++ b/lib/lp/bugs/mail/handler.py
@@ -13,7 +13,6 @@ import os
1313
14from lazr.lifecycle.event import ObjectCreatedEvent14from lazr.lifecycle.event import ObjectCreatedEvent
15from lazr.lifecycle.interfaces import IObjectCreatedEvent15from lazr.lifecycle.interfaces import IObjectCreatedEvent
16import six
17import transaction16import transaction
18from zope.component import getUtility17from zope.component import getUtility
19from zope.event import notify18from zope.event import notify
@@ -69,9 +68,6 @@ class BugTaskCommandGroup:
69 def __bool__(self):68 def __bool__(self):
70 return len(self._commands) > 069 return len(self._commands) > 0
7170
72 if six.PY2:
73 __nonzero__ = __bool__
74
75 def __str__(self):71 def __str__(self):
76 text_commands = [str(cmd) for cmd in self.commands]72 text_commands = [str(cmd) for cmd in self.commands]
77 return '\n'.join(text_commands).strip()73 return '\n'.join(text_commands).strip()
@@ -98,9 +94,6 @@ class BugCommandGroup(BugTaskCommandGroup):
98 else:94 else:
99 return super(BugCommandGroup, self).__bool__()95 return super(BugCommandGroup, self).__bool__()
10096
101 if six.PY2:
102 __nonzero__ = __bool__
103
104 def __str__(self):97 def __str__(self):
105 text_commands = [super(BugCommandGroup, self).__str__()]98 text_commands = [super(BugCommandGroup, self).__str__()]
106 for group in self.groups:99 for group in self.groups:
diff --git a/lib/lp/bugs/scripts/bugexport.py b/lib/lp/bugs/scripts/bugexport.py
index 70e340c..b607f40 100644
--- a/lib/lp/bugs/scripts/bugexport.py
+++ b/lib/lp/bugs/scripts/bugexport.py
@@ -8,7 +8,6 @@ __all__ = [
8 ]8 ]
99
10import base6410import base64
11import sys
1211
1312
14try:13try:
@@ -28,12 +27,6 @@ from lp.services.librarian.browser import ProxiedLibraryFileAlias
28BUGS_XMLNS = 'https://launchpad.net/xmlns/2006/bugs'27BUGS_XMLNS = 'https://launchpad.net/xmlns/2006/bugs'
2928
3029
31if sys.version_info[0] >= 3:
32 encodebytes = base64.encodebytes
33else:
34 encodebytes = base64.encodestring
35
36
37def addnode(parent, elementname, content, **attrs):30def addnode(parent, elementname, content, **attrs):
38 node = ET.SubElement(parent, elementname, attrs)31 node = ET.SubElement(parent, elementname, attrs)
39 node.text = content32 node.text = content
@@ -104,7 +97,8 @@ def serialise_bugtask(bugtask):
104 attachment.libraryfile.mimetype)97 attachment.libraryfile.mimetype)
105 # Attach the attachment file contents, base 64 encoded.98 # Attach the attachment file contents, base 64 encoded.
106 addnode(attachment_node, 'contents',99 addnode(attachment_node, 'contents',
107 encodebytes(attachment.libraryfile.read()).decode('ASCII'))100 base64.encodebytes(
101 attachment.libraryfile.read()).decode('ASCII'))
108102
109 return bug_node103 return bug_node
110104
diff --git a/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py b/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py
index 70ae789..f7530e2 100644
--- a/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py
+++ b/lib/lp/bugs/scripts/tests/test_bugsummaryrebuild.py
@@ -3,8 +3,6 @@
33
4__metaclass__ = type4__metaclass__ = type
55
6import sys
7
8from testtools.content import text_content6from testtools.content import text_content
9from testtools.matchers import MatchesRegex7from testtools.matchers import MatchesRegex
10import transaction8import transaction
@@ -153,12 +151,10 @@ class TestBugSummaryRebuild(TestCaseWithFactory):
153 rebuild_bugsummary_for_target(product, log)151 rebuild_bugsummary_for_target(product, log)
154 self.assertEqual(1, get_bugsummary_rows(product).count())152 self.assertEqual(1, get_bugsummary_rows(product).count())
155 self.assertEqual(0, get_bugsummaryjournal_rows(product).count())153 self.assertEqual(0, get_bugsummaryjournal_rows(product).count())
156 long_type = int if sys.version_info[0] >= 3 else long
157 self.assertThat(154 self.assertThat(
158 log.getLogBufferAndClear(),155 log.getLogBufferAndClear(),
159 MatchesRegex(156 MatchesRegex(
160 'DEBUG Rebuilding %s\nDEBUG Added {.*: %r}' %157 'DEBUG Rebuilding %s\nDEBUG Added {.*: 1}' % product.name))
161 (product.name, long_type(1))))
162158
163 def test_script(self):159 def test_script(self):
164 product = self.factory.makeProduct()160 product = self.factory.makeProduct()
diff --git a/lib/lp/code/browser/tests/test_branchmergeproposal.py b/lib/lp/code/browser/tests/test_branchmergeproposal.py
index c4a776d..5f21254 100644
--- a/lib/lp/code/browser/tests/test_branchmergeproposal.py
+++ b/lib/lp/code/browser/tests/test_branchmergeproposal.py
@@ -13,9 +13,11 @@ from datetime import (
13 datetime,13 datetime,
14 timedelta,14 timedelta,
15 )15 )
16from difflib import unified_diff16from difflib import (
17 diff_bytes,
18 unified_diff,
19 )
17import doctest20import doctest
18from functools import partial
19import hashlib21import hashlib
20import re22import re
2123
@@ -144,14 +146,6 @@ from lp.testing.views import (
144 )146 )
145147
146148
147if six.PY3:
148 from difflib import diff_bytes
149
150 unified_diff_bytes = partial(diff_bytes, unified_diff)
151else:
152 unified_diff_bytes = unified_diff
153
154
155class GitHostingClientMixin:149class GitHostingClientMixin:
156150
157 def setUp(self):151 def setUp(self):
@@ -1427,22 +1421,21 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
1427 def test_preview_diff_utf8(self):1421 def test_preview_diff_utf8(self):
1428 """A preview_diff in utf-8 should be decoded as utf-8."""1422 """A preview_diff in utf-8 should be decoded as utf-8."""
1429 text = ''.join(six.unichr(x) for x in range(255))1423 text = ''.join(six.unichr(x) for x in range(255))
1430 diff_bytes = ''.join(unified_diff([''], [text])).encode('utf-8')1424 diff = ''.join(unified_diff([''], [text])).encode('utf-8')
1431 self.setPreviewDiff(diff_bytes)1425 self.setPreviewDiff(diff)
1432 transaction.commit()1426 transaction.commit()
1433 view = create_initialized_view(self.bmp, '+index')1427 view = create_initialized_view(self.bmp, '+index')
1434 self.assertEqual(diff_bytes.decode('utf-8'),1428 self.assertEqual(diff.decode('utf-8'), view.preview_diff_text)
1435 view.preview_diff_text)
1436 self.assertTrue(view.diff_available)1429 self.assertTrue(view.diff_available)
14371430
1438 def test_preview_diff_all_chars(self):1431 def test_preview_diff_all_chars(self):
1439 """preview_diff should work on diffs containing all possible bytes."""1432 """preview_diff should work on diffs containing all possible bytes."""
1440 text = b''.join(six.int2byte(x) for x in range(255))1433 text = b''.join(six.int2byte(x) for x in range(255))
1441 diff_bytes = b''.join(unified_diff_bytes([b''], [text]))1434 diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
1442 self.setPreviewDiff(diff_bytes)1435 self.setPreviewDiff(diff)
1443 transaction.commit()1436 transaction.commit()
1444 view = create_initialized_view(self.bmp, '+index')1437 view = create_initialized_view(self.bmp, '+index')
1445 self.assertEqual(diff_bytes.decode('windows-1252', 'replace'),1438 self.assertEqual(diff.decode('windows-1252', 'replace'),
1446 view.preview_diff_text)1439 view.preview_diff_text)
1447 self.assertTrue(view.diff_available)1440 self.assertTrue(view.diff_available)
14481441
@@ -1450,8 +1443,8 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
1450 # The preview_diff will recover from a timeout set to get the1443 # The preview_diff will recover from a timeout set to get the
1451 # librarian content.1444 # librarian content.
1452 text = b''.join(six.int2byte(x) for x in range(255))1445 text = b''.join(six.int2byte(x) for x in range(255))
1453 diff_bytes = b''.join(unified_diff_bytes([b''], [text]))1446 diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
1454 preview_diff = self.setPreviewDiff(diff_bytes)1447 preview_diff = self.setPreviewDiff(diff)
1455 transaction.commit()1448 transaction.commit()
14561449
1457 def fake_open(*args):1450 def fake_open(*args):
@@ -1470,8 +1463,8 @@ class TestBranchMergeProposalView(TestCaseWithFactory):
1470 # librarian content. (This can happen e.g. on staging replicas of1463 # librarian content. (This can happen e.g. on staging replicas of
1471 # the production database.)1464 # the production database.)
1472 text = b''.join(six.int2byte(x) for x in range(255))1465 text = b''.join(six.int2byte(x) for x in range(255))
1473 diff_bytes = b''.join(unified_diff_bytes([b''], [text]))1466 diff = b''.join(diff_bytes(unified_diff, [b''], [text]))
1474 preview_diff = self.setPreviewDiff(diff_bytes)1467 preview_diff = self.setPreviewDiff(diff)
1475 transaction.commit()1468 transaction.commit()
14761469
1477 def fake_open(*args):1470 def fake_open(*args):
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 28239d7..2cb78bc 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -4296,9 +4296,6 @@ class ContactViaWebNotificationRecipientSet:
4296 """See `INotificationRecipientSet`."""4296 """See `INotificationRecipientSet`."""
4297 return len(self) > 04297 return len(self) > 0
42984298
4299 if six.PY2:
4300 __nonzero__ = __bool__
4301
4302 def getReason(self, person_or_email):4299 def getReason(self, person_or_email):
4303 """See `INotificationRecipientSet`."""4300 """See `INotificationRecipientSet`."""
4304 if person_or_email not in self:4301 if person_or_email not in self:
diff --git a/lib/lp/registry/interfaces/sourcepackagename.py b/lib/lp/registry/interfaces/sourcepackagename.py
index 89c0a8c..1d07542 100644
--- a/lib/lp/registry/interfaces/sourcepackagename.py
+++ b/lib/lp/registry/interfaces/sourcepackagename.py
@@ -10,7 +10,6 @@ __all__ = [
10 'ISourcePackageNameSet',10 'ISourcePackageNameSet',
11 ]11 ]
1212
13import six
14from zope.interface import (13from zope.interface import (
15 Attribute,14 Attribute,
16 Interface,15 Interface,
@@ -40,10 +39,6 @@ class ISourcePackageName(Interface):
40 def __str__():39 def __str__():
41 """Return the name"""40 """Return the name"""
4241
43 if six.PY2:
44 def __unicode__():
45 """Return the name"""
46
4742
48class ISourcePackageNameSet(Interface):43class ISourcePackageNameSet(Interface):
49 """A set of SourcePackageName."""44 """A set of SourcePackageName."""
diff --git a/lib/lp/registry/model/productrelease.py b/lib/lp/registry/model/productrelease.py
index 7ae8b4b..6dfc8b3 100644
--- a/lib/lp/registry/model/productrelease.py
+++ b/lib/lp/registry/model/productrelease.py
@@ -14,7 +14,6 @@ from io import (
14 BytesIO,14 BytesIO,
15 )15 )
16import os16import os
17import sys
1817
19from sqlobject import (18from sqlobject import (
20 ForeignKey,19 ForeignKey,
@@ -137,10 +136,7 @@ class ProductRelease(SQLBase):
137 file_size = len(file_or_data)136 file_size = len(file_or_data)
138 file_obj = BytesIO(file_or_data)137 file_obj = BytesIO(file_or_data)
139 else:138 else:
140 file_types = [BufferedIOBase]139 assert isinstance(file_or_data, BufferedIOBase), (
141 if sys.version_info[0] < 3:
142 file_types.append(file)
143 assert isinstance(file_or_data, tuple(file_types)), (
144 "file_or_data is not an expected type")140 "file_or_data is not an expected type")
145 file_obj = file_or_data141 file_obj = file_or_data
146 start = file_obj.tell()142 start = file_obj.tell()
diff --git a/lib/lp/registry/tests/test_nickname.py b/lib/lp/registry/tests/test_nickname.py
index dbe5c45..6ca86bb 100644
--- a/lib/lp/registry/tests/test_nickname.py
+++ b/lib/lp/registry/tests/test_nickname.py
@@ -5,8 +5,6 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8import sys
9
10from zope.component import getUtility8from zope.component import getUtility
119
12from lp.registry.interfaces.person import IPersonSet10from lp.registry.interfaces.person import IPersonSet
@@ -45,26 +43,17 @@ class TestNicknameGeneration(TestCaseWithFactory):
45 # adding random suffixes to the required length.43 # adding random suffixes to the required length.
46 self.assertIs(None, getUtility(IPersonSet).getByName('i'))44 self.assertIs(None, getUtility(IPersonSet).getByName('i'))
47 nick = generate_nick('i@example.com')45 nick = generate_nick('i@example.com')
48 if sys.version_info[0] >= 3:46 self.assertEqual('i-d', nick)
49 self.assertEqual('i-d', nick)
50 else:
51 self.assertEqual('i-b', nick)
5247
53 def test_can_create_noncolliding_nicknames(self):48 def test_can_create_noncolliding_nicknames(self):
54 # Given the same email address, generate_nick doesn't recreate the49 # Given the same email address, generate_nick doesn't recreate the
55 # same nick once that nick is used.50 # same nick once that nick is used.
56 self.factory.makePerson(name='bar')51 self.factory.makePerson(name='bar')
57 nick = generate_nick('bar@example.com')52 nick = generate_nick('bar@example.com')
58 if sys.version_info[0] >= 3:53 self.assertEqual('bar-1', nick)
59 self.assertEqual('bar-1', nick)
60 else:
61 self.assertEqual('bar-3', nick)
6254
63 # If we used the previously created nick and get another bar@ email55 # If we used the previously created nick and get another bar@ email
64 # address, another new nick is generated.56 # address, another new nick is generated.
65 self.factory.makePerson(name=nick)57 self.factory.makePerson(name=nick)
66 nick = generate_nick('bar@example.com')58 nick = generate_nick('bar@example.com')
67 if sys.version_info[0] >= 3:59 self.assertEqual('3-bar', nick)
68 self.assertEqual('3-bar', nick)
69 else:
70 self.assertEqual('5-bar', nick)
diff --git a/lib/lp/registry/tests/test_ssh.py b/lib/lp/registry/tests/test_ssh.py
index 2f3e700..006e185 100644
--- a/lib/lp/registry/tests/test_ssh.py
+++ b/lib/lp/registry/tests/test_ssh.py
@@ -5,8 +5,6 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8import sys
9
10from testtools.matchers import StartsWith8from testtools.matchers import StartsWith
11from zope.component import getUtility9from zope.component import getUtility
12from zope.security.proxy import removeSecurityProxy10from zope.security.proxy import removeSecurityProxy
@@ -205,14 +203,10 @@ class TestSSHKeySet(TestCaseWithFactory):
205 keyset.new,203 keyset.new,
206 person, 'ssh-rsa badkeytext comment'204 person, 'ssh-rsa badkeytext comment'
207 )205 )
208 if sys.version_info[0] >= 3:
209 expected_message = "unknown blob type: b'\\xc7_'"
210 else:
211 expected_message = "unknown blob type: \\xc7_"
212 self.assertRaisesWithContent(206 self.assertRaisesWithContent(
213 SSHKeyAdditionError,207 SSHKeyAdditionError,
214 "Invalid SSH key data: 'ssh-rsa asdfasdf comment' "208 "Invalid SSH key data: 'ssh-rsa asdfasdf comment' "
215 "(%s)" % expected_message,209 "(unknown blob type: b'\\xc7_')",
216 keyset.new,210 keyset.new,
217 person, 'ssh-rsa asdfasdf comment'211 person, 'ssh-rsa asdfasdf comment'
218 )212 )
diff --git a/lib/lp/scripts/utilities/importpedant.py b/lib/lp/scripts/utilities/importpedant.py
index 5bf143e..93e7da9 100644
--- a/lib/lp/scripts/utilities/importpedant.py
+++ b/lib/lp/scripts/utilities/importpedant.py
@@ -7,7 +7,6 @@ from operator import attrgetter
7import types7import types
8import warnings8import warnings
99
10import six
11from six.moves import builtins10from six.moves import builtins
1211
1312
@@ -174,8 +173,7 @@ class NotFoundPolicyViolation(PedantDisagreesError):
174# The names of the arguments form part of the interface of __import__(...),173# The names of the arguments form part of the interface of __import__(...),
175# and must not be changed, as code may choose to invoke __import__ using174# and must not be changed, as code may choose to invoke __import__ using
176# keyword arguments - e.g. the encodings module in Python 2.6.175# keyword arguments - e.g. the encodings module in Python 2.6.
177def import_pedant(name, globals={}, locals={}, fromlist=[],176def import_pedant(name, globals={}, locals={}, fromlist=[], level=0):
178 level=(0 if six.PY3 else -1)):
179 global naughty_imports177 global naughty_imports
180178
181 module = original_import(name, globals, locals, fromlist, level)179 module = original_import(name, globals, locals, fromlist, level)
diff --git a/lib/lp/scripts/utilities/test.py b/lib/lp/scripts/utilities/test.py
index 375d70c..00795c2 100755
--- a/lib/lp/scripts/utilities/test.py
+++ b/lib/lp/scripts/utilities/test.py
@@ -91,7 +91,7 @@ def configure_environment():
91 # Suppress accessibility warning because the test runner does not have UI.91 # Suppress accessibility warning because the test runner does not have UI.
92 os.environ['GTK_MODULES'] = ''92 os.environ['GTK_MODULES'] = ''
9393
94 if six.PY3 and distro.linux_distribution()[:2] == ('Ubuntu', '18.04'):94 if distro.linux_distribution()[:2] == ('Ubuntu', '18.04'):
95 # XXX cjwatson 2020-10-09: Certain versions of Python crash when95 # XXX cjwatson 2020-10-09: Certain versions of Python crash when
96 # importing readline into a process that has libedit loaded96 # importing readline into a process that has libedit loaded
97 # (https://bugs.python.org/issue38634,97 # (https://bugs.python.org/issue38634,
diff --git a/lib/lp/services/compat.py b/lib/lp/services/compat.py
index 4d8ee9d..3673a45 100644
--- a/lib/lp/services/compat.py
+++ b/lib/lp/services/compat.py
@@ -32,19 +32,13 @@ try:
32except ImportError:32except ImportError:
33 from unittest import mock33 from unittest import mock
3434
35import six35
3636def message_as_bytes(message):
3737 from email.generator import BytesGenerator
38if six.PY3:38 from email.policy import compat32
39 def message_as_bytes(message):39
40 from email.generator import BytesGenerator40 fp = io.BytesIO()
41 from email.policy import compat3241 g = BytesGenerator(
4242 fp, mangle_from_=False, maxheaderlen=0, policy=compat32)
43 fp = io.BytesIO()43 g.flatten(message)
44 g = BytesGenerator(44 return fp.getvalue()
45 fp, mangle_from_=False, maxheaderlen=0, policy=compat32)
46 g.flatten(message)
47 return fp.getvalue()
48else:
49 def message_as_bytes(message):
50 return message.as_string()
diff --git a/lib/lp/services/encoding.py b/lib/lp/services/encoding.py
index 3c1728b..aa5f74e 100644
--- a/lib/lp/services/encoding.py
+++ b/lib/lp/services/encoding.py
@@ -228,7 +228,7 @@ def wsgi_native_string(s):
228 Python 2, we enforce this here.228 Python 2, we enforce this here.
229 """229 """
230 result = six.ensure_str(s, encoding='ISO-8859-1')230 result = six.ensure_str(s, encoding='ISO-8859-1')
231 if six.PY3 and isinstance(s, six.text_type):231 if isinstance(s, six.text_type):
232 # Ensure we're limited to ISO-8859-1.232 # Ensure we're limited to ISO-8859-1.
233 result.encode('ISO-8859-1')233 result.encode('ISO-8859-1')
234 return result234 return result
diff --git a/lib/lp/services/limitedlist.py b/lib/lp/services/limitedlist.py
index 9c9ca8b..1cb0db5 100644
--- a/lib/lp/services/limitedlist.py
+++ b/lib/lp/services/limitedlist.py
@@ -6,8 +6,6 @@ __all__ = [
6 'LimitedList',6 'LimitedList',
7 ]7 ]
88
9import sys
10
119
12class LimitedList(list):10class LimitedList(list):
13 """A mutable sequence that takes a limited number of elements."""11 """A mutable sequence that takes a limited number of elements."""
@@ -64,15 +62,6 @@ class LimitedList(list):
64 self._ensureLength()62 self._ensureLength()
65 return result63 return result
6664
67 if sys.version_info[0] < 3:
68 # list.__setslice__ exists on Python 2, so we must override it in
69 # this subclass. (If it didn't exist, as is the case on Python 3,
70 # then __setitem__ above would be good enough.)
71 def __setslice__(self, i, j, sequence):
72 result = super(LimitedList, self).__setslice__(i, j, sequence)
73 self._ensureLength()
74 return result
75
76 def append(self, value):65 def append(self, value):
77 result = super(LimitedList, self).append(value)66 result = super(LimitedList, self).append(value)
78 self._ensureLength()67 self._ensureLength()
diff --git a/lib/lp/services/mail/interfaces.py b/lib/lp/services/mail/interfaces.py
index 41818a4..59fdfec 100644
--- a/lib/lp/services/mail/interfaces.py
+++ b/lib/lp/services/mail/interfaces.py
@@ -19,7 +19,6 @@ __all__ = [
19 'UnknownRecipientError',19 'UnknownRecipientError',
20 ]20 ]
2121
22import six
23from zope.interface import (22from zope.interface import (
24 Attribute,23 Attribute,
25 Interface,24 Interface,
@@ -156,9 +155,6 @@ class INotificationRecipientSet(Interface):
156 def __bool__():155 def __bool__():
157 """Return False when the set is empty, True when it's not."""156 """Return False when the set is empty, True when it's not."""
158157
159 if six.PY2:
160 __nonzero__ = __bool__
161
162 def getReason(person_or_email):158 def getReason(person_or_email):
163 """Return a reason tuple containing (text, header) for an address.159 """Return a reason tuple containing (text, header) for an address.
164160
diff --git a/lib/lp/services/mail/notificationrecipientset.py b/lib/lp/services/mail/notificationrecipientset.py
index 6004399..68f9014 100644
--- a/lib/lp/services/mail/notificationrecipientset.py
+++ b/lib/lp/services/mail/notificationrecipientset.py
@@ -88,9 +88,6 @@ class NotificationRecipientSet:
88 """See `INotificationRecipientSet`."""88 """See `INotificationRecipientSet`."""
89 return bool(self._personToRationale)89 return bool(self._personToRationale)
9090
91 if six.PY2:
92 __nonzero__ = __bool__
93
94 def getReason(self, person_or_email):91 def getReason(self, person_or_email):
95 """See `INotificationRecipientSet`."""92 """See `INotificationRecipientSet`."""
96 if zope_isinstance(person_or_email, six.string_types):93 if zope_isinstance(person_or_email, six.string_types):
diff --git a/lib/lp/services/scripts/base.py b/lib/lp/services/scripts/base.py
index cd3f19b..989eab6 100644
--- a/lib/lp/services/scripts/base.py
+++ b/lib/lp/services/scripts/base.py
@@ -468,11 +468,7 @@ def cronscript_enabled(control_url, name, log):
468 # traceback and continue on using the defaults.468 # traceback and continue on using the defaults.
469 try:469 try:
470 with response:470 with response:
471 if sys.version_info[:2] >= (3, 2):471 cron_config.read_file(io.StringIO(response.text))
472 read_file = cron_config.read_file
473 else:
474 read_file = cron_config.readfp
475 read_file(io.StringIO(response.text))
476 except Exception:472 except Exception:
477 log.exception("Error parsing %s", control_url)473 log.exception("Error parsing %s", control_url)
478474
diff --git a/lib/lp/services/tests/test_encoding.py b/lib/lp/services/tests/test_encoding.py
index 4a0e235..ed44acc 100644
--- a/lib/lp/services/tests/test_encoding.py
+++ b/lib/lp/services/tests/test_encoding.py
@@ -7,8 +7,6 @@ from doctest import (
7 )7 )
8import unittest8import unittest
99
10import six
11
12import lp.services.encoding10import lp.services.encoding
13from lp.services.encoding import wsgi_native_string11from lp.services.encoding import wsgi_native_string
14from lp.testing import TestCase12from lp.testing import TestCase
@@ -16,22 +14,14 @@ from lp.testing import TestCase
1614
17class TestWSGINativeString(TestCase):15class TestWSGINativeString(TestCase):
1816
19 def _toNative(self, s):
20 if six.PY3:
21 return s
22 else:
23 return s.encode('ISO-8859-1')
24
25 def test_not_bytes_or_unicode(self):17 def test_not_bytes_or_unicode(self):
26 self.assertRaises(TypeError, wsgi_native_string, object())18 self.assertRaises(TypeError, wsgi_native_string, object())
2719
28 def test_bytes_iso_8859_1(self):20 def test_bytes_iso_8859_1(self):
29 self.assertEqual(21 self.assertEqual(u'foo\xfe', wsgi_native_string(b'foo\xfe'))
30 self._toNative(u'foo\xfe'), wsgi_native_string(b'foo\xfe'))
3122
32 def test_unicode_iso_8859_1(self):23 def test_unicode_iso_8859_1(self):
33 self.assertEqual(24 self.assertEqual(u'foo\xfe', wsgi_native_string(u'foo\xfe'))
34 self._toNative(u'foo\xfe'), wsgi_native_string(u'foo\xfe'))
3525
36 def test_unicode_not_iso_8859_1(self):26 def test_unicode_not_iso_8859_1(self):
37 self.assertRaises(UnicodeEncodeError, wsgi_native_string, u'foo\u2014')27 self.assertRaises(UnicodeEncodeError, wsgi_native_string, u'foo\u2014')
diff --git a/lib/lp/services/twistedsupport/tests/test_xmlrpc.py b/lib/lp/services/twistedsupport/tests/test_xmlrpc.py
index 126d275..59e45fc 100644
--- a/lib/lp/services/twistedsupport/tests/test_xmlrpc.py
+++ b/lib/lp/services/twistedsupport/tests/test_xmlrpc.py
@@ -5,12 +5,6 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8import sys
9
10from testtools.matchers import (
11 LessThan,
12 Not,
13 )
14from twisted.python.failure import Failure8from twisted.python.failure import Failure
159
16from lp.services.twistedsupport import extract_result10from lp.services.twistedsupport import extract_result
@@ -58,11 +52,7 @@ class TestTrapFault(TestCase):
58 def assertRaisesFailure(self, failure, function, *args, **kwargs):52 def assertRaisesFailure(self, failure, function, *args, **kwargs):
59 try:53 try:
60 function(*args, **kwargs)54 function(*args, **kwargs)
61 except Failure as raised_failure:
62 self.assertThat(sys.version_info, LessThan((3, 0)))
63 self.assertEqual(failure, raised_failure)
64 except Exception as raised_exception:55 except Exception as raised_exception:
65 self.assertThat(sys.version_info, Not(LessThan((3, 0))))
66 self.assertEqual(failure.value, raised_exception)56 self.assertEqual(failure.value, raised_exception)
6757
68 def test_raises_non_faults(self):58 def test_raises_non_faults(self):
diff --git a/lib/lp/services/twistedsupport/xmlrpc.py b/lib/lp/services/twistedsupport/xmlrpc.py
index 3521641..70f5598 100644
--- a/lib/lp/services/twistedsupport/xmlrpc.py
+++ b/lib/lp/services/twistedsupport/xmlrpc.py
@@ -10,8 +10,6 @@ __all__ = [
10 'trap_fault',10 'trap_fault',
11 ]11 ]
1212
13import sys
14
15from twisted.internet import defer13from twisted.internet import defer
16from twisted.web import xmlrpc14from twisted.web import xmlrpc
1715
@@ -68,7 +66,4 @@ def trap_fault(failure, *fault_classes):
68 fault = failure.value66 fault = failure.value
69 if fault.faultCode in [cls.error_code for cls in fault_classes]:67 if fault.faultCode in [cls.error_code for cls in fault_classes]:
70 return fault68 return fault
71 if sys.version_info >= (3, 0):69 failure.raiseException()
72 failure.raiseException()
73 else:
74 raise failure
diff --git a/lib/lp/services/webapp/pgsession.py b/lib/lp/services/webapp/pgsession.py
index 0a5c664..de05da4 100644
--- a/lib/lp/services/webapp/pgsession.py
+++ b/lib/lp/services/webapp/pgsession.py
@@ -32,33 +32,30 @@ HOURS = 60 * MINUTES
32DAYS = 24 * HOURS32DAYS = 24 * HOURS
3333
3434
35if six.PY3:35class Python2FriendlyUnpickler(pickle._Unpickler):
36 class Python2FriendlyUnpickler(pickle._Unpickler):36 """An unpickler that handles Python 2 datetime objects.
37 """An unpickler that handles Python 2 datetime objects.37
3838 Python 3 versions before 3.6 fail to unpickle Python 2 datetime objects
39 Python 3 versions before 3.6 fail to unpickle Python 2 datetime39 (https://bugs.python.org/issue22005); even in Python >= 3.6 they require
40 objects (https://bugs.python.org/issue22005); even in Python >= 3.640 passing a different encoding to pickle.loads, which may have undesirable
41 they require passing a different encoding to pickle.loads, which may41 effects on other objects being unpickled. Work around this by instead
42 have undesirable effects on other objects being unpickled. Work42 patching in a different encoding just for the argument to
43 around this by instead patching in a different encoding just for the43 datetime.datetime.
44 argument to datetime.datetime.44 """
45 """
4645
47 def find_class(self, module, name):46 def find_class(self, module, name):
48 if module == 'datetime' and name == 'datetime':47 if module == 'datetime' and name == 'datetime':
49 original_encoding = self.encoding48 original_encoding = self.encoding
50 self.encoding = 'bytes'49 self.encoding = 'bytes'
5150
52 def datetime_factory(pickle_data):51 def datetime_factory(pickle_data):
53 self.encoding = original_encoding52 self.encoding = original_encoding
54 return datetime(pickle_data)53 return datetime(pickle_data)
5554
56 return datetime_factory55 return datetime_factory
57 else:56 else:
58 return super(Python2FriendlyUnpickler, self).find_class(57 return super(Python2FriendlyUnpickler, self).find_class(
59 module, name)58 module, name)
60else:
61 Python2FriendlyUnpickler = pickle.Unpickler
6259
6360
64class PGSessionBase:61class PGSessionBase:
diff --git a/lib/lp/services/webapp/publisher.py b/lib/lp/services/webapp/publisher.py
index 168b22e..f4d42cd 100644
--- a/lib/lp/services/webapp/publisher.py
+++ b/lib/lp/services/webapp/publisher.py
@@ -632,11 +632,6 @@ class CanonicalAbsoluteURL:
632 self.context = context632 self.context = context
633 self.request = request633 self.request = request
634634
635 if six.PY2:
636 def __unicode__(self):
637 """Returns the URL as a unicode string."""
638 raise NotImplementedError()
639
640 def __str__(self):635 def __str__(self):
641 """Returns an ASCII string with all unicode characters url quoted."""636 """Returns an ASCII string with all unicode characters url quoted."""
642 return canonical_url(self.context, self.request)637 return canonical_url(self.context, self.request)
diff --git a/lib/lp/services/webapp/servers.py b/lib/lp/services/webapp/servers.py
index d637916..a2ef356 100644
--- a/lib/lp/services/webapp/servers.py
+++ b/lib/lp/services/webapp/servers.py
@@ -211,9 +211,6 @@ class StepsToGo(six.Iterator):
211 def __bool__(self):211 def __bool__(self):
212 return bool(self._stack)212 return bool(self._stack)
213213
214 if six.PY2:
215 __nonzero__ = __bool__
216
217214
218class ApplicationServerSettingRequestFactory:215class ApplicationServerSettingRequestFactory:
219 """Create a request and call its setApplicationServer method.216 """Create a request and call its setApplicationServer method.
@@ -527,20 +524,9 @@ def get_query_string_params(request):
527 if query_string is None:524 if query_string is None:
528 query_string = ''525 query_string = ''
529526
530 kwargs = {}527 return parse_qs(
531 if not six.PY2:528 query_string, keep_blank_values=True,
532 kwargs['encoding'] = 'UTF-8'529 encoding='UTF-8', errors='replace')
533 kwargs['errors'] = 'replace'
534 parsed_qs = parse_qs(query_string, keep_blank_values=True, **kwargs)
535 if six.PY2:
536 decoded_qs = {}
537 for key, values in six.iteritems(parsed_qs):
538 decoded_qs[key] = [
539 (value.decode('UTF-8', 'replace') if isinstance(value, bytes)
540 else value)
541 for value in values]
542 parsed_qs = decoded_qs
543 return parsed_qs
544530
545531
546class LaunchpadBrowserRequestMixin:532class LaunchpadBrowserRequestMixin:
diff --git a/lib/lp/services/webapp/tests/test_servers.py b/lib/lp/services/webapp/tests/test_servers.py
index ed66bfa..1b09775 100644
--- a/lib/lp/services/webapp/tests/test_servers.py
+++ b/lib/lp/services/webapp/tests/test_servers.py
@@ -21,7 +21,6 @@ from lazr.restful.testing.webservice import (
21 IGenericEntry,21 IGenericEntry,
22 WebServiceTestCase,22 WebServiceTestCase,
23 )23 )
24import six
25from talisker.context import Context24from talisker.context import Context
26from talisker.logs import logging_context25from talisker.logs import logging_context
27from zope.component import (26from zope.component import (
@@ -441,15 +440,12 @@ class TestBasicLaunchpadRequest(TestCase):
441 def test_request_with_invalid_query_string_recovers(self):440 def test_request_with_invalid_query_string_recovers(self):
442 # When the query string has invalid utf-8, it is decoded with441 # When the query string has invalid utf-8, it is decoded with
443 # replacement.442 # replacement.
444 if six.PY2:443 # PEP 3333 requires environment variables to be native strings, so
445 env = {'QUERY_STRING': 'field.title=subproc\xe9s '}444 # we can't actually get a bytes object in here on Python 3 (both
446 else:445 # because the WSGI runner will never put it there, and because
447 # PEP 3333 requires environment variables to be native strings,446 # parse_qs would crash if we did). Test the next best thing, namely
448 # so we can't actually get a bytes object in here on Python 3447 # percent-encoded invalid UTF-8.
449 # (both because the WSGI runner will never put it there, and448 env = {'QUERY_STRING': 'field.title=subproc%E9s '}
450 # because parse_qs would crash if we did). Test the next best
451 # thing, namely percent-encoded invalid UTF-8.
452 env = {'QUERY_STRING': 'field.title=subproc%E9s '}
453 request = LaunchpadBrowserRequest(io.BytesIO(b''), env)449 request = LaunchpadBrowserRequest(io.BytesIO(b''), env)
454 self.assertEqual(450 self.assertEqual(
455 [u'subproc\ufffds '], request.query_string_params['field.title'])451 [u'subproc\ufffds '], request.query_string_params['field.title'])
diff --git a/lib/lp/services/webapp/url.py b/lib/lp/services/webapp/url.py
index e438fd9..3a05c33 100644
--- a/lib/lp/services/webapp/url.py
+++ b/lib/lp/services/webapp/url.py
@@ -6,7 +6,6 @@
6__metaclass__ = type6__metaclass__ = type
7__all__ = ['urlappend', 'urlparse', 'urlsplit']7__all__ = ['urlappend', 'urlparse', 'urlsplit']
88
9import six
10import six.moves.urllib.parse as urlparse_module9import six.moves.urllib.parse as urlparse_module
11from six.moves.urllib.parse import (10from six.moves.urllib.parse import (
12 urljoin,11 urljoin,
@@ -81,9 +80,7 @@ def urlappend(baseurl, path):
8180
82def _ensure_ascii_str(url):81def _ensure_ascii_str(url):
83 """Ensure that `url` only contains ASCII, and convert it to a `str`."""82 """Ensure that `url` only contains ASCII, and convert it to a `str`."""
84 if six.PY2:83 if isinstance(url, bytes):
85 url = url.encode('ascii')
86 elif isinstance(url, bytes):
87 url = url.decode('ascii')84 url = url.decode('ascii')
88 else:85 else:
89 # Ignore the result; just check that `url` is pure ASCII.86 # Ignore the result; just check that `url` is pure ASCII.
diff --git a/lib/lp/services/webhooks/payload.py b/lib/lp/services/webhooks/payload.py
index f7c7e3d..d73cd1b 100644
--- a/lib/lp/services/webhooks/payload.py
+++ b/lib/lp/services/webhooks/payload.py
@@ -12,7 +12,6 @@ __all__ = [
12from io import BytesIO12from io import BytesIO
1313
14from lazr.restful.interfaces import IFieldMarshaller14from lazr.restful.interfaces import IFieldMarshaller
15import six
16from zope.component import getMultiAdapter15from zope.component import getMultiAdapter
17from zope.interface import implementer16from zope.interface import implementer
18from zope.traversing.browser.interfaces import IAbsoluteURL17from zope.traversing.browser.interfaces import IAbsoluteURL
@@ -43,11 +42,6 @@ class WebhookAbsoluteURL:
43 self.context = context42 self.context = context
44 self.request = request43 self.request = request
4544
46 if six.PY2:
47 def __unicode__(self):
48 """Returns the URL as a unicode string."""
49 raise NotImplementedError()
50
51 def __str__(self):45 def __str__(self):
52 """Returns an ASCII string with all unicode characters url quoted."""46 """Returns an ASCII string with all unicode characters url quoted."""
53 return canonical_url(self.context, force_local_path=True)47 return canonical_url(self.context, force_local_path=True)
diff --git a/lib/lp/soyuz/adapters/archivesourcepublication.py b/lib/lp/soyuz/adapters/archivesourcepublication.py
index 34e4919..f04807d 100644
--- a/lib/lp/soyuz/adapters/archivesourcepublication.py
+++ b/lib/lp/soyuz/adapters/archivesourcepublication.py
@@ -17,7 +17,6 @@ __all__ = [
17from collections import defaultdict17from collections import defaultdict
1818
19from lazr.delegates import delegate_to19from lazr.delegates import delegate_to
20import six
21from zope.component import getUtility20from zope.component import getUtility
2221
23from lp.registry.model.distroseries import DistroSeries22from lp.registry.model.distroseries import DistroSeries
@@ -104,9 +103,6 @@ class ArchiveSourcePublications:
104 """Are there any sources to iterate?"""103 """Are there any sources to iterate?"""
105 return self.has_sources104 return self.has_sources
106105
107 if six.PY2:
108 __nonzero__ = __bool__
109
110 def __iter__(self):106 def __iter__(self):
111 """`ArchiveSourcePublication` iterator."""107 """`ArchiveSourcePublication` iterator."""
112 results = []108 results = []
diff --git a/lib/lp/soyuz/interfaces/binarypackagename.py b/lib/lp/soyuz/interfaces/binarypackagename.py
index bfef027..69973c6 100644
--- a/lib/lp/soyuz/interfaces/binarypackagename.py
+++ b/lib/lp/soyuz/interfaces/binarypackagename.py
@@ -11,7 +11,6 @@ __all__ = [
11 'IBinaryPackageNameSet',11 'IBinaryPackageNameSet',
12 ]12 ]
1313
14import six
15from zope.interface import Interface14from zope.interface import Interface
16from zope.schema import (15from zope.schema import (
17 Int,16 Int,
@@ -31,10 +30,6 @@ class IBinaryPackageName(Interface):
31 def __str__():30 def __str__():
32 """Return the name"""31 """Return the name"""
3332
34 if six.PY2:
35 def __unicode__():
36 """Return the name"""
37
3833
39class IBinaryPackageNameSet(Interface):34class IBinaryPackageNameSet(Interface):
4035
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index 32c9923..084cee1 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -38,7 +38,6 @@ from itertools import count
38import os38import os
39import sys39import sys
40from textwrap import dedent40from textwrap import dedent
41import types
42import uuid41import uuid
43import warnings42import warnings
4443
@@ -5210,7 +5209,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
5210# Some factory methods return simple Python types. We don't add5209# Some factory methods return simple Python types. We don't add
5211# security wrappers for them, as well as for objects created by5210# security wrappers for them, as well as for objects created by
5212# other Python libraries.5211# other Python libraries.
5213unwrapped_types = {5212unwrapped_types = frozenset({
5214 BaseRecipeBranch,5213 BaseRecipeBranch,
5215 DSCFile,5214 DSCFile,
5216 Message,5215 Message,
@@ -5218,10 +5217,7 @@ unwrapped_types = {
5218 int,5217 int,
5219 str,5218 str,
5220 six.text_type,5219 six.text_type,
5221 }5220 })
5222if sys.version_info[0] < 3:
5223 unwrapped_types.add(types.InstanceType)
5224unwrapped_types = frozenset(unwrapped_types)
52255221
52265222
5227def is_security_proxied_or_harmless(obj):5223def is_security_proxied_or_harmless(obj):
diff --git a/lib/lp/testing/systemdocs.py b/lib/lp/testing/systemdocs.py
index 5e9bdac..29bb200 100644
--- a/lib/lp/testing/systemdocs.py
+++ b/lib/lp/testing/systemdocs.py
@@ -232,19 +232,16 @@ class PrettyPrinter(pprint.PrettyPrinter, object):
232 return '"%s"' % obj, True, False232 return '"%s"' % obj, True, False
233 else:233 else:
234 return "'%s'" % obj.replace("'", "\\'"), True, False234 return "'%s'" % obj.replace("'", "\\'"), True, False
235 elif sys.version_info[0] < 3 and isinstance(obj, long):
236 return repr(int(obj)), True, False
237 else:235 else:
238 return super(PrettyPrinter, self).format(236 return super(PrettyPrinter, self).format(
239 obj, contexts, maxlevels, level)237 obj, contexts, maxlevels, level)
240238
241 # Disable wrapping of long strings on Python >= 3.5, which is unhelpful239 # Disable wrapping of long strings on Python >= 3.5, which is unhelpful
242 # in doctests. There seems to be no reasonable public API for this.240 # in doctests. There seems to be no reasonable public API for this.
243 if sys.version_info[:2] >= (3, 5):241 _dispatch = dict(pprint.PrettyPrinter._dispatch)
244 _dispatch = dict(pprint.PrettyPrinter._dispatch)242 del _dispatch[six.text_type.__repr__]
245 del _dispatch[six.text_type.__repr__]243 del _dispatch[bytes.__repr__]
246 del _dispatch[bytes.__repr__]244 del _dispatch[bytearray.__repr__]
247 del _dispatch[bytearray.__repr__]
248245
249246
250# XXX cjwatson 2018-05-13: Once all doctests are made safe for the standard247# XXX cjwatson 2018-05-13: Once all doctests are made safe for the standard
diff --git a/lib/lp/translations/doc/poexport-queue.txt b/lib/lp/translations/doc/poexport-queue.txt
index 7854639..562eb08 100644
--- a/lib/lp/translations/doc/poexport-queue.txt
+++ b/lib/lp/translations/doc/poexport-queue.txt
@@ -139,14 +139,12 @@ It's not clear that it's possible to trigger this failure mode normally on
139Python 3 at all, because bytes will just be formatted as b'...'. For now,139Python 3 at all, because bytes will just be formatted as b'...'. For now,
140inject a mock exception in that case so that the test can pass.140inject a mock exception in that case so that the test can pass.
141141
142 >>> if six.PY3:142 >>> from lp.services.compat import mock
143 ... from lp.services.compat import mock143 >>> patcher = mock.patch.object(result, 'failure')
144 ... patcher = mock.patch.object(result, 'failure')144 >>> mock_failure = patcher.start()
145 ... mock_failure = patcher.start()145 >>> mock_failure.__str__.side_effect = lambda: b'\xc3'.decode('UTF-8')
146 ... mock_failure.__str__.side_effect = lambda: b'\xc3'.decode('UTF-8')
147 >>> result.notify()146 >>> result.notify()
148 >>> if six.PY3:147 >>> patcher.stop()
149 ... patcher.stop()
150148
151 >>> test_emails = pop_notifications()149 >>> test_emails = pop_notifications()
152 >>> len(test_emails)150 >>> len(test_emails)
diff --git a/lib/lp/translations/model/translatedlanguage.py b/lib/lp/translations/model/translatedlanguage.py
index e9d120a..7c7606c 100644
--- a/lib/lp/translations/model/translatedlanguage.py
+++ b/lib/lp/translations/model/translatedlanguage.py
@@ -4,7 +4,6 @@
4__all__ = ['TranslatedLanguageMixin']4__all__ = ['TranslatedLanguageMixin']
55
6import pytz6import pytz
7import six
8from storm.expr import (7from storm.expr import (
9 Coalesce,8 Coalesce,
10 Desc,9 Desc,
@@ -75,9 +74,6 @@ class POFilesByPOTemplates(object):
75 def __bool__(self):74 def __bool__(self):
76 return bool(self.templates_collection.select(POTemplate).any())75 return bool(self.templates_collection.select(POTemplate).any())
7776
78 if six.PY2:
79 __nonzero__ = __bool__
80
8177
82@implementer(ITranslatedLanguage)78@implementer(ITranslatedLanguage)
83class TranslatedLanguageMixin(object):79class TranslatedLanguageMixin(object):
diff --git a/lib/sqlobject/__init__.py b/lib/sqlobject/__init__.py
index 5450477..bc94046 100644
--- a/lib/sqlobject/__init__.py
+++ b/lib/sqlobject/__init__.py
@@ -51,8 +51,6 @@ def sqlrepr(value, dbname=None):
51 return "'f'"51 return "'f'"
52 elif isinstance(value, int):52 elif isinstance(value, int):
53 return repr(int(value))53 return repr(int(value))
54 elif six.PY2 and isinstance(value, long):
55 return str(value)
56 elif isinstance(value, float):54 elif isinstance(value, float):
57 return repr(value)55 return repr(value)
58 elif value is None:56 elif value is None:
diff --git a/scripts/process-one-mail.py b/scripts/process-one-mail.py
index 0fa7484..3cb8598 100755
--- a/scripts/process-one-mail.py
+++ b/scripts/process-one-mail.py
@@ -31,10 +31,8 @@ class ProcessMail(LaunchpadScript):
31 # with handling a mailbox, which we're avoiding here.31 # with handling a mailbox, which we're avoiding here.
32 if len(self.args) >= 1:32 if len(self.args) >= 1:
33 from_file = open(self.args[0], 'rb')33 from_file = open(self.args[0], 'rb')
34 elif sys.version_info[0] >= 3:
35 from_file = sys.stdin.buffer
36 else:34 else:
37 from_file = sys.stdin35 from_file = sys.stdin.buffer
38 self.logger.debug("reading message from %r" % (from_file,))36 self.logger.debug("reading message from %r" % (from_file,))
39 raw_mail = from_file.read()37 raw_mail = from_file.read()
40 if from_file != sys.stdin:38 if from_file != sys.stdin:

Subscribers

People subscribed via source and target branches

to status/vote changes: