Merge lp:~cjwatson/lazr.restful/py3-unicode into lp:lazr.restful

Proposed by Colin Watson
Status: Merged
Merged at revision: 253
Proposed branch: lp:~cjwatson/lazr.restful/py3-unicode
Merge into: lp:lazr.restful
Diff against target: 396 lines (+52/-40)
9 files modified
src/lazr/restful/_operation.py (+3/-1)
src/lazr/restful/_resource.py (+13/-13)
src/lazr/restful/declarations.py (+4/-2)
src/lazr/restful/docs/webservice.rst (+3/-2)
src/lazr/restful/marshallers.py (+13/-11)
src/lazr/restful/testing/helpers.py (+3/-1)
src/lazr/restful/testing/webservice.py (+6/-5)
src/lazr/restful/tests/test_webservice.py (+5/-4)
src/lazr/restful/utils.py (+2/-1)
To merge this branch: bzr merge lp:~cjwatson/lazr.restful/py3-unicode
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Review via email: mp+387891@code.launchpad.net

Commit message

Port simple uses of str/unicode/basestring to Python 3.

Description of the change

Most cases are fairly obvious, but we need to pay some attention to whether str is intended to be a byte string or a native string. basestring normally means "native string or text" (i.e. six.string_types), but in a few places it means "bytes or text" instead: in particular, the return value from EntryResource.do_GET and CollectionResource.do_GET may be either.

To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lazr/restful/_operation.py'
2--- src/lazr/restful/_operation.py 2020-02-04 11:52:59 +0000
3+++ src/lazr/restful/_operation.py 2020-07-22 22:45:07 +0000
4@@ -5,6 +5,7 @@
5 from __future__ import absolute_import, print_function
6
7 import simplejson
8+import six
9
10 from zope.component import getMultiAdapter, getUtility, queryMultiAdapter
11 from zope.event import notify
12@@ -145,7 +146,8 @@
13 # has its response batched.
14 return True
15
16- if zope_isinstance(result, (basestring, dict, set, list, tuple)):
17+ if zope_isinstance(
18+ result, (bytes, six.text_type, dict, set, list, tuple)):
19 # Ordinary Python data structures generally are not
20 # batched.
21 return False
22
23=== modified file 'src/lazr/restful/_resource.py'
24--- src/lazr/restful/_resource.py 2020-06-30 15:52:03 +0000
25+++ src/lazr/restful/_resource.py 2020-07-22 22:45:07 +0000
26@@ -151,12 +151,12 @@
27
28 def decode_value(value):
29 """Return a unicode value curresponding to `value`."""
30- if isinstance(value, unicode):
31+ if isinstance(value, six.text_type):
32 return value
33- elif isinstance(value, str):
34+ elif isinstance(value, bytes):
35 return value.decode("utf-8")
36 else:
37- return unicode(value)
38+ return six.text_type(value)
39
40
41 def encode_value(value):
42@@ -164,17 +164,17 @@
43
44 Non-unicode strings are assumed to be UTF-8 already.
45 """
46- if isinstance(value, unicode):
47+ if isinstance(value, six.text_type):
48 return value.encode("utf-8")
49- elif isinstance(value, str):
50+ elif isinstance(value, bytes):
51 return value
52 else:
53- return str(value)
54+ return bytes(value)
55
56
57 def _default_html_renderer(value):
58 """The default technique for rendering a value as an HTML snippet."""
59- return cgi.escape(unicode(value))
60+ return cgi.escape(six.text_type(value))
61
62
63 @adapter(Interface, IField, IWebServiceClientRequest)
64@@ -701,7 +701,7 @@
65 :return: The result of the operation: either a string or an
66 object that needs to be serialized to JSON.
67 """
68- if not isinstance(operation_name, basestring):
69+ if not isinstance(operation_name, six.string_types):
70 self.request.response.setStatus(400)
71 return "Expected a single operation: %r" % (operation_name,)
72
73@@ -727,7 +727,7 @@
74 :return: The result of the operation: either a string or an
75 object that needs to be serialized to JSON.
76 """
77- if not isinstance(operation_name, basestring):
78+ if not isinstance(operation_name, six.string_types):
79 self.request.response.setStatus(400)
80 return "Expected a single operation: %r" % (operation_name,)
81
82@@ -1163,7 +1163,7 @@
83 # instead of whatever object the raise site
84 # thought would be a good idea.
85 if (len(e.args) > 0 and
86- isinstance(e.args[0], basestring)):
87+ isinstance(e.args[0], six.string_types)):
88 error = e.args[0]
89 else:
90 error = "Constraint not satisfied."
91@@ -1311,7 +1311,7 @@
92 # generating the representation might itself change across
93 # versions.
94 revno = getUtility(IWebServiceConfiguration).code_revision
95- return [core.encode('utf-8') for core in [revno, unicode(value)]]
96+ return [core.encode('utf-8') for core in [revno, six.text_type(value)]]
97
98 def _representation(self, media_type):
99 """Create a representation of the field value."""
100@@ -1547,7 +1547,7 @@
101 operation_name = self.request.form.pop('ws.op', None)
102 if operation_name is not None:
103 result = self.handleCustomGET(operation_name)
104- if isinstance(result, basestring):
105+ if isinstance(result, (bytes, six.text_type)):
106 # The custom operation took care of everything and
107 # just needs this string served to the client.
108 return result
109@@ -1788,7 +1788,7 @@
110 operation_name = self.request.form.pop('ws.op', None)
111 if operation_name is not None:
112 result = self.handleCustomGET(operation_name)
113- if isinstance(result, str) or isinstance(result, unicode):
114+ if isinstance(result, (bytes, six.text_type)):
115 # The custom operation took care of everything and
116 # just needs this string served to the client.
117 return result
118
119=== modified file 'src/lazr/restful/declarations.py'
120--- src/lazr/restful/declarations.py 2020-02-05 10:46:46 +0000
121+++ src/lazr/restful/declarations.py 2020-07-22 22:45:07 +0000
122@@ -47,6 +47,7 @@
123 import itertools
124 import sys
125
126+import six
127 from zope.component import getUtility, getGlobalSiteManager
128 from zope.interface import classImplements
129 from zope.interface.advice import addClassAdvisor
130@@ -738,7 +739,8 @@
131 # zope schema are expected to be unicode, whereas it's
132 # really possible that the method's default is a simple
133 # string.
134- if isinstance(default, str) and IText.providedBy(param_def):
135+ if (six.PY2 and
136+ isinstance(default, str) and IText.providedBy(param_def)):
137 default = unicode(default)
138 param_def.default = default
139 param_def.required = False
140@@ -1805,5 +1807,5 @@
141 # runtime. Use a generic string that won't conflict with a
142 # real version string.
143 version = "__Earliest"
144- name = "%s_%s" % (base_name, version.encode('utf8'))
145+ name = "%s_%s" % (base_name, six.ensure_str(version))
146 return make_identifier_safe(name)
147
148=== modified file 'src/lazr/restful/docs/webservice.rst'
149--- src/lazr/restful/docs/webservice.rst 2020-02-04 13:17:32 +0000
150+++ src/lazr/restful/docs/webservice.rst 2020-07-22 22:45:07 +0000
151@@ -1092,8 +1092,9 @@
152 'home page' for the web service.
153
154 >>> import simplejson
155+ >>> import six
156 >>> response = app(request)
157- >>> representation = simplejson.loads(unicode(response))
158+ >>> representation = simplejson.loads(six.text_type(response))
159
160 >>> representation["authors_collection_link"]
161 u'http://api.cookbooks.dev/beta/authors'
162@@ -1168,7 +1169,7 @@
163
164 >>> def load_json(s):
165 ... """Convert a JSON string to Unicode and then load it."""
166- ... return simplejson.loads(unicode(s))
167+ ... return simplejson.loads(six.text_type(s))
168
169 >>> representation = load_json(collection())
170 >>> representation['resource_type_link']
171
172=== modified file 'src/lazr/restful/marshallers.py'
173--- src/lazr/restful/marshallers.py 2020-06-30 15:52:03 +0000
174+++ src/lazr/restful/marshallers.py 2020-07-22 22:45:07 +0000
175@@ -29,6 +29,7 @@
176 from StringIO import StringIO
177
178 import simplejson
179+import six
180 from six.moves.urllib.parse import unquote
181
182 from zope.datetime import (
183@@ -89,7 +90,7 @@
184 request_host = full_request_host
185 request_port = default_port
186
187- if not isinstance(url, basestring):
188+ if not isinstance(url, six.string_types):
189 raise ValueError(u"got '%s', expected string: %r" % (
190 type(url).__name__, url))
191 if url.startswith('/'):
192@@ -178,10 +179,10 @@
193 if value != '':
194 try:
195 v = value
196- if isinstance(v, str):
197+ if isinstance(v, bytes):
198 v = v.decode('utf8') # assume utf8
199- elif not isinstance(v, unicode):
200- v = unicode(v)
201+ elif not isinstance(v, six.text_type):
202+ v = six.text_type(v)
203 value = simplejson.loads(v)
204 except (ValueError, TypeError):
205 # Pass the value as is. This saves client from having to encode
206@@ -267,7 +268,7 @@
207 class BytesFieldMarshaller(SimpleFieldMarshaller):
208 """FieldMarshaller for IBytes field."""
209
210- _type = str
211+ _type = bytes
212 _type_error_message = 'not a string: %r'
213
214 @property
215@@ -295,8 +296,8 @@
216 if safe_hasattr(value, 'seek'):
217 value.seek(0)
218 value = value.read()
219- elif not isinstance(value, basestring):
220- value = str(value)
221+ elif not isinstance(value, (bytes, six.text_type)):
222+ value = bytes(value)
223 else:
224 # Leave string conversion to _marshall_from_json_data.
225 pass
226@@ -307,7 +308,7 @@
227
228 Convert all strings to byte strings.
229 """
230- if isinstance(value, unicode):
231+ if isinstance(value, six.text_type):
232 value = value.encode('utf-8')
233 return super(
234 BytesFieldMarshaller, self)._marshall_from_json_data(value)
235@@ -316,7 +317,7 @@
236 class TextFieldMarshaller(SimpleFieldMarshaller):
237 """FieldMarshaller for IText fields."""
238
239- _type = unicode
240+ _type = six.text_type
241 _type_error_message = 'not a unicode string: %r'
242
243 def _marshall_from_request(self, value):
244@@ -324,7 +325,7 @@
245
246 Converts the value to unicode.
247 """
248- value = unicode(value)
249+ value = six.text_type(value)
250 return super(TextFieldMarshaller, self)._marshall_from_request(value)
251
252
253@@ -366,7 +367,8 @@
254 Looks up the value as a token in the vocabulary.
255 """
256 try:
257- return self.field.vocabulary.getTermByToken(str(value)).value
258+ return self.field.vocabulary.getTermByToken(
259+ six.text_type(value)).value
260 except LookupError:
261 raise ValueError(u"%r isn't a valid token" % value)
262
263
264=== modified file 'src/lazr/restful/testing/helpers.py'
265--- src/lazr/restful/testing/helpers.py 2020-02-04 11:52:59 +0000
266+++ src/lazr/restful/testing/helpers.py 2020-07-22 22:45:07 +0000
267@@ -50,7 +50,9 @@
268
269 :param response: an httplib HTTPResponse object.
270 """
271- response_unicode = str(response).decode("utf-8")
272+ response_unicode = str(response)
273+ if isinstance(response_unicode, bytes): # Python 2
274+ response_unicode = response_unicode.decode("utf-8")
275 return encode_unicode(response_unicode)
276
277
278
279=== modified file 'src/lazr/restful/testing/webservice.py'
280--- src/lazr/restful/testing/webservice.py 2020-02-04 21:53:16 +0000
281+++ src/lazr/restful/testing/webservice.py 2020-07-22 22:45:07 +0000
282@@ -28,6 +28,7 @@
283
284 import wsgi_intercept
285
286+import six
287 from six.moves.urllib.parse import (
288 quote,
289 urlencode,
290@@ -122,7 +123,7 @@
291 if result is None:
292 result = ''
293
294- if not isinstance(result, basestring):
295+ if not isinstance(result, six.string_types):
296 raise ValueError('only strings and None results are handled')
297
298 self.result = result
299@@ -209,7 +210,7 @@
300 """
301
302 def __init__(self, global_config, publication, **options):
303- if isinstance(publication, basestring):
304+ if isinstance(publication, six.string_types):
305 Application.__init__(self, global_config, publication, **options)
306 else:
307 self.publication = publication(global_config, **options)
308@@ -334,7 +335,7 @@
309 # To be properly marshalled all values must be strings or converted to
310 # JSON.
311 for key, value in args.items():
312- if not isinstance(value, basestring):
313+ if not isinstance(value, six.string_types):
314 args[key] = simplejson.dumps(value)
315 return urlencode(args)
316
317@@ -363,7 +364,7 @@
318
319 This may mean turning the value into a JSON string.
320 """
321- if not isinstance(value, basestring):
322+ if not isinstance(value, six.string_types):
323 value = simplejson.dumps(value)
324 return quote(value)
325
326@@ -408,7 +409,7 @@
327 def jsonBody(self):
328 """Return the body of the web service request as a JSON document."""
329 try:
330- json = simplejson.loads(unicode(self.body))
331+ json = simplejson.loads(six.ensure_text(self.body))
332 if isinstance(json, list):
333 json = sorted(json)
334 return json
335
336=== modified file 'src/lazr/restful/tests/test_webservice.py'
337--- src/lazr/restful/tests/test_webservice.py 2020-02-19 16:09:10 +0000
338+++ src/lazr/restful/tests/test_webservice.py 2020-07-22 22:45:07 +0000
339@@ -18,6 +18,7 @@
340 import simplejson
341 import unittest
342
343+import six
344 from zope.component import (
345 eventtesting,
346 getGlobalSiteManager,
347@@ -536,8 +537,8 @@
348 def resource(self, value_1="value 1", value_2="value 2"):
349 """Simplify the entry_resource call."""
350 with self.entry_resource(
351- IHasTwoFields, HasTwoFields,
352- unicode(value_1), unicode(value_2)) as resource:
353+ IHasTwoFields, HasTwoFields,
354+ six.text_type(value_1), six.text_type(value_2)) as resource:
355 yield resource
356
357 def test_web_layer_json_representation_omits_lp_html(self):
358@@ -598,7 +599,7 @@
359 json = None
360 with self.resource() as resource:
361 json_plus_xhtml = resource.JSON_PLUS_XHTML_TYPE
362- json = simplejson.loads(unicode(
363+ json = simplejson.loads(six.text_type(
364 resource._representation(json_plus_xhtml)))
365 resource.applyChanges(json, json_plus_xhtml)
366 self.assertEqual(resource.request.response.getStatus(), 209)
367@@ -607,7 +608,7 @@
368 self.register_html_field_renderer()
369 json = None
370 with self.resource() as resource:
371- json = simplejson.loads(unicode(
372+ json = simplejson.loads(six.text_type(
373 resource._representation(resource.JSON_PLUS_XHTML_TYPE)))
374 resource.applyChanges(json, resource.JSON_TYPE)
375 self.assertEqual(resource.request.response.getStatus(), 400)
376
377=== modified file 'src/lazr/restful/utils.py'
378--- src/lazr/restful/utils.py 2020-02-04 11:52:59 +0000
379+++ src/lazr/restful/utils.py 2020-07-22 22:45:07 +0000
380@@ -31,6 +31,7 @@
381 import subprocess
382
383 from simplejson import encoder
384+import six
385
386 from zope.component import getUtility
387 from zope.schema import getFieldsInOrder
388@@ -359,7 +360,7 @@
389
390 def smartquote(str):
391 """Return a copy of the string, with typographical quote marks applied."""
392- str = unicode(str)
393+ str = six.text_type(str)
394 str = re.compile(u'(^| )(")([^" ])').sub(u'\\1\u201c\\3', str)
395 str = re.compile(u'([^ "])(")($|[\s.,;:!?])').sub(u'\\1\u201d\\3', str)
396 return str

Subscribers

People subscribed via source and target branches