Merge ~cjwatson/launchpad:py3-isinstance-unicode into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: a7e5a7ea10f12601a0f81dff8e0cc22a268f4e29
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:py3-isinstance-unicode
Merge into: launchpad:master
Diff against target: 487 lines (+53/-35)
22 files modified
lib/lp/app/browser/root.py (+2/-1)
lib/lp/blueprints/browser/specificationgoal.py (+2/-1)
lib/lp/blueprints/browser/sprint.py (+1/-1)
lib/lp/registry/browser/person.py (+4/-3)
lib/lp/registry/interfaces/mailinglist.py (+1/-1)
lib/lp/registry/model/person.py (+3/-2)
lib/lp/services/beautifulsoup.py (+3/-1)
lib/lp/services/gpg/handler.py (+4/-3)
lib/lp/services/helpers.py (+4/-3)
lib/lp/services/identity/model/account.py (+2/-1)
lib/lp/services/mail/notificationrecipientset.py (+2/-1)
lib/lp/services/mail/sendmail.py (+2/-1)
lib/lp/services/webapp/publisher.py (+1/-1)
lib/lp/services/webapp/sorting.py (+5/-3)
lib/lp/soyuz/mail/packageupload.py (+1/-1)
lib/lp/testing/factory.py (+1/-1)
lib/lp/testing/gpgkeys/__init__.py (+3/-2)
lib/lp/testing/matchers.py (+2/-2)
lib/lp/translations/browser/browser_helpers.py (+3/-1)
lib/lp/translations/utilities/gettext_po_parser.py (+1/-1)
lib/lp/translations/utilities/xpi_header.py (+4/-3)
lib/sqlobject/__init__.py (+2/-1)
Reviewer Review Type Date Requested Status
Thiago F. Pappacena (community) Approve
Review via email: mp+388947@code.launchpad.net

Commit message

Port isinstance(..., unicode) checks to Python 3

Description of the change

In most cases, these can just be `isinstance(..., six.text_type)`, but some cases that also check Python 2 `str` (i.e. `bytes`) need slightly different treatment.

To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

LGTM

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/browser/root.py b/lib/lp/app/browser/root.py
2index ccfb0fd..0d47b6b 100644
3--- a/lib/lp/app/browser/root.py
4+++ b/lib/lp/app/browser/root.py
5@@ -15,6 +15,7 @@ import time
6 import feedparser
7 from lazr.batchnavigator.z3batching import batch
8 import requests
9+import six
10 from zope.component import getUtility
11 from zope.formlib.interfaces import ConversionError
12 from zope.interface import Interface
13@@ -427,7 +428,7 @@ class LaunchpadSearchView(LaunchpadFormView):
14 if isinstance(error, ConversionError):
15 self.setFieldError(
16 'text', 'Can not convert your search term.')
17- elif isinstance(error, unicode):
18+ elif isinstance(error, six.text_type):
19 continue
20 elif (error.field_name == 'text'
21 and isinstance(error.errors, TooLong)):
22diff --git a/lib/lp/blueprints/browser/specificationgoal.py b/lib/lp/blueprints/browser/specificationgoal.py
23index 2458791..003d01d 100644
24--- a/lib/lp/blueprints/browser/specificationgoal.py
25+++ b/lib/lp/blueprints/browser/specificationgoal.py
26@@ -10,6 +10,7 @@ __all__ = [
27 ]
28
29
30+import six
31 from zope.component import getUtility
32
33 from lp.blueprints.browser.specificationtarget import HasSpecificationsView
34@@ -79,7 +80,7 @@ class GoalDecideView(HasSpecificationsView, LaunchpadView):
35 action = 'Declined'
36
37 selected_specs = form['specification']
38- if isinstance(selected_specs, unicode):
39+ if isinstance(selected_specs, six.text_type):
40 # only a single item was selected, but we want to deal with a
41 # list for the general case, so convert it to a list
42 selected_specs = [selected_specs]
43diff --git a/lib/lp/blueprints/browser/sprint.py b/lib/lp/blueprints/browser/sprint.py
44index fabd3e3..aae704a 100644
45--- a/lib/lp/blueprints/browser/sprint.py
46+++ b/lib/lp/blueprints/browser/sprint.py
47@@ -458,7 +458,7 @@ class SprintTopicSetView(HasSpecificationsView, LaunchpadView):
48 action = 'Declined'
49
50 selected_specs = form['speclink']
51- if isinstance(selected_specs, unicode):
52+ if isinstance(selected_specs, six.text_type):
53 # only a single item was selected, but we want to deal with a
54 # list for the general case, so convert it to a list
55 selected_specs = [selected_specs]
56diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
57index a8ef6fc..f89f8e0 100644
58--- a/lib/lp/registry/browser/person.py
59+++ b/lib/lp/registry/browser/person.py
60@@ -65,6 +65,7 @@ from lazr.restful.interfaces import IWebServiceClientRequest
61 from lazr.restful.utils import smartquote
62 from lazr.uri import URI
63 import pytz
64+import six
65 from six.moves.urllib.parse import (
66 quote,
67 urlencode,
68@@ -2773,7 +2774,7 @@ class PersonEditEmailsView(LaunchpadFormView):
69 """
70 terms = []
71 for term in self.unvalidated_addresses:
72- if isinstance(term, unicode):
73+ if isinstance(term, six.text_type):
74 term = SimpleTerm(term)
75 else:
76 term = SimpleTerm(term, term.email)
77@@ -2814,7 +2815,7 @@ class PersonEditEmailsView(LaunchpadFormView):
78 "self.context.id(%s,%d) (%s)"
79 % (person.name, person.id, self.context.name, self.context.id,
80 email.email))
81- elif isinstance(email, unicode):
82+ elif isinstance(email, six.text_type):
83 tokenset = getUtility(ILoginTokenSet)
84 email = tokenset.searchByEmailRequesterAndType(
85 email, self.context, LoginTokenType.VALIDATEEMAIL)
86@@ -2940,7 +2941,7 @@ class PersonEditEmailsView(LaunchpadFormView):
87 if IEmailAddress.providedBy(emailaddress):
88 emailaddress.destroySelf()
89 email = emailaddress.email
90- elif isinstance(emailaddress, unicode):
91+ elif isinstance(emailaddress, six.text_type):
92 logintokenset = getUtility(ILoginTokenSet)
93 logintokenset.deleteByEmailRequesterAndType(
94 emailaddress, self.context, LoginTokenType.VALIDATEEMAIL)
95diff --git a/lib/lp/registry/interfaces/mailinglist.py b/lib/lp/registry/interfaces/mailinglist.py
96index 0924fba..ed735eb 100644
97--- a/lib/lp/registry/interfaces/mailinglist.py
98+++ b/lib/lp/registry/interfaces/mailinglist.py
99@@ -884,7 +884,7 @@ class BaseSubscriptionErrors(Exception):
100 non-ascii text (since a person's display name is used here).
101 :type error_string: unicode
102 """
103- assert isinstance(error_string, unicode), 'Unicode expected'
104+ assert isinstance(error_string, six.text_type), 'Unicode expected'
105 Exception.__init__(self, error_string)
106 self._error_string = error_string
107
108diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
109index a496847..5917c6e 100644
110--- a/lib/lp/registry/model/person.py
111+++ b/lib/lp/registry/model/person.py
112@@ -45,6 +45,7 @@ from lazr.restful.utils import (
113 smartquote,
114 )
115 import pytz
116+import six
117 from sqlobject import (
118 BoolCol,
119 ForeignKey,
120@@ -1296,7 +1297,7 @@ class Person(
121 return False
122
123 # Translate the team name to an ITeam if we were passed a team.
124- if isinstance(team, (str, unicode)):
125+ if isinstance(team, six.string_types):
126 team = PersonSet().getByName(team)
127 if team is None:
128 # No team, no membership.
129@@ -3316,7 +3317,7 @@ class PersonSet:
130 "account.")
131 db_updated = False
132
133- assert isinstance(openid_identifier, unicode)
134+ assert isinstance(openid_identifier, six.text_type)
135 assert openid_identifier != u'', (
136 "OpenID identifier must not be empty.")
137
138diff --git a/lib/lp/services/beautifulsoup.py b/lib/lp/services/beautifulsoup.py
139index 5a1862a..c1b5b44 100644
140--- a/lib/lp/services/beautifulsoup.py
141+++ b/lib/lp/services/beautifulsoup.py
142@@ -14,12 +14,14 @@ __all__ = [
143
144 from bs4 import BeautifulSoup as _BeautifulSoup
145 from bs4.element import SoupStrainer
146+import six
147
148
149 class BeautifulSoup(_BeautifulSoup):
150
151 def __init__(self, markup="", features="html.parser", **kwargs):
152- if not isinstance(markup, unicode) and "from_encoding" not in kwargs:
153+ if (not isinstance(markup, six.text_type) and
154+ "from_encoding" not in kwargs):
155 kwargs["from_encoding"] = "UTF-8"
156 super(BeautifulSoup, self).__init__(
157 markup=markup, features=features, **kwargs)
158diff --git a/lib/lp/services/gpg/handler.py b/lib/lp/services/gpg/handler.py
159index 41b7467..e3ac2df 100644
160--- a/lib/lp/services/gpg/handler.py
161+++ b/lib/lp/services/gpg/handler.py
162@@ -23,6 +23,7 @@ import tempfile
163 import gpgme
164 from lazr.restful.utils import get_current_browser_request
165 import requests
166+import six
167 from six.moves import http_client
168 from six.moves.urllib.parse import urlencode
169 from zope.interface import implementer
170@@ -212,8 +213,8 @@ class GPGHandler:
171 def getVerifiedSignature(self, content, signature=None):
172 """See IGPGHandler."""
173
174- assert not isinstance(content, unicode)
175- assert not isinstance(signature, unicode)
176+ assert not isinstance(content, six.text_type)
177+ assert not isinstance(signature, six.text_type)
178
179 ctx = get_gpgme_context()
180
181@@ -354,7 +355,7 @@ class GPGHandler:
182
183 def encryptContent(self, content, key):
184 """See IGPGHandler."""
185- if isinstance(content, unicode):
186+ if isinstance(content, six.text_type):
187 raise TypeError('Content cannot be Unicode.')
188
189 ctx = get_gpgme_context()
190diff --git a/lib/lp/services/helpers.py b/lib/lp/services/helpers.py
191index a23baa8..888c31e 100644
192--- a/lib/lp/services/helpers.py
193+++ b/lib/lp/services/helpers.py
194@@ -18,6 +18,7 @@ import subprocess
195 import tarfile
196 import warnings
197
198+import six
199 from zope.security.interfaces import ForbiddenAttribute
200
201
202@@ -54,7 +55,7 @@ def text_replaced(text, replacements, _cache={}):
203 cachekey = tuple(replacements.items())
204 if cachekey not in _cache:
205 L = []
206- if isinstance(text, unicode):
207+ if isinstance(text, six.text_type):
208 list_item = u'(%s)'
209 join_char = u'|'
210 else:
211@@ -350,9 +351,9 @@ def ensure_unicode(string):
212 """
213 if string is None:
214 return None
215- elif isinstance(string, unicode):
216+ elif isinstance(string, six.text_type):
217 return string
218- elif isinstance(string, basestring):
219+ elif isinstance(string, bytes):
220 try:
221 return string.decode('US-ASCII')
222 except UnicodeDecodeError:
223diff --git a/lib/lp/services/identity/model/account.py b/lib/lp/services/identity/model/account.py
224index b855f66..bfad289 100644
225--- a/lib/lp/services/identity/model/account.py
226+++ b/lib/lp/services/identity/model/account.py
227@@ -11,6 +11,7 @@ __all__ = [
228
229 import datetime
230
231+import six
232 from sqlobject import StringCol
233 from storm.locals import ReferenceSet
234 from zope.interface import implementer
235@@ -102,7 +103,7 @@ class AccountSet:
236
237 # Create an OpenIdIdentifier record if requested.
238 if openid_identifier is not None:
239- assert isinstance(openid_identifier, unicode)
240+ assert isinstance(openid_identifier, six.text_type)
241 identifier = OpenIdIdentifier()
242 identifier.account = account
243 identifier.identifier = openid_identifier
244diff --git a/lib/lp/services/mail/notificationrecipientset.py b/lib/lp/services/mail/notificationrecipientset.py
245index 5a62fc0..62e9391 100644
246--- a/lib/lp/services/mail/notificationrecipientset.py
247+++ b/lib/lp/services/mail/notificationrecipientset.py
248@@ -12,6 +12,7 @@ __all__ = [
249
250 from operator import attrgetter
251
252+import six
253 from zope.interface import implementer
254 from zope.security.proxy import isinstance as zope_isinstance
255
256@@ -73,7 +74,7 @@ class NotificationRecipientSet:
257
258 def __contains__(self, person_or_email):
259 """See `INotificationRecipientSet`."""
260- if zope_isinstance(person_or_email, (str, unicode)):
261+ if zope_isinstance(person_or_email, six.string_types):
262 return person_or_email in self._emailToPerson
263 elif IPerson.providedBy(person_or_email):
264 return person_or_email in self._personToRationale
265diff --git a/lib/lp/services/mail/sendmail.py b/lib/lp/services/mail/sendmail.py
266index b344b12..7cd0739 100644
267--- a/lib/lp/services/mail/sendmail.py
268+++ b/lib/lp/services/mail/sendmail.py
269@@ -46,6 +46,7 @@ from smtplib import SMTP
270 import sys
271
272 from lazr.restful.utils import get_current_browser_request
273+import six
274 from zope.component import getUtility
275 from zope.security.proxy import (
276 isinstance as zisinstance,
277@@ -218,7 +219,7 @@ class MailController(object):
278 def addAttachment(self, content, content_type='application/octet-stream',
279 inline=False, filename=None, charset=None):
280 attachment = Message()
281- if charset and isinstance(content, unicode):
282+ if charset and isinstance(content, six.text_type):
283 content = content.encode(charset)
284 attachment.add_header('Content-Type', content_type)
285 if inline:
286diff --git a/lib/lp/services/webapp/publisher.py b/lib/lp/services/webapp/publisher.py
287index a67601e..fe0316c 100644
288--- a/lib/lp/services/webapp/publisher.py
289+++ b/lib/lp/services/webapp/publisher.py
290@@ -824,7 +824,7 @@ def get_raw_form_value_from_current_request(field, field_name):
291 # Zope wrongly encodes any form element that doesn't look like a file,
292 # so re-fetch the file content if it has been encoded.
293 if request and field_name in request.form and isinstance(
294- request.form[field_name], unicode):
295+ request.form[field_name], six.text_type):
296 request._environ['wsgi.input'].seek(0)
297 fs = FieldStorage(fp=request._body_instream, environ=request._environ)
298 return fs[field_name].value
299diff --git a/lib/lp/services/webapp/sorting.py b/lib/lp/services/webapp/sorting.py
300index 648e4ff..efc4ee2 100644
301--- a/lib/lp/services/webapp/sorting.py
302+++ b/lib/lp/services/webapp/sorting.py
303@@ -10,6 +10,8 @@ __all__ = ['expand_numbers',
304
305 import re
306
307+import six
308+
309
310 def expand_numbers(unicode_text, fill_digits=4):
311 """Return a copy of the string with numbers zero filled.
312@@ -24,7 +26,7 @@ def expand_numbers(unicode_text, fill_digits=4):
313 u'branch-0002-0003.0012'
314
315 """
316- assert(isinstance(unicode_text, unicode))
317+ assert(isinstance(unicode_text, six.text_type))
318
319 def substitute_filled_numbers(match):
320 return match.group(0).zfill(fill_digits)
321@@ -53,8 +55,8 @@ def _reversed_number_comparator(lhs_text, rhs_text):
322 -1
323
324 """
325- assert isinstance(lhs_text, unicode)
326- assert isinstance(rhs_text, unicode)
327+ assert isinstance(lhs_text, six.text_type)
328+ assert isinstance(rhs_text, six.text_type)
329 translated_lhs_text = lhs_text.translate(reversed_numbers_table)
330 translated_rhs_text = rhs_text.translate(reversed_numbers_table)
331 return cmp(translated_lhs_text, translated_rhs_text)
332diff --git a/lib/lp/soyuz/mail/packageupload.py b/lib/lp/soyuz/mail/packageupload.py
333index 5a9e1f0..f194061 100644
334--- a/lib/lp/soyuz/mail/packageupload.py
335+++ b/lib/lp/soyuz/mail/packageupload.py
336@@ -111,7 +111,7 @@ def sanitize_string(s):
337 'ascii' codec can't decode byte 0xc4 in position 21: ordinal
338 not in range(128)
339 """
340- if isinstance(s, unicode):
341+ if isinstance(s, six.text_type):
342 return s
343 else:
344 return guess_encoding(s)
345diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
346index 4d93342..431cce1 100644
347--- a/lib/lp/testing/factory.py
348+++ b/lib/lp/testing/factory.py
349@@ -4178,7 +4178,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
350 binpackageformat = BinaryPackageFormat.DEB
351 if component is None:
352 component = build.source_package_release.component
353- elif isinstance(component, unicode):
354+ elif isinstance(component, six.text_type):
355 component = getUtility(IComponentSet)[component]
356 if isinstance(section_name, basestring):
357 section_name = self.makeSection(section_name)
358diff --git a/lib/lp/testing/gpgkeys/__init__.py b/lib/lp/testing/gpgkeys/__init__.py
359index 53a0845..d330c35 100644
360--- a/lib/lp/testing/gpgkeys/__init__.py
361+++ b/lib/lp/testing/gpgkeys/__init__.py
362@@ -24,6 +24,7 @@ import os
363
364 import gpgme
365 import scandir
366+import six
367 from zope.component import getUtility
368
369 from lp.registry.interfaces.gpg import IGPGKeySet
370@@ -126,10 +127,10 @@ def decrypt_content(content, password):
371 :content: encrypted data content
372 :password: unicode password to unlock the secret key in question
373 """
374- if isinstance(password, unicode):
375+ if isinstance(password, six.text_type):
376 raise TypeError('Password cannot be Unicode.')
377
378- if isinstance(content, unicode):
379+ if isinstance(content, six.text_type):
380 raise TypeError('Content cannot be Unicode.')
381
382 ctx = get_gpgme_context()
383diff --git a/lib/lp/testing/matchers.py b/lib/lp/testing/matchers.py
384index fcdba23..c64c461 100644
385--- a/lib/lp/testing/matchers.py
386+++ b/lib/lp/testing/matchers.py
387@@ -472,11 +472,11 @@ class EqualsIgnoringWhitespace(Equals):
388 """
389
390 def __init__(self, expected):
391- if isinstance(expected, (str, unicode)):
392+ if isinstance(expected, six.string_types):
393 expected = normalize_whitespace(expected)
394 super(EqualsIgnoringWhitespace, self).__init__(expected)
395
396 def match(self, observed):
397- if isinstance(observed, (str, unicode)):
398+ if isinstance(observed, six.string_types):
399 observed = normalize_whitespace(observed)
400 return super(EqualsIgnoringWhitespace, self).match(observed)
401diff --git a/lib/lp/translations/browser/browser_helpers.py b/lib/lp/translations/browser/browser_helpers.py
402index f85cdea..87dbd6d 100644
403--- a/lib/lp/translations/browser/browser_helpers.py
404+++ b/lib/lp/translations/browser/browser_helpers.py
405@@ -17,6 +17,8 @@ __all__ = [
406 from math import ceil
407 import re
408
409+import six
410+
411 from lp.services import helpers
412 from lp.services.webapp.escaping import html_escape
413 from lp.translations.interfaces.translations import TranslationConstants
414@@ -109,7 +111,7 @@ def convert_newlines_to_web_form(unicode_text):
415 if unicode_text is None:
416 return None
417
418- assert isinstance(unicode_text, unicode), (
419+ assert isinstance(unicode_text, six.text_type), (
420 "The given text must be unicode instead of %s" % type(unicode_text))
421
422 if unicode_text is None:
423diff --git a/lib/lp/translations/utilities/gettext_po_parser.py b/lib/lp/translations/utilities/gettext_po_parser.py
424index 27b9385..c11de08 100644
425--- a/lib/lp/translations/utilities/gettext_po_parser.py
426+++ b/lib/lp/translations/utilities/gettext_po_parser.py
427@@ -185,7 +185,7 @@ class POHeader:
428 return header_dictionary
429
430 def _decode(self, text):
431- if text is None or isinstance(text, unicode):
432+ if text is None or isinstance(text, six.text_type):
433 # There is noo need to do anything.
434 return text
435 charset = self.charset
436diff --git a/lib/lp/translations/utilities/xpi_header.py b/lib/lp/translations/utilities/xpi_header.py
437index 4d5b30b..d2c140e 100644
438--- a/lib/lp/translations/utilities/xpi_header.py
439+++ b/lib/lp/translations/utilities/xpi_header.py
440@@ -11,6 +11,7 @@ from email.utils import parseaddr
441 from StringIO import StringIO
442
443 import defusedxml.cElementTree as cElementTree
444+import six
445 from zope.interface import implementer
446
447 from lp.translations.interfaces.translationcommonformat import (
448@@ -38,15 +39,15 @@ class XpiHeader:
449 self.launchpad_export_date = None
450 self.comment = None
451
452- if isinstance(header_content, str):
453+ if isinstance(header_content, bytes):
454 try:
455 self._text = header_content.decode(self.charset)
456 except UnicodeDecodeError:
457 raise TranslationFormatInvalidInputError(
458 "XPI header is not encoded in %s." % self.charset)
459 else:
460- assert isinstance(header_content, unicode), (
461- "XPI header text is neither str nor unicode.")
462+ assert isinstance(header_content, six.text_type), (
463+ "XPI header text is neither bytes nor unicode.")
464 self._text = header_content
465
466 def getRawContent(self):
467diff --git a/lib/sqlobject/__init__.py b/lib/sqlobject/__init__.py
468index e43407d..1e85316 100644
469--- a/lib/sqlobject/__init__.py
470+++ b/lib/sqlobject/__init__.py
471@@ -8,6 +8,7 @@ __metaclass__ = type
472 # SKIP this file when reformatting, due to the sys mangling.
473 import datetime
474
475+import six
476 from storm.exceptions import NotOneError as SQLObjectMoreThanOneResultError
477 from storm.expr import SQL
478 from storm.sqlobject import *
479@@ -39,7 +40,7 @@ def sqlrepr(value, dbname=None):
480 return value.getquoted()
481 elif isinstance(value, SQL):
482 return value.expr
483- elif isinstance(value, (str, unicode)):
484+ elif isinstance(value, six.string_types):
485 for orig, repl in _sqlStringReplace:
486 value = value.replace(orig, repl)
487 return "E'%s'" % value

Subscribers

People subscribed via source and target branches

to status/vote changes: