python: Handle slight differences between Python 2 and 3.
* lang/python/helpers.c (pyDataWriteCb): Handle Python integers being returned on Python 2. (pyDataSeekCb): Likewise. * lang/python/pyme/core.py (Data.__init__): Fix testing for string argument. (Data.new_from_filepart): Likewise. * lang/python/pyme/util.py (is_a_string): New function. * lang/python/tests/t-encrypt-large.py (read_cb): Force evaluation of generator. * lang/python/tests/t-idiomatic.py: Partly skip test on Python 2. * lang/python/tests/t-verify.py (check_result): Here, the difference between 2 and 3 really matters. We cannot change the char * conversion in Python 2 without breaking all existing applications, and using bytestrings in Python 3 would be very inconvenient. Signed-off-by: Justus Winter <justus@g10code.com>
This commit is contained in:
parent
4abff7d750
commit
70a3be27a5
@ -833,17 +833,21 @@ static ssize_t pyDataWriteCb(void *hook, const void *buffer, size_t size)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! PyLong_Check(retval)) {
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
if (PyInt_Check(retval))
|
||||||
|
result = PyInt_AsSsize_t(retval);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (PyLong_Check(retval))
|
||||||
|
result = PyLong_AsSsize_t(retval);
|
||||||
|
else {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"expected int from read callback, got %s",
|
"expected int from write callback, got %s",
|
||||||
retval->ob_type->tp_name);
|
retval->ob_type->tp_name);
|
||||||
_pyme_stash_callback_exception(self);
|
_pyme_stash_callback_exception(self);
|
||||||
result = -1;
|
result = -1;
|
||||||
goto leave;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = PyLong_AsSsize_t(retval);
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
Py_XDECREF(retval);
|
Py_XDECREF(retval);
|
||||||
return result;
|
return result;
|
||||||
@ -894,21 +898,25 @@ static off_t pyDataSeekCb(void *hook, off_t offset, int whence)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! PyLong_Check(retval)) {
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
if (PyInt_Check(retval))
|
||||||
|
result = PyInt_AsLong(retval);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (PyLong_Check(retval))
|
||||||
|
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
|
||||||
|
result = PyLong_AsLongLong(retval);
|
||||||
|
#else
|
||||||
|
result = PyLong_AsLong(retval);
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"expected int from read callback, got %s",
|
"expected int from seek callback, got %s",
|
||||||
retval->ob_type->tp_name);
|
retval->ob_type->tp_name);
|
||||||
_pyme_stash_callback_exception(self);
|
_pyme_stash_callback_exception(self);
|
||||||
result = -1;
|
result = -1;
|
||||||
goto leave;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
|
|
||||||
result = PyLong_AsLongLong(retval);
|
|
||||||
#else
|
|
||||||
result = PyLong_AsLong(retval);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
Py_XDECREF(retval);
|
Py_XDECREF(retval);
|
||||||
return result;
|
return result;
|
||||||
|
@ -884,7 +884,7 @@ class Data(GpgmeWrapper):
|
|||||||
elif file != None and offset != None and length != None:
|
elif file != None and offset != None and length != None:
|
||||||
self.new_from_filepart(file, offset, length)
|
self.new_from_filepart(file, offset, length)
|
||||||
elif file != None:
|
elif file != None:
|
||||||
if type(file) == type("x"):
|
if util.is_a_string(file):
|
||||||
self.new_from_file(file, copy)
|
self.new_from_file(file, copy)
|
||||||
else:
|
else:
|
||||||
self.new_from_fd(file)
|
self.new_from_fd(file)
|
||||||
@ -961,7 +961,7 @@ class Data(GpgmeWrapper):
|
|||||||
filename = None
|
filename = None
|
||||||
fp = None
|
fp = None
|
||||||
|
|
||||||
if type(file) == type("x"):
|
if util.is_a_string(file):
|
||||||
filename = file
|
filename = file
|
||||||
else:
|
else:
|
||||||
fp = gpgme.fdopen(file.fileno(), file.mode)
|
fp = gpgme.fdopen(file.fileno(), file.mode)
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
# License along with this library; if not, write to the Free Software
|
# License along with this library; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
def process_constants(prefix, scope):
|
def process_constants(prefix, scope):
|
||||||
"""Called by the constant modules to load up the constants from the C
|
"""Called by the constant modules to load up the constants from the C
|
||||||
library starting with PREFIX. Matching constants will be inserted
|
library starting with PREFIX. Matching constants will be inserted
|
||||||
@ -36,3 +38,13 @@ def percent_escape(s):
|
|||||||
'%{0:2x}'.format(ord(c))
|
'%{0:2x}'.format(ord(c))
|
||||||
if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c
|
if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c
|
||||||
for c in s)
|
for c in s)
|
||||||
|
|
||||||
|
# Python2/3 compatibility
|
||||||
|
if sys.version_info[0] == 3:
|
||||||
|
# Python3
|
||||||
|
def is_a_string(x):
|
||||||
|
return isinstance(x, str)
|
||||||
|
else:
|
||||||
|
# Python2
|
||||||
|
def is_a_string(x):
|
||||||
|
return isinstance(x, basestring)
|
||||||
|
@ -37,7 +37,7 @@ def read_cb(amount):
|
|||||||
ntoread -= chunk
|
ntoread -= chunk
|
||||||
assert ntoread >= 0
|
assert ntoread >= 0
|
||||||
assert chunk >= 0
|
assert chunk >= 0
|
||||||
return bytes(random.randrange(256) for i in range(chunk))
|
return bytes(bytearray(random.randrange(256) for i in range(chunk)))
|
||||||
|
|
||||||
nwritten = 0
|
nwritten = 0
|
||||||
def write_cb(data):
|
def write_cb(data):
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public
|
# 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/>.
|
# License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sys
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -60,17 +61,21 @@ with tempfile.TemporaryFile() as source, \
|
|||||||
|
|
||||||
sign_and_verify(source, signed, sink)
|
sign_and_verify(source, signed, sink)
|
||||||
|
|
||||||
# XXX: Python's io.BytesIo.truncate does not work as advertised.
|
if sys.version_info[0] == 3:
|
||||||
# http://bugs.python.org/issue27261
|
# Python2's io.BytesIO does not implement the buffer interface,
|
||||||
bio = io.BytesIO()
|
# hence we cannot use it as sink.
|
||||||
bio.truncate(1)
|
|
||||||
if len(bio.getvalue()) != 1:
|
|
||||||
# This version of Python is affected, preallocate buffer.
|
|
||||||
preallocate = 128*b'\x00'
|
|
||||||
else:
|
|
||||||
preallocate = b''
|
|
||||||
|
|
||||||
# Demonstrate automatic wrapping of objects implementing the buffer
|
# XXX: Python's io.BytesIo.truncate does not work as advertised.
|
||||||
# interface, and the use of data objects with the 'with' statement.
|
# http://bugs.python.org/issue27261
|
||||||
with io.BytesIO(preallocate) as signed, pyme.Data() as sink:
|
bio = io.BytesIO()
|
||||||
sign_and_verify(b"Hallo Leute\n", signed, sink)
|
bio.truncate(1)
|
||||||
|
if len(bio.getvalue()) != 1:
|
||||||
|
# This version of Python is affected, preallocate buffer.
|
||||||
|
preallocate = 128*b'\x00'
|
||||||
|
else:
|
||||||
|
preallocate = b''
|
||||||
|
|
||||||
|
# Demonstrate automatic wrapping of objects implementing the buffer
|
||||||
|
# interface, and the use of data objects with the 'with' statement.
|
||||||
|
with io.BytesIO(preallocate) as signed, pyme.Data() as sink:
|
||||||
|
sign_and_verify(b"Hallo Leute\n", signed, sink)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public
|
# 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/>.
|
# License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sys
|
||||||
import os
|
import os
|
||||||
import pyme
|
import pyme
|
||||||
from pyme import core, constants, errors
|
from pyme import core, constants, errors
|
||||||
@ -67,8 +68,11 @@ def check_result(result, summary, validity, fpr, status, notation):
|
|||||||
|
|
||||||
if notation:
|
if notation:
|
||||||
expected_notations = {
|
expected_notations = {
|
||||||
"bar": b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f".decode() +
|
"bar": (b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f" +
|
||||||
" das waren Umlaute und jetzt ein prozent%-Zeichen",
|
b" das waren Umlaute und jetzt ein prozent%-Zeichen"
|
||||||
|
if sys.version_info[0] < 3 else
|
||||||
|
b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f".decode() +
|
||||||
|
" das waren Umlaute und jetzt ein prozent%-Zeichen"),
|
||||||
"foobar.1": "this is a notation data with 2 lines",
|
"foobar.1": "this is a notation data with 2 lines",
|
||||||
None: "http://www.gu.org/policy/",
|
None: "http://www.gu.org/policy/",
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user