python: Support status callbacks.
* lang/python/helpers.c (pyStatusCb): New function. (pygpgme_set_status_cb): Likewise. * lang/python/helpers.h (pygpgme_set_status_cb): New prototype. * lang/python/pyme/core.py (Context.__init__): Initialize 'last_statuscb'. (Context._free_statuscb): New function. (Context.set_status_cb): Likewise. * lang/python/tests/t-callbacks.py: Test status callbacks. Signed-off-by: Justus Winter <justus@gnupg.org>
This commit is contained in:
parent
72afb68f8c
commit
8b57f06e0c
@ -272,7 +272,72 @@ void pygpgme_set_progress_cb(gpgme_ctx_t ctx, PyObject *cb, PyObject **freelater
|
|||||||
*freelater = cb;
|
*freelater = cb;
|
||||||
gpgme_set_progress_cb(ctx, (gpgme_progress_cb_t) pyProgressCb, (void *) cb);
|
gpgme_set_progress_cb(ctx, (gpgme_progress_cb_t) pyProgressCb, (void *) cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Status callbacks. */
|
||||||
|
static gpgme_error_t pyStatusCb(void *hook, const char *keyword,
|
||||||
|
const char *args) {
|
||||||
|
gpgme_error_t err = 0;
|
||||||
|
PyObject *pyhook = (PyObject *) hook;
|
||||||
|
PyObject *self = NULL;
|
||||||
|
PyObject *func = NULL;
|
||||||
|
PyObject *dataarg = NULL;
|
||||||
|
PyObject *pyargs = NULL;
|
||||||
|
PyObject *retval = NULL;
|
||||||
|
|
||||||
|
assert (PyTuple_Check(pyhook));
|
||||||
|
assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
|
||||||
|
self = PyTuple_GetItem(pyhook, 0);
|
||||||
|
func = PyTuple_GetItem(pyhook, 1);
|
||||||
|
if (PyTuple_Size(pyhook) == 3) {
|
||||||
|
dataarg = PyTuple_GetItem(pyhook, 2);
|
||||||
|
pyargs = PyTuple_New(3);
|
||||||
|
} else {
|
||||||
|
pyargs = PyTuple_New(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyword)
|
||||||
|
PyTuple_SetItem(pyargs, 0, PyUnicode_DecodeUTF8(keyword, strlen (keyword),
|
||||||
|
"strict"));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
PyTuple_SetItem(pyargs, 0, Py_None);
|
||||||
|
}
|
||||||
|
PyTuple_SetItem(pyargs, 1, PyUnicode_DecodeUTF8(args, strlen (args),
|
||||||
|
"strict"));
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
err = gpg_error(GPG_ERR_GENERAL);
|
||||||
|
Py_DECREF(pyargs);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataarg) {
|
||||||
|
Py_INCREF(dataarg);
|
||||||
|
PyTuple_SetItem(pyargs, 2, dataarg);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = PyObject_CallObject(func, pyargs);
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
err = pygpgme_exception2code();
|
||||||
|
Py_DECREF(pyargs);
|
||||||
|
Py_XDECREF(retval);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (err)
|
||||||
|
pygpgme_stash_callback_exception(self);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pygpgme_set_status_cb(gpgme_ctx_t ctx, PyObject *cb,
|
||||||
|
PyObject **freelater) {
|
||||||
|
if (cb == Py_None) {
|
||||||
|
gpgme_set_status_cb(ctx, NULL, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Py_INCREF(cb);
|
||||||
|
*freelater = cb;
|
||||||
|
gpgme_set_status_cb(ctx, (gpgme_status_cb_t) pyStatusCb, (void *) cb);
|
||||||
|
}
|
||||||
|
|
||||||
/* Edit callbacks. */
|
/* Edit callbacks. */
|
||||||
gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
|
gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
|
||||||
|
@ -35,6 +35,8 @@ PyObject *pygpgme_raise_callback_exception(PyObject *self);
|
|||||||
void pygpgme_set_passphrase_cb(gpgme_ctx_t ctx, PyObject *cb,
|
void pygpgme_set_passphrase_cb(gpgme_ctx_t ctx, PyObject *cb,
|
||||||
PyObject **freelater);
|
PyObject **freelater);
|
||||||
void pygpgme_set_progress_cb(gpgme_ctx_t ctx, PyObject *cb, PyObject **freelater);
|
void pygpgme_set_progress_cb(gpgme_ctx_t ctx, PyObject *cb, PyObject **freelater);
|
||||||
|
void pygpgme_set_status_cb(gpgme_ctx_t ctx, PyObject *cb,
|
||||||
|
PyObject **freelater);
|
||||||
|
|
||||||
gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
|
gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
|
||||||
const char *args, int fd);
|
const char *args, int fd);
|
||||||
|
@ -64,6 +64,7 @@ class Context(GpgmeWrapper):
|
|||||||
super().__init__(wrapped)
|
super().__init__(wrapped)
|
||||||
self.last_passcb = None
|
self.last_passcb = None
|
||||||
self.last_progresscb = None
|
self.last_progresscb = None
|
||||||
|
self.last_statuscb = None
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
if not pygpgme:
|
if not pygpgme:
|
||||||
@ -91,6 +92,14 @@ class Context(GpgmeWrapper):
|
|||||||
pygpgme.delete_PyObject_p_p(self.last_progresscb)
|
pygpgme.delete_PyObject_p_p(self.last_progresscb)
|
||||||
self.last_progresscb = None
|
self.last_progresscb = None
|
||||||
|
|
||||||
|
def _free_statuscb(self):
|
||||||
|
if self.last_statuscb != None:
|
||||||
|
if pygpgme.pygpgme_clear_generic_cb:
|
||||||
|
pygpgme.pygpgme_clear_generic_cb(self.last_statuscb)
|
||||||
|
if pygpgme.delete_PyObject_p_p:
|
||||||
|
pygpgme.delete_PyObject_p_p(self.last_statuscb)
|
||||||
|
self.last_statuscb = None
|
||||||
|
|
||||||
def op_keylist_all(self, *args, **kwargs):
|
def op_keylist_all(self, *args, **kwargs):
|
||||||
self.op_keylist_start(*args, **kwargs)
|
self.op_keylist_start(*args, **kwargs)
|
||||||
key = self.op_keylist_next()
|
key = self.op_keylist_next()
|
||||||
@ -195,6 +204,29 @@ class Context(GpgmeWrapper):
|
|||||||
hookdata = (self, func, hook)
|
hookdata = (self, func, hook)
|
||||||
pygpgme.pygpgme_set_progress_cb(self.wrapped, hookdata, self.last_progresscb)
|
pygpgme.pygpgme_set_progress_cb(self.wrapped, hookdata, self.last_progresscb)
|
||||||
|
|
||||||
|
def set_status_cb(self, func, hook=None):
|
||||||
|
"""Sets the status callback to the function specified by FUNC. If
|
||||||
|
FUNC is None, the callback will be cleared.
|
||||||
|
|
||||||
|
The function will be called with two arguments, keyword and
|
||||||
|
args. If HOOK is not None, it will be supplied as third
|
||||||
|
argument.
|
||||||
|
|
||||||
|
Please see the GPGME manual for more information.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._free_statuscb()
|
||||||
|
if func == None:
|
||||||
|
hookdata = None
|
||||||
|
else:
|
||||||
|
self.last_statuscb = pygpgme.new_PyObject_p_p()
|
||||||
|
if hook == None:
|
||||||
|
hookdata = (self, func)
|
||||||
|
else:
|
||||||
|
hookdata = (self, func, hook)
|
||||||
|
pygpgme.pygpgme_set_status_cb(self.wrapped, hookdata,
|
||||||
|
self.last_statuscb)
|
||||||
|
|
||||||
def get_engine_info(self):
|
def get_engine_info(self):
|
||||||
"""Returns this context specific engine info"""
|
"""Returns this context specific engine info"""
|
||||||
return pygpgme.gpgme_ctx_get_engine_info(self.wrapped)
|
return pygpgme.gpgme_ctx_get_engine_info(self.wrapped)
|
||||||
|
@ -146,3 +146,38 @@ except Exception as e:
|
|||||||
assert e == myException
|
assert e == myException
|
||||||
else:
|
else:
|
||||||
assert False, "Expected an error, got none"
|
assert False, "Expected an error, got none"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Test the status callback.
|
||||||
|
source = core.Data("Hallo Leute\n")
|
||||||
|
sink = core.Data()
|
||||||
|
|
||||||
|
status_cb_called = False
|
||||||
|
def status_cb(keyword, args, hook=None):
|
||||||
|
global status_cb_called
|
||||||
|
status_cb_called = True
|
||||||
|
assert hook == cookie
|
||||||
|
|
||||||
|
c = core.Context()
|
||||||
|
c.set_status_cb(status_cb, cookie)
|
||||||
|
c.set_ctx_flag("full-status", "1")
|
||||||
|
c.op_encrypt([alpha], constants.ENCRYPT_ALWAYS_TRUST, source, sink)
|
||||||
|
assert status_cb_called
|
||||||
|
|
||||||
|
# Test exceptions.
|
||||||
|
source = core.Data("Hallo Leute\n")
|
||||||
|
sink = core.Data()
|
||||||
|
|
||||||
|
def status_cb(keyword, args):
|
||||||
|
raise myException
|
||||||
|
|
||||||
|
c = core.Context()
|
||||||
|
c.set_status_cb(status_cb, None)
|
||||||
|
c.set_ctx_flag("full-status", "1")
|
||||||
|
try:
|
||||||
|
c.op_encrypt([alpha], constants.ENCRYPT_ALWAYS_TRUST, source, sink)
|
||||||
|
except Exception as e:
|
||||||
|
assert e == myException
|
||||||
|
else:
|
||||||
|
assert False, "Expected an error, got none"
|
||||||
|
Loading…
Reference in New Issue
Block a user