python: Fix type translation.
authorJustus Winter <justus@gnupg.org>
Thu, 12 May 2016 09:21:58 +0000 (11:21 +0200)
committerJustus Winter <justus@gnupg.org>
Thu, 12 May 2016 09:49:17 +0000 (11:49 +0200)
* lang/python/gpgme.i: Adjust to Python3's string type being
'Unicode', not 'bytes'.  Fix type checking.
* lang/python/core.py (Data.write): Add docstring mentioning the
expected type of parameter 'buffer'.
(Data.read): Adjust read loop.  Also, use a saner chunk size, and join
all chunks at the end instead of adding them.
* lang/python/examples/simple.py: Adjust example.

Signed-off-by: Justus Winter <justus@gnupg.org>
lang/python/examples/simple.py
lang/python/gpgme.i
lang/python/pyme/core.py

index 739291e..4ff6d28 100755 (executable)
@@ -25,7 +25,7 @@ core.check_version(None)
 
 # Set up our input and output buffers.
 
-plain = core.Data(b'This is my message.')
+plain = core.Data('This is my message.')
 cipher = core.Data()
 
 # Initialize our context.
@@ -38,7 +38,7 @@ c.set_armor(1)
 sys.stdout.write("Enter name of your recipient: ")
 sys.stdout.flush()
 name = sys.stdin.readline().strip()
-c.op_keylist_start(name.encode(), 0)
+c.op_keylist_start(name, 0)
 r = c.op_keylist_next()
 
 if r == None:
@@ -48,6 +48,6 @@ else:
     try:
         c.op_encrypt([r], 1, plain, cipher)
         cipher.seek(0,0)
-        print(cipher.read())
+        sys.stdout.buffer.write(cipher.read())
     except errors.GPGMEError as ex:
         print(ex.getstring())
index 87efce7..7c11943 100644 (file)
 // Generate doc strings for all methods.
 %feature("autodoc", "0");
 
-// Allow use of None for strings.
+/* Allow use of Unicode objects, bytes, and None for strings.  */
 
 %typemap(in) const char * {
   if ($input == Py_None)
     $1 = NULL;
+  else if (PyUnicode_Check($input))
+    $1 = PyUnicode_AsUTF8($input);
   else if (PyBytes_Check($input))
     $1 = PyBytes_AsString($input);
   else {
     PyErr_Format(PyExc_TypeError,
-                 "arg %d: expected string or None, got %s",
+                 "arg %d: expected str, bytes, or None, got %s",
                 $argnum, $input->ob_type->tp_name);
     return NULL;
   }
 PyObject* object_to_gpgme_t(PyObject* input, const char* objtype, int argnum) {
   PyObject *pyname = NULL, *pypointer = NULL;
   pyname = PyObject_CallMethod(input, "_getctype", NULL);
-  if (pyname == NULL) {
-    PyErr_Format(PyExc_TypeError,
-                "arg %d: Expected an instance of type %s, but got %s",
-                argnum, objtype,
-                input == Py_None ? "None" : input->ob_type->tp_name);
-    return NULL;
-  }
-  if (strcmp(PyBytes_AsString(pyname), objtype) != 0) {
-    PyErr_Format(PyExc_TypeError,
-                "arg %d: Expected value of type %s, but got %s",
-                argnum, objtype, PyBytes_AsString(pyname));
-    Py_DECREF(pyname);
-    return NULL;
-  }
+  if (pyname && PyUnicode_Check(pyname))
+    {
+      if (strcmp(PyUnicode_AsUTF8(pyname), objtype) != 0)
+        {
+          PyErr_Format(PyExc_TypeError,
+                       "arg %d: Expected value of type %s, but got %s",
+                       argnum, objtype, PyUnicode_AsUTF8(pyname));
+          Py_DECREF(pyname);
+          return NULL;
+        }
+    }
+  else
+    {
+      PyErr_Format(PyExc_TypeError,
+                   "Protocol violation: Expected an instance of type str "
+                   "from _getctype, but got %s",
+                   pyname == NULL ? "NULL"
+                   : (pyname == Py_None ? "None" : pyname->ob_type->tp_name));
+      return NULL;
+    }
+
   Py_DECREF(pyname);
   pypointer = PyObject_GetAttrString(input, "wrapped");
   if (pypointer == NULL) {
@@ -243,7 +252,7 @@ gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
   }
 
   PyTuple_SetItem(pyargs, 0, PyLong_FromLong((long) status));
-  PyTuple_SetItem(pyargs, 1, PyBytes_FromString(args));
+  PyTuple_SetItem(pyargs, 1, PyUnicode_FromString(args));
   if (dataarg) {
     Py_INCREF(dataarg);                /* Because GetItem doesn't give a ref but SetItem taketh away */
     PyTuple_SetItem(pyargs, 2, dataarg);
@@ -254,8 +263,12 @@ gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
   if (PyErr_Occurred()) {
     err_status = pygpgme_exception2code();
   } else {
-    if (fd>=0 && retval) {
-      write(fd, PyBytes_AsString(retval), PyBytes_Size(retval));
+    if (fd>=0 && retval && PyUnicode_Check(retval)) {
+      const char *buffer;
+      Py_ssize_t size;
+
+      buffer = PyUnicode_AsUTF8AndSize(retval, &size);
+      write(fd, buffer, size);
       write(fd, "\n", 1);
     }
   }
index 09f0fa8..fd4802e 100644 (file)
@@ -377,10 +377,11 @@ class Data(GpgmeWrapper):
         self.new_from_fd(file)
 
     def write(self, buffer):
+        """Write buffer given as bytes."""
         errorcheck(pygpgme.gpgme_data_write(self.wrapped, buffer, len(buffer)))
 
     def read(self, size = -1):
-        """Read at most size bytes, returned as a string.
+        """Read at most size bytes, returned as bytes.
 
         If the size argument is negative or omitted, read until EOF is reached.
 
@@ -393,13 +394,13 @@ class Data(GpgmeWrapper):
         if size > 0:
             return pygpgme.gpgme_data_read(self.wrapped, size)
         else:
-            retval = ''
+            chunks = []
             while 1:
-                result = pygpgme.gpgme_data_read(self.wrapped, 10240)
+                result = pygpgme.gpgme_data_read(self.wrapped, 4096)
                 if len(result) == 0:
                     break
-                retval += result
-            return retval
+                chunks.append(result)
+            return b''.join(chunks)
 
 def pubkey_algo_name(algo):
     return pygpgme.gpgme_pubkey_algo_name(algo)