PEP8 compliance and other code fixes

* Ran all the .py files in src/ and below through Yapf.
* Included some manual edits of core.py, this time successfully making
  two notorious sections a bit more pythonic than scheming.
* Left the module imports as is.
* This will be committed if it passes the most essential test:
  compiling, installing and running it.

Signed-off-by: Ben McGinnes <ben@adversary.org>
This commit is contained in:
Ben McGinnes 2018-08-10 11:25:01 +10:00
parent b6d2a66b41
commit 94bf13e78e
10 changed files with 219 additions and 129 deletions

View File

@ -15,7 +15,6 @@
# You should have received a copy of the GNU Lesser General Public # You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""gpg: GnuPG Interface for Python (GPGME bindings) """gpg: GnuPG Interface for Python (GPGME bindings)
Welcome to gpg, the GnuPG Interface for Python. Welcome to gpg, the GnuPG Interface for Python.
@ -117,5 +116,7 @@ del gpgme
_ = [Context, Data, core, errors, constants, util, callbacks, version] _ = [Context, Data, core, errors, constants, util, callbacks, version]
del _ del _
__all__ = ["Context", "Data", __all__ = [
"core", "errors", "constants", "util", "callbacks", "version"] "Context", "Data", "core", "errors", "constants", "util", "callbacks",
"version"
]

View File

@ -20,6 +20,7 @@ del absolute_import, print_function, unicode_literals
from getpass import getpass from getpass import getpass
def passphrase_stdin(hint, desc, prev_bad, hook=None): def passphrase_stdin(hint, desc, prev_bad, hook=None):
"""This is a sample callback that will read a passphrase from """This is a sample callback that will read a passphrase from
the terminal. The hook here, if present, will be used to describe the terminal. The hook here, if present, will be used to describe
@ -32,10 +33,12 @@ def passphrase_stdin(hint, desc, prev_bad, hook=None):
print("Please supply %s' password%s:" % (hint, why)) print("Please supply %s' password%s:" % (hint, why))
return getpass() return getpass()
def progress_stdout(what, type, current, total, hook=None): def progress_stdout(what, type, current, total, hook=None):
print("PROGRESS UPDATE: what = %s, type = %d, current = %d, total = %d" %\ print("PROGRESS UPDATE: what = %s, type = %d, current = %d, total = %d" %\
(what, type, current, total)) (what, type, current, total))
def readcb_fh(count, hook): def readcb_fh(count, hook):
"""A callback for data. hook should be a Python file-like object.""" """A callback for data. hook should be a Python file-like object."""
if count: if count:

View File

@ -30,11 +30,13 @@ from . import create, event, keysign, md, pk, protocol, sigsum, status, validity
# A complication arises because 'import' is a reserved keyword. # A complication arises because 'import' is a reserved keyword.
# Import it as 'Import' instead. # Import it as 'Import' instead.
globals()['Import'] = getattr(__import__('', globals(), locals(), globals()['Import'] = getattr(
[str('import')], 1), "import") __import__('', globals(), locals(), [str('import')], 1), "import")
__all__ = ['data', 'event', 'import', 'keysign', 'keylist', 'md', 'pk', __all__ = [
'protocol', 'sig', 'sigsum', 'status', 'tofu', 'validity', 'create'] 'data', 'event', 'import', 'keysign', 'keylist', 'md', 'pk', 'protocol',
'sig', 'sigsum', 'status', 'tofu', 'validity', 'create'
]
# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact. We # GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact. We
# implement gpg.Context.op_edit using gpgme_op_interact, so the # implement gpg.Context.op_edit using gpgme_op_interact, so the

View File

@ -1,4 +1,3 @@
from __future__ import absolute_import, print_function, unicode_literals from __future__ import absolute_import, print_function, unicode_literals
del absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals

View File

@ -1,4 +1,3 @@
from __future__ import absolute_import, print_function, unicode_literals from __future__ import absolute_import, print_function, unicode_literals
del absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals

View File

@ -1,4 +1,3 @@
from __future__ import absolute_import, print_function, unicode_literals from __future__ import absolute_import, print_function, unicode_literals
del absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals

View File

@ -14,8 +14,8 @@ from . import constants
from . import errors from . import errors
from . import util from . import util
# Copyright (C) 2016-2017 g10 Code GmbH # Copyright (C) 2016-2018 g10 Code GmbH
# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net> # Copyright (C) 2004, 2008 Igor Belyi <belyi@users.sourceforge.net>
# Copyright (C) 2002 John Goerzen <jgoerzen@complete.org> # Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
@ -31,7 +31,6 @@ from . import util
# You should have received a copy of the GNU Lesser General Public # You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Core functionality """Core functionality
Core functionality of GPGME wrapped in a object-oriented fashion. Core functionality of GPGME wrapped in a object-oriented fashion.
@ -53,8 +52,8 @@ class GpgmeWrapper(object):
self.wrapped = wrapped self.wrapped = wrapped
def __repr__(self): def __repr__(self):
return '<{}/{!r}>'.format(super(GpgmeWrapper, self).__repr__(), return '<{}/{!r}>'.format(
self.wrapped) super(GpgmeWrapper, self).__repr__(), self.wrapped)
def __str__(self): def __str__(self):
acc = ['{}.{}'.format(__name__, self.__class__.__name__)] acc = ['{}.{}'.format(__name__, self.__class__.__name__)]
@ -102,10 +101,8 @@ class GpgmeWrapper(object):
_boolean_properties = set() _boolean_properties = set()
def __wrap_boolean_property(self, key, do_set=False, value=None): def __wrap_boolean_property(self, key, do_set=False, value=None):
get_func = getattr(gpgme, get_func = getattr(gpgme, "{}get_{}".format(self._cprefix, key))
"{}get_{}".format(self._cprefix, key)) set_func = getattr(gpgme, "{}set_{}".format(self._cprefix, key))
set_func = getattr(gpgme,
"{}set_{}".format(self._cprefix, key))
def get(slf): def get(slf):
return bool(get_func(slf.wrapped)) return bool(get_func(slf.wrapped))
@ -135,12 +132,14 @@ class GpgmeWrapper(object):
func = getattr(gpgme, name) func = getattr(gpgme, name)
if self._errorcheck(name): if self._errorcheck(name):
def _funcwrap(slf, *args): def _funcwrap(slf, *args):
result = func(slf.wrapped, *args) result = func(slf.wrapped, *args)
if slf._callback_excinfo: if slf._callback_excinfo:
gpgme.gpg_raise_callback_exception(slf) gpgme.gpg_raise_callback_exception(slf)
return errorcheck(result, name) return errorcheck(result, name)
else: else:
def _funcwrap(slf, *args): def _funcwrap(slf, *args):
result = func(slf.wrapped, *args) result = func(slf.wrapped, *args)
if slf._callback_excinfo: if slf._callback_excinfo:
@ -156,6 +155,7 @@ class GpgmeWrapper(object):
# Bind the method to 'self'. # Bind the method to 'self'.
def wrapper(*args): def wrapper(*args):
return _funcwrap(self, *args) return _funcwrap(self, *args)
wrapper.__doc__ = doc wrapper.__doc__ = doc
return wrapper return wrapper
@ -181,10 +181,15 @@ class Context(GpgmeWrapper):
""" """
def __init__(self, armor=False, textmode=False, offline=False, def __init__(self,
signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT, armor=False,
textmode=False,
offline=False,
signers=[],
pinentry_mode=constants.PINENTRY_MODE_DEFAULT,
protocol=constants.PROTOCOL_OpenPGP, protocol=constants.PROTOCOL_OpenPGP,
wrapped=None, home_dir=None): wrapped=None,
home_dir=None):
"""Construct a context object """Construct a context object
Keyword arguments: Keyword arguments:
@ -226,16 +231,23 @@ class Context(GpgmeWrapper):
return data.read() return data.read()
def __repr__(self): def __repr__(self):
return ( return ("Context(armor={0.armor}, "
"Context(armor={0.armor}, "
"textmode={0.textmode}, offline={0.offline}, " "textmode={0.textmode}, offline={0.offline}, "
"signers={0.signers}, pinentry_mode={0.pinentry_mode}, " "signers={0.signers}, pinentry_mode={0.pinentry_mode}, "
"protocol={0.protocol}, home_dir={0.home_dir}" "protocol={0.protocol}, home_dir={0.home_dir}"
")").format(self) ")").format(self)
def encrypt(self, plaintext, recipients=[], sign=True, sink=None, def encrypt(self,
passphrase=None, always_trust=False, add_encrypt_to=False, plaintext,
prepare=False, expect_sign=False, compress=True): recipients=[],
sign=True,
sink=None,
passphrase=None,
always_trust=False,
add_encrypt_to=False,
prepare=False,
expect_sign=False,
compress=True):
"""Encrypt data """Encrypt data
Encrypt the given plaintext for the given recipients. If the Encrypt the given plaintext for the given recipients. If the
@ -282,6 +294,7 @@ class Context(GpgmeWrapper):
def passphrase_cb(hint, desc, prev_bad, hook=None): def passphrase_cb(hint, desc, prev_bad, hook=None):
return passphrase return passphrase
self.set_passphrase_cb(passphrase_cb) self.set_passphrase_cb(passphrase_cb)
try: try:
@ -292,17 +305,18 @@ class Context(GpgmeWrapper):
except errors.GPGMEError as e: except errors.GPGMEError as e:
result = self.op_encrypt_result() result = self.op_encrypt_result()
sig_result = self.op_sign_result() if sign else None sig_result = self.op_sign_result() if sign else None
results = (self.__read__(sink, ciphertext), results = (self.__read__(sink, ciphertext), result, sig_result)
result, sig_result)
if e.getcode() == errors.UNUSABLE_PUBKEY: if e.getcode() == errors.UNUSABLE_PUBKEY:
if result.invalid_recipients: if result.invalid_recipients:
raise errors.InvalidRecipients(result.invalid_recipients, raise errors.InvalidRecipients(
result.invalid_recipients,
error=e.error, error=e.error,
results=results) results=results)
if e.getcode() == errors.UNUSABLE_SECKEY: if e.getcode() == errors.UNUSABLE_SECKEY:
sig_result = self.op_sign_result() sig_result = self.op_sign_result()
if sig_result.invalid_signers: if sig_result.invalid_signers:
raise errors.InvalidSigners(sig_result.invalid_signers, raise errors.InvalidSigners(
sig_result.invalid_signers,
error=e.error, error=e.error,
results=results) results=results)
# Otherwise, just raise the error, but attach the results # Otherwise, just raise the error, but attach the results
@ -360,6 +374,7 @@ class Context(GpgmeWrapper):
def passphrase_cb(hint, desc, prev_bad, hook=None): def passphrase_cb(hint, desc, prev_bad, hook=None):
return passphrase return passphrase
self.set_passphrase_cb(passphrase_cb) self.set_passphrase_cb(passphrase_cb)
try: try:
@ -371,8 +386,7 @@ class Context(GpgmeWrapper):
result = self.op_decrypt_result() result = self.op_decrypt_result()
verify_result = self.op_verify_result() if verify else None verify_result = self.op_verify_result() if verify else None
# Just raise the error, but attach the results first. # Just raise the error, but attach the results first.
e.results = (self.__read__(sink, plaintext), e.results = (self.__read__(sink, plaintext), result, verify_result)
result, verify_result)
raise e raise e
finally: finally:
if passphrase is not None: if passphrase is not None:
@ -384,8 +398,8 @@ class Context(GpgmeWrapper):
verify_result = self.op_verify_result() if verify else None verify_result = self.op_verify_result() if verify else None
results = (self.__read__(sink, plaintext), result, verify_result) results = (self.__read__(sink, plaintext), result, verify_result)
if result.unsupported_algorithm: if result.unsupported_algorithm:
raise errors.UnsupportedAlgorithm(result.unsupported_algorithm, raise errors.UnsupportedAlgorithm(
results=results) result.unsupported_algorithm, results=results)
if verify: if verify:
if any(s.status != errors.NO_ERROR if any(s.status != errors.NO_ERROR
@ -408,8 +422,8 @@ class Context(GpgmeWrapper):
if not ok: if not ok:
missing.append(key) missing.append(key)
if missing: if missing:
raise errors.MissingSignatures(verify_result, missing, raise errors.MissingSignatures(
results=results) verify_result, missing, results=results)
return results return results
@ -441,11 +455,11 @@ class Context(GpgmeWrapper):
try: try:
self.op_sign(data, signeddata, mode) self.op_sign(data, signeddata, mode)
except errors.GPGMEError as e: except errors.GPGMEError as e:
results = (self.__read__(sink, signeddata), results = (self.__read__(sink, signeddata), self.op_sign_result())
self.op_sign_result())
if e.getcode() == errors.UNUSABLE_SECKEY: if e.getcode() == errors.UNUSABLE_SECKEY:
if results[1].invalid_signers: if results[1].invalid_signers:
raise errors.InvalidSigners(results[1].invalid_signers, raise errors.InvalidSigners(
results[1].invalid_signers,
error=e.error, error=e.error,
results=results) results=results)
e.results = results e.results = results
@ -491,8 +505,7 @@ class Context(GpgmeWrapper):
self.op_verify(signed_data, None, data) self.op_verify(signed_data, None, data)
except errors.GPGMEError as e: except errors.GPGMEError as e:
# Just raise the error, but attach the results first. # Just raise the error, but attach the results first.
e.results = (self.__read__(sink, data), e.results = (self.__read__(sink, data), self.op_verify_result())
self.op_verify_result())
raise e raise e
results = (self.__read__(sink, data), self.op_verify_result()) results = (self.__read__(sink, data), self.op_verify_result())
@ -514,8 +527,8 @@ class Context(GpgmeWrapper):
if not ok: if not ok:
missing.append(key) missing.append(key)
if missing: if missing:
raise errors.MissingSignatures(results[1], missing, raise errors.MissingSignatures(
results=results) results[1], missing, results=results)
return results return results
@ -676,7 +689,9 @@ class Context(GpgmeWrapper):
return result return result
def keylist(self, pattern=None, secret=False, def keylist(self,
pattern=None,
secret=False,
mode=constants.keylist.mode.LOCAL, mode=constants.keylist.mode.LOCAL,
source=None): source=None):
"""List keys """List keys
@ -711,9 +726,17 @@ class Context(GpgmeWrapper):
key = self.op_keylist_next() key = self.op_keylist_next()
self.op_keylist_end() self.op_keylist_end()
def create_key(self, userid, algorithm=None, expires_in=0, expires=True, def create_key(self,
sign=False, encrypt=False, certify=False, userid,
authenticate=False, passphrase=None, force=False): algorithm=None,
expires_in=0,
expires=True,
sign=False,
encrypt=False,
certify=False,
authenticate=False,
passphrase=None,
force=False):
"""Create a primary key """Create a primary key
Create a primary key for the user id USERID. Create a primary key for the user id USERID.
@ -769,19 +792,23 @@ class Context(GpgmeWrapper):
def passphrase_cb(hint, desc, prev_bad, hook=None): def passphrase_cb(hint, desc, prev_bad, hook=None):
return passphrase return passphrase
self.set_passphrase_cb(passphrase_cb) self.set_passphrase_cb(passphrase_cb)
try: try:
self.op_createkey(userid, algorithm, 0, # reserved self.op_createkey(
expires_in, None, # extrakey userid,
((constants.create.SIGN if sign else 0) algorithm,
| (constants.create.ENCR if encrypt else 0) 0, # reserved
| (constants.create.CERT if certify else 0) expires_in,
| (constants.create.AUTH if authenticate else 0) None, # extrakey
| (constants.create.NOPASSWD ((constants.create.SIGN if sign else 0) |
if passphrase is None else 0) (constants.create.ENCR if encrypt else 0) |
| (0 if expires else constants.create.NOEXPIRE) (constants.create.CERT if certify else 0) |
| (constants.create.FORCE if force else 0))) (constants.create.AUTH if authenticate else 0) |
(constants.create.NOPASSWD if passphrase is None else 0) |
(0 if expires else constants.create.NOEXPIRE) |
(constants.create.FORCE if force else 0)))
finally: finally:
if util.is_a_string(passphrase): if util.is_a_string(passphrase):
self.pinentry_mode = old_pinentry_mode self.pinentry_mode = old_pinentry_mode
@ -790,8 +817,14 @@ class Context(GpgmeWrapper):
return self.op_genkey_result() return self.op_genkey_result()
def create_subkey(self, key, algorithm=None, expires_in=0, expires=True, def create_subkey(self,
sign=False, encrypt=False, authenticate=False, key,
algorithm=None,
expires_in=0,
expires=True,
sign=False,
encrypt=False,
authenticate=False,
passphrase=None): passphrase=None):
"""Create a subkey """Create a subkey
@ -845,19 +878,20 @@ class Context(GpgmeWrapper):
def passphrase_cb(hint, desc, prev_bad, hook=None): def passphrase_cb(hint, desc, prev_bad, hook=None):
return passphrase return passphrase
self.set_passphrase_cb(passphrase_cb) self.set_passphrase_cb(passphrase_cb)
try: try:
self.op_createsubkey(key, algorithm, 0, # reserved self.op_createsubkey(
key,
algorithm,
0, # reserved
expires_in, expires_in,
((constants.create.SIGN if sign else 0) ((constants.create.SIGN if sign else 0) |
| (constants.create.ENCR if encrypt else 0) (constants.create.ENCR if encrypt else 0) |
| (constants.create.AUTH (constants.create.AUTH if authenticate else 0) |
if authenticate else 0) (constants.create.NOPASSWD if passphrase is None else 0) |
| (constants.create.NOPASSWD (0 if expires else constants.create.NOEXPIRE)))
if passphrase is None else 0)
| (0 if expires
else constants.create.NOEXPIRE)))
finally: finally:
if util.is_a_string(passphrase): if util.is_a_string(passphrase):
self.pinentry_mode = old_pinentry_mode self.pinentry_mode = old_pinentry_mode
@ -943,8 +977,11 @@ class Context(GpgmeWrapper):
""" """
self.op_tofu_policy(key, policy) self.op_tofu_policy(key, policy)
def assuan_transact(self, command, def assuan_transact(self,
data_cb=None, inquire_cb=None, status_cb=None): command,
data_cb=None,
inquire_cb=None,
status_cb=None):
"""Issue a raw assuan command """Issue a raw assuan command
This function can be used to issue a raw assuan command to the This function can be used to issue a raw assuan command to the
@ -975,12 +1012,10 @@ class Context(GpgmeWrapper):
errptr = gpgme.new_gpgme_error_t_p() errptr = gpgme.new_gpgme_error_t_p()
err = gpgme.gpgme_op_assuan_transact_ext( err = gpgme.gpgme_op_assuan_transact_ext(
self.wrapped, self.wrapped, cmd, (weakref.ref(self), data_cb)
cmd, if data_cb else None, (weakref.ref(self), inquire_cb)
(weakref.ref(self), data_cb) if data_cb else None, if inquire_cb else None, (weakref.ref(self), status_cb)
(weakref.ref(self), inquire_cb) if inquire_cb else None, if status_cb else None, errptr)
(weakref.ref(self), status_cb) if status_cb else None,
errptr)
if self._callback_excinfo: if self._callback_excinfo:
gpgme.gpg_raise_callback_exception(self) gpgme.gpg_raise_callback_exception(self)
@ -1019,8 +1054,8 @@ class Context(GpgmeWrapper):
else: else:
opaquedata = (weakref.ref(self), func) opaquedata = (weakref.ref(self), func)
result = gpgme.gpgme_op_interact(self.wrapped, key, flags, result = gpgme.gpgme_op_interact(self.wrapped, key, flags, opaquedata,
opaquedata, sink) sink)
if self._callback_excinfo: if self._callback_excinfo:
gpgme.gpg_raise_callback_exception(self) gpgme.gpg_raise_callback_exception(self)
errorcheck(result) errorcheck(result)
@ -1079,13 +1114,14 @@ class Context(GpgmeWrapper):
# $ grep '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \ # $ grep '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \
# | grep -v _op_ | awk "/\(gpgme_ctx/ { printf (\"'%s',\\n\", \$2) } " # | grep -v _op_ | awk "/\(gpgme_ctx/ { printf (\"'%s',\\n\", \$2) } "
return ((name.startswith('gpgme_op_') and not return ((name.startswith('gpgme_op_') and not
name.endswith('_result')) or name in name.endswith('_result')) or name in {
{'gpgme_new', 'gpgme_set_ctx_flag', 'gpgme_set_protocol', 'gpgme_new', 'gpgme_set_ctx_flag', 'gpgme_set_protocol',
'gpgme_set_sub_protocol', 'gpgme_set_keylist_mode', 'gpgme_set_sub_protocol', 'gpgme_set_keylist_mode',
'gpgme_set_pinentry_mode', 'gpgme_set_locale', 'gpgme_set_pinentry_mode', 'gpgme_set_locale',
'gpgme_ctx_set_engine_info', 'gpgme_signers_add', 'gpgme_ctx_set_engine_info', 'gpgme_signers_add',
'gpgme_sig_notation_add', 'gpgme_set_sender', 'gpgme_sig_notation_add', 'gpgme_set_sender',
'gpgme_cancel', 'gpgme_cancel_async', 'gpgme_get_key'}) 'gpgme_cancel', 'gpgme_cancel_async', 'gpgme_get_key'
})
_boolean_properties = {'armor', 'textmode', 'offline'} _boolean_properties = {'armor', 'textmode', 'offline'}
@ -1319,8 +1355,8 @@ class Context(GpgmeWrapper):
magic numbers will break as a result. magic numbers will break as a result.
""" """
warnings.warn("Call to deprecated method op_edit.", warnings.warn(
category=DeprecationWarning) "Call to deprecated method op_edit.", category=DeprecationWarning)
return self.interact(key, func, sink=out, fnc_value=fnc_value) return self.interact(key, func, sink=out, fnc_value=fnc_value)
@ -1362,8 +1398,13 @@ class Data(GpgmeWrapper):
'gpgme_data_identify', 'gpgme_data_identify',
} }
def __init__(self, string=None, file=None, offset=None, def __init__(self,
length=None, cbs=None, copy=True): string=None,
file=None,
offset=None,
length=None,
cbs=None,
copy=True):
"""Initialize a new gpgme_data_t object. """Initialize a new gpgme_data_t object.
If no args are specified, make it an empty object. If no args are specified, make it an empty object.
@ -1451,8 +1492,8 @@ class Data(GpgmeWrapper):
def new_from_mem(self, string, copy=True): def new_from_mem(self, string, copy=True):
tmp = gpgme.new_gpgme_data_t_p() tmp = gpgme.new_gpgme_data_t_p()
errorcheck(gpgme.gpgme_data_new_from_mem(tmp, string, len(string), errorcheck(
copy)) gpgme.gpgme_data_new_from_mem(tmp, string, len(string), copy))
self.wrapped = gpgme.gpgme_data_t_p_value(tmp) self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
gpgme.delete_gpgme_data_t_p(tmp) gpgme.delete_gpgme_data_t_p(tmp)
@ -1471,11 +1512,11 @@ class Data(GpgmeWrapper):
def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None): def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None):
tmp = gpgme.new_gpgme_data_t_p() tmp = gpgme.new_gpgme_data_t_p()
if hook is not None: if hook is not None:
hookdata = (weakref.ref(self), hookdata = (weakref.ref(self), read_cb, write_cb, seek_cb,
read_cb, write_cb, seek_cb, release_cb, hook) release_cb, hook)
else: else:
hookdata = (weakref.ref(self), hookdata = (weakref.ref(self), read_cb, write_cb, seek_cb,
read_cb, write_cb, seek_cb, release_cb) release_cb)
gpgme.gpg_data_new_from_cbs(self, hookdata, tmp) gpgme.gpg_data_new_from_cbs(self, hookdata, tmp)
self.wrapped = gpgme.gpgme_data_t_p_value(tmp) self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
gpgme.delete_gpgme_data_t_p(tmp) gpgme.delete_gpgme_data_t_p(tmp)
@ -1498,11 +1539,12 @@ class Data(GpgmeWrapper):
else: else:
fp = gpgme.fdopen(file.fileno(), file.mode) fp = gpgme.fdopen(file.fileno(), file.mode)
if fp is None: if fp is None:
raise ValueError("Failed to open file from %s arg %s" % raise ValueError("Failed to open file from %s arg %s" % (str(
(str(type(file)), str(file))) type(file)), str(file)))
errorcheck(gpgme.gpgme_data_new_from_filepart(tmp, filename, fp, errorcheck(
offset, length)) gpgme.gpgme_data_new_from_filepart(tmp, filename, fp, offset,
length))
self.wrapped = gpgme.gpgme_data_t_p_value(tmp) self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
gpgme.delete_gpgme_data_t_p(tmp) gpgme.delete_gpgme_data_t_p(tmp)
@ -1637,6 +1679,7 @@ def addrspec_from_uid(uid):
def check_version(version=None): def check_version(version=None):
return gpgme.gpgme_check_version(version) return gpgme.gpgme_check_version(version)
# check_version also makes sure that several subsystems are properly # check_version also makes sure that several subsystems are properly
# initialized, and it must be run at least once before invoking any # initialized, and it must be run at least once before invoking any
# other function. We do it here so that the user does not have to do # other function. We do it here so that the user does not have to do

View File

@ -30,6 +30,7 @@ EOF = None
util.process_constants('GPG_ERR_', globals()) util.process_constants('GPG_ERR_', globals())
del util del util
class GpgError(Exception): class GpgError(Exception):
"""A GPG Error """A GPG Error
@ -55,6 +56,7 @@ class GpgError(Exception):
exception objects. exception objects.
""" """
def __init__(self, error=None, context=None, results=None): def __init__(self, error=None, context=None, results=None):
self.error = error self.error = error
self.context = context self.context = context
@ -93,6 +95,7 @@ class GpgError(Exception):
msgs.append(self.code_str) msgs.append(self.code_str)
return ': '.join(msgs) return ': '.join(msgs)
class GPGMEError(GpgError): class GPGMEError(GpgError):
'''Generic error '''Generic error
@ -101,24 +104,30 @@ class GPGMEError(GpgError):
returns an error. This is the error that was used in PyME. returns an error. This is the error that was used in PyME.
''' '''
@classmethod @classmethod
def fromSyserror(cls): def fromSyserror(cls):
return cls(gpgme.gpgme_err_code_from_syserror()) return cls(gpgme.gpgme_err_code_from_syserror())
@property @property
def message(self): def message(self):
return self.context return self.context
def getstring(self): def getstring(self):
return str(self) return str(self)
def getcode(self): def getcode(self):
return self.code return self.code
def getsource(self): def getsource(self):
return self.source return self.source
def errorcheck(retval, extradata = None): def errorcheck(retval, extradata=None):
if retval: if retval:
raise GPGMEError(retval, extradata) raise GPGMEError(retval, extradata)
class KeyNotFound(GPGMEError, KeyError): class KeyNotFound(GPGMEError, KeyError):
"""Raised if a key was not found """Raised if a key was not found
@ -127,63 +136,76 @@ class KeyNotFound(GPGMEError, KeyError):
indicating EOF, and a KeyError. indicating EOF, and a KeyError.
""" """
def __init__(self, keystr): def __init__(self, keystr):
self.keystr = keystr self.keystr = keystr
GPGMEError.__init__(self, EOF) GPGMEError.__init__(self, EOF)
def __str__(self): def __str__(self):
return self.keystr return self.keystr
# These errors are raised in the idiomatic interface code. # These errors are raised in the idiomatic interface code.
class EncryptionError(GpgError): class EncryptionError(GpgError):
pass pass
class InvalidRecipients(EncryptionError): class InvalidRecipients(EncryptionError):
def __init__(self, recipients, **kwargs): def __init__(self, recipients, **kwargs):
EncryptionError.__init__(self, **kwargs) EncryptionError.__init__(self, **kwargs)
self.recipients = recipients self.recipients = recipients
def __str__(self): def __str__(self):
return ", ".join("{}: {}".format(r.fpr, return ", ".join("{}: {}".format(r.fpr, gpgme.gpgme_strerror(r.reason))
gpgme.gpgme_strerror(r.reason))
for r in self.recipients) for r in self.recipients)
class DeryptionError(GpgError): class DeryptionError(GpgError):
pass pass
class UnsupportedAlgorithm(DeryptionError): class UnsupportedAlgorithm(DeryptionError):
def __init__(self, algorithm, **kwargs): def __init__(self, algorithm, **kwargs):
DeryptionError.__init__(self, **kwargs) DeryptionError.__init__(self, **kwargs)
self.algorithm = algorithm self.algorithm = algorithm
def __str__(self): def __str__(self):
return self.algorithm return self.algorithm
class SigningError(GpgError): class SigningError(GpgError):
pass pass
class InvalidSigners(SigningError): class InvalidSigners(SigningError):
def __init__(self, signers, **kwargs): def __init__(self, signers, **kwargs):
SigningError.__init__(self, **kwargs) SigningError.__init__(self, **kwargs)
self.signers = signers self.signers = signers
def __str__(self): def __str__(self):
return ", ".join("{}: {}".format(s.fpr, return ", ".join("{}: {}".format(s.fpr, gpgme.gpgme_strerror(s.reason))
gpgme.gpgme_strerror(s.reason))
for s in self.signers) for s in self.signers)
class VerificationError(GpgError): class VerificationError(GpgError):
def __init__(self, result, **kwargs): def __init__(self, result, **kwargs):
GpgError.__init__(self, **kwargs) GpgError.__init__(self, **kwargs)
self.result = result self.result = result
class BadSignatures(VerificationError): class BadSignatures(VerificationError):
def __str__(self): def __str__(self):
return ", ".join("{}: {}".format(s.fpr, return ", ".join("{}: {}".format(s.fpr, gpgme.gpgme_strerror(s.status))
gpgme.gpgme_strerror(s.status))
for s in self.result.signatures for s in self.result.signatures
if s.status != NO_ERROR) if s.status != NO_ERROR)
class MissingSignatures(VerificationError): class MissingSignatures(VerificationError):
def __init__(self, result, missing, **kwargs): def __init__(self, result, missing, **kwargs):
VerificationError.__init__(self, result, **kwargs) VerificationError.__init__(self, result, **kwargs)
self.missing = missing self.missing = missing
def __str__(self): def __str__(self):
return ", ".join(k.subkeys[0].fpr for k in self.missing) return ", ".join(k.subkeys[0].fpr for k in self.missing)

View File

@ -19,7 +19,6 @@
from __future__ import absolute_import, print_function, unicode_literals from __future__ import absolute_import, print_function, unicode_literals
del absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals
"""Robust result objects """Robust result objects
Results returned by the underlying library are fragile, i.e. they are Results returned by the underlying library are fragile, i.e. they are
@ -30,23 +29,28 @@ therefore create deep copies of the results.
""" """
class Result(object): class Result(object):
"""Result object """Result object
Describes the result of an operation. Describes the result of an operation.
""" """
"""Convert to types""" """Convert to types"""
_type = {} _type = {}
"""Map functions over list attributes""" """Map functions over list attributes"""
_map = {} _map = {}
"""Automatically copy unless blacklisted""" """Automatically copy unless blacklisted"""
_blacklist = { _blacklist = {
'acquire', 'append', 'disown', 'next', 'own', 'this', 'thisown', 'acquire',
'append',
'disown',
'next',
'own',
'this',
'thisown',
} }
def __init__(self, fragile): def __init__(self, fragile):
for key, func in self._type.items(): for key, func in self._type.items():
if hasattr(fragile, key): if hasattr(fragile, key):
@ -67,52 +71,67 @@ class Result(object):
def __repr__(self): def __repr__(self):
return '{}({})'.format( return '{}({})'.format(
self.__class__.__name__, self.__class__.__name__,
', '.join('{}={!r}'.format(k, getattr(self, k)) ', '.join('{}={!r}'.format(k, getattr(self, k)) for k in dir(self)
for k in dir(self) if not k.startswith('_'))) if not k.startswith('_')))
class InvalidKey(Result): class InvalidKey(Result):
pass pass
class EncryptResult(Result): class EncryptResult(Result):
_map = dict(invalid_recipients=InvalidKey) _map = dict(invalid_recipients=InvalidKey)
class Recipient(Result): class Recipient(Result):
pass pass
class DecryptResult(Result): class DecryptResult(Result):
_type = dict(wrong_key_usage=bool, is_de_vs=bool) _type = dict(wrong_key_usage=bool, is_de_vs=bool)
_map = dict(recipients=Recipient) _map = dict(recipients=Recipient)
class NewSignature(Result): class NewSignature(Result):
pass pass
class SignResult(Result): class SignResult(Result):
_map = dict(invalid_signers=InvalidKey, signatures=NewSignature) _map = dict(invalid_signers=InvalidKey, signatures=NewSignature)
class Notation(Result): class Notation(Result):
pass pass
class Signature(Result): class Signature(Result):
_type = dict(wrong_key_usage=bool, chain_model=bool, is_de_vs=bool) _type = dict(wrong_key_usage=bool, chain_model=bool, is_de_vs=bool)
_map = dict(notations=Notation) _map = dict(notations=Notation)
class VerifyResult(Result): class VerifyResult(Result):
_map = dict(signatures=Signature) _map = dict(signatures=Signature)
class ImportStatus(Result): class ImportStatus(Result):
pass pass
class ImportResult(Result): class ImportResult(Result):
_map = dict(imports=ImportStatus) _map = dict(imports=ImportStatus)
class GenkeyResult(Result): class GenkeyResult(Result):
_type = dict(primary=bool, sub=bool) _type = dict(primary=bool, sub=bool)
class KeylistResult(Result): class KeylistResult(Result):
_type = dict(truncated=bool) _type = dict(truncated=bool)
class VFSMountResult(Result): class VFSMountResult(Result):
pass pass
class EngineInfo(Result): class EngineInfo(Result):
pass pass

View File

@ -21,6 +21,7 @@ del absolute_import, print_function, unicode_literals
import sys import sys
def process_constants(prefix, scope): def process_constants(prefix, scope):
"""Called by the constant modules to load up the constants from the C """Called by the constant modules to load up the constants from the C
library starting with PREFIX. Matching constants will be inserted library starting with PREFIX. Matching constants will be inserted
@ -30,18 +31,20 @@ def process_constants(prefix, scope):
""" """
from . import gpgme from . import gpgme
index = len(prefix) index = len(prefix)
constants = {identifier[index:]: getattr(gpgme, identifier) constants = {
for identifier in dir(gpgme) identifier[index:]: getattr(gpgme, identifier)
if identifier.startswith(prefix)} for identifier in dir(gpgme) if identifier.startswith(prefix)
}
scope.update(constants) scope.update(constants)
return list(constants.keys()) return list(constants.keys())
def percent_escape(s): def percent_escape(s):
return ''.join( return ''.join('%{0:2x}'.format(ord(c))
'%{0:2x}'.format(ord(c))
if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c
for c in s) for c in s)
# Python2/3 compatibility # Python2/3 compatibility
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
# Python3 # Python3