[pypy-commit] cffi default: Progress for Python 3, but not done
arigo
noreply at buildbot.pypy.org
Tue Oct 30 12:17:01 CET 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1020:adc872f1af4f
Date: 2012-10-30 12:16 +0100
http://bitbucket.org/cffi/cffi/changeset/adc872f1af4f/
Log: Progress for Python 3, but not done
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -207,6 +207,10 @@
#include "minibuffer.h"
+#if PY_MAJOR_VERSION >= 3
+# include "file_emulator.h"
+#endif
+
#ifdef HAVE_WCHAR_H
# include "wchar_helper.h"
#endif
@@ -1729,8 +1733,10 @@
/* from a unicode, we add the null terminator */
length = _my_PyUnicode_SizeAsWideChar(init) + 1;
}
- else if (PyFile_Check(init) && (ctitem->ct_flags & CT_IS_FILE)) {
+ else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) {
output_data[0] = (char *)PyFile_AsFile(init);
+ if (output_data[0] == NULL && PyErr_Occurred())
+ return -1;
return 1;
}
else {
@@ -2462,9 +2468,13 @@
return new_simple_cdata(cdsrc->c_data, ct);
}
}
- if (PyFile_Check(ob) && (ct->ct_flags & CT_POINTER) &&
- (ct->ct_itemdescr->ct_flags & CT_IS_FILE)) {
- return new_simple_cdata((char *)PyFile_AsFile(ob), ct);
+ if ((ct->ct_flags & CT_POINTER) &&
+ (ct->ct_itemdescr->ct_flags & CT_IS_FILE) &&
+ PyFile_Check(ob)) {
+ FILE *f = PyFile_AsFile(ob);
+ if (f == NULL && PyErr_Occurred())
+ return NULL;
+ return new_simple_cdata((char *)f, ct);
}
value = _my_PyLong_AsUnsignedLongLong(ob, 0);
if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
@@ -4599,8 +4609,9 @@
{
char *result;
if (convert_from_object((char *)&result, ct, obj) < 0) {
- if (PyFile_Check(obj) && (ct->ct_flags & CT_POINTER) &&
- (ct->ct_itemdescr->ct_flags & CT_IS_FILE)) {
+ if ((ct->ct_flags & CT_POINTER) &&
+ (ct->ct_itemdescr->ct_flags & CT_IS_FILE) &&
+ PyFile_Check(obj)) {
PyErr_Clear();
return (char *)PyFile_AsFile(obj);
}
diff --git a/c/file_emulator.h b/c/file_emulator.h
new file mode 100644
--- /dev/null
+++ b/c/file_emulator.h
@@ -0,0 +1,78 @@
+
+/* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */
+
+extern PyTypeObject PyIOBase_Type;
+
+
+#define PyFile_Check(p) PyObject_IsInstance(p, (PyObject *)&PyIOBase_Type)
+
+
+void _close_file_capsule(PyObject *ob_capsule)
+{
+ FILE *f = (FILE *)PyCapsule_GetPointer(ob_capsule, "FILE");
+ if (f != NULL)
+ fclose(f);
+}
+
+
+static FILE *PyFile_AsFile(PyObject *ob_file)
+{
+ PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL;
+ FILE *f = NULL;
+ int fd;
+ char *mode;
+ _Py_IDENTIFIER(flush);
+ _Py_IDENTIFIER(mode);
+ _Py_IDENTIFIER(__cffi_FILE);
+
+ ob = _PyObject_CallMethodId(ob_file, &PyId_flush, NULL);
+ if (ob == NULL)
+ goto fail;
+ Py_DECREF(ob);
+
+ ob_capsule = _PyObject_GetAttrId(ob_file, &PyId___cffi_FILE);
+ if (ob_capsule == NULL) {
+ PyErr_Clear();
+
+ fd = PyObject_AsFileDescriptor(ob_file);
+ if (fd < 0)
+ goto fail;
+
+ ob_mode = _PyObject_GetAttrId(ob_file, &PyId_mode);
+ if (ob_mode == NULL)
+ goto fail;
+ mode = PyText_AsUTF8(ob_mode);
+ if (mode == NULL)
+ goto fail;
+
+ fd = dup(fd);
+ if (fd < 0) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto fail;
+ }
+
+ f = fdopen(fd, mode);
+ if (f == NULL) {
+ close(fd);
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto fail;
+ }
+ Py_DECREF(ob_mode);
+ ob_mode = NULL;
+
+ ob_capsule = PyCapsule_New(f, "FILE", _close_file_capsule);
+ if (ob_capsule == NULL) {
+ fclose(f);
+ goto fail;
+ }
+
+ if (_PyObject_SetAttrId(ob_file, &PyId___cffi_FILE, ob_capsule) < 0)
+ goto fail;
+ }
+ return PyCapsule_GetPointer(ob_capsule, "FILE");
+
+ fail:
+ Py_XDECREF(ob_mode);
+ Py_XDECREF(ob_capsule);
+ return NULL;
+}
diff --git a/c/minibuffer.h b/c/minibuffer.h
--- a/c/minibuffer.h
+++ b/c/minibuffer.h
@@ -121,6 +121,83 @@
};
#if PY_MAJOR_VERSION >= 3
+/* pfffffffffffff pages of copy-paste from listobject.c */
+static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i;
+ i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ if (i < 0)
+ i += self->mb_size;
+ return mb_item(self, i);
+ }
+ else if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->mb_size,
+ &start, &stop, &step, &slicelength) < 0)
+ return NULL;
+
+ if (step == 1)
+ return mb_slice(self, start, stop);
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "buffer doesn't support slicing with step != 1");
+ return NULL;
+ }
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "buffer indices must be integers, not %.200s",
+ item->ob_type->tp_name);
+ return NULL;
+ }
+}
+static int
+mb_ass_subscript(MiniBufferObj* self, PyObject* item, PyObject* value)
+{
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred())
+ return -1;
+ if (i < 0)
+ i += self->mb_size;
+ return mb_ass_item(self, i, value);
+ }
+ else if (PySlice_Check(item)) {
+ Py_ssize_t start, stop, step, slicelength;
+
+ if (PySlice_GetIndicesEx(item, self->mb_size,
+ &start, &stop, &step, &slicelength) < 0) {
+ return -1;
+ }
+
+ if (step == 1)
+ return mb_ass_slice(self, start, stop, value);
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "buffer doesn't support slicing with step != 1");
+ return -1;
+ }
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "buffer indices must be integers, not %.200s",
+ item->ob_type->tp_name);
+ return -1;
+ }
+}
+
+static PyMappingMethods mb_as_mapping = {
+ (lenfunc)mb_length, /*mp_length*/
+ (binaryfunc)mb_subscript, /*mp_subscript*/
+ (objobjargproc)mb_ass_subscript, /*mp_ass_subscript*/
+};
+#endif
+
+#if PY_MAJOR_VERSION >= 3
# define MINIBUF_TPFLAGS (Py_TPFLAGS_DEFAULT)
#else
# define MINIBUF_TPFLAGS (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER)
@@ -139,7 +216,11 @@
0, /* tp_repr */
0, /* tp_as_number */
&mb_as_sequence, /* tp_as_sequence */
+#if PY_MAJOR_VERSION < 3
0, /* tp_as_mapping */
+#else
+ &mb_as_mapping, /* tp_as_mapping */
+#endif
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -10,6 +10,7 @@
mandatory_b_prefix = ''
mandatory_u_prefix = 'u'
bytechr = chr
+ bitem2bchr = lambda x: x
class U(object):
def __add__(self, other):
return eval('u'+repr(other).replace(r'\\u', r'\u')
@@ -23,6 +24,7 @@
mandatory_b_prefix = 'b'
mandatory_u_prefix = ''
bytechr = lambda n: bytes([n])
+ bitem2bchr = bytechr
u = ""
def size_of_int():
@@ -1808,7 +1810,10 @@
assert (p < s) ^ (p > s)
def test_buffer():
- import __builtin__
+ try:
+ import __builtin__
+ except ImportError:
+ import builtins as __builtin__
BShort = new_primitive_type("short")
s = newp(new_pointer_type(BShort), 100)
assert sizeof(s) == size_of_ptr()
@@ -1830,7 +1835,7 @@
except IndexError:
py.test.raises(IndexError, "buf[i]")
else:
- assert buf[i] == expected
+ assert buf[i] == bitem2bchr(expected)
# --mb_slice--
assert buf[:] == b"hi there\x00"
for i in range(-12, 12):
@@ -1839,33 +1844,34 @@
for j in range(-12, 12):
assert buf[i:j] == b"hi there\x00"[i:j]
# --misc--
- assert list(buf) == list(b"hi there\x00")
+ assert list(buf) == list(map(bitem2bchr, b"hi there\x00"))
# --mb_as_buffer--
- py.test.raises(TypeError, __builtin__.buffer, c)
- bf1 = __builtin__.buffer(buf)
- assert len(bf1) == len(buf) and bf1[3] == "t"
+ if hasattr(__builtin__, 'buffer'): # Python <= 2.7
+ py.test.raises(TypeError, __builtin__.buffer, c)
+ bf1 = __builtin__.buffer(buf)
+ assert len(bf1) == len(buf) and bf1[3] == "t"
if hasattr(__builtin__, 'memoryview'): # Python >= 2.7
py.test.raises(TypeError, memoryview, c)
mv1 = memoryview(buf)
- assert len(mv1) == len(buf) and mv1[3] == "t"
+ assert len(mv1) == len(buf) and mv1[3] in (b"t", ord(b"t"))
# --mb_ass_item--
- expected = list(b"hi there\x00")
+ expected = list(map(bitem2bchr, b"hi there\x00"))
for i in range(-12, 12):
try:
- expected[i] = chr(i & 0xff)
+ expected[i] = bytechr(i & 0xff)
except IndexError:
- py.test.raises(IndexError, "buf[i] = chr(i & 0xff)")
+ py.test.raises(IndexError, "buf[i] = bytechr(i & 0xff)")
else:
- buf[i] = chr(i & 0xff)
+ buf[i] = bytechr(i & 0xff)
assert list(buf) == expected
# --mb_ass_slice--
buf[:] = b"hi there\x00"
- assert list(buf) == list(c) == list(b"hi there\x00")
+ assert list(buf) == list(c) == list(map(bitem2bchr, b"hi there\x00"))
py.test.raises(ValueError, 'buf[:] = b"shorter"')
py.test.raises(ValueError, 'buf[:] = b"this is much too long!"')
buf[4:2] = b"" # no effect, but should work
assert buf[:] == b"hi there\x00"
- expected = list(b"hi there\x00")
+ expected = list(map(bitem2bchr, b"hi there\x00"))
x = 0
for i in range(-12, 12):
for j in range(-12, 12):
@@ -1873,10 +1879,10 @@
stop = j if j >= 0 else j + len(buf)
start = max(0, min(len(buf), start))
stop = max(0, min(len(buf), stop))
- sample = chr(x & 0xff) * (stop - start)
+ sample = bytechr(x & 0xff) * (stop - start)
x += 1
buf[i:j] = sample
- expected[i:j] = sample
+ expected[i:j] = map(bitem2bchr, sample)
assert list(buf) == expected
def test_getcname():
@@ -2249,6 +2255,11 @@
assert len(p) == 4
assert list(p) == [b"f", b"o", b"o", b"\x00"]
+# XXX hack
+if sys.version_info >= (3,):
+ import posix, io
+ posix.fdopen = io.open
+
def test_FILE():
if sys.platform == "win32":
py.test.skip("testing FILE not implemented")
@@ -2266,8 +2277,8 @@
#
import posix
fdr, fdw = posix.pipe()
- fr1 = posix.fdopen(fdr, 'r', 256)
- fw1 = posix.fdopen(fdw, 'w', 256)
+ fr1 = posix.fdopen(fdr, 'rb', 256)
+ fw1 = posix.fdopen(fdw, 'wb', 256)
#
fw1.write(b"X")
res = fputs(b"hello world\n", fw1)
More information about the pypy-commit
mailing list