Merge lp:~xnox/lazr.restfulclient/fixes into lp:lazr.restfulclient

Proposed by Dimitri John Ledkov
Status: Merged
Merged at revision: 137
Proposed branch: lp:~xnox/lazr.restfulclient/fixes
Merge into: lp:lazr.restfulclient
Diff against target: 743 lines (+84/-310)
9 files modified
buildout.cfg (+1/-1)
ez_setup.py (+0/-241)
setup.py (+6/-7)
src/lazr/restfulclient/_browser.py (+14/-23)
src/lazr/restfulclient/authorize/oauth.py (+2/-1)
src/lazr/restfulclient/resource.py (+22/-12)
src/lazr/restfulclient/tests/test_atomicfilecache.py (+29/-15)
src/lazr/restfulclient/tests/test_error.py (+2/-2)
src/lazr/restfulclient/tests/test_oauth.py (+8/-8)
To merge this branch: bzr merge lp:~xnox/lazr.restfulclient/fixes
Reviewer Review Type Date Requested Status
Barry Warsaw Needs Information
LAZR Developers Pending
Review via email: mp+224945@code.launchpad.net

Commit message

Simplify setup.py and fix one python3 syntax error.

To post a comment you must log in.
lp:~xnox/lazr.restfulclient/fixes updated
139. By Dimitri John Ledkov

SSLHandshakeError is gone in python3, add compat.

140. By Dimitri John Ledkov

Resurect bootstrap.py

141. By Dimitri John Ledkov

Depreciation warning readfp -> read_file

142. By Dimitri John Ledkov

Take 1 at unicode

143. By Dimitri John Ledkov

More stuff

144. By Dimitri John Ledkov

Distch six

145. By Dimitri John Ledkov

Fix standalone buildout

146. By Dimitri John Ledkov

drop unused things

147. By Dimitri John Ledkov

Revert to minimise diff

148. By Dimitri John Ledkov

url must be string

149. By Dimitri John Ledkov

More crap

Revision history for this message
Barry Warsaw (barry) wrote :

A few minor comments and one important question. (inline of course)

review: Needs Information
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Replied.

Revision history for this message
Barry Warsaw (barry) wrote :

On Jul 14, 2014, at 10:20 PM, Dimitri John Ledkov wrote:

>> try:
>> + from httplib2 import SSLHandshakeError
>> +except ImportError:
>> + from httplib2 import HttpLib2Error as SSLHandshakeError
>> +try:
>
>yes, it does. But it's only used to catch the error, and re-raise it with a
>helpful message that "there is an option to ignore ssl certificate
>errors". The actual class of the error has changed, but i believe the text of
>the error comes from the underlying library. This keeps compat in python2,
>and the worst case scenario the error is re-raised regardless.

So I had a look at the actual code where this is used. Ug.

>Maybe I should remove all error catching and thus not use either
>SSLHandshakeError nor HttpLib2Error?

That does seem better. Then release notes or documentation can describe
LP_DISABLE_SSL_CERTIFICATE_VALIDATION.

lp:~xnox/lazr.restfulclient/fixes updated
150. By Dimitri John Ledkov

Whitespace and review fixes, drop SSLHandshakeError handling.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'buildout.cfg'
2--- buildout.cfg 2012-06-19 13:28:22 +0000
3+++ buildout.cfg 2014-07-28 15:39:09 +0000
4@@ -17,7 +17,7 @@
5
6 [standalone_test]
7 recipe = zc.recipe.testrunner
8-eggs = lazr.restfulclient
9+eggs = lazr.restfulclient [test]
10 defaults = '--tests-pattern ^tests --exit-with-status --suite-name standalone_tests'.split()
11
12 [docs]
13
14=== removed file 'ez_setup.py'
15--- ez_setup.py 2010-03-24 15:14:12 +0000
16+++ ez_setup.py 1970-01-01 00:00:00 +0000
17@@ -1,241 +0,0 @@
18-#!python
19-"""Bootstrap setuptools installation
20-
21-If you want to use setuptools in your package's setup.py, just include this
22-file in the same directory with it, and add this to the top of your setup.py::
23-
24- from ez_setup import use_setuptools
25- use_setuptools()
26-
27-If you want to require a specific version of setuptools, set a download
28-mirror, or use an alternate download directory, you can do so by supplying
29-the appropriate options to ``use_setuptools()``.
30-
31-This file can also be run as a script to install or upgrade setuptools.
32-"""
33-import sys
34-DEFAULT_VERSION = "0.6c11"
35-DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
36-
37-md5_data = {
38- 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
39- 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
40- 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
41- 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
42- 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
43- 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
44- 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
45- 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
46- 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
47- 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
48- 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
49- 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
50- 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
51- 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
52- 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
53- 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
54- 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
55- 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
56- 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
57- 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
58- 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
59- 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
60- 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
61- 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
62- 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
63- 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
64- 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
65- 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
66- 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
67- 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
68-}
69-
70-import sys, os
71-
72-def _validate_md5(egg_name, data):
73- if egg_name in md5_data:
74- from md5 import md5
75- digest = md5(data).hexdigest()
76- if digest != md5_data[egg_name]:
77- print >>sys.stderr, (
78- "md5 validation of %s failed! (Possible download problem?)"
79- % egg_name
80- )
81- sys.exit(2)
82- return data
83-
84-
85-def use_setuptools(
86- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
87- download_delay=15, min_version=None
88-):
89- """Automatically find/download setuptools and make it available on sys.path
90-
91- `version` should be a valid setuptools version number that is available
92- as an egg for download under the `download_base` URL (which should end with
93- a '/'). `to_dir` is the directory where setuptools will be downloaded, if
94- it is not already available. If `download_delay` is specified, it should
95- be the number of seconds that will be paused before initiating a download,
96- should one be required. If an older version of setuptools is installed,
97- this routine will print a message to ``sys.stderr`` and raise SystemExit in
98- an attempt to abort the calling script.
99- """
100- # Work around a hack in the ez_setup.py file from simplejson==1.7.3.
101- if min_version:
102- version = min_version
103-
104- was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
105- def do_download():
106- egg = download_setuptools(version, download_base, to_dir, download_delay)
107- sys.path.insert(0, egg)
108- import setuptools; setuptools.bootstrap_install_from = egg
109- try:
110- import pkg_resources
111- except ImportError:
112- return do_download()
113- try:
114- pkg_resources.require("setuptools>="+version); return
115- except pkg_resources.VersionConflict, e:
116- if was_imported:
117- print >>sys.stderr, (
118- "The required version of setuptools (>=%s) is not available, and\n"
119- "can't be installed while this script is running. Please install\n"
120- " a more recent version first, using 'easy_install -U setuptools'."
121- "\n\n(Currently using %r)"
122- ) % (version, e.args[0])
123- sys.exit(2)
124- else:
125- del pkg_resources, sys.modules['pkg_resources'] # reload ok
126- return do_download()
127- except pkg_resources.DistributionNotFound:
128- return do_download()
129-
130-def download_setuptools(
131- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
132- delay = 15
133-):
134- """Download setuptools from a specified location and return its filename
135-
136- `version` should be a valid setuptools version number that is available
137- as an egg for download under the `download_base` URL (which should end
138- with a '/'). `to_dir` is the directory where the egg will be downloaded.
139- `delay` is the number of seconds to pause before an actual download attempt.
140- """
141- import urllib2, shutil
142- egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
143- url = download_base + egg_name
144- saveto = os.path.join(to_dir, egg_name)
145- src = dst = None
146- if not os.path.exists(saveto): # Avoid repeated downloads
147- try:
148- from distutils import log
149- if delay:
150- log.warn("""
151----------------------------------------------------------------------------
152-This script requires setuptools version %s to run (even to display
153-help). I will attempt to download it for you (from
154-%s), but
155-you may need to enable firewall access for this script first.
156-I will start the download in %d seconds.
157-
158-(Note: if this machine does not have network access, please obtain the file
159-
160- %s
161-
162-and place it in this directory before rerunning this script.)
163----------------------------------------------------------------------------""",
164- version, download_base, delay, url
165- ); from time import sleep; sleep(delay)
166- log.warn("Downloading %s", url)
167- src = urllib2.urlopen(url)
168- # Read/write all in one block, so we don't create a corrupt file
169- # if the download is interrupted.
170- data = _validate_md5(egg_name, src.read())
171- dst = open(saveto,"wb"); dst.write(data)
172- finally:
173- if src: src.close()
174- if dst: dst.close()
175- return os.path.realpath(saveto)
176-
177-def main(argv, version=DEFAULT_VERSION):
178- """Install or upgrade setuptools and EasyInstall"""
179- try:
180- import setuptools
181- except ImportError:
182- egg = None
183- try:
184- egg = download_setuptools(version, delay=0)
185- sys.path.insert(0,egg)
186- from setuptools.command.easy_install import main
187- return main(list(argv)+[egg]) # we're done here
188- finally:
189- if egg and os.path.exists(egg):
190- os.unlink(egg)
191- else:
192- if setuptools.__version__ == '0.0.1':
193- print >>sys.stderr, (
194- "You have an obsolete version of setuptools installed. Please\n"
195- "remove it from your system entirely before rerunning this script."
196- )
197- sys.exit(2)
198-
199- req = "setuptools>="+version
200- import pkg_resources
201- try:
202- pkg_resources.require(req)
203- except pkg_resources.VersionConflict:
204- try:
205- from setuptools.command.easy_install import main
206- except ImportError:
207- from easy_install import main
208- main(list(argv)+[download_setuptools(delay=0)])
209- sys.exit(0) # try to force an exit
210- else:
211- if argv:
212- from setuptools.command.easy_install import main
213- main(argv)
214- else:
215- print "Setuptools version",version,"or greater has been installed."
216- print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
217-
218-def update_md5(filenames):
219- """Update our built-in md5 registry"""
220-
221- import re
222- from md5 import md5
223-
224- for name in filenames:
225- base = os.path.basename(name)
226- f = open(name,'rb')
227- md5_data[base] = md5(f.read()).hexdigest()
228- f.close()
229-
230- data = [" %r: %r,\n" % it for it in md5_data.items()]
231- data.sort()
232- repl = "".join(data)
233-
234- import inspect
235- srcfile = inspect.getsourcefile(sys.modules[__name__])
236- f = open(srcfile, 'rb'); src = f.read(); f.close()
237-
238- match = re.search("\nmd5_data = {\n([^}]+)}", src)
239- if not match:
240- print >>sys.stderr, "Internal error!"
241- sys.exit(2)
242-
243- src = src[:match.start(1)] + repl + src[match.end(1):]
244- f = open(srcfile,'w')
245- f.write(src)
246- f.close()
247-
248-
249-if __name__=='__main__':
250- if len(sys.argv)>2 and sys.argv[1]=='--md5update':
251- update_md5(sys.argv[2:])
252- else:
253- main(sys.argv[1:])
254-
255-
256-
257-
258-
259
260=== modified file 'setup.py'
261--- setup.py 2014-06-05 11:25:42 +0000
262+++ setup.py 2014-07-28 15:39:09 +0000
263@@ -16,9 +16,6 @@
264 # You should have received a copy of the GNU Lesser General Public License
265 # along with lazr.restfulclient. If not, see <http://www.gnu.org/licenses/>.
266
267-import ez_setup
268-ez_setup.use_setuptools()
269-
270 import sys
271 from setuptools import setup, find_packages
272
273@@ -45,6 +42,7 @@
274 namespace_packages=['lazr'],
275 packages=find_packages('src'),
276 package_dir={'':'src'},
277+ package_data={'lazr.restfulclient': ['version.txt']},
278 include_package_data=True,
279 zip_safe=False,
280 maintainer='LAZR Developers',
281@@ -56,11 +54,9 @@
282 license='LGPL v3',
283 install_requires=[
284 'httplib2',
285- 'lazr.authentication',
286 'oauth',
287 'setuptools',
288 'wadllib>=1.1.4',
289- 'wsgi_intercept',
290 ],
291 url='https://launchpad.net/lazr.restfulclient',
292 download_url= 'https://launchpad.net/lazr.restfulclient/+download',
293@@ -73,8 +69,11 @@
294 extras_require=dict(
295 docs=['Sphinx',
296 'z3c.recipe.sphinxdoc'],
297- test=['lazr.restful>=0.11.0',
298- 'van.testing'],
299+ test=[
300+ 'lazr.authentication',
301+ 'lazr.restful>=0.11.0',
302+ 'wsgi_intercept',
303+ ],
304 ),
305 test_suite='lazr.restfulclient.tests',
306 )
307
308=== modified file 'src/lazr/restfulclient/_browser.py'
309--- src/lazr/restfulclient/_browser.py 2014-06-05 11:25:42 +0000
310+++ src/lazr/restfulclient/_browser.py 2014-07-28 15:39:09 +0000
311@@ -41,7 +41,6 @@
312 from time import sleep
313 from httplib2 import (
314 Http,
315- SSLHandshakeError,
316 urlnorm,
317 )
318 try:
319@@ -86,7 +85,12 @@
320 """
321
322 try:
323- if re_url_scheme.match(filename):
324+ if isinstance(filename, unicode_type):
325+ filename_match = filename.encode('utf-8')
326+ else:
327+ filename_match = filename
328+
329+ if re_url_scheme.match(filename_match):
330 if isinstance(filename, bytes):
331 filename = filename.decode('utf-8')
332 filename = filename.encode('idna')
333@@ -97,8 +101,8 @@
334 if isinstance(filename, unicode_type):
335 filename = filename.encode('utf-8')
336 filemd5 = _md5(filename).hexdigest()
337- filename = re_url_scheme.sub("", filename)
338- filename = re_slash.sub(",", filename)
339+ filename = re_url_scheme.sub(b"", filename)
340+ filename = re_slash.sub(b",", filename)
341
342 # This is the part that we changed. In stock httplib2, the
343 # filename is trimmed if it's longer than 200 characters, and then
344@@ -118,7 +122,7 @@
345 maximum_length_before_md5_sum = maximum_filename_length - 32 - 1
346 if len(filename) > maximum_length_before_md5_sum:
347 filename=filename[:maximum_length_before_md5_sum]
348- return ",".join((filename, filemd5))
349+ return ",".join((filename.decode('utf-8'), filemd5))
350
351
352 def ssl_certificate_validation_disabled():
353@@ -162,7 +166,7 @@
354 def _request(self, conn, host, absolute_uri, request_uri, method, body,
355 headers, redirections, cachekey):
356 """Use the authorizer to authorize an outgoing request."""
357- if headers.has_key('authorization'):
358+ if 'authorization' in headers:
359 # There's an authorization header left over from a
360 # previous request that resulted in a redirect. Resources
361 # protected by OAuth or HTTP Digest must send a distinct
362@@ -308,7 +312,6 @@
363 key = key + '-' + self.request_media_type
364 return safename(key)
365
366-
367 def _getCachedHeader(self, uri, header):
368 """Retrieve a cached value for an HTTP header."""
369 (scheme, authority, request_uri, cachekey) = urlnorm(uri)
370@@ -370,25 +373,15 @@
371 "don't have the server-side permission to see.")
372
373 # Add extra headers for the request.
374- headers = {'Accept' : media_type}
375+ headers = {'Accept': media_type}
376 if self.user_agent is not None:
377 headers['User-Agent'] = self.user_agent
378 if isinstance(self._connection.cache, MultipleRepresentationCache):
379 self._connection.cache.request_media_type = media_type
380 if extra_headers is not None:
381 headers.update(extra_headers)
382- # Make the request.
383- try:
384- response, content = self._request_and_retry(
385- str(url), method=method, body=data, headers=headers)
386- except SSLHandshakeError, e:
387- msg = str(e)
388- if "SSL3_GET_SERVER_CERTIFICATE:certificate verify failed" in msg:
389- raise SSLHandshakeError(
390- "%s: perhaps set LP_DISABLE_SSL_CERTIFICATE_VALIDATION if "
391- "certificate validation failed and you genuinely trust the "
392- "remote server." % (e,))
393- raise
394+ response, content = self._request_and_retry(
395+ str(url), method=method, body=data, headers=headers)
396 if response.status == 304:
397 # The resource didn't change.
398 if content == '':
399@@ -447,10 +440,8 @@
400 wadl_type = 'application/vnd.sun.wadl+xml'
401 response, content = self._request(url, media_type=wadl_type)
402 url = str(url)
403- if not isinstance(url, bytes):
404- url = url.encode('utf-8')
405 if not isinstance(content, bytes):
406- content = content.encode('utf-8')
407+ content = content.encode('utf-8')
408 return Application(url, content)
409
410 def post(self, url, method_name, **kws):
411
412=== modified file 'src/lazr/restfulclient/authorize/oauth.py'
413--- src/lazr/restfulclient/authorize/oauth.py 2012-06-04 19:54:58 +0000
414+++ src/lazr/restfulclient/authorize/oauth.py 2014-07-28 15:39:09 +0000
415@@ -159,7 +159,8 @@
416 """
417 # Attempt to load the access token from the file.
418 parser = SafeConfigParser()
419- parser.readfp(readable_file)
420+ reader = getattr(parser, 'read_file', parser.readfp)
421+ reader(readable_file)
422 # Check the version number and extract the access token and
423 # secret. Then convert these to the appropriate instances.
424 if not parser.has_section(CREDENTIALS_FILE_VERSION):
425
426=== modified file 'src/lazr/restfulclient/resource.py'
427--- src/lazr/restfulclient/resource.py 2014-06-06 23:21:56 +0000
428+++ src/lazr/restfulclient/resource.py 2014-07-28 15:39:09 +0000
429@@ -55,6 +55,14 @@
430 import types
431 import urllib
432
433+import sys
434+if sys.version_info[0] >= 3:
435+ text_type = str
436+ binary_type = bytes
437+else:
438+ text_type = unicode
439+ binary_type = str
440+
441 from lazr.uri import URI
442 from wadllib.application import Resource as WadlResource
443
444@@ -371,7 +379,9 @@
445 if self._wadl_resource.representation is None:
446 # Get a representation of the linked resource.
447 representation = self._root._browser.get(self._wadl_resource)
448- representation = loads(unicode(representation))
449+ if isinstance(representation, binary_type):
450+ representation = representation.decode('utf-8')
451+ representation = loads(text_type(representation))
452
453 # In rare cases, the resource type served by the
454 # server conflicts with the type the client thought
455@@ -381,7 +391,7 @@
456 # XXX This should probably be moved into a hook method
457 # defined by Entry, since it's not relevant to other
458 # resource types.
459- if type(representation) == types.DictType:
460+ if isinstance(representation, dict):
461 type_link = representation['resource_type_link']
462 if (type_link is not None
463 and type_link != self._wadl_resource.type_url):
464@@ -521,7 +531,7 @@
465 url = str(self._root_uri.append(url))
466 document = self._browser.get(url)
467 try:
468- representation = loads(unicode(document))
469+ representation = loads(text_type(document))
470 except ValueError:
471 raise ValueError("%s doesn't serve a JSON document." % url)
472 type_link = representation.get("resource_type_link")
473@@ -574,7 +584,7 @@
474 # and option values (because JSON-encoding them will screw
475 # up wadllib's parameter validation). The option value thing
476 # is a little hacky, but it's the best solution for now.
477- if not key in send_as_is_params:
478+ if key not in send_as_is_params:
479 args[key] = dumps(value, cls=DatetimeJSONEncoder)
480 if http_method in ('get', 'head', 'delete'):
481 url = self.wadl_method.build_request_url(**args)
482@@ -616,7 +626,7 @@
483 HeaderDictionary(response))
484 wadl_parameter = wadl_response.get_parameter('Location')
485 wadl_resource = wadl_parameter.linked_resource
486- # Fetch a representation of the new resource.
487+ # Fetch a representation of the new resource.
488 response, content = self.root._browser._request(
489 wadl_resource.url)
490 # Return an instance of the appropriate lazr.restful
491@@ -637,13 +647,13 @@
492 # The operation returned a document with nothing
493 # special about it.
494 if content_type == self.JSON_MEDIA_TYPE:
495- return loads(unicode(content))
496+ return loads(text_type(content))
497 # We don't know how to process the content.
498 return content
499
500 # The operation returned a representation of some
501 # resource. Instantiate a Resource object for it.
502- document = loads(unicode(content))
503+ document = loads(text_type(content))
504 if document is None:
505 # The operation returned a null value.
506 return document
507@@ -767,7 +777,7 @@
508 if response.status == 209 and content_type == self.JSON_MEDIA_TYPE:
509 # The server sent back a new representation of the object.
510 # Use it in preference to the existing representation.
511- new_representation = loads(unicode(content))
512+ new_representation = loads(text_type(content))
513 self._wadl_resource.representation = new_representation
514 self._wadl_resource.media_type = content_type
515
516@@ -786,7 +796,7 @@
517 :rtype: int
518 """
519 total_size = self.total_size
520- if type(total_size) == types.IntType:
521+ if isinstance(total_size, int):
522 # The size was a number present in the collection
523 # representation.
524 return total_size
525@@ -813,7 +823,7 @@
526 if next_link is None:
527 break
528 current_page = loads(
529- unicode(self._root._browser.get(URI(next_link))))
530+ text_type(self._root._browser.get(URI(next_link))))
531
532 def __getitem__(self, key):
533 """Look up a slice, or a subordinate resource by index.
534@@ -886,7 +896,7 @@
535 # Iterate over pages until we have the correct number of entries.
536 while more_needed > 0 and page_url is not None:
537 representation = loads(
538- unicode(self._root._browser.get(page_url)))
539+ text_type(self._root._browser.get(page_url)))
540 current_page_entries = representation['entries']
541 entry_dicts += current_page_entries[:more_needed]
542 more_needed = desired_size - len(entry_dicts)
543@@ -1011,7 +1021,7 @@
544 # the resource describes itself.
545 try:
546 representation = loads(
547- unicode(self._root._browser.get(url)))
548+ text_type(self._root._browser.get(url)))
549 except HTTPError as error:
550 # There's no resource corresponding to the given ID.
551 if error.response.status == 404:
552
553=== modified file 'src/lazr/restfulclient/tests/test_atomicfilecache.py'
554--- src/lazr/restfulclient/tests/test_atomicfilecache.py 2012-06-04 19:54:58 +0000
555+++ src/lazr/restfulclient/tests/test_atomicfilecache.py 2014-07-28 15:39:09 +0000
556@@ -23,6 +23,13 @@
557 import tempfile
558 import unittest
559
560+import sys
561+PY3 = sys.version_info[0] >= 3
562+if PY3:
563+ binary_type = bytes
564+else:
565+ binary_type = str
566+
567 import httplib2
568
569 from lazr.restfulclient._browser import AtomicFileCache
570@@ -56,15 +63,15 @@
571 def test_set_key(self):
572 # A key set with set() can be got by get().
573 cache = self.make_file_cache()
574- cache.set('key', 'value')
575- self.assertEqual('value', cache.get('key'))
576+ cache.set('key', b'value')
577+ self.assertEqual(b'value', cache.get('key'))
578
579 def test_set_twice_overrides(self):
580 # Setting a key again overrides the value.
581 cache = self.make_file_cache()
582- cache.set('key', 'value')
583- cache.set('key', 'new-value')
584- self.assertEqual('new-value', cache.get('key'))
585+ cache.set('key', b'value')
586+ cache.set('key', b'new-value')
587+ self.assertEqual(b'new-value', cache.get('key'))
588
589 def test_delete_absent_key(self):
590 # Deleting a key that's not there does nothing.
591@@ -76,7 +83,7 @@
592 # A key once set can be deleted. Further attempts to get that key
593 # return None.
594 cache = self.make_file_cache()
595- cache.set('key', 'value')
596+ cache.set('key', b'value')
597 cache.delete('key')
598 self.assertIs(None, cache.get('key'))
599
600@@ -101,7 +108,7 @@
601 # probably a bug in httplib2.FileCache.
602 cache = self.make_file_cache()
603 self.assertRaises(TypeError, cache.set, 'answer', 42)
604- self.assertEqual('', cache.get('answer'))
605+ self.assertEqual(b'', cache.get('answer'))
606
607 def test_get_unicode(self):
608 # get() can retrieve unicode keys.
609@@ -110,19 +117,20 @@
610
611 def test_set_unicode_keys(self):
612 cache = self.make_file_cache()
613- cache.set(self.unicode_text, 'value')
614- self.assertEqual('value', cache.get(self.unicode_text))
615+ cache.set(self.unicode_text, b'value')
616+ self.assertEqual(b'value', cache.get(self.unicode_text))
617
618 def test_set_unicode_value(self):
619 # set() cannot store unicode values. Values must be bytes.
620 cache = self.make_file_cache()
621+ error = TypeError if PY3 else UnicodeEncodeError
622 self.assertRaises(
623- UnicodeEncodeError, cache.set, 'key', self.unicode_text)
624+ error, cache.set, 'key', self.unicode_text)
625
626 def test_delete_unicode(self):
627 # delete() can remove unicode keys.
628 cache = self.make_file_cache()
629- cache.set(self.unicode_text, 'value')
630+ cache.set(self.unicode_text, b'value')
631 cache.delete(self.unicode_text)
632 self.assertIs(None, cache.get(self.unicode_text))
633
634@@ -132,6 +140,12 @@
635
636 file_cache_factory = AtomicFileCache
637
638+ @staticmethod
639+ def prefix_safename(x):
640+ if isinstance(x, binary_type):
641+ x = x.decode('utf-8')
642+ return AtomicFileCache.TEMPFILE_PREFIX + x
643+
644 def test_set_non_string_value(self):
645 # set() raises TypeError if asked to set a key to a non-string value.
646 # Attempts to retrieve that value act is if it were never set.
647@@ -144,16 +158,16 @@
648 # Implementation-specific tests follow.
649
650 def test_bad_safename_get(self):
651- safename = lambda x: AtomicFileCache.TEMPFILE_PREFIX + x
652+ safename = self.prefix_safename
653 cache = AtomicFileCache(self.cache_dir, safename)
654 self.assertRaises(ValueError, cache.get, 'key')
655
656 def test_bad_safename_set(self):
657- safename = lambda x: AtomicFileCache.TEMPFILE_PREFIX + x
658+ safename = self.prefix_safename
659 cache = AtomicFileCache(self.cache_dir, safename)
660- self.assertRaises(ValueError, cache.set, 'key', 'value')
661+ self.assertRaises(ValueError, cache.set, 'key', b'value')
662
663 def test_bad_safename_delete(self):
664- safename = lambda x: AtomicFileCache.TEMPFILE_PREFIX + x
665+ safename = self.prefix_safename
666 cache = AtomicFileCache(self.cache_dir, safename)
667 self.assertRaises(ValueError, cache.delete, 'key')
668
669=== modified file 'src/lazr/restfulclient/tests/test_error.py'
670--- src/lazr/restfulclient/tests/test_error.py 2010-07-19 14:15:11 +0000
671+++ src/lazr/restfulclient/tests/test_error.py 2014-07-28 15:39:09 +0000
672@@ -39,10 +39,10 @@
673 request = DummyRequest(status)
674 error = error_for(request, content)
675 if expected_error is None:
676- self.assertEquals(error, None)
677+ self.assertIsNone(error)
678 else:
679 self.assertTrue(isinstance(error, expected_error))
680- self.assertEquals(content, error.content)
681+ self.assertEqual(content, error.content)
682
683 def test_no_error_for_2xx(self):
684 """Make sure a 2xx response code yields no error."""
685
686=== modified file 'src/lazr/restfulclient/tests/test_oauth.py'
687--- src/lazr/restfulclient/tests/test_oauth.py 2010-10-28 22:22:32 +0000
688+++ src/lazr/restfulclient/tests/test_oauth.py 2014-07-28 15:39:09 +0000
689@@ -39,14 +39,14 @@
690
691 def test_data_fields(self):
692 consumer = Consumer("key", "secret", "application")
693- self.assertEquals(consumer.key, "key")
694- self.assertEquals(consumer.secret, "secret")
695- self.assertEquals(consumer.application_name, "application")
696+ self.assertEqual(consumer.key, "key")
697+ self.assertEqual(consumer.secret, "secret")
698+ self.assertEqual(consumer.application_name, "application")
699
700 def test_default_application_name(self):
701 # Application name defaults to None
702 consumer = Consumer("key", "secret")
703- self.assertEquals(consumer.application_name, None)
704+ self.assertEqual(consumer.application_name, None)
705
706
707 class TestSystemWideConsumer(unittest.TestCase):
708@@ -105,7 +105,7 @@
709 self._set_platform(('Fooix', 'String2', 'String3'), 'FooOS')
710 self._set_hostname("foo")
711 consumer = oauth.SystemWideConsumer("app name")
712- self.assertEquals(
713+ self.assertEqual(
714 consumer.key, 'System-wide: Fooix (foo)')
715
716 def test_empty_linux_distribution(self):
717@@ -115,7 +115,7 @@
718 self._set_platform(('', '', ''), 'BarOS')
719 self._set_hostname("bar")
720 consumer = oauth.SystemWideConsumer("app name")
721- self.assertEquals(
722+ self.assertEqual(
723 consumer.key, 'System-wide: BarOS (bar)')
724
725 def test_broken_linux_distribution(self):
726@@ -125,7 +125,7 @@
727 self._set_platform(self._broken, 'BazOS')
728 self._set_hostname("baz")
729 consumer = oauth.SystemWideConsumer("app name")
730- self.assertEquals(
731+ self.assertEqual(
732 consumer.key, 'System-wide: BazOS (baz)')
733
734
735@@ -150,7 +150,7 @@
736
737 # Make sure the file is readable and writable by the user, but
738 # not by anyone else.
739- self.assertEquals(stat.S_IMODE(os.stat(credentials_path).st_mode),
740+ self.assertEqual(stat.S_IMODE(os.stat(credentials_path).st_mode),
741 stat.S_IREAD | stat.S_IWRITE)
742
743 loaded_credentials = OAuthAuthorizer.load_from_path(credentials_path)

Subscribers

People subscribed via source and target branches