diff options
Diffstat (limited to 'lang/python')
| -rw-r--r-- | lang/python/gpgme.i | 13 | ||||
| -rw-r--r-- | lang/python/helpers.c | 65 | ||||
| -rw-r--r-- | lang/python/helpers.h | 2 | ||||
| -rw-r--r-- | lang/python/tests/Makefile.am | 3 | ||||
| -rwxr-xr-x | lang/python/tests/t-idiomatic.py | 47 | 
5 files changed, 127 insertions, 3 deletions
| diff --git a/lang/python/gpgme.i b/lang/python/gpgme.i index e3c761d4..e3695823 100644 --- a/lang/python/gpgme.i +++ b/lang/python/gpgme.i @@ -113,13 +113,17 @@  }  // Special handling for references to our objects. -%typemap(in) gpgme_data_t DATAIN { +%typemap(in) gpgme_data_t DATAIN (PyObject *wrapper) { +  /* If we create a temporary wrapper object, we will store it in +     wrapperN, where N is $argnum.  Here in this fragment, SWIG will +     automatically append $argnum.  */ +  wrapper = NULL;    if ($input == Py_None)      $1 = NULL;    else {      PyObject *pypointer = NULL; -    if((pypointer=object_to_gpgme_t($input, "$1_ltype", $argnum)) == NULL) +    if((pypointer=object_to_gpgme_data_t($input, $argnum, &wrapper)) == NULL)        return NULL;      /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */ @@ -135,6 +139,11 @@    }  } +%typemap(freearg) gpgme_data_t DATAIN { +  /* Free the temporary wrapper, if any.  */ +  Py_XDECREF(wrapper$argnum); +} +  %apply gpgme_data_t DATAIN {gpgme_data_t plain, gpgme_data_t cipher,  			gpgme_data_t sig, gpgme_data_t signed_text,  			gpgme_data_t plaintext, gpgme_data_t keydata, diff --git a/lang/python/helpers.c b/lang/python/helpers.c index 3ecbacc7..7e1c1c34 100644 --- a/lang/python/helpers.c +++ b/lang/python/helpers.c @@ -180,6 +180,71 @@ object_to_gpgme_t(PyObject *input, const char *objtype, int argnum)    return pypointer;  } +/* Convert object to a pointer to gpgme type, version for data +   objects.  Constructs a wrapper Python on the fly e.g. for file-like +   objects with a fileno method, returning it in WRAPPER.  This object +   must be de-referenced when no longer needed.  */ +PyObject * +object_to_gpgme_data_t(PyObject *input, int argnum, PyObject **wrapper) +{ +  static PyObject *Data = NULL; +  PyObject *data = input; +  PyObject *fd; +  PyObject *result; +  *wrapper = NULL; + +  if (Data == NULL) { +    PyObject *core; +    PyObject *from_list = PyList_New(0); +    core = PyImport_ImportModuleLevel("core", PyEval_GetGlobals(), +                                      PyEval_GetLocals(), from_list, 1); +    Py_XDECREF(from_list); +    if (core) { +      Data = PyDict_GetItemString(PyModule_GetDict(core), "Data"); +      Py_XINCREF(Data); +    } +    else +      return NULL; +  } + +  fd = PyObject_CallMethod(input, "fileno", NULL); +  if (fd) { +    /* File-like object with file number.  */ +    PyObject *args = NULL; +    PyObject *kw = NULL; + +    /* We don't need the fd, as we have no constructor accepting file +       descriptors directly.  */ +    Py_DECREF(fd); + +    args = PyTuple_New(0); +    kw = PyDict_New(); +    if (args == NULL || kw == NULL) +      { +      fail: +        Py_XDECREF(args); +        Py_XDECREF(kw); +        return NULL; +      } + +    if (PyDict_SetItemString(kw, "file", input) < 0) +      goto fail; + +    *wrapper = PyObject_Call(Data, args, kw); +    if (*wrapper == NULL) +      goto fail; + +    Py_DECREF(args); +    Py_DECREF(kw); +    data = *wrapper; +  } +  else +    PyErr_Clear(); + +  result = object_to_gpgme_t(data, "gpgme_data_t", argnum); +  return result; +} +  /* Callback support.  */ diff --git a/lang/python/helpers.h b/lang/python/helpers.h index 952b31f2..24502631 100644 --- a/lang/python/helpers.h +++ b/lang/python/helpers.h @@ -29,6 +29,8 @@ void pygpgme_exception_init(void);  gpgme_error_t pygpgme_exception2code(void);  PyObject *object_to_gpgme_t(PyObject *input, const char *objtype, int argnum); +PyObject *object_to_gpgme_data_t(PyObject *input, int argnum, +				 PyObject **wrapper);  void pygpgme_clear_generic_cb(PyObject **cb);  PyObject *pygpgme_raise_callback_exception(PyObject *self); diff --git a/lang/python/tests/Makefile.am b/lang/python/tests/Makefile.am index 12db3a57..b51562cc 100644 --- a/lang/python/tests/Makefile.am +++ b/lang/python/tests/Makefile.am @@ -46,7 +46,8 @@ py_tests = t-wrapper.py \  	t-edit.py \  	t-wait.py \  	t-encrypt-large.py \ -	t-file-name.py +	t-file-name.py \ +	t-idiomatic.py  TESTS = $(top_srcdir)/tests/gpg/initial.test \  	$(py_tests) \ diff --git a/lang/python/tests/t-idiomatic.py b/lang/python/tests/t-idiomatic.py new file mode 100755 index 00000000..05a377e4 --- /dev/null +++ b/lang/python/tests/t-idiomatic.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2016 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General +# Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +import os +import tempfile +from pyme import core, constants, errors +import support + +support.init_gpgme(constants.PROTOCOL_OpenPGP) +c = core.Context() + +# Demonstrate automatic wrapping of file-like objects with 'fileno' +# method. +with tempfile.TemporaryFile() as source, \ +     tempfile.TemporaryFile() as signed, \ +     tempfile.TemporaryFile() as sink: +    source.write(b"Hallo Leute\n") +    source.seek(0, os.SEEK_SET) + +    c.op_sign(source, signed, constants.SIG_MODE_NORMAL) +    signed.seek(0, os.SEEK_SET) +    c.op_verify(signed, None, sink) +    result = c.op_verify_result() + +    assert len(result.signatures) == 1, "Unexpected number of signatures" +    sig = result.signatures[0] +    assert sig.summary == 0 +    assert errors.GPGMEError(sig.status).getcode() == errors.NO_ERROR + +    sink.seek(0, os.SEEK_SET) +    assert sink.read() == b"Hallo Leute\n" | 
