diff --git a/Orange/widgets/credentials.py b/Orange/widgets/credentials.py index eb6132bfa45..48bc2497339 100644 --- a/Orange/widgets/credentials.py +++ b/Orange/widgets/credentials.py @@ -1,7 +1,11 @@ +import logging + import keyring SERVICE_NAME = 'Orange3 - {}' +log = logging.getLogger(__name__) + class CredentialManager: """ @@ -13,13 +17,11 @@ class CredentialManager: Examples: >>> cm = CredentialManager('Widget Name') - >>> cm.username = 'Orange' # store username - >>> cm.password = 'Secret' # store password - - >>> cm.username # get username - 'Orange' - >>> cm.password # get password - 'Secret' + >>> cm.some_secret = 'api-key-1234' + >>> cm.some_secret + 'api-key-1234' + >>> del cm.some_secret + >>> cm.some_secret """ def __init__(self, service_name): self.__dict__['__service_name'] = SERVICE_NAME.format(service_name) @@ -29,10 +31,22 @@ def service_name(self): return self.__dict__['__service_name'] def __setattr__(self, key, value): - keyring.set_password(self.service_name, key, value) + try: + keyring.set_password(self.service_name, key, value) + except Exception: + log.exception("Failed to set secret '%s' of '%r'.", + key, self.service_name) def __getattr__(self, item): - return keyring.get_password(self.service_name, item) + try: + return keyring.get_password(self.service_name, item) + except Exception: + log.exception("Failed to get secret '%s' of '%r'.", + item, self.service_name) def __delattr__(self, item): - keyring.delete_password(self.service_name, item) + try: + keyring.delete_password(self.service_name, item) + except Exception: + log.exception("Failed to delete secret '%s' of '%r'.", + item, self.service_name) diff --git a/Orange/widgets/tests/test_credentials.py b/Orange/widgets/tests/test_credentials.py index 5d9341913e5..67899a71446 100644 --- a/Orange/widgets/tests/test_credentials.py +++ b/Orange/widgets/tests/test_credentials.py @@ -1,12 +1,41 @@ import unittest +from unittest.mock import patch from Orange.widgets.credentials import CredentialManager -class CredentialManagerTests(unittest.TestCase): +class TestCredentialManager(unittest.TestCase): + def setUp(self): + self.cm = CredentialManager('Orange') + self.cm.key = "Foo" + def test_credential_manager(self): cm = CredentialManager('Orange') cm.key = 'Foo' self.assertEqual(cm.key, 'Foo') del cm.key self.assertEqual(cm.key, None) + + def test_set_password(self): + """ + Handle error when setting password fails. + GH-2354 + """ + with patch("keyring.set_password", side_effect=Exception): + self.cm.key = "" + + def test_delete_password(self): + """ + Handling error when deleting password fails + GH-2354 + """ + with patch("keyring.delete_password", side_effect=Exception): + del self.cm.key + + def test_get_password(self): + """ + Handling errors when getting password fails. + GH-2354 + """ + with patch("keyring.get_password", side_effect=Exception): + self.assertEqual(self.cm.key, None)