diff --git a/lang/python/examples/simple.py b/lang/python/examples/simple.py index 739291ed..4ff6d285 100755 --- a/lang/python/examples/simple.py +++ b/lang/python/examples/simple.py @@ -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()) diff --git a/lang/python/gpgme.i b/lang/python/gpgme.i index 87efce73..7c11943c 100644 --- a/lang/python/gpgme.i +++ b/lang/python/gpgme.i @@ -24,16 +24,18 @@ // 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; } @@ -49,20 +51,27 @@ 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); } } diff --git a/lang/python/pyme/core.py b/lang/python/pyme/core.py index 09f0fa88..fd4802ec 100644 --- a/lang/python/pyme/core.py +++ b/lang/python/pyme/core.py @@ -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)