Merge lp:~dobey/ubuntu-sso-client/update-4-0 into lp:ubuntu-sso-client/stable-4-0

Proposed by dobey
Status: Merged
Approved by: dobey
Approved revision: no longer in the source branch.
Merged at revision: 960
Proposed branch: lp:~dobey/ubuntu-sso-client/update-4-0
Merge into: lp:ubuntu-sso-client/stable-4-0
Diff against target: 1801 lines (+311/-618)
50 files modified
bin/ubuntu-sso-login (+1/-1)
setup.py (+2/-4)
ubuntu_sso/account.py (+5/-5)
ubuntu_sso/gtk/gui.py (+23/-5)
ubuntu_sso/gtk/tests/test_gui.py (+14/-5)
ubuntu_sso/keyring/tests/test_linux.py (+1/-1)
ubuntu_sso/logger.py (+2/-2)
ubuntu_sso/main/__init__.py (+1/-1)
ubuntu_sso/main/linux.py (+6/-1)
ubuntu_sso/main/tests/test_linux.py (+59/-0)
ubuntu_sso/networkstate/darwin.py (+2/-2)
ubuntu_sso/networkstate/linux.py (+3/-3)
ubuntu_sso/networkstate/windows.py (+1/-1)
ubuntu_sso/qt/__init__.py (+1/-1)
ubuntu_sso/qt/current_user_sign_in_page.py (+1/-3)
ubuntu_sso/qt/main/__init__.py (+2/-0)
ubuntu_sso/qt/main/tests/test_main.py (+1/-0)
ubuntu_sso/qt/proxy_dialog.py (+1/-1)
ubuntu_sso/qt/setup_account_page.py (+2/-3)
ubuntu_sso/qt/sso_wizard_page.py (+2/-2)
ubuntu_sso/qt/tests/test_arrow.py (+1/-1)
ubuntu_sso/qt/tests/test_common.py (+3/-3)
ubuntu_sso/qt/tests/test_current_user_sign_in_page.py (+1/-1)
ubuntu_sso/qt/tests/test_setup_account.py (+1/-2)
ubuntu_sso/tests/test_account.py (+1/-1)
ubuntu_sso/tests/test_credentials.py (+2/-1)
ubuntu_sso/utils/__init__.py (+1/-1)
ubuntu_sso/utils/ipc.py (+3/-3)
ubuntu_sso/utils/runner/glib.py (+1/-1)
ubuntu_sso/utils/runner/tests/test_glib.py (+1/-1)
ubuntu_sso/utils/runner/tests/test_qt.py (+2/-2)
ubuntu_sso/utils/runner/tx.py (+2/-2)
ubuntu_sso/utils/tcpactivation.py (+5/-1)
ubuntu_sso/utils/tests/test_common.py (+1/-0)
ubuntu_sso/utils/tests/test_tcpactivation.py (+49/-50)
ubuntu_sso/utils/txsecrets.py (+1/-1)
ubuntu_sso/utils/webclient/common.py (+2/-2)
ubuntu_sso/utils/webclient/gsettings.py (+9/-2)
ubuntu_sso/utils/webclient/libsoup.py (+1/-1)
ubuntu_sso/utils/webclient/qtnetwork.py (+3/-3)
ubuntu_sso/utils/webclient/restful.py (+12/-1)
ubuntu_sso/utils/webclient/tests/test_gsettings.py (+32/-0)
ubuntu_sso/utils/webclient/tests/test_restful.py (+44/-0)
ubuntu_sso/utils/webclient/tests/test_webclient.py (+2/-2)
ubuntu_sso/utils/webclient/timestamp.py (+1/-1)
ubuntu_sso/xdg_base_directory/__init__.py (+0/-104)
ubuntu_sso/xdg_base_directory/tests/__init__.py (+0/-29)
ubuntu_sso/xdg_base_directory/tests/test_common.py (+0/-91)
ubuntu_sso/xdg_base_directory/tests/test_windows.py (+0/-157)
ubuntu_sso/xdg_base_directory/windows.py (+0/-113)
To merge this branch: bzr merge lp:~dobey/ubuntu-sso-client/update-4-0
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) Approve
Roberto Alsina (community) Approve
Review via email: mp+112380@code.launchpad.net

Commit message

[Mike McCracken]

    - Delay importing twisted.internet.reactor to avoid creating default reactor when we need qt4reactor. (LP: #1017672)
    - Correctly bring main sso client window to the front on OS X. (LP: #1012837)
    - Fixes bug with loading incorrect plug-ins caused by ignoring qt.conf. (LP: #1010102)

[Alejandro Cura]

    - Account for g_variant_print type annotations (LP: #1007109).

[Brian Curtin]

    - Move from iteritems/itervalues to items/values for Python 3 support.
    - Use Python 3 style exception handling syntax.

[Rodney Dawes]

    - Remove the xdg_base_directory module as it duplicates dirspec now.
    - Disable the color validation for warning labels due to new GTK+ breaking it.
    - Ensure we are using strict ssl with the system ca-certificates.crt file.
    - Trap DBusException when getting the SessionBus, and add a test case for it.

[Manuel de la Pena]

    - Changed tests so that they use u1-dev-tools better and do not get blocked in the clean up (LP: #1009071).

[Natalia Bidart]

    - Added a little more logging to the webclient when doing REST calls.

[Roberto Alsina]

    - Remove back buttons in signin/signup pages (Fixes LP: #1009107).

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

+1 looks good

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

Voting does not meet specified criteria. Required: Approve >= 1, Disapprove == 0, Needs Fixing == 0, Needs Information == 0, Resubmit == 0, Pending == 0. Got: 1 Approve, 1 Pending.

Revision history for this message
Alejandro J. Cura (alecu) wrote :

+1 looks just like trunk

review: Approve
960. By Brian Curtin

[Mike McCracken]

    - Delay importing twisted.internet.reactor to avoid creating default reactor when we need qt4reactor. (LP: #1017672)
    - Correctly bring main sso client window to the front on OS X. (LP: #1012837)
    - Fixes bug with loading incorrect plug-ins caused by ignoring qt.conf. (LP: #1010102)

[Alejandro Cura]

    - Account for g_variant_print type annotations (LP: #1007109).

[Brian Curtin]

    - Move from iteritems/itervalues to items/values for Python 3 support.
    - Use Python 3 style exception handling syntax.

[Rodney Dawes]

    - Remove the xdg_base_directory module as it duplicates dirspec now.
    - Disable the color validation for warning labels due to new GTK+ breaking it.
    - Ensure we are using strict ssl with the system ca-certificates.crt file.
    - Trap DBusException when getting the SessionBus, and add a test case for it.

[Manuel de la Pena]

    - Changed tests so that they use u1-dev-tools better and do not get blocked in the clean up (LP: #1009071).

[Natalia Bidart]

    - Added a little more logging to the webclient when doing REST calls.

[Roberto Alsina]

    - Remove back buttons in signin/signup pages (Fixes LP: #1009107).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/ubuntu-sso-login'
2--- bin/ubuntu-sso-login 2012-05-18 14:25:49 +0000
3+++ bin/ubuntu-sso-login 2012-06-27 15:30:29 +0000
4@@ -57,7 +57,7 @@
5 # need to create the QApplication before installing the reactor
6 if os.environ.get('TESTABILITY', False):
7 sys.argv.append('-testability')
8- QtGui.QApplication(sys.argv)
9+ app = QtGui.QApplication(sys.argv)
10
11 # pylint: disable=F0401
12 import qt4reactor
13
14=== modified file 'setup.py'
15--- setup.py 2012-06-05 19:55:04 +0000
16+++ setup.py 2012-06-27 15:30:29 +0000
17@@ -301,8 +301,8 @@
18 author='Natalia Bidart',
19 author_email='natalia.bidart@canonical.com',
20 description='Ubuntu Single Sign-On client',
21- long_description='Desktop service to allow applications to sign in' \
22- 'to Ubuntu services via SSO',
23+ long_description=('Desktop service to allow applications to sign in'
24+ 'to Ubuntu services via SSO'),
25 url='https://launchpad.net/ubuntu-sso-client',
26 extra_path='ubuntu-sso-client',
27 data_files=data_files,
28@@ -325,8 +325,6 @@
29 'ubuntu_sso.utils.runner.tests',
30 'ubuntu_sso.utils.webclient',
31 'ubuntu_sso.utils.webclient.tests',
32- 'ubuntu_sso.xdg_base_directory',
33- 'ubuntu_sso.xdg_base_directory.tests',
34 ],
35 cmdclass=cmdclass,
36 **extra)
37
38=== modified file 'ubuntu_sso/account.py'
39--- ubuntu_sso/account.py 2012-05-29 16:56:45 +0000
40+++ ubuntu_sso/account.py 2012-06-27 15:30:29 +0000
41@@ -110,7 +110,7 @@
42 def _format_webservice_errors(self, errdict):
43 """Turn each list of strings in the errdict into a LF separated str."""
44 result = {}
45- for key, val in errdict.iteritems():
46+ for key, val in errdict.items():
47 # workaround until bug #624955 is solved
48 if isinstance(val, basestring):
49 result[key] = val
50@@ -197,7 +197,7 @@
51 finally:
52 restful_client.shutdown()
53
54- logger.debug('login: authentication successful! consumer_key: %r, ' \
55+ logger.debug('login: authentication successful! consumer_key: %r, '
56 'token_name: %r', credentials['consumer_key'], token_name)
57 defer.returnValue(credentials)
58
59@@ -212,7 +212,7 @@
60 finally:
61 restful_client.shutdown()
62 key = 'preferred_email'
63- result = key in me_info and me_info[key] != None
64+ result = key in me_info and me_info[key] is not None
65
66 logger.info('is_validated: consumer_key: %r, result: %r.',
67 token['consumer_key'], result)
68@@ -249,7 +249,7 @@
69 try:
70 operation = u"registration.request_password_reset_token"
71 result = yield restful_client.restcall(operation, email=email)
72- except WebClientError, e:
73+ except WebClientError as e:
74 logger.exception('request_password_reset_token failed with:')
75 raise ResetPasswordTokenError(e[1].split('\n')[0])
76 finally:
77@@ -275,7 +275,7 @@
78 u"registration.set_new_password",
79 email=email, token=token,
80 new_password=new_password)
81- except WebClientError, e:
82+ except WebClientError as e:
83 logger.exception('set_new_password failed with:')
84 raise NewPasswordError(e[1].split('\n')[0])
85 finally:
86
87=== modified file 'ubuntu_sso/gtk/gui.py'
88--- ubuntu_sso/gtk/gui.py 2012-04-11 16:38:28 +0000
89+++ ubuntu_sso/gtk/gui.py 2012-06-27 15:30:29 +0000
90@@ -109,6 +109,12 @@
91 LARGE_MARKUP = u'<span size="x-large">%s</span>'
92
93
94+# SSL properties and certs location
95+STRICT_SSL_PROP = 'ssl-strict'
96+CERTS_FILE_PROP = 'ssl-ca-file'
97+CA_CERT_FILE = '/etc/ssl/certs/ca-certificates.crt'
98+
99+
100 def log_call(f):
101 """Decorator to log call funtions."""
102
103@@ -356,7 +362,7 @@
104 if app_name == self.app_name:
105 result = f(app_name, *args, **kwargs)
106 else:
107- logger.info('%s: ignoring call since received app_name '\
108+ logger.info('%s: ignoring call since received app_name '
109 '%r (expected %r)',
110 f.__name__, app_name, self.app_name)
111 return result
112@@ -365,7 +371,7 @@
113
114 def _setup_signals(self):
115 """Bind signals to callbacks to be able to test the pages."""
116- for signal, method in self._signals.iteritems():
117+ for signal, method in self._signals.items():
118 actual = self._signals_receivers.get(signal)
119 if actual is not None:
120 msg = 'Signal %r is already connected with %r.'
121@@ -703,7 +709,7 @@
122 if os.path.exists(self._captcha_filename):
123 os.remove(self._captcha_filename)
124
125- for signal, match in self._signals_receivers.iteritems():
126+ for signal, match in self._signals_receivers.items():
127 self.backend.disconnect_from_signal(signal, match)
128
129 # hide the main window
130@@ -790,7 +796,7 @@
131 self.user_email = email1
132 self.user_password = password1
133
134- logger.info('Calling register_user with email %r, password <hidden>,' \
135+ logger.info('Calling register_user with email %r, password <hidden>,'
136 ' name %r, captcha_id %r and captcha_solution %r.', email1,
137 name, self._captcha_id, captcha_solution)
138
139@@ -943,7 +949,7 @@
140 return
141
142 email = self.reset_email_entry.get_text()
143- logger.info('Calling set_new_password with email %r, token %r and ' \
144+ logger.info('Calling set_new_password with email %r, token %r and '
145 'new password: <hidden>.', email, token)
146 f = self.backend.set_new_password
147 error_handler = partial(self._handle_error, f,
148@@ -953,11 +959,23 @@
149
150 self._set_current_page(self.processing_vbox)
151
152+ def _webkit_init_ssl(self):
153+ """Set the WebKit ssl strictness."""
154+ # delay the import of webkit to be able to build without it
155+ from gi.repository import WebKit # pylint: disable=E0611
156+
157+ # Set the Soup session to be strict and use system CA certs
158+ session = WebKit.get_default_session()
159+ session.set_property(STRICT_SSL_PROP, True)
160+ session.set_property(CERTS_FILE_PROP, CA_CERT_FILE)
161+
162 def _add_webkit_browser(self):
163 """Add the webkit browser for the t&c."""
164 # delay the import of webkit to be able to build without it
165 from gi.repository import WebKit # pylint: disable=E0611
166
167+ self._webkit_init_ssl()
168+
169 browser = WebKit.WebView()
170
171 browser.connect('notify::load-status',
172
173=== modified file 'ubuntu_sso/gtk/tests/test_gui.py'
174--- ubuntu_sso/gtk/tests/test_gui.py 2012-04-11 16:38:28 +0000
175+++ ubuntu_sso/gtk/tests/test_gui.py 2012-06-27 15:30:29 +0000
176@@ -168,6 +168,7 @@
177 self.memento = MementoHandler()
178 self.memento.setLevel(logging.DEBUG)
179 gui.logger.addHandler(self.memento)
180+ self.addCleanup(gui.logger.removeHandler, self.memento)
181
182 def _set_called(self, *args, **kwargs):
183 """Set _called to True."""
184@@ -446,9 +447,10 @@
185 self.assertEqual(actual, message)
186
187 # content color is correct
188- expected = gui.WARNING_TEXT_COLOR
189- actual = label.get_style().fg[Gtk.StateFlags.NORMAL]
190- self.assert_color_equal(expected, actual)
191+ # FIXME - New GTK+ 3.5 breaks this check - see bug #1014772
192+ # expected = gui.WARNING_TEXT_COLOR
193+ # actual = label.get_style().fg[Gtk.StateFlags.NORMAL]
194+ # self.assert_color_equal(expected, actual)
195
196 def assert_correct_entry_warning(self, entry, message):
197 """Check that a warning is shown displaying 'message'."""
198@@ -911,6 +913,7 @@
199 def setUp(self):
200 yield super(TermsAndConditionsBrowserTestCase, self).setUp()
201 self.patch(WebKit, 'WebView', FakedEmbeddedBrowser)
202+ self.patch(self.ui, '_webkit_init_ssl', self._set_called)
203
204 self.ui.tc_button.clicked()
205 self.addCleanup(self.ui.tc_browser_vbox.hide)
206@@ -919,6 +922,12 @@
207 assert len(children) == 1
208 self.browser = children[0]
209
210+ def test_ssl_validation(self):
211+ """The browser is set to validate SSL."""
212+ self.assertEqual(self._called, ((), {}),
213+ '_webkit_init_ssl should be called when creating a '
214+ 'webkit browser.')
215+
216 def test_tc_browser_is_created_when_tc_page_is_shown(self):
217 """The browser is created when the TC button is clicked."""
218 self.ui.on_tc_browser_notify_load_status(self.browser)
219@@ -1983,7 +1992,7 @@
220 """Callbacks are connected to signals of interest."""
221 msg1 = 'callback %r for signal %r must be added to the backend.'
222 msg2 = 'callback %r for signal %r must be added to the ui log.'
223- for signal, method in self.ui._signals.iteritems():
224+ for signal, method in self.ui._signals.items():
225 actual = self.ui.backend.callbacks.get(signal)
226 self.assertEqual([method], actual, msg1 % (method, signal))
227 actual = self.ui._signals_receivers.get(signal)
228@@ -1992,7 +2001,7 @@
229 def test_callbacks_only_log_when_app_name_doesnt_match(self):
230 """Callbacks do nothing but logging when app_name doesn't match."""
231 mismatch_app_name = self.ui.app_name * 2
232- for method in self.ui._signals.itervalues():
233+ for method in self.ui._signals.values():
234 msgs = ('ignoring', method.__name__, repr(mismatch_app_name))
235 method(mismatch_app_name, 'dummy')
236 self.assertTrue(self.memento.check(logging.INFO, *msgs))
237
238=== modified file 'ubuntu_sso/keyring/tests/test_linux.py'
239--- ubuntu_sso/keyring/tests/test_linux.py 2012-04-09 17:38:24 +0000
240+++ ubuntu_sso/keyring/tests/test_linux.py 2012-06-27 15:30:29 +0000
241@@ -137,7 +137,7 @@
242
243 def get_mock_service(self):
244 """Create only one instance of the mock service per test."""
245- if self.mock_service == None:
246+ if self.mock_service is None:
247 self.mock_service = MockSecretService()
248 return self.mock_service
249
250
251=== modified file 'ubuntu_sso/logger.py'
252--- ubuntu_sso/logger.py 2012-04-09 17:38:24 +0000
253+++ ubuntu_sso/logger.py 2012-06-27 15:30:29 +0000
254@@ -37,11 +37,11 @@
255 import os
256 import sys
257
258+from dirspec.basedir import xdg_cache_home
259+from dirspec.utils import unicode_path
260 from functools import wraps
261 from logging.handlers import RotatingFileHandler
262
263-from ubuntu_sso.xdg_base_directory import unicode_path, xdg_cache_home
264-
265 LOGFOLDER = os.path.join(xdg_cache_home, 'sso')
266 # create log folder if it doesn't exists
267 if not os.path.exists(unicode_path(LOGFOLDER)):
268
269=== modified file 'ubuntu_sso/main/__init__.py'
270--- ubuntu_sso/main/__init__.py 2012-05-21 14:28:14 +0000
271+++ ubuntu_sso/main/__init__.py 2012-06-27 15:30:29 +0000
272@@ -348,7 +348,7 @@
273
274 def _parse_args(self, args):
275 """Retrieve values from the generic param 'args'."""
276- result = dict(i for i in args.iteritems() if i[0] in self.valid_keys)
277+ result = dict(i for i in args.items() if i[0] in self.valid_keys)
278 result[WINDOW_ID_KEY] = int(args.get(WINDOW_ID_KEY, 0))
279 return result
280
281
282=== modified file 'ubuntu_sso/main/linux.py'
283--- ubuntu_sso/main/linux.py 2012-04-10 10:43:48 +0000
284+++ ubuntu_sso/main/linux.py 2012-06-27 15:30:29 +0000
285@@ -342,10 +342,15 @@
286
287 def __init__(self, root):
288 self.root = root
289- self.bus = dbus.SessionBus()
290 self.sso_login = None
291 self.cred_manager = None
292
293+ try:
294+ self.bus = dbus.SessionBus()
295+ except dbus.service.DBusException as e:
296+ logger.exception(e)
297+ shutdown_func()
298+
299 def start(self):
300 """Start listening, nothing async to be done in this platform."""
301 # Register DBus service for making sure we run only one instance
302
303=== added file 'ubuntu_sso/main/tests/test_linux.py'
304--- ubuntu_sso/main/tests/test_linux.py 1970-01-01 00:00:00 +0000
305+++ ubuntu_sso/main/tests/test_linux.py 2012-06-27 15:30:29 +0000
306@@ -0,0 +1,59 @@
307+# -*- coding: utf-8 -*-
308+#
309+# Copyright 2012 Canonical Ltd.
310+#
311+# This program is free software: you can redistribute it and/or modify it
312+# under the terms of the GNU General Public License version 3, as published
313+# by the Free Software Foundation.
314+#
315+# This program is distributed in the hope that it will be useful, but
316+# WITHOUT ANY WARRANTY; without even the implied warranties of
317+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
318+# PURPOSE. See the GNU General Public License for more details.
319+#
320+# You should have received a copy of the GNU General Public License along
321+# with this program. If not, see <http://www.gnu.org/licenses/>.
322+#
323+# In addition, as a special exception, the copyright holders give
324+# permission to link the code of portions of this program with the
325+# OpenSSL library under certain conditions as described in each
326+# individual source file, and distribute linked combinations
327+# including the two.
328+# You must obey the GNU General Public License in all respects
329+# for all of the code used other than OpenSSL. If you modify
330+# file(s) with this exception, you may extend this exception to your
331+# version of the file(s), but you are not obligated to do so. If you
332+# do not wish to do so, delete this exception statement from your
333+# version. If you delete this exception statement from all source
334+# files in the program, then also delete it here.
335+"""Tests for the main SSO Linux client code."""
336+
337+# pylint: disable=C0103
338+do_tests = False
339+try:
340+ import dbus
341+ import dbus.service
342+ from ubuntu_sso.main import linux as main
343+ do_tests = True
344+except ImportError:
345+ do_tests = False
346+# pylint enable=C0103
347+
348+from ubuntuone.devtools.testcases import BaseTestCase, skipIf
349+
350+
351+@skipIf(not do_tests, 'Tests only work with DBus and linux imports.')
352+class LinuxProxyTestCase(BaseTestCase):
353+ """Test some Linux specific cases."""
354+
355+ def test_dbus_missing_exists_clean(self):
356+ """Test that dbus-daemon not being available gives us a clean exit."""
357+ def patched(*args, **kwargs):
358+ """Method to patch in for testing."""
359+ raise dbus.service.DBusException(
360+ 'org.freedesktop.DBus.Error.NoServer')
361+
362+ self.patch(dbus, "SessionBus", patched)
363+ self.patch(main, "shutdown_func", patched)
364+ self.assertRaises(dbus.service.DBusException,
365+ main.UbuntuSSOProxy, None)
366
367=== modified file 'ubuntu_sso/networkstate/darwin.py'
368--- ubuntu_sso/networkstate/darwin.py 2012-05-21 14:48:25 +0000
369+++ ubuntu_sso/networkstate/darwin.py 2012-06-27 15:30:29 +0000
370@@ -126,7 +126,7 @@
371 CFRelease(target)
372
373 if not ok:
374- logger.error("Error getting reachability status of '%s'" % \
375+ logger.error("Error getting reachability status of '%s'" %
376 HOSTNAME_TO_CHECK)
377 raise NetworkFailException()
378
379@@ -298,6 +298,6 @@
380 """
381 try:
382 return defer.succeed(check_connected_state())
383- except Exception, e: # pylint: disable=W0703
384+ except Exception as e: # pylint: disable=W0703
385 logger.exception("Exception calling check_connected_state:")
386 return defer.fail(NetworkFailException(e))
387
388=== modified file 'ubuntu_sso/networkstate/linux.py'
389--- ubuntu_sso/networkstate/linux.py 2012-05-24 04:20:08 +0000
390+++ ubuntu_sso/networkstate/linux.py 2012-06-27 15:30:29 +0000
391@@ -79,7 +79,7 @@
392 # the user has connected in some other way
393 self.call_result_cb(ONLINE)
394 else:
395- logger.error("Error contacting NetworkManager: %s" % \
396+ logger.error("Error contacting NetworkManager: %s" %
397 str(error))
398 self.call_result_cb(UNKNOWN)
399
400@@ -107,7 +107,7 @@
401 nm_proxy.Get(NM_DBUS_INTERFACE, "State",
402 reply_handler=self.got_state,
403 error_handler=self.got_error)
404- except Exception, e: # pylint: disable=W0703
405+ except Exception as e: # pylint: disable=W0703
406 self.got_error(e)
407
408
409@@ -127,7 +127,7 @@
410 try:
411 network = NetworkManagerState(got_state)
412 network.find_online_state()
413- except Exception, e:
414+ except Exception as e:
415 logger.exception('is_machine_connected failed with:')
416 d.errback(NetworkFailException(e))
417 # pylint: enable=W0702, W0703
418
419=== modified file 'ubuntu_sso/networkstate/windows.py'
420--- ubuntu_sso/networkstate/windows.py 2012-04-09 17:38:24 +0000
421+++ ubuntu_sso/networkstate/windows.py 2012-06-27 15:30:29 +0000
422@@ -184,7 +184,7 @@
423 flags = DWORD()
424 connected = wininet.InternetGetConnectedState(byref(flags), None)
425 return defer.succeed(connected == 1)
426- except Exception, e:
427+ except Exception as e:
428 logger.exception('is_machine_connected failed with:')
429 return defer.fail(NetworkFailException(e))
430 # pylint: enable=W0703, W0702
431
432=== modified file 'ubuntu_sso/qt/__init__.py'
433--- ubuntu_sso/qt/__init__.py 2012-04-23 13:32:52 +0000
434+++ ubuntu_sso/qt/__init__.py 2012-06-27 15:30:29 +0000
435@@ -75,7 +75,7 @@
436 if 'errtype' in errordict:
437 del errordict['errtype']
438 result = '\n'.join(
439- [('%s: %s' % (k, v)) for k, v in errordict.iteritems()])
440+ [('%s: %s' % (k, v)) for k, v in errordict.items()])
441 else:
442 result = GENERIC_BACKEND_ERROR
443 logger.error('build_general_error_message with unknown error: %r',
444
445=== modified file 'ubuntu_sso/qt/current_user_sign_in_page.py'
446--- ubuntu_sso/qt/current_user_sign_in_page.py 2012-04-09 17:38:24 +0000
447+++ ubuntu_sso/qt/current_user_sign_in_page.py 2012-06-27 15:30:29 +0000
448@@ -97,9 +97,7 @@
449 self.setButtonText(QtGui.QWizard.CancelButton, CANCEL_BUTTON)
450 # Layout without custom button 1,
451 # without finish button
452- self.wizard().setButtonLayout([
453- QtGui.QWizard.BackButton,
454- QtGui.QWizard.Stretch])
455+ self.wizard().setButtonLayout([])
456
457 # Set sign_in_button as default when the page is shown.
458 self.ui.sign_in_button.setDefault(True)
459
460=== modified file 'ubuntu_sso/qt/main/__init__.py'
461--- ubuntu_sso/qt/main/__init__.py 2012-05-09 18:00:22 +0000
462+++ ubuntu_sso/qt/main/__init__.py 2012-06-27 15:30:29 +0000
463@@ -80,5 +80,7 @@
464 ui.size(), app.desktop().availableGeometry())
465 ui.setGeometry(style)
466 ui.show()
467+ if sys.platform == 'darwin':
468+ ui.raise_()
469
470 source.main_start(app)
471
472=== modified file 'ubuntu_sso/qt/main/tests/test_main.py'
473--- ubuntu_sso/qt/main/tests/test_main.py 2012-05-09 17:48:32 +0000
474+++ ubuntu_sso/qt/main/tests/test_main.py 2012-06-27 15:30:29 +0000
475@@ -53,6 +53,7 @@
476 """Fake setGeometry."""
477
478 show = setGeometry
479+ raise_ = lambda self: None
480
481
482 class FakeDesktop(object):
483
484=== modified file 'ubuntu_sso/qt/proxy_dialog.py'
485--- ubuntu_sso/qt/proxy_dialog.py 2012-04-09 17:38:24 +0000
486+++ ubuntu_sso/qt/proxy_dialog.py 2012-06-27 15:30:29 +0000
487@@ -116,7 +116,7 @@
488 try:
489 logger.debug('Save credentials as for domain %s.', self.domain)
490 yield self.keyring.set_credentials(self.domain, creds)
491- except Exception, e:
492+ except Exception as e:
493 logger.exception('Could not set credentials:')
494 self.done(EXCEPTION_RAISED)
495 logger.debug('Stored creds')
496
497=== modified file 'ubuntu_sso/qt/setup_account_page.py'
498--- ubuntu_sso/qt/setup_account_page.py 2012-05-01 12:48:42 +0000
499+++ ubuntu_sso/qt/setup_account_page.py 2012-06-27 15:30:29 +0000
500@@ -154,7 +154,6 @@
501
502 # Button setup
503 self.wizard().setButtonLayout([
504- QtGui.QWizard.BackButton,
505 QtGui.QWizard.Stretch,
506 QtGui.QWizard.CustomButton3])
507
508@@ -246,8 +245,8 @@
509 common.NORMAL))
510
511 self.ui.refresh_label.linkActivated.connect(self.hide_error)
512- self.ui.refresh_label.linkActivated.connect(lambda url: \
513- self._refresh_captcha())
514+ self.ui.refresh_label.linkActivated.connect(
515+ lambda url: self._refresh_captcha())
516 # We need to check if we enable the button on many signals
517 self.ui.name_edit.textEdited.connect(self._enable_setup_button)
518 self.ui.email_edit.textEdited.connect(self._enable_setup_button)
519
520=== modified file 'ubuntu_sso/qt/sso_wizard_page.py'
521--- ubuntu_sso/qt/sso_wizard_page.py 2012-04-09 17:38:24 +0000
522+++ ubuntu_sso/qt/sso_wizard_page.py 2012-06-27 15:30:29 +0000
523@@ -253,7 +253,7 @@
524 if app_name == self.app_name:
525 result = f(app_name, *args, **kwargs)
526 else:
527- logger.info('%s: ignoring call since received app_name '\
528+ logger.info('%s: ignoring call since received app_name '
529 '"%s" (expected "%s")',
530 f.__name__, app_name, self.app_name)
531 return result
532@@ -262,7 +262,7 @@
533
534 def _setup_signals(self):
535 """Bind signals to callbacks to be able to test the pages."""
536- for signal, method in self._signals.iteritems():
537+ for signal, method in self._signals.items():
538 actual = self._signals_receivers.get(signal)
539 if actual is not None:
540 msg = 'Signal %r is already connected with %r.'
541
542=== modified file 'ubuntu_sso/qt/tests/test_arrow.py'
543--- ubuntu_sso/qt/tests/test_arrow.py 2012-04-09 17:38:24 +0000
544+++ ubuntu_sso/qt/tests/test_arrow.py 2012-06-27 15:30:29 +0000
545@@ -96,7 +96,7 @@
546 arrow = QArrow(QArrow.RIGHT)
547 self.patch(arrow, 'style', self.style)
548
549- for key, value in directions_map.iteritems():
550+ for key, value in directions_map.items():
551 self.style.called = []
552 arrow.direction = key
553 arrow.paintEvent(None)
554
555=== modified file 'ubuntu_sso/qt/tests/test_common.py'
556--- ubuntu_sso/qt/tests/test_common.py 2012-04-09 17:38:24 +0000
557+++ ubuntu_sso/qt/tests/test_common.py 2012-06-27 15:30:29 +0000
558@@ -350,7 +350,7 @@
559 result = build_general_error_message(err_dict)
560
561 expected = '\n'.join(
562- [('%s: %s' % (k, v)) for k, v in err_dict.iteritems()])
563+ [('%s: %s' % (k, v)) for k, v in err_dict.items()])
564 self.assertEqual(result, expected)
565
566 def test_with_random_keys_with_errtype(self):
567@@ -362,8 +362,8 @@
568 result = build_general_error_message(err_dict)
569
570 expected = '\n'.join(
571- [('%s: %s' % (k, v)) \
572- for k, v in {'my_bad': error, 'odd_error': error2}.iteritems()])
573+ [('%s: %s' % (k, v))
574+ for k, v in {'my_bad': error, 'odd_error': error2}.items()])
575 self.assertEqual(result, expected)
576
577 def test_with_not_dict(self):
578
579=== modified file 'ubuntu_sso/qt/tests/test_current_user_sign_in_page.py'
580--- ubuntu_sso/qt/tests/test_current_user_sign_in_page.py 2012-04-09 17:38:24 +0000
581+++ ubuntu_sso/qt/tests/test_current_user_sign_in_page.py 2012-06-27 15:30:29 +0000
582@@ -59,7 +59,7 @@
583 self.assertEqual(wizard.buttons_text[QtGui.QWizard.CancelButton],
584 "Cancel")
585 self.assertIn(('setButtonLayout',
586- (([QtGui.QWizard.BackButton, QtGui.QWizard.Stretch],), {})),
587+ (([],), {})),
588 wizard.called)
589 self.assertTrue(button.properties['default'])
590 self.assertFalse(button.isEnabled())
591
592=== modified file 'ubuntu_sso/qt/tests/test_setup_account.py'
593--- ubuntu_sso/qt/tests/test_setup_account.py 2012-04-09 17:38:24 +0000
594+++ ubuntu_sso/qt/tests/test_setup_account.py 2012-06-27 15:30:29 +0000
595@@ -207,8 +207,7 @@
596 self.ui.initializePage()
597
598 # set up account button
599- expected = [QtGui.QWizard.BackButton, QtGui.QWizard.Stretch,
600- QtGui.QWizard.CustomButton3]
601+ expected = [QtGui.QWizard.Stretch, QtGui.QWizard.CustomButton3]
602 self.assertIn(('setButtonLayout', ((expected,), {})),
603 self.ui.wizard().called)
604 self.assertEqual(gui.SET_UP_ACCOUNT_BUTTON,
605
606=== modified file 'ubuntu_sso/tests/test_account.py'
607--- ubuntu_sso/tests/test_account.py 2012-05-29 16:58:30 +0000
608+++ ubuntu_sso/tests/test_account.py 2012-06-27 15:30:29 +0000
609@@ -230,7 +230,7 @@
610
611 def verify_frc_shutdown(self):
612 """Verify that the FakeRestfulClient was stopped."""
613- assert self.frc.started == False, "Restfulclient must be shut down."
614+ assert self.frc.started is False, "Restfulclient must be shut down."
615
616 @defer.inlineCallbacks
617 def test_generate_captcha(self):
618
619=== modified file 'ubuntu_sso/tests/test_credentials.py'
620--- ubuntu_sso/tests/test_credentials.py 2012-05-04 18:48:54 +0000
621+++ ubuntu_sso/tests/test_credentials.py 2012-06-27 15:30:29 +0000
622@@ -122,6 +122,7 @@
623 self.memento = MementoHandler()
624 self.memento.setLevel(logging.DEBUG)
625 credentials.logger.addHandler(self.memento)
626+ self.addCleanup(credentials.logger.removeHandler, self.memento)
627
628 self.patch(credentials, 'get_bin_dir', lambda: self.bin_dir)
629
630@@ -147,7 +148,7 @@
631
632 def test_creation_parameters_are_stored(self):
633 """Creation parameters are stored."""
634- for key, value in KWARGS.iteritems():
635+ for key, value in KWARGS.items():
636 self.assertEqual(getattr(self.obj, key), value)
637
638 def test_tc_url_defaults_to_none(self):
639
640=== modified file 'ubuntu_sso/utils/__init__.py'
641--- ubuntu_sso/utils/__init__.py 2012-04-25 14:17:16 +0000
642+++ ubuntu_sso/utils/__init__.py 2012-06-27 15:30:29 +0000
643@@ -165,7 +165,7 @@
644 logger.debug("Calculated server-local time skew: %r",
645 self.skew)
646 #pylint: disable=W0703
647- except Exception, server_error:
648+ except Exception as server_error:
649 logger.debug("Error while verifying the server time skew: %r",
650 server_error)
651 self.next_check = local_time + self.ERROR_INTERVAL
652
653=== modified file 'ubuntu_sso/utils/ipc.py'
654--- ubuntu_sso/utils/ipc.py 2012-05-16 09:48:55 +0000
655+++ ubuntu_sso/utils/ipc.py 2012-06-27 15:30:29 +0000
656@@ -132,7 +132,7 @@
657
658 def remote_unregister_to_signals(self, client):
659 """Allow a client to unregister from the signal."""
660- for connected_clients in self.clients_per_signal.itervalues():
661+ for connected_clients in self.clients_per_signal.values():
662 if client in connected_clients:
663 connected_clients.remove(client)
664
665@@ -198,7 +198,7 @@
666 super(BaseService, self).__init__()
667 self.factory = None
668 self.listener = None
669- for name, service_class in self.services.iteritems():
670+ for name, service_class in self.services.items():
671 service = service_class(*a, **kw)
672 setattr(self, name, service)
673 setattr(self, 'remote_get_%s' % name,
674@@ -344,7 +344,7 @@
675 """Request all the diff remote objects used for the communication."""
676 logger.debug('Requesting remote objects (%r) for %s',
677 self.clients.keys(), self.__class__.__name__)
678- for name, client_class in self.clients.iteritems():
679+ for name, client_class in self.clients.items():
680 remote = yield root.callRemote('get_%s' % name)
681 setattr(self, name, client_class(remote))
682
683
684=== modified file 'ubuntu_sso/utils/runner/glib.py'
685--- ubuntu_sso/utils/runner/glib.py 2012-04-09 17:38:24 +0000
686+++ ubuntu_sso/utils/runner/glib.py 2012-06-27 15:30:29 +0000
687@@ -89,7 +89,7 @@
688
689 try:
690 pid, _, _, _ = GLib.spawn_async(argv=bytes_args, flags=flags)
691- except GLib.GError, e:
692+ except GLib.GError as e:
693 handle_error(e)
694 else:
695 logger.debug('Spawning the program %r with the glib mainloop '
696
697=== modified file 'ubuntu_sso/utils/runner/tests/test_glib.py'
698--- ubuntu_sso/utils/runner/tests/test_glib.py 2012-04-09 17:38:24 +0000
699+++ ubuntu_sso/utils/runner/tests/test_glib.py 2012-06-27 15:30:29 +0000
700@@ -87,7 +87,7 @@
701
702 try:
703 subprocess.call(argv)
704- except Exception, e:
705+ except Exception as e:
706 exc = GLib.GError()
707 exc.message = str(e)
708 exc.code = 42
709
710=== modified file 'ubuntu_sso/utils/runner/tests/test_qt.py'
711--- ubuntu_sso/utils/runner/tests/test_qt.py 2012-04-09 17:38:24 +0000
712+++ ubuntu_sso/utils/runner/tests/test_qt.py 2012-06-27 15:30:29 +0000
713@@ -86,12 +86,12 @@
714
715 try:
716 subprocess.call(bytes_args)
717- except OSError, e:
718+ except OSError as e:
719 if e.errno == 2:
720 self.error.emit(self.FailedToStart)
721 else:
722 self.error.emit(e)
723- except Exception, e:
724+ except Exception as e:
725 self.error.emit(e)
726 else:
727 self.finished.emit(self._status_code)
728
729=== modified file 'ubuntu_sso/utils/runner/tx.py'
730--- ubuntu_sso/utils/runner/tx.py 2012-04-09 17:38:24 +0000
731+++ ubuntu_sso/utils/runner/tx.py 2012-06-27 15:30:29 +0000
732@@ -102,9 +102,9 @@
733
734 try:
735 d = utils.getProcessOutputAndValue(program, bytes_args, env=os.environ)
736- except OSError, e:
737+ except OSError as e:
738 error_handler(msg=e, failed_to_start=True)
739- except Exception, e:
740+ except Exception as e:
741 error_handler(msg=e, failed_to_start=False)
742 else:
743 logger.debug('Spawning the program %r with the twisted reactor '
744
745=== modified file 'ubuntu_sso/utils/tcpactivation.py'
746--- ubuntu_sso/utils/tcpactivation.py 2012-05-03 11:42:55 +0000
747+++ ubuntu_sso/utils/tcpactivation.py 2012-06-27 15:30:29 +0000
748@@ -30,7 +30,7 @@
749
750 import subprocess
751
752-from twisted.internet import defer, error, protocol, reactor
753+from twisted.internet import defer, error, protocol
754 from twisted.internet.endpoints import clientFromString
755
756 LOCALHOST = "127.0.0.1"
757@@ -43,6 +43,7 @@
758
759 def async_sleep(delay):
760 """Fire the returned deferred after some specified delay."""
761+ from twisted.internet import reactor
762 d = defer.Deferred()
763 # pylint: disable=E1101
764 reactor.callLater(delay, d.callback, None)
765@@ -87,11 +88,13 @@
766
767 def clientConnectionLost(self, connector, reason):
768 """The connection was lost."""
769+ protocol.ClientFactory.clientConnectionLost(self, connector, reason)
770 if not self.d.called:
771 self.d.callback(False)
772
773 def clientConnectionFailed(self, connector, reason):
774 """The connection failed."""
775+ protocol.ClientFactory.clientConnectionFailed(self, connector, reason)
776 if not self.d.called:
777 self.d.callback(False)
778
779@@ -116,6 +119,7 @@
780 @defer.inlineCallbacks
781 def is_already_running(self):
782 """Check if the instance is already running."""
783+ from twisted.internet import reactor
784 factory = PortDetectFactory()
785 client = clientFromString(reactor, self.config.description.client)
786 try:
787
788=== modified file 'ubuntu_sso/utils/tests/test_common.py'
789--- ubuntu_sso/utils/tests/test_common.py 2012-04-17 20:27:21 +0000
790+++ ubuntu_sso/utils/tests/test_common.py 2012-06-27 15:30:29 +0000
791@@ -106,6 +106,7 @@
792 self.memento = MementoHandler()
793 self.memento.setLevel(logging.DEBUG)
794 utils.logger.addHandler(self.memento)
795+ self.addCleanup(utils.logger.removeHandler, self.memento)
796
797 self.get_dir = getattr(utils, self.DIR_GETTER)
798
799
800=== modified file 'ubuntu_sso/utils/tests/test_tcpactivation.py'
801--- ubuntu_sso/utils/tests/test_tcpactivation.py 2012-05-03 12:36:08 +0000
802+++ ubuntu_sso/utils/tests/test_tcpactivation.py 2012-06-27 15:30:29 +0000
803@@ -35,7 +35,8 @@
804 # this test module access a few protected members (starting with _)
805 # pylint: disable=W0212
806
807-from twisted.internet import defer, protocol, reactor, task
808+import twisted.internet
809+from twisted.internet import defer, protocol, task
810 from twisted.trial.unittest import TestCase
811
812 # pylint: disable=W0611
813@@ -72,7 +73,7 @@
814 self.transport.write(data)
815
816
817-class FakeServerFactory(protocol.Factory):
818+class FakeServerFactory(protocol.ServerFactory):
819 """A factory for the test server."""
820
821 protocol = FakeServerProtocol
822@@ -97,37 +98,6 @@
823 self.client = client_description
824
825
826-class FakeConnectedClient(object):
827- """Fake class use to patch connections."""
828-
829- def __init__(self, testcase, inner):
830- """Create a new instance."""
831- self.testcase = testcase
832- self.inner = inner
833-
834- @defer.inlineCallbacks
835- def connect(self, factory):
836- """Connect using the given factory."""
837- # we need to get the class of the factory and patch it
838- yield self.testcase.connect_client(PortDetectFactory)
839- self.inner.factory = self.testcase.client_factory
840- defer.returnValue(self.testcase.connector)
841-
842-
843-class WrapperFactory(object):
844- """Wrapps a factory so that it can be replaced in a test."""
845-
846- def __init__(self, factory):
847- self.factory = None
848-
849- def __call__(self, *args, **kwargs):
850- return self
851-
852- def is_listening(self):
853- """Return if the service is listening."""
854- return self.factory.is_listening()
855-
856-
857 class AsyncSleepTestCase(TestCase):
858 """Tests for the async_sleep function."""
859
860@@ -137,7 +107,7 @@
861 yield super(AsyncSleepTestCase, self).setUp()
862 self.test_timeout = 5.0
863 self.clock = task.Clock()
864- self.patch(tcpactivation, "reactor", self.clock)
865+ self.patch(twisted.internet, "reactor", self.clock)
866 self.d = tcpactivation.async_sleep(self.test_timeout)
867
868 def test_async_sleep_not_fired_immediately(self):
869@@ -231,7 +201,7 @@
870 self.assertEqual(config.description, SAMPLE_CLIENT_DESCRIPTION)
871
872
873-class ActivationDetectorTestCase(ServerTestCase):
874+class ActivationDetectorTestCase(TestCase):
875 """Tests for the ActivationDetector class."""
876
877 timeoue = 3
878@@ -270,15 +240,29 @@
879 @defer.inlineCallbacks
880 def test_is_already_running(self):
881 """The is_already_running method returns True if already started."""
882- inner = WrapperFactory(None)
883-
884- self.patch(tcpactivation, 'PortDetectFactory', inner)
885- client = FakeConnectedClient(self, inner)
886+ server = self.get_server()
887+ self.addCleanup(server.clean_up)
888+
889+ class TestConnect(object):
890+ """A fake connection object."""
891+
892+ # pylint: disable=E0213
893+ @defer.inlineCallbacks
894+ def connect(my_self, factory):
895+ """A fake connection."""
896+
897+ connected_factory = yield server.connect_client(
898+ PortDetectFactory)
899+ self.patch(factory, 'is_listening',
900+ connected_factory.is_listening)
901+ defer.returnValue(connected_factory)
902+ # pylint: enable=E0213
903
904 self.patch(tcpactivation, 'clientFromString',
905- lambda *args: client)
906-
907- yield self.listen_server(FakeServerFactory)
908+ lambda *args: TestConnect())
909+
910+ yield server.listen_server(protocol.ServerFactory)
911+
912 # pylint: disable=E1101
913 ad = ActivationDetector(self.config)
914 result = yield ad.is_already_running()
915@@ -347,7 +331,7 @@
916 """Test the _wait_server_active method."""
917 ac = ActivationClient(self.config)
918 clock = task.Clock()
919- self.patch(tcpactivation, "reactor", clock)
920+ self.patch(twisted.internet, "reactor", clock)
921 self.patch(ac, "is_already_running", lambda: defer.succeed(False))
922
923 d = ac._wait_server_active()
924@@ -363,7 +347,7 @@
925 """If the server takes too long to start then timeout."""
926 ac = ActivationClient(self.config)
927 clock = task.Clock()
928- self.patch(tcpactivation, "reactor", clock)
929+ self.patch(twisted.internet, "reactor", clock)
930 self.patch(ac, "is_already_running", lambda: defer.succeed(False))
931 d = ac._wait_server_active()
932 clock.pump([tcpactivation.DELAY_BETWEEN_CHECKS] *
933@@ -420,15 +404,28 @@
934 @defer.inlineCallbacks
935 def test_get_description_fails_if_service_already_started(self):
936 """The get_description method fails if service already started."""
937- inner = WrapperFactory(None)
938-
939- self.patch(tcpactivation, 'PortDetectFactory', inner)
940- client = FakeConnectedClient(self, inner)
941+ server = self.get_server()
942+ self.addCleanup(server.clean_up)
943+
944+ class TestConnect(object):
945+ """A fake connection object."""
946+
947+ # pylint: disable=E0213
948+ @defer.inlineCallbacks
949+ def connect(my_self, factory):
950+ """A fake connection."""
951+
952+ connected_factory = yield server.connect_client(
953+ PortDetectFactory)
954+ self.patch(factory, 'is_listening',
955+ connected_factory.is_listening)
956+ defer.returnValue(connected_factory)
957+ # pylint: enable=E0213
958
959 self.patch(tcpactivation, 'clientFromString',
960- lambda *args: client)
961+ lambda *args: TestConnect())
962
963- yield self.listen_server(FakeServerFactory)
964+ yield server.listen_server(protocol.ServerFactory)
965
966 ai = ActivationInstance(self.config)
967 yield self.assertFailure(ai.get_server_description(),
968@@ -438,6 +435,7 @@
969
970 def server_test(config):
971 """An IRL test of the server."""
972+ from twisted.internet import reactor
973
974 def got_description(description):
975 """The description was found."""
976@@ -472,6 +470,7 @@
977
978 def client_test(config):
979 """An IRL test of the client."""
980+ from twisted.internet import reactor
981 print "starting the client."
982 ac = ActivationClient(config)
983 d = ac.get_active_client_description()
984
985=== modified file 'ubuntu_sso/utils/txsecrets.py'
986--- ubuntu_sso/utils/txsecrets.py 2012-04-09 17:38:24 +0000
987+++ ubuntu_sso/utils/txsecrets.py 2012-06-27 15:30:29 +0000
988@@ -100,7 +100,7 @@
989 self.service.OpenSession(ALGORITHM, parameters,
990 reply_handler=session_opened,
991 error_handler=d.errback)
992- except dbus.exceptions.DBusException, e:
993+ except dbus.exceptions.DBusException as e:
994 d.errback(e)
995 return d
996
997
998=== modified file 'ubuntu_sso/utils/webclient/common.py'
999--- ubuntu_sso/utils/webclient/common.py 2012-04-12 12:07:46 +0000
1000+++ ubuntu_sso/utils/webclient/common.py 2012-06-27 15:30:29 +0000
1001@@ -206,7 +206,7 @@
1002 try:
1003 creds = yield keyring.get_credentials(str(domain))
1004 logger.debug('Got credentials from keyring.')
1005- except Exception, e:
1006+ except Exception as e:
1007 logger.error('Error when retrieving the creds.')
1008 raise WebClientError('Error when retrieving the creds.', e)
1009 if creds is not None:
1010@@ -249,7 +249,7 @@
1011
1012 try:
1013 return_code = yield self._launch_proxy_creds_dialog(domain, retry)
1014- except Exception, e:
1015+ except Exception as e:
1016 logger.error('Error when running external ui process.')
1017 raise WebClientError('Error when running external ui process.', e)
1018
1019
1020=== modified file 'ubuntu_sso/utils/webclient/gsettings.py'
1021--- ubuntu_sso/utils/webclient/gsettings.py 2012-04-09 17:38:24 +0000
1022+++ ubuntu_sso/utils/webclient/gsettings.py 2012-06-27 15:30:29 +0000
1023@@ -30,7 +30,11 @@
1024
1025 import subprocess
1026
1027+from ubuntu_sso.logger import setup_logging
1028+
1029+logger = setup_logging("ubuntu_sso.utils.webclient.gsettings")
1030 GSETTINGS_CMDLINE = "gsettings list-recursively org.gnome.system.proxy"
1031+CANNOT_PARSE_WARNING = "Cannot parse gsettings value: %r"
1032
1033
1034 def parse_proxy_host(hostname):
1035@@ -80,12 +84,15 @@
1036 continue
1037 if value.startswith("'"):
1038 parsed_value = value[1:-1]
1039- elif value.startswith('['):
1040+ elif value.startswith(('[', '@')):
1041 parsed_value = value
1042 elif value in ('true', 'false'):
1043 parsed_value = (value == 'true')
1044+ elif value.isdigit():
1045+ parsed_value = int(value)
1046 else:
1047- parsed_value = int(value)
1048+ logger.warning(CANNOT_PARSE_WARNING, value)
1049+ parsed_value = value
1050 relative_key = (path + "." + key)[base_len:]
1051 gsettings[relative_key] = parsed_value
1052 mode = gsettings["mode"]
1053
1054=== modified file 'ubuntu_sso/utils/webclient/libsoup.py'
1055--- ubuntu_sso/utils/webclient/libsoup.py 2012-04-12 12:07:46 +0000
1056+++ ubuntu_sso/utils/webclient/libsoup.py 2012-06-27 15:30:29 +0000
1057@@ -131,7 +131,7 @@
1058 d = defer.Deferred()
1059 message = self.soup.Message.new(method, uri)
1060
1061- for key, value in headers.iteritems():
1062+ for key, value in headers.items():
1063 message.request_headers.append(key, value)
1064
1065 if post_content:
1066
1067=== modified file 'ubuntu_sso/utils/webclient/qtnetwork.py'
1068--- ubuntu_sso/utils/webclient/qtnetwork.py 2012-04-24 14:05:22 +0000
1069+++ ubuntu_sso/utils/webclient/qtnetwork.py 2012-06-27 15:30:29 +0000
1070@@ -158,14 +158,14 @@
1071 headers = yield self.build_request_headers(uri, method, extra_headers,
1072 oauth_credentials)
1073
1074- for key, value in headers.iteritems():
1075+ for key, value in headers.items():
1076 request.setRawHeader(key, value)
1077
1078 post_buffer = QBuffer()
1079 post_buffer.setData(post_content)
1080 try:
1081 result = yield self._perform_request(request, method, post_buffer)
1082- except ProxyUnauthorizedError, e:
1083+ except ProxyUnauthorizedError as e:
1084 app_proxy = QNetworkProxy.applicationProxy()
1085 proxy_host = app_proxy.hostName() if app_proxy else "proxy server"
1086 got_creds = yield self.request_proxy_auth_credentials(
1087@@ -221,7 +221,7 @@
1088 QSslCertificate.CountryName: 'country_name',
1089 QSslCertificate.StateOrProvinceName: 'state_name'}
1090 details = {}
1091- for info, title in detail_titles.iteritems():
1092+ for info, title in detail_titles.items():
1093 details[title] = str(cert.issuerInfo(info))
1094 return self.format_ssl_details(details)
1095
1096
1097=== modified file 'ubuntu_sso/utils/webclient/restful.py'
1098--- ubuntu_sso/utils/webclient/restful.py 2012-04-09 17:38:24 +0000
1099+++ ubuntu_sso/utils/webclient/restful.py 2012-06-27 15:30:29 +0000
1100@@ -33,8 +33,11 @@
1101
1102 from twisted.internet import defer
1103
1104+from ubuntu_sso.logger import setup_logging
1105 from ubuntu_sso.utils import webclient
1106
1107+logger = setup_logging("ubuntu_sso.utils.webclient.restful")
1108+
1109 POST_HEADERS = {
1110 "content-type": "application/x-www-form-urlencoded",
1111 }
1112@@ -67,11 +70,19 @@
1113 encoded_args = urllib.urlencode(params)
1114 iri = self.service_iri + namespace
1115 creds = self.oauth_credentials
1116+ logger.debug('Performing REST call to %r.', iri)
1117 result = yield self.webclient.request(iri, method="POST",
1118 oauth_credentials=creds,
1119 post_content=encoded_args,
1120 extra_headers=POST_HEADERS)
1121- defer.returnValue(json.loads(result.content))
1122+ try:
1123+ response = json.loads(result.content)
1124+ except:
1125+ logger.exception('Can not load json from REST request response '
1126+ '(content is %r).', result.content)
1127+ raise
1128+ else:
1129+ defer.returnValue(response)
1130
1131 def shutdown(self):
1132 """Stop the webclient used by this class."""
1133
1134=== modified file 'ubuntu_sso/utils/webclient/tests/test_gsettings.py'
1135--- ubuntu_sso/utils/webclient/tests/test_gsettings.py 2012-04-09 17:38:24 +0000
1136+++ ubuntu_sso/utils/webclient/tests/test_gsettings.py 2012-06-27 15:30:29 +0000
1137@@ -28,7 +28,10 @@
1138 # files in the program, then also delete it here.
1139 """Test the gsettings parser."""
1140
1141+import logging
1142+
1143 from twisted.trial.unittest import TestCase
1144+from ubuntuone.devtools.handlers import MementoHandler
1145
1146 from ubuntu_sso.utils.webclient import gsettings
1147 from ubuntu_sso.utils.webclient.tests import (
1148@@ -91,6 +94,35 @@
1149 """Test a parser of gsettings."""
1150 self._assert_parser_anonymous('https')
1151
1152+ def test_gsettings_empty_ignore_hosts(self):
1153+ """Missing values in the ignore hosts."""
1154+ troublesome_value = "@as []"
1155+ template_values = dict(BASE_GSETTINGS_VALUES)
1156+ template_values["ignore_hosts"] = troublesome_value
1157+ fake_output = TEMPLATE_GSETTINGS_OUTPUT.format(**template_values)
1158+ self.patch(gsettings.subprocess, "check_output",
1159+ lambda _: fake_output)
1160+ ps = gsettings.get_proxy_settings()
1161+ self.assertEqual(ps, {})
1162+
1163+ def test_gsettings_cannot_parse(self):
1164+ """Some weird setting that cannot be parsed is logged with warning."""
1165+ memento = MementoHandler()
1166+ memento.setLevel(logging.DEBUG)
1167+ gsettings.logger.addHandler(memento)
1168+ self.addCleanup(gsettings.logger.removeHandler, memento)
1169+
1170+ troublesome_value = "#bang"
1171+ template_values = dict(BASE_GSETTINGS_VALUES)
1172+ template_values["ignore_hosts"] = troublesome_value
1173+ fake_output = TEMPLATE_GSETTINGS_OUTPUT.format(**template_values)
1174+ self.patch(gsettings.subprocess, "check_output",
1175+ lambda _: fake_output)
1176+ ps = gsettings.get_proxy_settings()
1177+ self.assertTrue(memento.check_warning(gsettings.CANNOT_PARSE_WARNING %
1178+ troublesome_value))
1179+ self.assertEqual(ps, {})
1180+
1181 def test_gsettings_parser_http_authenticated(self):
1182 """Test a parser of gsettings."""
1183 template_values = dict(BASE_GSETTINGS_VALUES)
1184
1185=== modified file 'ubuntu_sso/utils/webclient/tests/test_restful.py'
1186--- ubuntu_sso/utils/webclient/tests/test_restful.py 2012-04-09 17:38:24 +0000
1187+++ ubuntu_sso/utils/webclient/tests/test_restful.py 2012-06-27 15:30:29 +0000
1188@@ -28,9 +28,11 @@
1189 # files in the program, then also delete it here.
1190 """Tests for the proxy-enabled restful client."""
1191
1192+import logging
1193 import urlparse
1194
1195 from twisted.internet import defer
1196+from ubuntuone.devtools.handlers import MementoHandler
1197 from ubuntuone.devtools.testcases import TestCase
1198
1199 from ubuntu_sso.utils.webclient import restful
1200@@ -184,3 +186,45 @@
1201 yield rc.restcall(SAMPLE_OPERATION, **SAMPLE_ARGS)
1202 _, _, kwargs = self.wc.called[0]
1203 self.assertEqual(kwargs["oauth_credentials"], SAMPLE_OAUTH_CREDS)
1204+
1205+
1206+class LogginTestCase(BaseTestCase):
1207+ """Ensure that proper debug logging is done."""
1208+
1209+ @defer.inlineCallbacks
1210+ def setUp(self):
1211+ """Initialize this testcase."""
1212+ yield super(LogginTestCase, self).setUp()
1213+ self.memento = MementoHandler()
1214+ restful.logger.addHandler(self.memento)
1215+ restful.logger.setLevel(logging.DEBUG)
1216+ self.addCleanup(restful.logger.removeHandler, self.memento)
1217+
1218+ self.rc = restful.RestfulClient(SAMPLE_SERVICE_IRI)
1219+ self.addCleanup(self.rc.shutdown)
1220+
1221+ @defer.inlineCallbacks
1222+ def test_log_rest_call(self):
1223+ """Check that proper DEBUG is made for every REST call."""
1224+ yield self.rc.restcall(SAMPLE_OPERATION, **SAMPLE_ARGS)
1225+
1226+ expected_msgs = (
1227+ SAMPLE_SERVICE_IRI + SAMPLE_NAMESPACE,
1228+ )
1229+ self.assertTrue(self.memento.check_debug(*expected_msgs))
1230+
1231+ @defer.inlineCallbacks
1232+ def test_log_json_loads_exception(self):
1233+ """Check that json load errors are properly logged."""
1234+ invalid_json = 'NOTAVALIDJSON'
1235+ self.patch(self.wc, 'return_value', invalid_json)
1236+ yield self.assertFailure(self.rc.restcall(SAMPLE_OPERATION),
1237+ ValueError)
1238+
1239+ self.memento.debug = True
1240+ expected_msgs = (
1241+ ValueError,
1242+ 'Can not load json from REST request response',
1243+ invalid_json
1244+ )
1245+ self.assertTrue(self.memento.check_exception(*expected_msgs))
1246
1247=== modified file 'ubuntu_sso/utils/webclient/tests/test_webclient.py'
1248--- ubuntu_sso/utils/webclient/tests/test_webclient.py 2012-04-24 14:05:22 +0000
1249+++ ubuntu_sso/utils/webclient/tests/test_webclient.py 2012-06-27 15:30:29 +0000
1250@@ -753,7 +753,7 @@
1251
1252 self.assertEqual(method, "OAuth")
1253
1254- for k, expected_value in self.expected_params.iteritems():
1255+ for k, expected_value in self.expected_params.items():
1256 self.assertIn(k, params)
1257 if expected_value is not ANY_VALUE:
1258 self.assertEqual(params[k], expected_value)
1259@@ -782,7 +782,7 @@
1260 self.assert_headers_correct(request.to_header())
1261 self.assertEqual(request.http_url, self.sample_url)
1262 if params is not None:
1263- for param, value in params.iteritems():
1264+ for param, value in params.items():
1265 self.assertIn(param, request.parameters)
1266 actual = request.parameters[param]
1267 self.assertEqual(value, actual)
1268
1269=== modified file 'ubuntu_sso/utils/webclient/timestamp.py'
1270--- ubuntu_sso/utils/webclient/timestamp.py 2012-04-09 17:38:24 +0000
1271+++ ubuntu_sso/utils/webclient/timestamp.py 2012-06-27 15:30:29 +0000
1272@@ -83,7 +83,7 @@
1273 logger.debug("Calculated server time skew: %r", self.skew)
1274 # We just log all exceptions while trying to get the server time
1275 # pylint: disable=W0703
1276- except Exception, e:
1277+ except Exception as e:
1278 logger.debug("Error while verifying server time skew: %r", e)
1279 self.next_check = local_time + self.ERROR_INTERVAL
1280 # delay import, otherwise a default reactor gets installed
1281
1282=== removed directory 'ubuntu_sso/xdg_base_directory'
1283=== removed file 'ubuntu_sso/xdg_base_directory/__init__.py'
1284--- ubuntu_sso/xdg_base_directory/__init__.py 2012-04-09 17:38:24 +0000
1285+++ ubuntu_sso/xdg_base_directory/__init__.py 1970-01-01 00:00:00 +0000
1286@@ -1,104 +0,0 @@
1287-# -*- coding: utf-8 -*-
1288-#
1289-# Copyright 2011-2012 Canonical Ltd.
1290-#
1291-# This program is free software: you can redistribute it and/or modify it
1292-# under the terms of the GNU General Public License version 3, as published
1293-# by the Free Software Foundation.
1294-#
1295-# This program is distributed in the hope that it will be useful, but
1296-# WITHOUT ANY WARRANTY; without even the implied warranties of
1297-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1298-# PURPOSE. See the GNU General Public License for more details.
1299-#
1300-# You should have received a copy of the GNU General Public License along
1301-# with this program. If not, see <http://www.gnu.org/licenses/>.
1302-#
1303-# In addition, as a special exception, the copyright holders give
1304-# permission to link the code of portions of this program with the
1305-# OpenSSL library under certain conditions as described in each
1306-# individual source file, and distribute linked combinations
1307-# including the two.
1308-# You must obey the GNU General Public License in all respects
1309-# for all of the code used other than OpenSSL. If you modify
1310-# file(s) with this exception, you may extend this exception to your
1311-# version of the file(s), but you are not obligated to do so. If you
1312-# do not wish to do so, delete this exception statement from your
1313-# version. If you delete this exception statement from all source
1314-# files in the program, then also delete it here.
1315-"""XDG multiplatform."""
1316-
1317-import os
1318-import sys
1319-import warnings
1320-
1321-
1322-def unicode_path(utf8path):
1323- """Turn an utf8 path into a unicode path."""
1324- return utf8path.decode("utf-8")
1325-
1326-
1327-def native_path(utf8path):
1328- """Turn an utf8 path into a path useable in the current encoding."""
1329- warnings.warn('native_path will be removed soon', DeprecationWarning)
1330- return unicode_path(utf8path)
1331-
1332-
1333-def syncdaemon_path(mbcspath):
1334- """Turn a mbcs path in a utf-8 path as CURRENTLY used inside syncdaemon."""
1335- warnings.warn('syncdaemon_path will be removed soon', DeprecationWarning)
1336- return mbcspath.decode(sys.getfilesystemencoding()).encode("utf-8")
1337-
1338-
1339-# pylint: disable=C0103,F0401,E0611,E1101
1340-if sys.platform == "win32":
1341- from ubuntu_sso.xdg_base_directory import windows
1342- source = windows
1343- xdg_home = source.home_path
1344-else:
1345- import xdg.BaseDirectory
1346- source = xdg.BaseDirectory
1347- xdg_home = os.path.expanduser('~')
1348-
1349-xdg_cache_home = source.xdg_cache_home
1350-
1351-xdg_config_home = source.xdg_config_home
1352-xdg_config_dirs = source.xdg_config_dirs
1353-
1354-xdg_data_home = source.xdg_data_home
1355-xdg_data_dirs = source.xdg_data_dirs
1356-
1357-
1358-def load_config_paths(*resource):
1359- """Iterator of configuration paths.
1360-
1361- Return an iterator which gives each directory named 'resource' in
1362- the configuration search path. Information provided by earlier
1363- directories should take precedence over later ones (ie, the user's
1364- config dir comes first).
1365- """
1366- resource = os.path.join(*resource)
1367- for config_dir in xdg_config_dirs:
1368- path = os.path.join(config_dir, resource)
1369- # access the file system always with unicode
1370- # to properly behave in some operating systems
1371- if os.path.exists(unicode_path(path)):
1372- yield path
1373-
1374-
1375-def save_config_path(*resource):
1376- """Path to save configuration.
1377-
1378- Ensure $XDG_CONFIG_HOME/<resource>/ exists, and return its path.
1379- 'resource' should normally be the name of your application. Use this
1380- when SAVING configuration settings. Use the xdg_config_dirs variable
1381- for loading.
1382- """
1383- resource = os.path.join(*resource)
1384- assert not resource.startswith('/')
1385- path = os.path.join(xdg_config_home, resource)
1386- # access the file system always with unicode
1387- # to properly behave in some operating systems
1388- if not os.path.isdir(unicode_path(path)):
1389- os.makedirs(unicode_path(path), 0700)
1390- return path
1391
1392=== removed directory 'ubuntu_sso/xdg_base_directory/tests'
1393=== removed file 'ubuntu_sso/xdg_base_directory/tests/__init__.py'
1394--- ubuntu_sso/xdg_base_directory/tests/__init__.py 2012-04-09 17:38:24 +0000
1395+++ ubuntu_sso/xdg_base_directory/tests/__init__.py 1970-01-01 00:00:00 +0000
1396@@ -1,29 +0,0 @@
1397-# ubuntu_sso - Ubuntu Single Sign On client support for desktop apps
1398-#
1399-# Copyright 2009-2012 Canonical Ltd.
1400-#
1401-# This program is free software: you can redistribute it and/or modify it
1402-# under the terms of the GNU General Public License version 3, as published
1403-# by the Free Software Foundation.
1404-#
1405-# This program is distributed in the hope that it will be useful, but
1406-# WITHOUT ANY WARRANTY; without even the implied warranties of
1407-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1408-# PURPOSE. See the GNU General Public License for more details.
1409-#
1410-# You should have received a copy of the GNU General Public License along
1411-# with this program. If not, see <http://www.gnu.org/licenses/>.
1412-#
1413-# In addition, as a special exception, the copyright holders give
1414-# permission to link the code of portions of this program with the
1415-# OpenSSL library under certain conditions as described in each
1416-# individual source file, and distribute linked combinations
1417-# including the two.
1418-# You must obey the GNU General Public License in all respects
1419-# for all of the code used other than OpenSSL. If you modify
1420-# file(s) with this exception, you may extend this exception to your
1421-# version of the file(s), but you are not obligated to do so. If you
1422-# do not wish to do so, delete this exception statement from your
1423-# version. If you delete this exception statement from all source
1424-# files in the program, then also delete it here.
1425-"""XDG tests."""
1426
1427=== removed file 'ubuntu_sso/xdg_base_directory/tests/test_common.py'
1428--- ubuntu_sso/xdg_base_directory/tests/test_common.py 2012-04-09 17:38:24 +0000
1429+++ ubuntu_sso/xdg_base_directory/tests/test_common.py 1970-01-01 00:00:00 +0000
1430@@ -1,91 +0,0 @@
1431-# -*- coding: utf-8 -*-
1432-#
1433-# Authors: Natalia B. Bidart <natalia.bidart@canonical.com>
1434-#
1435-# Copyright 2011-2012 Canonical Ltd.
1436-#
1437-# This program is free software: you can redistribute it and/or modify it
1438-# under the terms of the GNU General Public License version 3, as published
1439-# by the Free Software Foundation.
1440-#
1441-# This program is distributed in the hope that it will be useful, but
1442-# WITHOUT ANY WARRANTY; without even the implied warranties of
1443-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1444-# PURPOSE. See the GNU General Public License for more details.
1445-#
1446-# You should have received a copy of the GNU General Public License along
1447-# with this program. If not, see <http://www.gnu.org/licenses/>.
1448-#
1449-# In addition, as a special exception, the copyright holders give
1450-# permission to link the code of portions of this program with the
1451-# OpenSSL library under certain conditions as described in each
1452-# individual source file, and distribute linked combinations
1453-# including the two.
1454-# You must obey the GNU General Public License in all respects
1455-# for all of the code used other than OpenSSL. If you modify
1456-# file(s) with this exception, you may extend this exception to your
1457-# version of the file(s), but you are not obligated to do so. If you
1458-# do not wish to do so, delete this exception statement from your
1459-# version. If you delete this exception statement from all source
1460-# files in the program, then also delete it here.
1461-"""Platform independent tests for the XDG constants."""
1462-
1463-import os
1464-
1465-from twisted.trial.unittest import TestCase
1466-
1467-from ubuntu_sso import xdg_base_directory
1468-
1469-
1470-class TestBaseDirectory(TestCase):
1471- """Tests for the BaseDirectory module."""
1472-
1473- def assert_utf8_bytes(self, value):
1474- """Check that 'value' is a bytes sequence encoded with utf-8."""
1475- self.assertIsInstance(value, str)
1476- try:
1477- value.decode('utf-8')
1478- except UnicodeDecodeError:
1479- self.fail('%r should be a utf8 encoded string.' % value)
1480-
1481- def test_xdg_home_is_utf8_bytes(self):
1482- """The returned path is bytes."""
1483- actual = xdg_base_directory.xdg_home
1484- self.assert_utf8_bytes(actual)
1485-
1486- def test_xdg_cache_home_is_utf8_bytes(self):
1487- """The returned path is bytes."""
1488- actual = xdg_base_directory.xdg_cache_home
1489- self.assert_utf8_bytes(actual)
1490-
1491- def test_xdg_config_home_is_utf8_bytes(self):
1492- """The returned path is bytes."""
1493- actual = xdg_base_directory.xdg_config_home
1494- self.assert_utf8_bytes(actual)
1495-
1496- def test_xdg_config_dirs_are_bytes(self):
1497- """The returned path is bytes."""
1498- result = xdg_base_directory.xdg_config_dirs
1499- for actual in result:
1500- self.assert_utf8_bytes(actual)
1501-
1502- def test_xdg_data_home_is_utf8_bytes(self):
1503- """The returned path is bytes."""
1504- actual = xdg_base_directory.xdg_data_home
1505- self.assert_utf8_bytes(actual)
1506-
1507- def test_xdg_data_dirs_are_bytes(self):
1508- """The returned path is bytes."""
1509- result = xdg_base_directory.xdg_data_dirs
1510- for actual in result:
1511- self.assert_utf8_bytes(actual)
1512-
1513- def test_load_config_paths_filter(self):
1514- """Since those folders don't exist, this should be empty."""
1515- self.assertEqual(list(xdg_base_directory.load_config_paths("x")), [])
1516-
1517- def test_save_config_path(self):
1518- """The path should end with xdg_config/x (respecting the separator)."""
1519- self.patch(os, "makedirs", lambda *args: None)
1520- result = xdg_base_directory.save_config_path("x")
1521- self.assertEqual(result.split(os.sep)[-2:], ['xdg_config', 'x'])
1522
1523=== removed file 'ubuntu_sso/xdg_base_directory/tests/test_windows.py'
1524--- ubuntu_sso/xdg_base_directory/tests/test_windows.py 2012-04-09 17:38:24 +0000
1525+++ ubuntu_sso/xdg_base_directory/tests/test_windows.py 1970-01-01 00:00:00 +0000
1526@@ -1,157 +0,0 @@
1527-# -*- coding: utf-8 -*-
1528-#
1529-# Copyright 2011-2012 Canonical Ltd.
1530-#
1531-# This program is free software: you can redistribute it and/or modify it
1532-# under the terms of the GNU General Public License version 3, as published
1533-# by the Free Software Foundation.
1534-#
1535-# This program is distributed in the hope that it will be useful, but
1536-# WITHOUT ANY WARRANTY; without even the implied warranties of
1537-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1538-# PURPOSE. See the GNU General Public License for more details.
1539-#
1540-# You should have received a copy of the GNU General Public License along
1541-# with this program. If not, see <http://www.gnu.org/licenses/>.
1542-#
1543-# In addition, as a special exception, the copyright holders give
1544-# permission to link the code of portions of this program with the
1545-# OpenSSL library under certain conditions as described in each
1546-# individual source file, and distribute linked combinations
1547-# including the two.
1548-# You must obey the GNU General Public License in all respects
1549-# for all of the code used other than OpenSSL. If you modify
1550-# file(s) with this exception, you may extend this exception to your
1551-# version of the file(s), but you are not obligated to do so. If you
1552-# do not wish to do so, delete this exception statement from your
1553-# version. If you delete this exception statement from all source
1554-# files in the program, then also delete it here.
1555-"""Windows-specific tests for the XDG constants."""
1556-
1557-import os
1558-import sys
1559-
1560-from twisted.trial.unittest import TestCase
1561-
1562-
1563-# pylint: disable=E1101, E0611, F0401
1564-import win32com.shell
1565-from ubuntu_sso.xdg_base_directory.windows import (
1566- get_config_dirs,
1567- get_data_dirs,
1568- get_env_path,
1569- get_special_folders,
1570-)
1571-
1572-
1573-class FakeShellConModule(object):
1574- """Override CSIDL_ constants."""
1575-
1576- CSIDL_PROFILE = 0
1577- CSIDL_LOCAL_APPDATA = 1
1578- CSIDL_COMMON_APPDATA = 2
1579-
1580-
1581-class FakeShellModule(object):
1582-
1583- """Fake Shell Module."""
1584-
1585- def __init__(self):
1586- """Set the proper mapping between CSIDL_ consts."""
1587- self.values = {
1588- 0: u'c:\\path\\to\\users\\home',
1589- 1: u'c:\\path\\to\\users\\home\\appData\\local',
1590- 2: u'c:\\programData',
1591- }
1592-
1593- # pylint: disable=C0103
1594- def SHGetFolderPath(self, dummy0, shellconValue, dummy2, dummy3):
1595- """Override SHGetFolderPath functionality."""
1596- return self.values[shellconValue]
1597- # pylint: enable=C0103
1598-
1599-
1600-class TestBaseDirectoryWindows(TestCase):
1601- """Tests for the BaseDirectory module."""
1602-
1603- def test_get_special_folders(self):
1604- """Make sure we can import the platform module."""
1605-
1606- shell_module = FakeShellModule()
1607- self.patch(win32com.shell, "shell", shell_module)
1608- self.patch(win32com.shell, "shellcon", FakeShellConModule())
1609- special_folders = get_special_folders()
1610- self.assertTrue('Personal' in special_folders)
1611- self.assertTrue('Local AppData' in special_folders)
1612- self.assertTrue('AppData' in special_folders)
1613- self.assertTrue('Common AppData' in special_folders)
1614-
1615- self.assertTrue(special_folders['Personal'] == \
1616- shell_module.values[FakeShellConModule.CSIDL_PROFILE])
1617- self.assertTrue(special_folders['Local AppData'] == \
1618- shell_module.values[FakeShellConModule.CSIDL_LOCAL_APPDATA])
1619- self.assertTrue(special_folders['Local AppData'].startswith(
1620- special_folders['AppData']))
1621- self.assertTrue(special_folders['Common AppData'] == \
1622- shell_module.values[FakeShellConModule.CSIDL_COMMON_APPDATA])
1623-
1624- for val in special_folders.itervalues():
1625- self.assertIsInstance(val, str)
1626- val.decode('utf8')
1627- # Should not raise exceptions
1628-
1629- def test_get_data_dirs(self):
1630- """Check thet get_data_dirs uses pathsep correctly."""
1631- bad_sep = filter(lambda x: x not in os.pathsep, ":;")
1632- dir_list = ["A", "B", bad_sep, "C"]
1633- self.patch(os, "environ",
1634- dict(XDG_DATA_DIRS=os.pathsep.join(
1635- dir_list)))
1636- dirs = get_data_dirs()
1637- self.assertEqual(dirs, dir_list)
1638-
1639- def test_get_config_dirs(self):
1640- """Check thet get_data_dirs uses pathsep correctly."""
1641- bad_sep = filter(lambda x: x not in os.pathsep, ":;")
1642- dir_list = ["A", "B", bad_sep, "C"]
1643- self.patch(os, "environ",
1644- dict(XDG_CONFIG_DIRS=os.pathsep.join(
1645- dir_list)))
1646- dirs = get_config_dirs()[1:]
1647- self.assertEqual(dirs, dir_list)
1648-
1649- def set_fake_environ(self, key, value):
1650- """Set (and restore) a fake environ variable."""
1651- if key in os.environ:
1652- prev = os.environ[key]
1653- self.addCleanup(os.environ.__setitem__, key, prev)
1654- else:
1655- self.addCleanup(os.environ.__delitem__, key)
1656- os.environ[key] = value
1657-
1658- def unset_fake_environ(self, key):
1659- """Unset (and restore) a fake environ variable."""
1660- if key in os.environ:
1661- current_value = os.environ[key]
1662- self.addCleanup(os.environ.__setitem__, key, current_value)
1663- del(os.environ[key])
1664-
1665- def test_get_env_path_var(self):
1666- """Test that get_env_path transforms an env var."""
1667- fake_path = u"C:\\Users\\Ñandú"
1668- fake_env_var = "FAKE_ENV_VAR"
1669-
1670- mbcs_path = fake_path.encode(sys.getfilesystemencoding())
1671- utf8_path = fake_path.encode("utf-8")
1672-
1673- self.set_fake_environ(fake_env_var, mbcs_path)
1674- self.assertEqual(get_env_path(fake_env_var, "unexpected"), utf8_path)
1675-
1676- def test_get_env_path_no_var(self):
1677- """Test that get_env_path returns the default when env var not set."""
1678- fake_path = u"C:\\Users\\Ñandú"
1679- fake_env_var = "fake_env_var"
1680- default = fake_path.encode(sys.getfilesystemencoding())
1681-
1682- self.unset_fake_environ(fake_env_var)
1683- self.assertEqual(get_env_path(fake_env_var, default), default)
1684
1685=== removed file 'ubuntu_sso/xdg_base_directory/windows.py'
1686--- ubuntu_sso/xdg_base_directory/windows.py 2012-04-09 17:38:24 +0000
1687+++ ubuntu_sso/xdg_base_directory/windows.py 1970-01-01 00:00:00 +0000
1688@@ -1,113 +0,0 @@
1689-# -*- coding: utf-8 -*-
1690-#
1691-# Copyright 2011-2012 Canonical Ltd.
1692-#
1693-# This program is free software: you can redistribute it and/or modify it
1694-# under the terms of the GNU General Public License version 3, as published
1695-# by the Free Software Foundation.
1696-#
1697-# This program is distributed in the hope that it will be useful, but
1698-# WITHOUT ANY WARRANTY; without even the implied warranties of
1699-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1700-# PURPOSE. See the GNU General Public License for more details.
1701-#
1702-# You should have received a copy of the GNU General Public License along
1703-# with this program. If not, see <http://www.gnu.org/licenses/>.
1704-#
1705-# In addition, as a special exception, the copyright holders give
1706-# permission to link the code of portions of this program with the
1707-# OpenSSL library under certain conditions as described in each
1708-# individual source file, and distribute linked combinations
1709-# including the two.
1710-# You must obey the GNU General Public License in all respects
1711-# for all of the code used other than OpenSSL. If you modify
1712-# file(s) with this exception, you may extend this exception to your
1713-# version of the file(s), but you are not obligated to do so. If you
1714-# do not wish to do so, delete this exception statement from your
1715-# version. If you delete this exception statement from all source
1716-# files in the program, then also delete it here.
1717-"""XDG helpers for windows."""
1718-
1719-import os
1720-import sys
1721-
1722-
1723-# pylint: disable=C0103
1724-def get_special_folders():
1725- """ Routine to grab all the Windows Special Folders locations.
1726-
1727- If successful, returns dictionary
1728- of shell folder locations indexed on Windows keyword for each;
1729- otherwise, returns an empty dictionary.
1730- """
1731- # pylint: disable=W0621, F0401, E0611
1732- special_folders = {}
1733-
1734- from win32com.shell import shell, shellcon
1735- # CSIDL_LOCAL_APPDATA = C:\Users\<username>\AppData\Local
1736- # CSIDL_PROFILE = C:\Users\<username>
1737- # CSIDL_COMMON_APPDATA = C:\ProgramData
1738- # More information on these constants at
1739- # http://msdn.microsoft.com/en-us/library/bb762494
1740-
1741- # as per http://msdn.microsoft.com/en-us/library/windows/desktop/bb762181,
1742- # SHGetFolderPath is deprecated, we should migrate to SHGetKnownFolderPath
1743- # (http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188)
1744- get_path = lambda name: shell.SHGetFolderPath(
1745- 0, getattr(shellcon, name), None, 0).encode('utf8')
1746- special_folders['Personal'] = get_path("CSIDL_PROFILE")
1747- special_folders['Local AppData'] = get_path("CSIDL_LOCAL_APPDATA")
1748- special_folders['AppData'] = os.path.dirname(
1749- special_folders['Local AppData'])
1750- special_folders['Common AppData'] = get_path("CSIDL_COMMON_APPDATA")
1751- return special_folders
1752-
1753-
1754-def get_env_path(key, default):
1755- """Get a utf8 path from an environment variable."""
1756- if key in os.environ:
1757- # on windows, environment variables are mbcs bytes
1758- # so we must turn them into utf-8 Syncdaemon paths
1759- path = os.environ.get(key)
1760- return path.decode(sys.getfilesystemencoding()).encode("utf-8")
1761- else:
1762- return default
1763-
1764-
1765-special_folders = get_special_folders()
1766-
1767-home_path = special_folders['Personal']
1768-app_local_data_path = special_folders['Local AppData']
1769-app_global_data_path = special_folders['Common AppData']
1770-
1771-xdg_data_home = get_env_path('XDG_DATA_HOME',
1772- os.path.join(app_local_data_path, 'xdg'))
1773-
1774-xdg_cache_home = get_env_path('XDG_CACHE_HOME',
1775- os.path.join(xdg_data_home, 'cache'))
1776-
1777-xdg_config_home = get_env_path('XDG_CONFIG_HOME',
1778- app_local_data_path)
1779-
1780-
1781-def get_data_dirs():
1782- """Returns XDG data directories."""
1783- return get_env_path('XDG_DATA_DIRS',
1784- '{0}{1}{2}'.format(app_local_data_path, os.pathsep,
1785- app_global_data_path)).split(os.pathsep)
1786-
1787-
1788-xdg_data_dirs = get_data_dirs()
1789-
1790-
1791-def get_config_dirs():
1792- """Return XDG config directories."""
1793- return [xdg_config_home] + \
1794- get_env_path('XDG_CONFIG_DIRS',
1795- app_global_data_path,
1796- ).split(os.pathsep)
1797-
1798-xdg_config_dirs = get_config_dirs()
1799-
1800-xdg_data_dirs = filter(lambda x: x, xdg_data_dirs)
1801-xdg_config_dirs = filter(lambda x: x, xdg_config_dirs)

Subscribers

People subscribed via source and target branches

to all changes: