Merge lp:~elopio/canonical-identity-provider/tox_and_py2+3 into lp:~canonical-isd-hackers/canonical-identity-provider/ssoclient

Proposed by Leo Arias
Status: Merged
Approved by: Leo Arias
Approved revision: no longer in the source branch.
Merged at revision: 18
Proposed branch: lp:~elopio/canonical-identity-provider/tox_and_py2+3
Merge into: lp:~canonical-isd-hackers/canonical-identity-provider/ssoclient
Diff against target: 271 lines (+70/-32)
8 files modified
Makefile (+5/-10)
ssoclient/__init__.py (+1/-1)
ssoclient/tests/__init__.py (+0/-1)
ssoclient/tests/test_v2.py (+35/-13)
ssoclient/v2/client.py (+14/-6)
ssoclient/v2/errors.py (+3/-1)
ssoclient/v2/http.py (+3/-0)
tox.ini (+9/-0)
To merge this branch: bzr merge lp:~elopio/canonical-identity-provider/tox_and_py2+3
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Approve
Review via email: mp+197279@code.launchpad.net

Commit message

Made the code compatible with py2.7 and py3.3. All tests in tox passing for both environments.
Added tox to test in both environments.

To post a comment you must log in.
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2013-09-13 15:24:49 +0000
3+++ Makefile 2013-12-02 15:17:20 +0000
4@@ -1,19 +1,14 @@
5-ENV_PATH=.env
6-PIP=pip
7-PYTHON=python
8-VIRTUALENV=virtualenv
9+TOX_PATH=.tox
10
11 .PHONY: clean env test
12
13 all: clean env test
14
15 env:
16- $(VIRTUALENV) $(ENV_PATH)
17+ tox --notest
18
19 clean:
20- rm -rf $(ENV_PATH)
21- rm -rf mock-*.egg oauthlib-*.egg requests-*.egg requests_oauthlib-*.egg
22- rm -rf ssoclient.egg-info
23+ rm -rf $(TOX_PATH)
24
25-test: env
26- . $(ENV_PATH)/bin/activate && $(PYTHON) setup.py test
27+test:
28+ tox
29
30=== modified file 'ssoclient/__init__.py'
31--- ssoclient/__init__.py 2013-09-13 15:13:08 +0000
32+++ ssoclient/__init__.py 2013-12-02 15:17:20 +0000
33@@ -1,4 +1,4 @@
34 # Copyright 2013 Canonical Ltd. This software is licensed under
35 # the GNU Affero General Public License version 3 (see the file
36 # LICENSE).
37-__version__ = '2.0'
38+__version__ = '2.1'
39
40=== modified file 'ssoclient/tests/__init__.py'
41--- ssoclient/tests/__init__.py 2013-09-13 15:13:08 +0000
42+++ ssoclient/tests/__init__.py 2013-12-02 15:17:20 +0000
43@@ -1,4 +1,3 @@
44 # Copyright 2013 Canonical Ltd. This software is licensed under
45 # the GNU Affero General Public License version 3 (see the file
46 # LICENSE).
47-
48
49=== modified file 'ssoclient/tests/test_v2.py'
50--- ssoclient/tests/test_v2.py 2013-11-07 18:27:41 +0000
51+++ ssoclient/tests/test_v2.py 2013-12-02 15:17:20 +0000
52@@ -3,12 +3,21 @@
53 # Copyright 2013 Canonical Ltd. This software is licensed under
54 # the GNU Affero General Public License version 3 (see the file
55 # LICENSE).
56+
57+from __future__ import unicode_literals
58+
59+try:
60+ str = unicode
61+except NameError:
62+ pass # Forward compatibility with Py3k
63+
64 import json
65 import unittest
66
67 from datetime import datetime
68
69 from mock import (
70+ ANY,
71 MagicMock,
72 patch,
73 )
74@@ -92,7 +101,7 @@
75 response = Response()
76 response.status_code = status_code
77 if content is not None and json_dump:
78- content = json.dumps(content)
79+ content = str(json.dumps(content)).encode('utf-8')
80 response._content = content
81 return response
82
83@@ -105,7 +114,7 @@
84 return response
85
86 def test_error_code_raises_correct_exception(self):
87- for code, exc in ERRORS.iteritems():
88+ for code, exc in ERRORS.items():
89 response = mock_response(exc.status_code, dict(code=code))
90 with self.assertRaises(exc):
91 self.do_test(response)
92@@ -241,7 +250,7 @@
93 credentials['consumer_key'], credentials['consumer_secret'],
94 credentials['token_key'], credentials['token_secret'],
95 )
96- self.assertTrue(all(isinstance(val, unicode) for
97+ self.assertTrue(all(isinstance(val, str) for
98 val in self.mock_oauth.call_args[0]))
99
100
101@@ -388,8 +397,14 @@
102 self.mock_request.assert_called_once_with(
103 'POST', 'http://foo.com/tokens/password',
104 headers={'Content-Type': 'application/json'},
105- data='{"token": null, "email": "%s"}' % self.email,
106+ data=ANY
107 )
108+ # Load the data string into a dictionary so the order of the keys
109+ # doesn't matter.
110+ _, kwargs = self.mock_request.call_args
111+ self.assertEqual(
112+ {'token': None, 'email': self.email},
113+ json.loads(kwargs.get('data')))
114
115 def test_request_password_reset_without_email(self):
116 self.mock_request.return_value = mock_response(
117@@ -411,11 +426,17 @@
118 self.email, 'token1234')
119
120 self.assertEqual(response, content)
121- self.assertEqual(self.mock_request.call_args, [
122- ('POST', 'http://foo.com/tokens/password'),
123- {'headers': {'Content-Type': 'application/json'},
124- 'data': '{"token": "token1234", "email": "%s"}' % self.email},
125- ])
126+ self.mock_request.assert_called_once_with(
127+ 'POST', 'http://foo.com/tokens/password',
128+ headers={'Content-Type': 'application/json'},
129+ data=ANY
130+ )
131+ # Load the data string into a dictionary so the order of the keys
132+ # doesn't matter.
133+ _, kwargs = self.mock_request.call_args
134+ self.assertEqual(
135+ {'token': 'token1234', 'email': self.email},
136+ json.loads(kwargs.get('data')))
137
138 def test_request_password_reset_for_suspended_account(self):
139 self.mock_request.return_value = mock_response(
140@@ -717,7 +738,7 @@
141 self.mock_request.return_value = mock_response(
142 200, dict(is_valid=True))
143
144- http_url = u'http://localhost/~/test/doc/dåc-id'
145+ http_url = 'http://localhost/~/test/doc/dåc-id'
146 result = self.client.validate_request(
147 http_url=http_url, http_method='GET', authorization='something')
148
149@@ -729,16 +750,17 @@
150 self.mock_request.return_value = mock_response(
151 200, dict(is_valid=True))
152
153- http_url = u'http://localhost/~/test/doc/dåc-id'.encode('utf-8')
154+ http_url = 'http://localhost/~/test/doc/dåc-id'
155 result = self.client.validate_request(
156- http_url=http_url, http_method='GET', authorization='something')
157+ http_url=http_url.encode('utf-8'), http_method='GET',
158+ authorization='something')
159
160 self.assertEqual(result, {'is_valid': True})
161 self.assert_validate_request_called(
162 http_url=http_url, authorization='something')
163
164 def test_non_ascii_url_not_utf8_encoded(self):
165- http_url = u'http://localhost/~/test/doc/dåc-id'.encode('latin-1')
166+ http_url = 'http://localhost/~/test/doc/dåc-id'.encode('latin-1')
167
168 with self.assertRaises(errors.ClientError) as ctx:
169 self.client.validate_request(
170
171=== modified file 'ssoclient/v2/client.py'
172--- ssoclient/v2/client.py 2013-11-29 16:01:45 +0000
173+++ ssoclient/v2/client.py 2013-12-02 15:17:20 +0000
174@@ -1,6 +1,14 @@
175 # Copyright 2013 Canonical Ltd. This software is licensed under
176 # the GNU Affero General Public License version 3 (see the file
177 # LICENSE).
178+
179+from __future__ import unicode_literals
180+
181+try:
182+ str = unicode
183+except NameError:
184+ pass # Forward compatibility with Py3k
185+
186 import logging
187
188 from datetime import datetime
189@@ -49,10 +57,10 @@
190 # json library is in use.
191 # oauthlib requires them to be unicode - so we coerce to be sure.
192 if credentials is not None:
193- consumer_key = unicode(credentials.get('consumer_key', ''))
194- consumer_secret = unicode(credentials.get('consumer_secret', ''))
195- token_key = unicode(credentials.get('token_key', ''))
196- token_secret = unicode(credentials.get('token_secret', ''))
197+ consumer_key = str(credentials.get('consumer_key', ''))
198+ consumer_secret = str(credentials.get('consumer_secret', ''))
199+ token_key = str(credentials.get('token_key', ''))
200+ token_secret = str(credentials.get('token_secret', ''))
201 oauth = OAuth1(
202 consumer_key,
203 consumer_secret,
204@@ -83,7 +91,7 @@
205 return result
206
207 def account_details(self, openid, token=None, expand=False):
208- openid = unicode(openid)
209+ openid = str(openid)
210 oauth = self._unicode_credentials(token)
211 url = '/accounts/%s?expand=%s' % (openid, str(expand).lower())
212
213@@ -143,7 +151,7 @@
214 raise errors.ClientError(msg=msg)
215
216 http_url = data.get('http_url', '')
217- if not isinstance(http_url, unicode):
218+ if not isinstance(http_url, str):
219 try:
220 data['http_url'] = http_url.decode('utf-8')
221 except UnicodeError:
222
223=== modified file 'ssoclient/v2/errors.py'
224--- ssoclient/v2/errors.py 2013-09-30 20:47:01 +0000
225+++ ssoclient/v2/errors.py 2013-12-02 15:17:20 +0000
226@@ -2,6 +2,8 @@
227 # the GNU Affero General Public License version 3 (see the file
228 # LICENSE).
229
230+from __future__ import unicode_literals
231+
232 class UnexpectedApiError(Exception):
233 """An unexpected client error."""
234
235@@ -39,7 +41,7 @@
236 # of a subclass - so still fetch it from the payload body
237 code = body.get('code')
238 msg = "%s: %s" % (response.status_code, code)
239- extra = ', '.join('%s: %r' % i for i in self.extra.iteritems())
240+ extra = ', '.join('%s: %r' % i for i in self.extra.items())
241 if extra:
242 msg += ' (%s)' % extra
243 super(ApiException, self).__init__(msg)
244
245=== modified file 'ssoclient/v2/http.py'
246--- ssoclient/v2/http.py 2013-10-01 00:17:10 +0000
247+++ ssoclient/v2/http.py 2013-12-02 15:17:20 +0000
248@@ -1,6 +1,9 @@
249 # Copyright 2013 Canonical Ltd. This software is licensed under
250 # the GNU Affero General Public License version 3 (see the file
251 # LICENSE).
252+
253+from __future__ import unicode_literals
254+
255 import functools
256 import json
257
258
259=== added file 'tox.ini'
260--- tox.ini 1970-01-01 00:00:00 +0000
261+++ tox.ini 2013-12-02 15:17:20 +0000
262@@ -0,0 +1,9 @@
263+# Copyright 2013 Canonical Ltd. This software is licensed under
264+# the GNU Affero General Public License version 3 (see the file
265+# LICENSE).
266+
267+[tox]
268+envlist = py27, py33
269+
270+[testenv]
271+commands = {envpython} setup.py test

Subscribers

People subscribed via source and target branches