Merge lp:~xnox/launchpadlib/py3-new into lp:launchpadlib

Proposed by Dimitri John Ledkov
Status: Merged
Merged at revision: 137
Proposed branch: lp:~xnox/launchpadlib/py3-new
Merge into: lp:launchpadlib
Diff against target: 1015 lines (+211/-323)
13 files modified
MANIFEST.in (+0/-1)
buildout.cfg (+1/-0)
ez_setup.py (+0/-241)
setup.py (+0/-3)
src/launchpadlib/credentials.py (+37/-10)
src/launchpadlib/launchpad.py (+8/-6)
src/launchpadlib/testing/launchpad.py (+9/-6)
src/launchpadlib/testing/tests/test_launchpad.py (+1/-1)
src/launchpadlib/tests/test_credential_store.py (+27/-15)
src/launchpadlib/tests/test_http.py (+12/-12)
src/launchpadlib/tests/test_launchpad.py (+26/-26)
src/launchpadlib/uris.py (+5/-2)
versions.cfg (+85/-0)
To merge this branch: bzr merge lp:~xnox/launchpadlib/py3-new
Reviewer Review Type Date Requested Status
LAZR Developers Pending
Review via email: mp+225691@code.launchpad.net

Commit message

Initial python3 port.

To post a comment you must log in.
lp:~xnox/launchpadlib/py3-new updated
140. By Dimitri John Ledkov

Remove ez_setup

141. By Dimitri John Ledkov

json.loads text only

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

Generally looks good. I have only minor comments.

lp:~xnox/launchpadlib/py3-new updated
142. By Dimitri John Ledkov

Address barry's review comments.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'MANIFEST.in'
2--- MANIFEST.in 2009-05-30 18:49:47 +0000
3+++ MANIFEST.in 2014-07-14 20:30:23 +0000
4@@ -1,4 +1,3 @@
5-include ez_setup.py
6 exclude MANIFEST.in buildout.cfg bootstrap.py .bzrignore
7 global-include *.txt *.xsl *.png
8 prune _bootstrap
9
10=== modified file 'buildout.cfg'
11--- buildout.cfg 2011-01-07 18:01:06 +0000
12+++ buildout.cfg 2014-07-14 20:30:23 +0000
13@@ -1,4 +1,5 @@
14 [buildout]
15+extends = versions.cfg
16 parts =
17 interpreter
18 test
19
20=== removed file 'ez_setup.py'
21--- ez_setup.py 2010-03-24 16:21:31 +0000
22+++ ez_setup.py 1970-01-01 00:00:00 +0000
23@@ -1,241 +0,0 @@
24-#!python
25-"""Bootstrap setuptools installation
26-
27-If you want to use setuptools in your package's setup.py, just include this
28-file in the same directory with it, and add this to the top of your setup.py::
29-
30- from ez_setup import use_setuptools
31- use_setuptools()
32-
33-If you want to require a specific version of setuptools, set a download
34-mirror, or use an alternate download directory, you can do so by supplying
35-the appropriate options to ``use_setuptools()``.
36-
37-This file can also be run as a script to install or upgrade setuptools.
38-"""
39-import sys
40-DEFAULT_VERSION = "0.6c11"
41-DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
42-
43-md5_data = {
44- 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
45- 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
46- 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
47- 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
48- 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
49- 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
50- 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
51- 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
52- 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
53- 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
54- 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
55- 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
56- 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
57- 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
58- 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
59- 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
60- 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
61- 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
62- 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
63- 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
64- 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
65- 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
66- 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
67- 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
68- 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
69- 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
70- 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
71- 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
72- 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
73- 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
74-}
75-
76-import sys, os
77-
78-def _validate_md5(egg_name, data):
79- if egg_name in md5_data:
80- from md5 import md5
81- digest = md5(data).hexdigest()
82- if digest != md5_data[egg_name]:
83- print >>sys.stderr, (
84- "md5 validation of %s failed! (Possible download problem?)"
85- % egg_name
86- )
87- sys.exit(2)
88- return data
89-
90-
91-def use_setuptools(
92- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
93- download_delay=15, min_version=None
94-):
95- """Automatically find/download setuptools and make it available on sys.path
96-
97- `version` should be a valid setuptools version number that is available
98- as an egg for download under the `download_base` URL (which should end with
99- a '/'). `to_dir` is the directory where setuptools will be downloaded, if
100- it is not already available. If `download_delay` is specified, it should
101- be the number of seconds that will be paused before initiating a download,
102- should one be required. If an older version of setuptools is installed,
103- this routine will print a message to ``sys.stderr`` and raise SystemExit in
104- an attempt to abort the calling script.
105- """
106- # Work around a hack in the ez_setup.py file from simplejson==1.7.3.
107- if min_version:
108- version = min_version
109-
110- was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
111- def do_download():
112- egg = download_setuptools(version, download_base, to_dir, download_delay)
113- sys.path.insert(0, egg)
114- import setuptools; setuptools.bootstrap_install_from = egg
115- try:
116- import pkg_resources
117- except ImportError:
118- return do_download()
119- try:
120- pkg_resources.require("setuptools>="+version); return
121- except pkg_resources.VersionConflict, e:
122- if was_imported:
123- print >>sys.stderr, (
124- "The required version of setuptools (>=%s) is not available, and\n"
125- "can't be installed while this script is running. Please install\n"
126- " a more recent version first, using 'easy_install -U setuptools'."
127- "\n\n(Currently using %r)"
128- ) % (version, e.args[0])
129- sys.exit(2)
130- else:
131- del pkg_resources, sys.modules['pkg_resources'] # reload ok
132- return do_download()
133- except pkg_resources.DistributionNotFound:
134- return do_download()
135-
136-def download_setuptools(
137- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
138- delay = 15
139-):
140- """Download setuptools from a specified location and return its filename
141-
142- `version` should be a valid setuptools version number that is available
143- as an egg for download under the `download_base` URL (which should end
144- with a '/'). `to_dir` is the directory where the egg will be downloaded.
145- `delay` is the number of seconds to pause before an actual download attempt.
146- """
147- import urllib2, shutil
148- egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
149- url = download_base + egg_name
150- saveto = os.path.join(to_dir, egg_name)
151- src = dst = None
152- if not os.path.exists(saveto): # Avoid repeated downloads
153- try:
154- from distutils import log
155- if delay:
156- log.warn("""
157----------------------------------------------------------------------------
158-This script requires setuptools version %s to run (even to display
159-help). I will attempt to download it for you (from
160-%s), but
161-you may need to enable firewall access for this script first.
162-I will start the download in %d seconds.
163-
164-(Note: if this machine does not have network access, please obtain the file
165-
166- %s
167-
168-and place it in this directory before rerunning this script.)
169----------------------------------------------------------------------------""",
170- version, download_base, delay, url
171- ); from time import sleep; sleep(delay)
172- log.warn("Downloading %s", url)
173- src = urllib2.urlopen(url)
174- # Read/write all in one block, so we don't create a corrupt file
175- # if the download is interrupted.
176- data = _validate_md5(egg_name, src.read())
177- dst = open(saveto,"wb"); dst.write(data)
178- finally:
179- if src: src.close()
180- if dst: dst.close()
181- return os.path.realpath(saveto)
182-
183-def main(argv, version=DEFAULT_VERSION):
184- """Install or upgrade setuptools and EasyInstall"""
185- try:
186- import setuptools
187- except ImportError:
188- egg = None
189- try:
190- egg = download_setuptools(version, delay=0)
191- sys.path.insert(0,egg)
192- from setuptools.command.easy_install import main
193- return main(list(argv)+[egg]) # we're done here
194- finally:
195- if egg and os.path.exists(egg):
196- os.unlink(egg)
197- else:
198- if setuptools.__version__ == '0.0.1':
199- print >>sys.stderr, (
200- "You have an obsolete version of setuptools installed. Please\n"
201- "remove it from your system entirely before rerunning this script."
202- )
203- sys.exit(2)
204-
205- req = "setuptools>="+version
206- import pkg_resources
207- try:
208- pkg_resources.require(req)
209- except pkg_resources.VersionConflict:
210- try:
211- from setuptools.command.easy_install import main
212- except ImportError:
213- from easy_install import main
214- main(list(argv)+[download_setuptools(delay=0)])
215- sys.exit(0) # try to force an exit
216- else:
217- if argv:
218- from setuptools.command.easy_install import main
219- main(argv)
220- else:
221- print "Setuptools version",version,"or greater has been installed."
222- print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
223-
224-def update_md5(filenames):
225- """Update our built-in md5 registry"""
226-
227- import re
228- from md5 import md5
229-
230- for name in filenames:
231- base = os.path.basename(name)
232- f = open(name,'rb')
233- md5_data[base] = md5(f.read()).hexdigest()
234- f.close()
235-
236- data = [" %r: %r,\n" % it for it in md5_data.items()]
237- data.sort()
238- repl = "".join(data)
239-
240- import inspect
241- srcfile = inspect.getsourcefile(sys.modules[__name__])
242- f = open(srcfile, 'rb'); src = f.read(); f.close()
243-
244- match = re.search("\nmd5_data = {\n([^}]+)}", src)
245- if not match:
246- print >>sys.stderr, "Internal error!"
247- sys.exit(2)
248-
249- src = src[:match.start(1)] + repl + src[match.end(1):]
250- f = open(srcfile,'w')
251- f.write(src)
252- f.close()
253-
254-
255-if __name__=='__main__':
256- if len(sys.argv)>2 and sys.argv[1]=='--md5update':
257- update_md5(sys.argv[2:])
258- else:
259- main(sys.argv[1:])
260-
261-
262-
263-
264-
265
266=== modified file 'setup.py'
267--- setup.py 2013-07-20 23:05:20 +0000
268+++ setup.py 2014-07-14 20:30:23 +0000
269@@ -18,9 +18,6 @@
270
271 """Setup for the launchpadlib library."""
272
273-import ez_setup
274-ez_setup.use_setuptools()
275-
276 import sys
277 from setuptools import setup, find_packages
278
279
280=== modified file 'src/launchpadlib/credentials.py'
281--- src/launchpadlib/credentials.py 2013-07-20 23:05:20 +0000
282+++ src/launchpadlib/credentials.py 2014-07-14 20:30:23 +0000
283@@ -14,6 +14,8 @@
284 # You should have received a copy of the GNU Lesser General Public License
285 # along with launchpadlib. If not, see <http://www.gnu.org/licenses/>.
286
287+from __future__ import print_function
288+
289 """launchpadlib credentials and authentication support."""
290
291 __metaclass__ = type
292@@ -28,13 +30,23 @@
293 ]
294
295 import cgi
296-from cStringIO import StringIO
297+try:
298+ from cStringIO import StringIO
299+except ImportError:
300+ from io import StringIO
301+
302 import httplib2
303 import os
304 import stat
305 import time
306-from urllib import urlencode
307-from urlparse import urljoin
308+try:
309+ from urllib.parse import urlencode
310+except ImportError:
311+ from urllib import urlencode
312+try:
313+ from urllib.parse import urljoin
314+except ImportError:
315+ from urlparse import urljoin
316 import webbrowser
317 from base64 import (
318 b64decode,
319@@ -46,6 +58,14 @@
320 except ImportError:
321 import simplejson as json
322
323+if bytes is str:
324+ # Python 2
325+ unicode_type = unicode
326+ binary_type = str
327+else:
328+ unicode_type = str
329+ binary_type = bytes
330+
331 from lazr.restfulclient.errors import HTTPError
332 from lazr.restfulclient.authorize.oauth import (
333 AccessToken as _AccessToken,
334@@ -116,6 +136,8 @@
335 sio = StringIO()
336 self.save(sio)
337 serialized = sio.getvalue()
338+ if isinstance(serialized, unicode_type):
339+ serialized = serialized.encode('utf-8')
340 return serialized
341
342 @classmethod
343@@ -125,6 +147,8 @@
344 This should probably be moved into OAuthAuthorizer.
345 """
346 credentials = cls()
347+ if not isinstance(value, unicode_type):
348+ value = value.decode('utf-8')
349 credentials.load(StringIO(value))
350 return credentials
351
352@@ -164,6 +188,8 @@
353 if token_format == self.DICT_TOKEN_FORMAT:
354 headers['Accept'] = 'application/json'
355 response, content = _http_post(url, headers, params)
356+ if isinstance(content, binary_type):
357+ content = content.decode('utf-8')
358 if token_format == self.DICT_TOKEN_FORMAT:
359 params = json.loads(content)
360 if context is not None:
361@@ -272,7 +298,7 @@
362 self.do_save(credentials, unique_consumer_id)
363 except EXPLOSIVE_ERRORS:
364 raise
365- except Exception, e:
366+ except Exception as e:
367 if self.credential_save_failed is None:
368 raise e
369 self.credential_save_failed()
370@@ -327,7 +353,7 @@
371 integrating third-party websites into Launchpad.
372 """
373
374- B64MARKER = "<B64>"
375+ B64MARKER = b"<B64>"
376
377 @staticmethod
378 def _ensure_keyring_imported():
379@@ -359,7 +385,8 @@
380 credential_string = keyring.get_password(
381 'launchpadlib', unique_key)
382 if credential_string is not None:
383- credential_string = credential_string.encode('utf8')
384+ if isinstance(credential_string, unicode_type):
385+ credential_string = credential_string.encode('utf8')
386 if credential_string.startswith(self.B64MARKER):
387 try:
388 credential_string = b64decode(
389@@ -586,7 +613,7 @@
390 does not require any user interaction--it's solely
391 informative.
392 """
393- print message
394+ print(message)
395
396 def make_end_user_authorize_token(self, credentials, request_token):
397 """Have the end-user authorize the token in their browser."""
398@@ -600,7 +627,7 @@
399 credentials.exchange_request_token_for_access_token(
400 self.web_root)
401 break
402- except HTTPError, e:
403+ except HTTPError as e:
404 if e.response.status == 403:
405 # The user decided not to authorize this
406 # application.
407@@ -610,8 +637,8 @@
408 pass
409 else:
410 # There was an error accessing the server.
411- print "Unexpected response from Launchpad:"
412- print e
413+ print("Unexpected response from Launchpad:")
414+ print(e)
415
416
417 class TokenAuthorizationException(Exception):
418
419=== modified file 'src/launchpadlib/launchpad.py'
420--- src/launchpadlib/launchpad.py 2011-11-10 15:29:38 +0000
421+++ src/launchpadlib/launchpad.py 2014-07-14 20:30:23 +0000
422@@ -22,7 +22,10 @@
423 ]
424
425 import os
426-import urlparse
427+try:
428+ from urllib.parse import urlsplit
429+except:
430+ from urlparse import urlsplit
431 import warnings
432
433 from lazr.restfulclient.resource import (
434@@ -596,15 +599,14 @@
435 raise ValueError("Must set $HOME or pass 'launchpadlib_dir' to "
436 "indicate location to store cached data")
437 if not os.path.exists(launchpadlib_dir):
438- os.makedirs(launchpadlib_dir, 0700)
439- os.chmod(launchpadlib_dir, 0700)
440+ os.makedirs(launchpadlib_dir, 0o700)
441+ os.chmod(launchpadlib_dir, 0o700)
442 # Determine the real service root.
443 service_root = uris.lookup_service_root(service_root)
444 # Each service root has its own cache and credential dirs.
445- scheme, host_name, path, query, fragment = urlparse.urlsplit(
446- service_root)
447+ scheme, host_name, path, query, fragment = urlsplit(service_root)
448 service_root_dir = os.path.join(launchpadlib_dir, host_name)
449 cache_path = os.path.join(service_root_dir, 'cache')
450 if not os.path.exists(cache_path):
451- os.makedirs(cache_path, 0700)
452+ os.makedirs(cache_path, 0o700)
453 return (service_root, launchpadlib_dir, cache_path, service_root_dir)
454
455=== modified file 'src/launchpadlib/testing/launchpad.py'
456--- src/launchpadlib/testing/launchpad.py 2011-09-15 09:15:42 +0000
457+++ src/launchpadlib/testing/launchpad.py 2014-07-14 20:30:23 +0000
458@@ -66,7 +66,10 @@
459 """
460
461 from datetime import datetime
462-
463+import collections
464+import sys
465+if sys.version_info[0] >= 3:
466+ basestring = str
467
468 JSON_MEDIA_TYPE = "application/json"
469
470@@ -202,7 +205,7 @@
471 result = self._children.get(name, _marker)
472 if result is _marker:
473 result = self._values.get(name, _marker)
474- if callable(result):
475+ if isinstance(result, collections.Callable):
476 return self._wrap_method(name, result)
477 if name in self.special_methods:
478 return lambda: True
479@@ -276,8 +279,8 @@
480 @param partial_object: A dict with key/value pairs representing
481 attributes and methods.
482 """
483- for name, value in partial_object.iteritems():
484- if callable(value):
485+ for name, value in partial_object.items():
486+ if isinstance(value, collections.Callable):
487 # Performs an integrity check.
488 self._get_method(resource_type, name)
489 else:
490@@ -299,11 +302,11 @@
491 """
492 name = None
493 child_resource_type = None
494- for name, value in partial_object.iteritems():
495+ for name, value in partial_object.items():
496 if name == "entries":
497 name, child_resource_type = (
498 self._check_entries(resource_type, value))
499- elif callable(value):
500+ elif isinstance(value, collections.Callable):
501 # Performs an integrity check.
502 self._get_method(resource_type, name)
503 else:
504
505=== modified file 'src/launchpadlib/testing/tests/test_launchpad.py'
506--- src/launchpadlib/testing/tests/test_launchpad.py 2011-09-13 13:48:51 +0000
507+++ src/launchpadlib/testing/tests/test_launchpad.py 2014-07-14 20:30:23 +0000
508@@ -109,7 +109,7 @@
509 A L{FakeLaunchpad} instantiated without credentials has its
510 C{credentials} attribute set to C{None}.
511 """
512- self.assertEqual(None, self.launchpad.credentials)
513+ self.assertIsNone(self.launchpad.credentials)
514
515 def test_set_undefined_property(self):
516 """
517
518=== modified file 'src/launchpadlib/tests/test_credential_store.py'
519--- src/launchpadlib/tests/test_credential_store.py 2011-12-02 18:57:15 +0000
520+++ src/launchpadlib/tests/test_credential_store.py 2014-07-14 20:30:23 +0000
521@@ -22,6 +22,12 @@
522
523 from base64 import b64decode
524
525+if bytes is str:
526+ # Python 2
527+ unicode_type = unicode
528+else:
529+ unicode_type = str
530+
531 from launchpadlib.testing.helpers import (
532 fake_keyring,
533 InMemoryKeyring,
534@@ -60,7 +66,7 @@
535 credential = self.make_credential("consumer key")
536 self.store.save(credential, "unique key")
537 credential2 = self.store.load("unique key")
538- self.assertEquals(credential.consumer.key, credential2.consumer.key)
539+ self.assertEqual(credential.consumer.key, credential2.consumer.key)
540
541 def test_unique_id_doesnt_matter(self):
542 # If a file contains a credential, that credential will be
543@@ -68,7 +74,7 @@
544 credential = self.make_credential("consumer key")
545 self.store.save(credential, "some key")
546 credential2 = self.store.load("some other key")
547- self.assertEquals(credential.consumer.key, credential2.consumer.key)
548+ self.assertEqual(credential.consumer.key, credential2.consumer.key)
549
550 def test_file_only_contains_one_credential(self):
551 # A credential file may contain only one credential. If you
552@@ -80,7 +86,7 @@
553 self.store.save(credential1, "unique key 1")
554 self.store.save(credential1, "unique key 2")
555 loaded = self.store.load("unique key 1")
556- self.assertEquals(loaded.consumer.key, credential2.consumer.key)
557+ self.assertEqual(loaded.consumer.key, credential2.consumer.key)
558
559
560 class TestKeyringCredentialStore(CredentialStoreTestCase):
561@@ -96,7 +102,7 @@
562 credential = self.make_credential("consumer key")
563 self.store.save(credential, "unique key")
564 credential2 = self.store.load("unique key")
565- self.assertEquals(
566+ self.assertEqual(
567 credential.consumer.key, credential2.consumer.key)
568
569 def test_lookup_by_unique_key(self):
570@@ -110,11 +116,12 @@
571 self.store.save(credential2, "key 2")
572
573 loaded1 = self.store.load("key 1")
574- self.assertEquals(
575+ self.assertTrue(loaded1)
576+ self.assertEqual(
577 credential1.consumer.key, loaded1.consumer.key)
578
579 loaded2 = self.store.load("key 2")
580- self.assertEquals(
581+ self.assertEqual(
582 credential2.consumer.key, loaded2.consumer.key)
583
584 def test_reused_unique_id_overwrites_old_credential(self):
585@@ -129,14 +136,14 @@
586 self.store.save(credential2, "the only key")
587
588 loaded = self.store.load("the only key")
589- self.assertEquals(
590+ self.assertEqual(
591 credential2.consumer.key, loaded.consumer.key)
592
593 def test_bad_unique_id_returns_none(self):
594 # Trying to load a credential without providing a good unique
595 # ID will get you None.
596 with fake_keyring(self.keyring):
597- self.assertEquals(None, self.store.load("no such key"))
598+ self.assertIsNone(self.store.load("no such key"))
599
600 def test_keyring_returns_unicode(self):
601 # Kwallet is reported to sometimes return Unicode, which broke the
602@@ -144,18 +151,23 @@
603 # handled correctly. (See bug lp:877374)
604 class UnicodeInMemoryKeyring(InMemoryKeyring):
605 def get_password(self, service, username):
606- return unicode(
607- super(UnicodeInMemoryKeyring, self).get_password(
608- service, username))
609+ password = super(UnicodeInMemoryKeyring, self).get_password(
610+ service, username)
611+ if isinstance(password, unicode_type):
612+ password = password.encode('utf-8')
613+ return password
614
615 self.keyring = UnicodeInMemoryKeyring()
616 with fake_keyring(self.keyring):
617 credential = self.make_credential("consumer key")
618+ self.assertTrue(credential)
619+ # Shouldn't this test actually use a unicodish key?!
620 self.store.save(credential, "unique key")
621 credential2 = self.store.load("unique key")
622- self.assertEquals(
623+ self.assertTrue(credential2)
624+ self.assertEqual(
625 credential.consumer.key, credential2.consumer.key)
626- self.assertEquals(
627+ self.assertEqual(
628 credential.consumer.secret, credential2.consumer.secret)
629
630 def test_nonencoded_key_handled(self):
631@@ -172,9 +184,9 @@
632 credential = self.make_credential("consumer key")
633 self.store.save(credential, "unique key")
634 credential2 = self.store.load("unique key")
635- self.assertEquals(
636+ self.assertEqual(
637 credential.consumer.key, credential2.consumer.key)
638- self.assertEquals(
639+ self.assertEqual(
640 credential.consumer.secret, credential2.consumer.secret)
641
642 def test_corrupted_key_handled(self):
643
644=== modified file 'src/launchpadlib/tests/test_http.py'
645--- src/launchpadlib/tests/test_http.py 2014-05-12 13:21:36 +0000
646+++ src/launchpadlib/tests/test_http.py 2014-07-14 20:30:23 +0000
647@@ -174,10 +174,10 @@
648 Response(200, SIMPLE_WADL),
649 Response(200, SIMPLE_JSON)]
650
651- self.assertEquals(self.engine.access_tokens_obtained, 0)
652+ self.assertEqual(self.engine.access_tokens_obtained, 0)
653 launchpad = SimulatedResponsesLaunchpad.login_with(
654 'application name', authorization_engine=self.engine)
655- self.assertEquals(self.engine.access_tokens_obtained, 1)
656+ self.assertEqual(self.engine.access_tokens_obtained, 1)
657
658 def test_bad_token(self):
659 """If our token is bad, we get another one."""
660@@ -186,10 +186,10 @@
661 Response(200, SIMPLE_WADL),
662 Response(200, SIMPLE_JSON)]
663
664- self.assertEquals(self.engine.access_tokens_obtained, 0)
665+ self.assertEqual(self.engine.access_tokens_obtained, 0)
666 launchpad = SimulatedResponsesLaunchpad.login_with(
667 'application name', authorization_engine=self.engine)
668- self.assertEquals(self.engine.access_tokens_obtained, 2)
669+ self.assertEqual(self.engine.access_tokens_obtained, 2)
670
671 def test_expired_token(self):
672 """If our token is expired, we get another one."""
673@@ -199,10 +199,10 @@
674 Response(200, SIMPLE_WADL),
675 Response(200, SIMPLE_JSON)]
676
677- self.assertEquals(self.engine.access_tokens_obtained, 0)
678+ self.assertEqual(self.engine.access_tokens_obtained, 0)
679 launchpad = SimulatedResponsesLaunchpad.login_with(
680 'application name', authorization_engine=self.engine)
681- self.assertEquals(self.engine.access_tokens_obtained, 2)
682+ self.assertEqual(self.engine.access_tokens_obtained, 2)
683
684 def test_unknown_token(self):
685 """If our token is unknown, we get another one."""
686@@ -212,10 +212,10 @@
687 Response(200, SIMPLE_WADL),
688 Response(200, SIMPLE_JSON)]
689
690- self.assertEquals(self.engine.access_tokens_obtained, 0)
691+ self.assertEqual(self.engine.access_tokens_obtained, 0)
692 launchpad = SimulatedResponsesLaunchpad.login_with(
693 'application name', authorization_engine=self.engine)
694- self.assertEquals(self.engine.access_tokens_obtained, 2)
695+ self.assertEqual(self.engine.access_tokens_obtained, 2)
696
697 def test_delayed_error(self):
698 """We get another token no matter when the error happens."""
699@@ -224,10 +224,10 @@
700 Response(401, "Expired token."),
701 Response(200, SIMPLE_JSON)]
702
703- self.assertEquals(self.engine.access_tokens_obtained, 0)
704+ self.assertEqual(self.engine.access_tokens_obtained, 0)
705 launchpad = SimulatedResponsesLaunchpad.login_with(
706 'application name', authorization_engine=self.engine)
707- self.assertEquals(self.engine.access_tokens_obtained, 2)
708+ self.assertEqual(self.engine.access_tokens_obtained, 2)
709
710 def test_many_errors(self):
711 """We'll keep getting new tokens as long as tokens are the problem."""
712@@ -237,10 +237,10 @@
713 Response(401, "Expired token."),
714 Response(401, "Invalid token."),
715 Response(200, SIMPLE_JSON)]
716- self.assertEquals(self.engine.access_tokens_obtained, 0)
717+ self.assertEqual(self.engine.access_tokens_obtained, 0)
718 launchpad = SimulatedResponsesLaunchpad.login_with(
719 'application name', authorization_engine=self.engine)
720- self.assertEquals(self.engine.access_tokens_obtained, 4)
721+ self.assertEqual(self.engine.access_tokens_obtained, 4)
722
723 def test_other_unauthorized(self):
724 """If the token is not at fault, a 401 error raises an exception."""
725
726=== modified file 'src/launchpadlib/tests/test_launchpad.py'
727--- src/launchpadlib/tests/test_launchpad.py 2014-05-12 13:26:58 +0000
728+++ src/launchpadlib/tests/test_launchpad.py 2014-07-14 20:30:23 +0000
729@@ -82,7 +82,7 @@
730 self.assertEqual(len(caught), 1)
731 warning, = caught
732 self.assertTrue(issubclass(warning.category, DeprecationWarning))
733- self.assertTrue("no longer exists" in warning.message.message)
734+ self.assertIn("no longer exists", str(warning))
735
736 def test_short_names(self):
737 # Ensure the short service names are all supported.
738@@ -180,7 +180,7 @@
739 root = uris.service_roots['staging'] + version
740 try:
741 Launchpad(None, None, None, service_root=root, version=version)
742- except ValueError, e:
743+ except ValueError as e:
744 self.assertTrue(str(e).startswith(
745 "It looks like you're using a service root that incorporates "
746 'the name of the web service version ("version-foo")'))
747@@ -239,7 +239,7 @@
748 # The credentials are stored unencrypted in the file you
749 # specify.
750 credentials = Credentials.load_from_path(filename)
751- self.assertEquals(credentials.consumer.key,
752+ self.assertEqual(credentials.consumer.key,
753 launchpad.credentials.consumer.key)
754 os.remove(filename)
755
756@@ -305,7 +305,7 @@
757 launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib')
758 # Verify a newly created-by-hand directory is insecure
759 os.mkdir(launchpadlib_dir)
760- os.chmod(launchpadlib_dir, 0755)
761+ os.chmod(launchpadlib_dir, 0o755)
762 self.assertTrue(os.path.isdir(launchpadlib_dir))
763 statinfo = os.stat(launchpadlib_dir)
764 mode = stat.S_IMODE(statinfo.st_mode)
765@@ -337,7 +337,7 @@
766 launchpad = NoNetworkLaunchpad.login_with(
767 'not important', service_root=SERVICE_ROOT,
768 launchpadlib_dir=launchpadlib_dir, version="foo")
769- self.assertEquals(launchpad.passed_in_args['version'], 'foo')
770+ self.assertEqual(launchpad.passed_in_args['version'], 'foo')
771
772 # Now execute the same test a second time. This time, the
773 # credentials are loaded from disk and a different code path
774@@ -346,7 +346,7 @@
775 launchpad = NoNetworkLaunchpad.login_with(
776 'not important', service_root=SERVICE_ROOT,
777 launchpadlib_dir=launchpadlib_dir, version="bar")
778- self.assertEquals(launchpad.passed_in_args['version'], 'bar')
779+ self.assertEqual(launchpad.passed_in_args['version'], 'bar')
780
781 def test_application_name_is_propagated(self):
782 # Create a Launchpad instance for a given application name.
783@@ -357,7 +357,7 @@
784 launchpad = NoNetworkLaunchpad.login_with(
785 'very important', service_root=SERVICE_ROOT,
786 launchpadlib_dir=launchpadlib_dir)
787- self.assertEquals(
788+ self.assertEqual(
789 launchpad.credentials.consumer.application_name, 'very important')
790
791 # Now execute the same test a second time. This time, the
792@@ -368,7 +368,7 @@
793 launchpad = NoNetworkLaunchpad.login_with(
794 'very important', service_root=SERVICE_ROOT,
795 launchpadlib_dir=launchpadlib_dir)
796- self.assertEquals(
797+ self.assertEqual(
798 launchpad.credentials.consumer.application_name, 'very important')
799
800 def test_authorization_engine_is_propagated(self):
801@@ -378,8 +378,8 @@
802 engine = NoNetworkAuthorizationEngine(
803 SERVICE_ROOT, 'application name')
804 NoNetworkLaunchpad.login_with(authorization_engine=engine)
805- self.assertEquals(engine.request_tokens_obtained, 1)
806- self.assertEquals(engine.access_tokens_obtained, 1)
807+ self.assertEqual(engine.request_tokens_obtained, 1)
808+ self.assertEqual(engine.access_tokens_obtained, 1)
809
810 def test_login_with_must_identify_application(self):
811 # If you call login_with without identifying your application
812@@ -443,10 +443,10 @@
813 # levels into login_with().
814 launchpad = NoNetworkLaunchpad.login_with(
815 consumer_name="consumer", allow_access_levels=['FOO'])
816- self.assertEquals(launchpad.credentials.consumer.key, "consumer")
817- self.assertEquals(launchpad.credentials.consumer.application_name,
818+ self.assertEqual(launchpad.credentials.consumer.key, "consumer")
819+ self.assertEqual(launchpad.credentials.consumer.application_name,
820 None)
821- self.assertEquals(launchpad.authorization_engine.allow_access_levels,
822+ self.assertEqual(launchpad.authorization_engine.allow_access_levels,
823 ['FOO'])
824
825 def test_desktop_integration_doesnt_happen_without_consumer_name(self):
826@@ -456,7 +456,7 @@
827 # integration is performed.
828 launchpad = NoNetworkLaunchpad.login_with(
829 'application name', allow_access_levels=['FOO'])
830- self.assertEquals(launchpad.authorization_engine.allow_access_levels,
831+ self.assertEqual(launchpad.authorization_engine.allow_access_levels,
832 ['DESKTOP_INTEGRATION'])
833
834 def test_no_credentials_creates_new_credential(self):
835@@ -471,7 +471,7 @@
836 NoNetworkAuthorizationEngine.ACCESS_TOKEN_KEY)
837 self.assertEqual(launchpad.credentials.consumer.application_name,
838 'app name')
839- self.assertEquals(launchpad.authorization_engine.allow_access_levels,
840+ self.assertEqual(launchpad.authorization_engine.allow_access_levels,
841 ['DESKTOP_INTEGRATION'])
842 # The expected arguments were passed in to the Launchpad
843 # constructor.
844@@ -580,16 +580,16 @@
845 with warnings.catch_warnings(record=True) as caught:
846 warnings.simplefilter("always")
847 NoNetworkLaunchpad.login('consumer', 'token', 'secret')
848- self.assertEquals(len(caught), 1)
849- self.assertEquals(caught[0].category, DeprecationWarning)
850+ self.assertEqual(len(caught), 1)
851+ self.assertEqual(caught[0].category, DeprecationWarning)
852
853 def test_get_token_and_login_is_deprecated(self):
854 # get_token_and_login() works but triggers a deprecation warning.
855 with warnings.catch_warnings(record=True) as caught:
856 warnings.simplefilter("always")
857 NoNetworkLaunchpad.get_token_and_login('consumer')
858- self.assertEquals(len(caught), 1)
859- self.assertEquals(caught[0].category, DeprecationWarning)
860+ self.assertEqual(len(caught), 1)
861+ self.assertEqual(caught[0].category, DeprecationWarning)
862
863
864 class TestCredenitialSaveFailedCallback(unittest.TestCase):
865@@ -624,7 +624,7 @@
866 'not important', service_root=service_root,
867 launchpadlib_dir=launchpadlib_dir,
868 credential_save_failed=callback)
869- self.assertEquals(len(callback_called), 1)
870+ self.assertEqual(len(callback_called), 1)
871
872 def test_default_credentials_save_failed_is_to_raise_exception(self):
873 # If saving the credentials did not succeed and no callback was
874@@ -666,18 +666,18 @@
875 launchpadlib_dir=launchpadlib_dir)
876 consumer_name = launchpad.credentials.consumer.key
877
878- application_key = keyring.data.keys()[0][1]
879+ application_key = list(keyring.data.keys())[0][1]
880
881 # Both the consumer name (normally the name of the application) and
882 # the service root (the URL of the service being accessed) are
883 # included in the key when storing credentials.
884- self.assert_(service_root in application_key)
885- self.assert_(consumer_name in application_key)
886+ self.assertIn(service_root, application_key)
887+ self.assertIn(consumer_name, application_key)
888
889 # The key used to store the credentials is of this structure (and
890 # shouldn't change between releases or stored credentials will be
891 # "forgotten").
892- self.assertEquals(application_key, consumer_name + '@' + service_root)
893+ self.assertEqual(application_key, consumer_name + '@' + service_root)
894
895 def test_same_app_different_servers(self):
896 launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib')
897@@ -698,8 +698,8 @@
898 # is of the test mechanism, not a test assertion).
899 assert len(keyring.data.keys()) == 2
900
901- application_key_1 = keyring.data.keys()[0][1]
902- application_key_2 = keyring.data.keys()[1][1]
903+ application_key_1 = list(keyring.data.keys())[0][1]
904+ application_key_2 = list(keyring.data.keys())[1][1]
905 self.assertNotEqual(application_key_1, application_key_2)
906
907
908
909=== modified file 'src/launchpadlib/uris.py'
910--- src/launchpadlib/uris.py 2014-05-12 13:26:49 +0000
911+++ src/launchpadlib/uris.py 2014-07-14 20:30:23 +0000
912@@ -26,8 +26,11 @@
913 'lookup_web_root',
914 'web_root_for_service_root',
915 ]
916-
917-from urlparse import urlparse
918+try:
919+ from urllib.parse import urlparse
920+except ImportError:
921+ from urlparse import urlparse
922+
923 import warnings
924 from lazr.uri import URI
925
926
927=== added file 'versions.cfg'
928--- versions.cfg 1970-01-01 00:00:00 +0000
929+++ versions.cfg 2014-07-14 20:30:23 +0000
930@@ -0,0 +1,85 @@
931+[buildout]
932+versions = versions
933+allow-picked-versions = false
934+use-dependency-links = false
935+
936+
937+[versions]
938+# Alphabetical, case-SENSITIVE, blank line after this comment
939+
940+Jinja2 = 2.5.5
941+Pygments = 1.4
942+RestrictedPython = 3.6.0
943+Sphinx = 1.0.1
944+ZConfig = 2.7.1
945+ZODB3 = 3.9.2
946+distribute = 0.6.27
947+docutils = 0.5
948+elementtree = 1.2.7-20070827-preview
949+epydoc = 3.0.1
950+fixtures = 0.3.9
951+grokcore.component = 1.6
952+httplib2 = 0.7.4
953+lazr.authentication = 0.1.2
954+lazr.batchnavigator = 1.2.7
955+lazr.delegates = 1.2.0
956+lazr.enum = 1.1.2
957+lazr.lifecycle = 1.0
958+lazr.restful = 0.19.7
959+lazr.uri = 1.0.2
960+lazr.restfulclient = 0.13.3
961+testresources = 0.2.7
962+keyring = 3.8
963+lxml = 2.2.7
964+martian = 0.11
965+oauth = 1.0.1
966+pytz = 2010o
967+setuptools = 0.6c11
968+simplejson = 2.5.0
969+testtools = 0.9.11
970+transaction = 1.0.0
971+van.testing = 3.0.0
972+wadllib = 1.2.0
973+wsgi-intercept = 0.5.1
974+wsgiref = 0.1.2
975+z3c.recipe.scripts = 1.0.1
976+z3c.recipe.sphinxdoc = 0.0.8
977+z3c.recipe.staticlxml = 0.7.1
978+z3c.recipe.tag = 0.2.0
979+zc.buildout = 1.5.2
980+zc.lockfile = 1.0.0
981+zc.recipe.cmmi = 1.3.1
982+zc.recipe.egg = 1.3.2
983+zc.recipe.testrunner = 1.4.0
984+zdaemon = 2.0.4
985+zope.annotation = 3.5.0
986+zope.app.pagetemplate = 3.11.2
987+zope.browser = 1.3
988+zope.browserpage = 3.12.2
989+zope.cachedescriptors = 3.5.1
990+zope.component = 3.10.0
991+zope.configuration = 3.6.0
992+zope.contenttype = 3.5.1
993+zope.copy = 3.5.0
994+zope.datetime = 3.4.0
995+zope.dublincore = 3.8.1
996+zope.event = 3.5.0-1
997+zope.exceptions = 3.5.2
998+zope.hookable = 3.4.1
999+zope.i18n = 3.7.4
1000+zope.i18nmessageid = 3.5.3
1001+zope.interface = 3.5.2
1002+zope.lifecycleevent = 3.6.2
1003+zope.location = 3.9.0
1004+zope.pagetemplate = 3.5.2
1005+zope.processlifetime = 1.0
1006+zope.proxy = 3.6.1
1007+zope.publisher = 3.12.6
1008+zope.schema = 3.7.1
1009+zope.security = 3.8.0
1010+zope.size = 3.4.1
1011+zope.tal = 3.5.2
1012+zope.tales = 3.5.1
1013+zope.testing = 3.10.2
1014+zope.testrunner = 4.0.0b5
1015+zope.traversing = 3.13.1

Subscribers

People subscribed via source and target branches