python: Make 'get_key' more idiomatic.
authorJustus Winter <justus@g10code.com>
Thu, 13 Oct 2016 11:13:23 +0000 (13:13 +0200)
committerJustus Winter <justus@g10code.com>
Thu, 13 Oct 2016 11:19:49 +0000 (13:19 +0200)
* lang/python/pyme/core.py (Context.get_key): Raise errors.KeyNotFound
if the key is not found.  This error is both a KeyError for idiomatic
error handling as well as a GPGMEError so we don't break existing
code.
* lang/python/pyme/errors.py (KeyNotFound): New class.
* lang/python/tests/support.py (no_such_key): New variable.
* lang/python/tests/t-keylist.py: Test the new behavior.

Signed-off-by: Justus Winter <justus@g10code.com>
lang/python/pyme/core.py
lang/python/pyme/errors.py
lang/python/tests/support.py
lang/python/tests/t-keylist.py

index cd5217f..f0eab43 100644 (file)
@@ -680,11 +680,19 @@ class Context(GpgmeWrapper):
                         -- the matching key
 
         Raises:
+        KeyError       -- if the key was not found
         GPGMEError     -- as signaled by the underlying library
 
         """
         ptr = gpgme.new_gpgme_key_t_p()
-        errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
+
+        try:
+            errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
+        except errors.GPGMEError as e:
+            if e.getcode() == errors.EOF:
+                raise errors.KeyNotFound(fpr)
+            raise e
+
         key = gpgme.gpgme_key_t_p_value(ptr)
         gpgme.delete_gpgme_key_t_p(ptr)
         assert key
index e26c747..0fd85ef 100644 (file)
@@ -21,10 +21,12 @@ del absolute_import, print_function, unicode_literals
 from . import gpgme
 from . import util
 
-util.process_constants('GPG_ERR_', globals())
+# To appease static analysis tools, we define some constants here.
+# They are overwritten with the proper values by process_constants.
+NO_ERROR = None
+EOF = None
 
-# To appease static analysis tools, we define some constants here:
-NO_ERROR = 0
+util.process_constants('GPG_ERR_', globals())
 
 class PymeError(Exception):
     pass
@@ -58,6 +60,20 @@ def errorcheck(retval, extradata = None):
     if retval:
         raise GPGMEError(retval, extradata)
 
+class KeyNotFound(GPGMEError, KeyError):
+    """Raised if a key was not found
+
+    GPGME indicates this condition with EOF, which is not very
+    idiomatic.  We raise this error that is both a GPGMEError
+    indicating EOF, and a KeyError.
+
+    """
+    def __init__(self, keystr):
+        self.keystr = keystr
+        GPGMEError.__init__(self, EOF)
+    def __str__(self):
+        return self.keystr
+
 # These errors are raised in the idiomatic interface code.
 
 class EncryptionError(PymeError):
index 4d7135e..f1ffdc3 100644 (file)
@@ -27,6 +27,7 @@ alpha = "A0FF4590BB6122EDEF6E3C542D727CC768697734"
 bob = "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2"
 encrypt_only = "F52770D5C4DB41408D918C9F920572769B9FE19C"
 sign_only = "7CCA20CCDE5394CEE71C9F0BFED153F12F18F45D"
+no_such_key = "A" * 40
 
 def make_filename(name):
     return os.path.join(os.environ['top_srcdir'], 'tests', 'gpg', name)
index 5e8b333..f7f6674 100755 (executable)
@@ -20,6 +20,7 @@
 from __future__ import absolute_import, print_function, unicode_literals
 del absolute_import, print_function, unicode_literals
 
+import pyme
 from pyme import core, constants
 import support
 
@@ -244,3 +245,25 @@ for i, key in enumerate(c.keylist()):
 
     if misc_check:
         misc_check (uids[0][0], key)
+
+
+# check get_key()
+with pyme.Context() as c:
+  c.get_key(support.alpha)
+  c.get_key(support.alpha, secret=True)
+
+  c.get_key(support.bob)
+  try:
+    c.get_key(support.bob, secret=True)
+  except KeyError:
+    pass
+  else:
+    assert False, "Expected KeyError"
+
+  # Legacy error
+  try:
+    c.get_key(support.no_such_key)
+  except pyme.errors.GPGMEError:
+    pass
+  else:
+    assert False, "Expected GPGMEError"