Merge lp:~xnox/lazr.restfulclient/fixes into lp:lazr.restfulclient
- fixes
- Merge into trunk
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 |
Related bugs: |
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.
Description of the change
- 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
Dimitri John Ledkov (xnox) wrote : | # |
Replied.
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_
- 150. By Dimitri John Ledkov
-
Whitespace and review fixes, drop SSLHandshakeError handling.
Preview Diff
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) |
A few minor comments and one important question. (inline of course)