1. Jason R. Coombs
  2. keyring

Commits

Jason R. Coombs  committed 3a076ae Merge
  • Participants
  • Parent commits e47a66c, d1cc275
  • Branches default

Comments (0)

Files changed (6)

File buildout.cfg

View file
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = keyring
+eggs = keyring [test]
 defaults = '--tests-pattern tests --exit-with-status'.split()
 working-directory = .
 
 
 distribute = 0.6.14
 setuptools = 0.6c11
+unittest2 = 0.5.1
 z3c.recipe.scripts = 1.0.1
 zc.buildout = 1.5.2
 zc.recipe.egg = 1.3.2

File keyring/backend.py

View file
 Created by Kang Zhang on 2009-07-09
 """
 
+import getpass
 import os
 import sys
 import ConfigParser
             status = -1
         return status
 
+    def _getpass(self, *args, **kwargs):
+        """Wrap getpass.getpass(), so that we can override it when testing.
+        """
+
+        return getpass.getpass(*args, **kwargs)
+
     def _init_file(self):
         """Init the password file, set the password for it.
         """
 
-        print("Please set a password for your new keyring")
         password = None
         while 1:
             if not password:
-                import getpass
-                password = getpass.getpass()
-                password2 = getpass.getpass('Password (again): ')
+                password = self._getpass("Please set a password for your new keyring")
+                password2 = self._getpass('Password (again): ')
                 if password != password2:
                     sys.stderr.write("Error: Your passwords didn't match\n")
                     password = None
         if not self._check_file():
             self._init_file()
 
-        print "Please input your password for the keyring"
-        import getpass
-        password = getpass.getpass()
+        password = self._getpass("Please input your password for the keyring")
 
         if not self._auth(password):
             sys.stderr.write("Wrong password for the keyring.\n")

File keyring/cli.py

View file
 """Simple command line interface to get/set password from a keyring"""
 
 import getpass
-import optparse
+from optparse import OptionParser
 import sys
 
 import keyring
 import keyring.core
 
 
-def input_password(prompt):
-    """Ask for a password to the user.
+class CommandLineTool(object):
+    def __init__(self):
+        self.parser = OptionParser(usage="%prog [get|set] SERVICE USERNAME")
+        self.parser.add_option("-p", "--keyring-path",
+                               dest="keyring_path", default=None,
+                               help="Path to the keyring backend")
+        self.parser.add_option("-b", "--keyring-backend",
+                               dest="keyring_backend", default=None,
+                               help="Name of the keyring backend")
 
-    This mostly exists to ease the testing process.
-    """
+    def run(self, argv):
+        opts, args = self.parser.parse_args(argv)
 
-    return getpass.getpass(prompt)
+        try:
+            kind, service, username = args
+        except ValueError:
+            if len(args) == 0:
+                # Be nice with the user if he just tries to launch the tool
+                self.parser.print_help()
+                return 1
+            else:
+                self.parser.error("Wrong number of arguments")
 
+        if opts.keyring_backend is not None:
+            try:
+                backend = keyring.core.load_keyring(opts.keyring_path,
+                                                    opts.keyring_backend)
+                keyring.set_keyring(backend)
+            except Exception, e:
+                # Tons of things can go wrong here:
+                #   ImportError when using "fjkljfljkl"
+                #   AttributeError when using "os.path.bar"
+                #   TypeError when using "__builtins__.str"
+                # So, we play on the safe side, and catch everything.
+                self.parser.error("Unable to load specified keyring: %s" % e)
 
-def output_password(password):
-    """Output the password to the user.
 
-    This mostly exists to ease the testing process.
-    """
+        if kind == 'get':
+            password = keyring.get_password(service, username)
+            if password is None:
+                return 1
 
-    print password
+            self.output_password(password)
+            return 0
+
+        elif kind == 'set':
+            password = self.input_password("Password for '%s' in '%s': " %
+                                           (username, service))
+            keyring.set_password(service, username, password)
+            return 0
+
+        else:
+            self.parser.error("You can only 'get' or 'set' a password.")
+            pass
+
+    def input_password(self, prompt):
+        """Ask for a password to the user.
+
+        This mostly exists to ease the testing process.
+        """
+
+        return getpass.getpass(prompt)
+
+
+    def output_password(self, password):
+        """Output the password to the user.
+
+        This mostly exists to ease the testing process.
+        """
+
+        print password
 
 
 def main(argv=None):
     """Main command line interface."""
 
-    parser = optparse.OptionParser(usage="%prog [get|set] SERVICE USERNAME")
-    parser.add_option("-p", "--keyring-path", dest="keyring_path", default=None,
-                      help="Path to the keyring backend")
-    parser.add_option("-b", "--keyring-backend", dest="keyring_backend", default=None,
-                      help="Name of the keyring backend")
 
     if argv is None:
         argv = sys.argv[1:]
 
-    opts, args = parser.parse_args(argv)
-
-    try:
-        kind, service, username = args
-    except ValueError:
-        if len(args) == 0:
-            # Be nice with the user if he just tries to launch the tool
-            parser.print_help()
-            return 1
-        else:
-            parser.error("Wrong number of arguments")
-
-    if opts.keyring_backend is not None:
-        try:
-            backend = keyring.core.load_keyring(opts.keyring_path, opts.keyring_backend)
-            keyring.set_keyring(backend)
-        except Exception, e:
-            # Tons of things can go wrong here:
-            #   ImportError when using "fjkljfljkl"
-            #   AttributeError when using "os.path.bar"
-            #   TypeError when using "__builtins__.str"
-            # So, we play on the safe side, and catch everything.
-            parser.error("Unable to load specified keyring: %s" % e)
-
-
-    if kind == 'get':
-        password = keyring.get_password(service, username)
-        if password is None:
-            return 1
-
-        output_password(password)
-        return 0
-
-    elif kind == 'set':
-        password = input_password("Password for '%s' in '%s': " %
-                                  (username, service))
-        keyring.set_password(service, username, password)
-        return 0
-
-    else:
-        parser.error("You can only 'get' or 'set' a password.")
+    cli = CommandLineTool()
+    return cli.run(argv)
 
 
 if __name__ == '__main__':

File keyring/tests/test_backend.py

View file
 created by Kang Zhang 2009-07-14
 """
 
-
-import commands
 import contextlib
 import os
 import random
 import string
 import sys
+import tempfile
 import types
-import unittest
+
+try:
+    # Python < 2.7 annd Python >= 3.0 < 3.1
+    import unittest2 as unittest
+except ImportError:
+    import unittest
 
 import keyring.backend
 from keyring.backend import PasswordSetError
         result += random.choice(source)
     return result
 
-def backup(file):
-    """Backup the file as file.bak
-    """
-    commands.getoutput( "mv %s{,.bak}" % file )
 
-def restore(file):
-    """Restore the file from file.bak
-    """
-    commands.getoutput( "mv %s{.bak,}" % file )
+def is_win32_crypto_supported():
+    try:
+        from keyring.backends import win32_crypto
+        if sys.platform in ['win32'] and sys.getwindowsversion()[-2] == 2:
+            return True
+    except ImportError:
+        pass
+    return False
+
+def is_osx_keychain_supported():
+    return sys.platform in ('mac','darwin')
+
+def is_kwallet_supported():
+    supported = keyring.backend.KDEKWallet().supported()
+    if supported == -1:
+        return False
+    return True
+
+def is_crypto_supported():
+    try:
+        from Crypto.Cipher import AES
+        import crypt
+    except ImportError:
+        return False
+    return True
+
+def is_gnomekeyring_supported():
+    supported = keyring.backend.GnomeKeyring().supported()
+    if supported == -1:
+        return False
+    return True
+
+def is_qt4_supported():
+    try:
+        from PyQt4.QtGui import QApplication
+    except ImportError:
+        return False
+    return True
+
+def is_winvault_supported():
+    try:
+        from keyring.backend import WinVaultKeyring
+        if sys.platform in ['win32'] and sys.getwindowsversion().major >= 6:
+            return True
+    except ImportError:
+        pass
+    return False
+
 
 class BackendBasicTestCase(unittest.TestCase):
     """Test for the keyring's basic funtions. password_set and password_get
     def check_set_get(self, service, username, password):
         keyring = self.keyring
 
-        if self.supported() == -1: # skip the unsupported keyring
-            return
-
         # for the non-existent password
         self.assertEqual(keyring.get_password(service, username), None)
 
         multiple users. This test exercises that test for each of the
         backends.
         """
-        if self.supported() == -1: # skip the unsupported keyring
-            return
 
         keyring = self.keyring
         self.set_password('service1', 'user1', 'password1')
         self.assertEqual(keyring.get_password('service1', 'user1'),
             'password1')
 
-    def supported(self):
-        """Return the correct value for supported.
-        """
-        return -1
-
-    def test_supported(self):
-        """Test the keyring's supported value.
-        """
-        self.assertEqual(self.keyring.supported(), self.supported())
-
+@unittest.skipUnless(is_osx_keychain_supported(),
+                     "Need OS X")
 class OSXKeychainTestCase(BackendBasicTestCase):
     __test__ = True
 
     def init_keyring(self):
-        print >> sys.stderr, "Testing OSXKeychain, following password prompts are for this keyring"
         return keyring.backend.OSXKeychain()
 
-    def supported(self):
-        if sys.platform in ('mac','darwin'):
-            return 1
-        return -1
 
+@unittest.skipUnless(is_gnomekeyring_supported(),
+                     "Need GnomeKeyring")
 class GnomeKeyringTestCase(BackendBasicTestCase):
     __test__ = True
 
                     DBUS_SESSION_BUS_ADDRESS='1')
 
     def init_keyring(self):
-        print >> sys.stderr, "Testing GnomeKeyring, following password prompts are for this keyring"
         return keyring.backend.GnomeKeyring()
 
     def test_supported(self):
                 self.assertEqual(0, self.keyring.supported())
 
 
+@unittest.skipUnless(is_kwallet_supported(),
+                     "Need KWallet")
 class KDEKWalletTestCase(BackendBasicTestCase):
     __test__ = True
 
     def init_keyring(self):
-        print >> sys.stderr, "Testing KDEKWallet, following password prompts are for this keyring"
         return keyring.backend.KDEKWallet()
 
-    def supported(self):
-        return self.keyring.supported()
-
 
 class UnOpenableKWallet(object):
     """A module-like object used to test KDE wallet fall-back."""
             None)
 
 
+@unittest.skipUnless(is_kwallet_supported() and
+                     is_qt4_supported(),
+                     "Need KWallet and Qt4")
 class KDEKWalletInQApplication(unittest.TestCase):
-
-
     def test_QApplication(self):
         try:
             from PyKDE4.kdeui import KWallet
             return
 
         app = QApplication([])
-        wallet=keyring.backend.open_kwallet()
-        self.assertTrue(isinstance(wallet,KWallet.Wallet),msg="The object wallet should be type<KWallet.Wallet> but it is: %s"%repr(wallet))
+        wallet = keyring.backend.open_kwallet()
+        self.assertTrue(isinstance(wallet, KWallet.Wallet),
+                        msg="The object wallet should be type "
+                        "<KWallet.Wallet> but it is: %s" % repr(wallet))
         app.exit()
 
 
     __test__ = False
 
     def setUp(self):
-        """Backup the file before the test
-        """
         super(FileKeyringTestCase, self).setUp()
-
-        self.file_path = os.path.join(os.path.expanduser("~"),
-            self.keyring.filename())
-        backup(self.file_path)
+        self.keyring = self.init_keyring()
+        self.keyring.file_path = self.tmp_keyring_file = tempfile.mktemp()
 
     def tearDown(self):
-        """Restore the keyring file.
-        """
-        restore(self.file_path)
+        try:
+            os.unlink(self.tmp_keyring_file)
+        except OSError, e:
+            if e.errno != 2: # No such file or directory
+                raise
 
     def test_encrypt_decrypt(self):
-        if self.supported() == -1: # skip the unsupported platform
-            return
-
         password = random_string(20)
         encyrpted = self.keyring.encrypt(password)
 
         self.assertEqual(password, self.keyring.decrypt(encyrpted))
 
+
 class UncryptedFileKeyringTestCase(FileKeyringTestCase):
     __test__ = True
 
     def init_keyring(self):
-        print >> sys.stderr, "Testing UnecryptedFile, following password prompts are for this keyring"
         return keyring.backend.UncryptedFileKeyring()
 
-    def supported(self):
-        return 0
 
+@unittest.skipUnless(is_crypto_supported(),
+                     "Need Crypto module")
 class CryptedFileKeyringTestCase(FileKeyringTestCase):
     __test__ = True
 
+    def setUp(self):
+        super(self.__class__, self).setUp()
+        self.keyring._getpass = lambda *args, **kwargs: "abcdef"
+
     def init_keyring(self):
-        print >> sys.stderr, "Testing CryptedFile, following password prompts are for this keyring"
         return keyring.backend.CryptedFileKeyring()
 
-    def supported(self):
-        try:
-            from Crypto.Cipher import AES
-            import crypt
-            return 0
-        except ImportError:
-            pass
-        return -1
 
+@unittest.skipUnless(is_win32_crypto_supported(),
+                     "Need Windows")
 class Win32CryptoKeyringTestCase(FileKeyringTestCase):
     __test__ = True
 
     def init_keyring(self):
-        print >> sys.stderr, "Testing Win32Crypto, following password prompts are for this keyring"
         return keyring.backend.Win32CryptoKeyring()
 
-    def supported(self):
-        try:
-            from keyring.backends import win32_crypto
-            if sys.platform in ['win32'] and sys.getwindowsversion()[-2] == 2:
-                return 1
-        except ImportError:
-            pass
-        return -1
 
+@unittest.skipUnless(is_winvault_supported(),
+                     "Need WinVault")
 class WinVaultKeyringTestCase(BackendBasicTestCase):
-
     def tearDown(self):
         # clean up any credentials created
         for cred in self.credentials_created:
                 print >> sys.stderr, e
 
     def init_keyring(self):
-        print >> sys.stderr, "Testing WinVault, following password prompts are for this keyring"
         return keyring.backend.WinVaultKeyring()
 
-    def supported(self):
-        try:
-            from keyring.backend import WinVaultKeyring
-            if sys.platform in ['win32'] and sys.getwindowsversion().major >= 6:
-                return 1
-        except ImportError:
-            pass
-        return -1
-
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(OSXKeychainTestCase))

File keyring/tests/test_cli.py

View file
 class CommandLineTestCase(unittest.TestCase):
     def setUp(self):
         self.old_keyring = keyring.get_keyring()
-        self.old_input_password = cli.input_password
-        self.old_output_password = cli.output_password
+
+        self.cli = cli.CommandLineTool()
+        self.cli.input_password = self.return_password
+        self.cli.output_password = self.save_password
+        self.cli.parser.error = self.mock_error
+        self.cli.parser.print_help = lambda: None
 
         keyring.set_keyring(SimpleKeyring())
+
         self.password = ""
         self.password_returned = None
-        cli.input_password = self.return_password
-        cli.output_password = self.save_password
+        self.last_error = None
 
     def tearDown(self):
         keyring.set_keyring(self.old_keyring)
-        cli.input_password = self.old_input_password
-        cli.output_password = self.old_output_password
 
     def return_password(self, *args, **kwargs):
         return self.password
     def save_password(self, password):
         self.password_returned = password
 
+    def mock_error(self, error):
+        self.last_error = error
+        raise SystemExit()
 
     def test_wrong_arguments(self):
-        self.assertEqual(1, cli.main([]))
+        self.assertEqual(1, self.cli.run([]))
 
-        self.assertRaises(SystemExit, cli.main, ["get"])
-        self.assertRaises(SystemExit, cli.main, ["get", "foo"])
-        self.assertRaises(SystemExit, cli.main, ["get", "foo", "bar", "baz"])
+        self.assertRaises(SystemExit, self.cli.run, ["get"])
+        self.assertRaises(SystemExit, self.cli.run, ["get", "foo"])
+        self.assertRaises(SystemExit, self.cli.run,
+                          ["get", "foo", "bar", "baz"])
 
-        self.assertRaises(SystemExit, cli.main, ["set"])
-        self.assertRaises(SystemExit, cli.main, ["set", "foo"])
-        self.assertRaises(SystemExit, cli.main, ["set", "foo", "bar", "baz"])
+        self.assertRaises(SystemExit, self.cli.run, ["set"])
+        self.assertRaises(SystemExit, self.cli.run, ["set", "foo"])
+        self.assertRaises(SystemExit, self.cli.run,
+                          ["set", "foo", "bar", "baz"])
 
-        self.assertRaises(SystemExit, cli.main, ["foo", "bar", "baz"])
+        self.assertRaises(SystemExit, self.cli.run, ["foo", "bar", "baz"])
 
     def test_get_unexistent_password(self):
-        self.assertEqual(1, cli.main(["get", "foo", "bar"]))
+        self.assertEqual(1, self.cli.run(["get", "foo", "bar"]))
         self.assertEqual(None, self.password_returned)
 
     def test_set_and_get_password(self):
         self.password = "plop"
-        self.assertEqual(0, cli.main(["set", "foo", "bar"]))
-        self.assertEqual(0, cli.main(["get", "foo", "bar"]))
+        self.assertEqual(0, self.cli.run(["set", "foo", "bar"]))
+        self.assertEqual(0, self.cli.run(["get", "foo", "bar"]))
         self.assertEqual("plop", self.password_returned)
 
     def test_load_builtin_backend(self):
-        self.assertEqual(1, cli.main(["get",
-                                      "-b", "keyring.backend.UncryptedFileKeyring",
-                                      "foo", "bar"]))
+        self.assertEqual(1, self.cli.run([
+            "get",
+            "-b", "keyring.backend.UncryptedFileKeyring",
+            "foo", "bar"]))
         backend = keyring.get_keyring()
         self.assertTrue(isinstance(backend,
                                    keyring.backend.UncryptedFileKeyring))
 
     def test_load_specific_backend_with_path(self):
         keyring_path = os.path.join(os.path.dirname(keyring.__file__), 'tests')
-        self.assertEqual(0, cli.main(["get",
-                                      "-b", "test_cli.FakeKeyring",
-                                      "-p", keyring_path,
-                                      "foo", "bar"]))
+        self.assertEqual(0, self.cli.run(["get",
+                                          "-b", "test_cli.FakeKeyring",
+                                          "-p", keyring_path,
+                                          "foo", "bar"]))
 
         backend = keyring.get_keyring()
         # Somehow, this doesn't work, because the full dotted name of the class
         self.assertEqual(FakeKeyring.PASSWORD, self.password_returned)
 
     def test_load_wrong_keyrings(self):
-        self.assertRaises(SystemExit, cli.main,
-                         ["get", "foo", "bar",
-                          "-b", "blablabla" # ImportError
-                         ])
-        self.assertRaises(SystemExit, cli.main,
-                         ["get", "foo", "bar",
-                          "-b", "os.path.blabla" # AttributeError
-                         ])
-        self.assertRaises(SystemExit, cli.main,
-                         ["get", "foo", "bar",
-                          "-b", "__builtin__.str" # TypeError
-                         ])
+        self.assertRaises(SystemExit, self.cli.run,
+                          ["get", "foo", "bar",
+                           "-b", "blablabla" # ImportError
+                          ])
+        self.assertRaises(SystemExit, self.cli.run,
+                          ["get", "foo", "bar",
+                           "-b", "os.path.blabla" # AttributeError
+                          ])
+        self.assertRaises(SystemExit, self.cli.run,
+                          ["get", "foo", "bar",
+                           "-b", "__builtin__.str" # TypeError
+                          ])
 
 
 

File setup.py

View file
 Setup the Keyring Lib for Python.
 """
 
-import sys, os, subprocess
-from distutils.version import StrictVersion
+import sys
 
-def runcmd(cmd, env):
-    p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                         stderr=subprocess.PIPE, env=env)
-    out, err = p.communicate()
-    return out, err
 
 setup_params = dict(
     name = 'keyring',
     platforms = ["Many"],
     packages = ['keyring', 'keyring.tests', 'keyring.util',
                 'keyring.backends'],
+    extras_require={'test': []},
 )
 
+
 if sys.version_info >= (3,0):
     setup_params.update(
         use_2to3=True,
     )
 
+elif sys.version_info < (2, 7) or (
+    sys.version >= (3, 0) and sys.version < (3, 1)):
+    # Provide unittest2 for Python which doesn't contain the new unittest module
+    # (appears in Python 2.7 and Python 3.1)
+    setup_params.update(
+        tests_require=['unittest2'],
+    )
+    setup_params['extras_require']['test'].append('unittest2')
+
+
 if __name__ == '__main__':
     try:
         from setuptools import setup