python: Fix type translation.

* 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>
This commit is contained in:
Justus Winter 2016-05-12 11:21:58 +02:00
parent bbeee5e1a0
commit d60deb8a12
3 changed files with 41 additions and 27 deletions

View File

@ -25,7 +25,7 @@ core.check_version(None)
# Set up our input and output buffers. # 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() cipher = core.Data()
# Initialize our context. # Initialize our context.
@ -38,7 +38,7 @@ c.set_armor(1)
sys.stdout.write("Enter name of your recipient: ") sys.stdout.write("Enter name of your recipient: ")
sys.stdout.flush() sys.stdout.flush()
name = sys.stdin.readline().strip() name = sys.stdin.readline().strip()
c.op_keylist_start(name.encode(), 0) c.op_keylist_start(name, 0)
r = c.op_keylist_next() r = c.op_keylist_next()
if r == None: if r == None:
@ -48,6 +48,6 @@ else:
try: try:
c.op_encrypt([r], 1, plain, cipher) c.op_encrypt([r], 1, plain, cipher)
cipher.seek(0,0) cipher.seek(0,0)
print(cipher.read()) sys.stdout.buffer.write(cipher.read())
except errors.GPGMEError as ex: except errors.GPGMEError as ex:
print(ex.getstring()) print(ex.getstring())

View File

@ -24,16 +24,18 @@
// Generate doc strings for all methods. // Generate doc strings for all methods.
%feature("autodoc", "0"); %feature("autodoc", "0");
// Allow use of None for strings. /* Allow use of Unicode objects, bytes, and None for strings. */
%typemap(in) const char * { %typemap(in) const char * {
if ($input == Py_None) if ($input == Py_None)
$1 = NULL; $1 = NULL;
else if (PyUnicode_Check($input))
$1 = PyUnicode_AsUTF8($input);
else if (PyBytes_Check($input)) else if (PyBytes_Check($input))
$1 = PyBytes_AsString($input); $1 = PyBytes_AsString($input);
else { else {
PyErr_Format(PyExc_TypeError, 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); $argnum, $input->ob_type->tp_name);
return NULL; return NULL;
} }
@ -49,20 +51,27 @@
PyObject* object_to_gpgme_t(PyObject* input, const char* objtype, int argnum) { PyObject* object_to_gpgme_t(PyObject* input, const char* objtype, int argnum) {
PyObject *pyname = NULL, *pypointer = NULL; PyObject *pyname = NULL, *pypointer = NULL;
pyname = PyObject_CallMethod(input, "_getctype", NULL); pyname = PyObject_CallMethod(input, "_getctype", NULL);
if (pyname == NULL) { if (pyname && PyUnicode_Check(pyname))
PyErr_Format(PyExc_TypeError, {
"arg %d: Expected an instance of type %s, but got %s", if (strcmp(PyUnicode_AsUTF8(pyname), objtype) != 0)
argnum, objtype, {
input == Py_None ? "None" : input->ob_type->tp_name); PyErr_Format(PyExc_TypeError,
return NULL; "arg %d: Expected value of type %s, but got %s",
} argnum, objtype, PyUnicode_AsUTF8(pyname));
if (strcmp(PyBytes_AsString(pyname), objtype) != 0) { Py_DECREF(pyname);
PyErr_Format(PyExc_TypeError, return NULL;
"arg %d: Expected value of type %s, but got %s", }
argnum, objtype, PyBytes_AsString(pyname)); }
Py_DECREF(pyname); else
return NULL; {
} 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); Py_DECREF(pyname);
pypointer = PyObject_GetAttrString(input, "wrapped"); pypointer = PyObject_GetAttrString(input, "wrapped");
if (pypointer == NULL) { 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, 0, PyLong_FromLong((long) status));
PyTuple_SetItem(pyargs, 1, PyBytes_FromString(args)); PyTuple_SetItem(pyargs, 1, PyUnicode_FromString(args));
if (dataarg) { if (dataarg) {
Py_INCREF(dataarg); /* Because GetItem doesn't give a ref but SetItem taketh away */ Py_INCREF(dataarg); /* Because GetItem doesn't give a ref but SetItem taketh away */
PyTuple_SetItem(pyargs, 2, dataarg); PyTuple_SetItem(pyargs, 2, dataarg);
@ -254,8 +263,12 @@ gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
if (PyErr_Occurred()) { if (PyErr_Occurred()) {
err_status = pygpgme_exception2code(); err_status = pygpgme_exception2code();
} else { } else {
if (fd>=0 && retval) { if (fd>=0 && retval && PyUnicode_Check(retval)) {
write(fd, PyBytes_AsString(retval), PyBytes_Size(retval)); const char *buffer;
Py_ssize_t size;
buffer = PyUnicode_AsUTF8AndSize(retval, &size);
write(fd, buffer, size);
write(fd, "\n", 1); write(fd, "\n", 1);
} }
} }

View File

@ -377,10 +377,11 @@ class Data(GpgmeWrapper):
self.new_from_fd(file) self.new_from_fd(file)
def write(self, buffer): def write(self, buffer):
"""Write buffer given as bytes."""
errorcheck(pygpgme.gpgme_data_write(self.wrapped, buffer, len(buffer))) errorcheck(pygpgme.gpgme_data_write(self.wrapped, buffer, len(buffer)))
def read(self, size = -1): 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. If the size argument is negative or omitted, read until EOF is reached.
@ -393,13 +394,13 @@ class Data(GpgmeWrapper):
if size > 0: if size > 0:
return pygpgme.gpgme_data_read(self.wrapped, size) return pygpgme.gpgme_data_read(self.wrapped, size)
else: else:
retval = '' chunks = []
while 1: while 1:
result = pygpgme.gpgme_data_read(self.wrapped, 10240) result = pygpgme.gpgme_data_read(self.wrapped, 4096)
if len(result) == 0: if len(result) == 0:
break break
retval += result chunks.append(result)
return retval return b''.join(chunks)
def pubkey_algo_name(algo): def pubkey_algo_name(algo):
return pygpgme.gpgme_pubkey_algo_name(algo) return pygpgme.gpgme_pubkey_algo_name(algo)