[Pkg-gnupg-commit] [gpgme] 160/412: python: Wrap file-like objects on demand.

Daniel Kahn Gillmor dkg at fifthhorseman.net
Thu Sep 22 21:26:38 UTC 2016


This is an automated email from the git hooks/post-receive script.

dkg pushed a commit to branch master
in repository gpgme.

commit 8196edf9ca5c8f2f02553e7f22d9c79dbd229882
Author: Justus Winter <justus at g10code.com>
Date:   Mon Jun 6 13:11:15 2016 +0200

    python: Wrap file-like objects on demand.
    
    * lang/python/gpgme.i (gpgme_data_t): Use new function to create
    wrapper objects if necessary, and deallocate them after the function
    call.
    * lang/python/helpers.c (object_to_gpgme_data_t): New function.
    * lang/python/helpers.h (object_to_gpgme_data_t): New prototype.
    * lang/python/tests/Makefile.am (pytests): Add new test.
    * lang/python/tests/t-idiomatic.py: New file.
    
    Signed-off-by: Justus Winter <justus at g10code.com>
---
 lang/python/gpgme.i              | 13 ++++++--
 lang/python/helpers.c            | 65 ++++++++++++++++++++++++++++++++++++++++
 lang/python/helpers.h            |  2 ++
 lang/python/tests/Makefile.am    |  3 +-
 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 e3c761d..e369582 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 3ecbacc..7e1c1c3 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 952b31f..2450263 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 12db3a5..b51562c 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 0000000..05a377e
--- /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"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gpgme.git



More information about the Pkg-gnupg-commit mailing list