[pypy-commit] cffi default: hg merge 'python3-port': support Python 3.x as well. Thanks Amaury for

arigo noreply at buildbot.pypy.org
Sun Aug 12 21:45:15 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r829:639587ab290c
Date: 2012-08-12 21:22 +0200
http://bitbucket.org/cffi/cffi/changeset/639587ab290c/

Log:	hg merge 'python3-port': support Python 3.x as well. Thanks Amaury
	for doing the first part of this! Right now tested only with Python
	3.3. Hard to run the test suite on Python 3.2 because of the u''
	literals.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -22,6 +22,45 @@
 # define USE__THREAD
 #endif
 
+#if PY_MAJOR_VERSION >= 3
+# define STR_OR_BYTES "bytes"
+# define PyText_Type PyUnicode_Type
+# define PyText_Check PyUnicode_Check
+# define PyText_FromFormat PyUnicode_FromFormat
+# define PyText_AsUTF8 _PyUnicode_AsString   /* PyUnicode_AsUTF8 in Py3.3 */
+# define PyText_AS_UTF8 _PyUnicode_AsString
+# define PyText_GetSize PyUnicode_GetSize
+# define PyText_FromString PyUnicode_FromString
+# define PyText_FromStringAndSize PyUnicode_FromStringAndSize
+# define PyText_InternInPlace PyUnicode_InternInPlace
+#else
+# define STR_OR_BYTES "str"
+# define PyText_Type PyString_Type
+# define PyText_Check PyString_Check
+# define PyText_FromFormat PyString_FromFormat
+# define PyText_AsUTF8 PyString_AsString
+# define PyText_AS_UTF8 PyString_AS_STRING
+# define PyText_GetSize PyString_GetSize
+# define PyText_FromString PyString_FromString
+# define PyText_FromStringAndSize PyString_FromStringAndSize
+# define PyText_InternInPlace PyString_InternInPlace
+#endif 
+
+#if PY_MAJOR_VERSION >= 3
+# define PyInt_FromLong PyLong_FromLong
+# define PyInt_FromSsize_t PyLong_FromSsize_t
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+/* This is the default on Python3 and constant has been removed. */
+# define Py_TPFLAGS_CHECKTYPES 0
+#endif
+
+#if PY_MAJOR_VERSION < 3
+#define PyCapsule_New(pointer, name, destructor)        \
+    (PyCObject_FromVoidPtr(pointer, destructor))
+#endif
+
 /************************************************************/
 
 /* base type flag: exactly one of the following: */
@@ -210,7 +249,7 @@
 static PyObject *
 ctypedescr_repr(CTypeDescrObject *ct)
 {
-    return PyString_FromFormat("<ctype '%s'>", ct->ct_name);
+    return PyText_FromFormat("<ctype '%s'>", ct->ct_name);
 }
 
 static void
@@ -279,7 +318,7 @@
     PyObject *d_key, *d_value;
     while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) {
         if (d_value == (PyObject *)cf)
-            return PyString_AsString(d_key);
+            return PyText_AsUTF8(d_key);
     }
     return NULL;
 }
@@ -302,10 +341,10 @@
 #define OFF(x) offsetof(CFieldObject, x)
 
 static PyMemberDef cfield_members[] = {
-    {"type", T_OBJECT, OFF(cf_type), RO},
-    {"offset", T_PYSSIZET, OFF(cf_offset), RO},
-    {"bitshift", T_SHORT, OFF(cf_bitshift), RO},
-    {"bitsize", T_SHORT, OFF(cf_bitsize), RO},
+    {"type", T_OBJECT, OFF(cf_type), READONLY},
+    {"offset", T_PYSSIZET, OFF(cf_offset), READONLY},
+    {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY},
+    {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY},
     {NULL}      /* Sentinel */
 };
 #undef OFF
@@ -351,10 +390,13 @@
        Like PyLong_AsLongLong(), this version accepts a Python int too, and
        does convertions from other types of objects.  The difference is that
        this version refuses floats. */
+#if PY_MAJOR_VERSION < 3
     if (PyInt_Check(ob)) {
         return PyInt_AS_LONG(ob);
     }
-    else if (PyLong_Check(ob)) {
+    else 
+#endif
+    if (PyLong_Check(ob)) {
         return PyLong_AsLongLong(ob);
     }
     else {
@@ -371,7 +413,11 @@
         if (io == NULL)
             return -1;
 
+#if PY_MAJOR_VERSION < 3
         if (PyInt_Check(io) || PyLong_Check(io)) {
+#else
+        if (PyLong_Check(io)) {
+#endif
             res = _my_PyLong_AsLongLong(io);
         }
         else {
@@ -391,13 +437,16 @@
        does convertions from other types of objects.  If 'strict', complains
        with OverflowError and refuses floats.  If '!strict', rounds floats
        and masks the result. */
+#if PY_MAJOR_VERSION < 3
     if (PyInt_Check(ob)) {
         long value1 = PyInt_AS_LONG(ob);
         if (strict && value1 < 0)
             goto negative;
         return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1;
     }
-    else if (PyLong_Check(ob)) {
+    else
+#endif
+    if (PyLong_Check(ob)) {
         if (strict) {
             if (_PyLong_Sign(ob) < 0)
                 goto negative;
@@ -421,7 +470,11 @@
         if (io == NULL)
             return (unsigned PY_LONG_LONG)-1;
 
+#if PY_MAJOR_VERSION < 3
         if (PyInt_Check(io) || PyLong_Check(io)) {
+#else
+        if (PyLong_Check(io)) {
+#endif
             res = _my_PyLong_AsUnsignedLongLong(io, strict);
         }
         else {
@@ -545,10 +598,11 @@
 static PyObject *convert_enum_string_to_int(CTypeDescrObject *ct, PyObject *ob)
 {
     PyObject *d_value;
-
-    if (PyString_AS_STRING(ob)[0] == '#') {
-        char *number = PyString_AS_STRING(ob) + 1;   /* strip initial '#' */
-        PyObject *ob2 = PyString_FromString(number);
+    char *p = PyText_AS_UTF8(ob);
+
+    if (p[0] == '#') {
+        char *number = p + 1;       /* strip initial '#' */
+        PyObject *ob2 = PyText_FromString(number);
         if (ob2 == NULL)
             return NULL;
 
@@ -560,8 +614,7 @@
         if (d_value == NULL) {
             PyErr_Format(PyExc_ValueError,
                          "'%s' is not an enumerator for %s",
-                         PyString_AS_STRING(ob),
-                         ct->ct_name);
+                         p, ct->ct_name);
             return NULL;
         }
         Py_INCREF(d_value);
@@ -611,7 +664,7 @@
             if (d_value != NULL)
                 Py_INCREF(d_value);
             else
-                d_value = PyString_FromFormat("#%d", (int)value);
+                d_value = PyText_FromFormat("#%d", (int)value);
             return d_value;
         }
         else if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG)
@@ -642,7 +695,7 @@
     }
     else if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
         if (ct->ct_size == sizeof(char))
-            return PyString_FromStringAndSize(data, 1);
+            return PyBytes_FromStringAndSize(data, 1);
 #ifdef HAVE_WCHAR_H
         else
             return _my_PyUnicode_FromWideChar((wchar_t *)data, 1);
@@ -697,15 +750,15 @@
     if (s == NULL)
         return -1;
     PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'",
-                 PyString_AS_STRING(s), ct_name);
+                 PyText_AS_UTF8(s), ct_name);
     Py_DECREF(s);
     return -1;
 }
 
 static int _convert_to_char(PyObject *init)
 {
-    if (PyString_Check(init) && PyString_GET_SIZE(init) == 1) {
-        return (unsigned char)(PyString_AS_STRING(init)[0]);
+    if (PyBytes_Check(init) && PyBytes_GET_SIZE(init) == 1) {
+        return (unsigned char)(PyBytes_AS_STRING(init)[0]);
     }
     if (CData_Check(init) &&
            (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) &&
@@ -713,8 +766,8 @@
         return *(unsigned char *)((CDataObject *)init)->c_data;
     }
     PyErr_Format(PyExc_TypeError,
-                 "initializer for ctype 'char' must be a string of length 1, "
-                 "not %.200s", Py_TYPE(init)->tp_name);
+                 "initializer for ctype 'char' must be a "STR_OR_BYTES
+                 " of length 1, not %.200s", Py_TYPE(init)->tp_name);
     return -1;
 }
 
@@ -800,20 +853,20 @@
         if (ctitem->ct_size == sizeof(char)) {
             char *srcdata;
             Py_ssize_t n;
-            if (!PyString_Check(init)) {
-                expected = "str or list or tuple";
+            if (!PyBytes_Check(init)) {
+                expected = STR_OR_BYTES" or list or tuple";
                 goto cannot_convert;
             }
-            n = PyString_GET_SIZE(init);
+            n = PyBytes_GET_SIZE(init);
             if (ct->ct_length >= 0 && n > ct->ct_length) {
                 PyErr_Format(PyExc_IndexError,
-                             "initializer string is too long for '%s' "
+                             "initializer "STR_OR_BYTES" is too long for '%s' "
                              "(got %zd characters)", ct->ct_name, n);
                 return -1;
             }
             if (n != ct->ct_length)
                 n++;
-            srcdata = PyString_AS_STRING(init);
+            srcdata = PyBytes_AS_STRING(init);
             memcpy(data, srcdata, n);
             return 0;
         }
@@ -896,7 +949,7 @@
             else {
                 PyObject *ob;
                 PyErr_Clear();
-                if (!PyString_Check(init)) {
+                if (!PyText_Check(init)) {
                     expected = "str or int";
                     goto cannot_convert;
                 }
@@ -1069,9 +1122,9 @@
         PyErr_Format(PyExc_OverflowError,
                      "value %s outside the range allowed by the "
                      "bit field width: %s <= x <= %s",
-                     PyString_AS_STRING(svalue),
-                     PyString_AS_STRING(sfmin),
-                     PyString_AS_STRING(sfmax));
+                     PyText_AS_UTF8(svalue),
+                     PyText_AS_UTF8(sfmin),
+                     PyText_AS_UTF8(sfmax));
        skip:
         Py_XDECREF(svalue);
         Py_XDECREF(sfmin);
@@ -1164,8 +1217,8 @@
 
 static PyObject *cdata_repr(CDataObject *cd)
 {
-    char *p, *extra;
-    PyObject *result, *s = NULL;
+    char *extra;
+    PyObject *result, *s;
 
     if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) {
         if (!(cd->c_type->ct_flags & CT_IS_LONGDOUBLE)) {
@@ -1174,29 +1227,23 @@
                 return NULL;
             s = PyObject_Repr(o);
             Py_DECREF(o);
-            if (s == NULL)
-                return NULL;
-            p = PyString_AS_STRING(s);
         }
         else {
             long double lvalue = read_raw_longdouble_data(cd->c_data);
-            s = PyString_FromStringAndSize(NULL, 128);   /* big enough */
-            if (s == NULL)
-                return NULL;
-            p = PyString_AS_STRING(s);
-            sprintf(p, "%LE", lvalue);
+            char buffer[128];   /* big enough */
+            sprintf(buffer, "%LE", lvalue);
+            s = PyText_FromString(buffer);
         }
     }
     else {
         if (cd->c_data != NULL) {
-            s = PyString_FromFormat("%p", cd->c_data);
-            if (s == NULL)
-                return NULL;
-            p = PyString_AS_STRING(s);
+            s = PyText_FromFormat("%p", cd->c_data);
         }
         else
-            p = "NULL";
+            s = PyText_FromString("NULL");
     }
+    if (s == NULL)
+        return NULL;
     /* it's slightly confusing to get "<cdata 'struct foo' 0x...>" because the
        struct foo is not owned.  Trying to make it clearer, write in this
        case "<cdata 'struct foo &' 0x...>". */
@@ -1204,9 +1251,10 @@
         extra = " &";
     else
         extra = "";
-    result = PyString_FromFormat("<cdata '%s%s' %s>",
-                                 cd->c_type->ct_name, extra, p);
-    Py_XDECREF(s);
+    result = PyText_FromFormat("<cdata '%s%s' %s>",
+                               cd->c_type->ct_name, extra,
+                               PyText_AsUTF8(s));
+    Py_DECREF(s);
     return result;
 }
 
@@ -1222,8 +1270,8 @@
     else
         size = cd->c_type->ct_size;
 
-    return PyString_FromFormat("<cdata '%s' owning %zd bytes>",
-                               cd->c_type->ct_name, size);
+    return PyText_FromFormat("<cdata '%s' owning %zd bytes>",
+                             cd->c_type->ct_name, size);
 
  callback_repr:
     {
@@ -1235,8 +1283,8 @@
         s = PyObject_Repr(PyTuple_GET_ITEM(args, 1));
         if (s == NULL)
             return NULL;
-        res = PyString_FromFormat("<cdata '%s' calling %s>",
-                                  cd->c_type->ct_name, PyString_AsString(s));
+        res = PyText_FromFormat("<cdata '%s' calling %s>",
+                                cd->c_type->ct_name, PyText_AsUTF8(s));
         Py_DECREF(s);
         return res;
     }
@@ -1270,7 +1318,11 @@
     }
     else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) {
         PyObject *o = cdata_float(cd);
+#if PY_MAJOR_VERSION < 3
         PyObject *r = o ? PyNumber_Int(o) : NULL;
+#else
+        PyObject *r = o ? PyNumber_Long(o) : NULL;
+#endif
         Py_XDECREF(o);
         return r;
     }
@@ -1279,6 +1331,7 @@
     return NULL;
 }
 
+#if PY_MAJOR_VERSION < 3
 static PyObject *cdata_long(CDataObject *cd)
 {
     PyObject *res = cdata_int(cd);
@@ -1289,6 +1342,7 @@
     }
     return res;
 }
+#endif
 
 static PyObject *cdata_float(CDataObject *cd)
 {
@@ -1517,7 +1571,11 @@
             return NULL;
         }
         diff = (cdv->c_data - cdw->c_data) / ct->ct_itemdescr->ct_size;
+#if PY_MAJOR_VERSION < 3
         return PyInt_FromSsize_t(diff);
+#else
+        return PyLong_FromSsize_t(diff);
+#endif
     }
 
     return _cdata_add_or_sub(v, w, -1);
@@ -1603,14 +1661,14 @@
 {
     /* 'ctptr' is here a pointer type 'ITEM *'.  Accept as argument an
        initializer for an array 'ITEM[]'.  This includes the case of
-       passing a Python string to a 'char *' argument. */
+       passing a Python byte string to a 'char *' argument. */
     Py_ssize_t length, datasize;
     CTypeDescrObject *ctitem = ctptr->ct_itemdescr;
     PyObject *result;
     char *data;
 
     /* XXX some code duplication, how to avoid it? */
-    if (PyString_Check(init)) {
+    if (PyBytes_Check(init)) {
         /* from a string: just returning the string here is fine.
            We assume that the C code won't modify the 'char *' data. */
         if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
@@ -1643,11 +1701,11 @@
         return NULL;
     }
 
-    result = PyString_FromStringAndSize(NULL, datasize);
+    result = PyBytes_FromStringAndSize(NULL, datasize);
     if (result == NULL)
         return NULL;
 
-    data = PyString_AS_STRING(result);
+    data = PyBytes_AS_STRING(result);
     memset(data, 0, datasize);
     if (convert_array_from_object(data, ctptr, init) < 0) {
         Py_DECREF(result);
@@ -1742,7 +1800,11 @@
             }
             PyTuple_SET_ITEM(fvarargs, i, (PyObject *)ct);
         }
+#if PY_MAJOR_VERSION < 3
         fabi = PyInt_AS_LONG(PyTuple_GET_ITEM(signature, 0));
+#else
+        fabi = PyLong_AS_LONG(PyTuple_GET_ITEM(signature, 0));
+#endif
         cif_descr = fb_prepare_cif(fvarargs, fresult, fabi);
         if (cif_descr == NULL)
             goto error;
@@ -1775,7 +1837,7 @@
                 if (string != Py_None) {
                     if (string == NULL)
                         goto error;
-                    ((char **)data)[0] = PyString_AS_STRING(string);
+                    ((char **)data)[0] = PyBytes_AS_STRING(string);
                     ((char **)data)[1] = (char *)string;
                     assert(i < nargs_declared); /* otherwise, obj is a CData */
                     free_me_until = i + 1;
@@ -1856,7 +1918,9 @@
     (binaryfunc)cdata_add,      /*nb_add*/
     (binaryfunc)cdata_sub,      /*nb_subtract*/
     0,                          /*nb_multiply*/
+#if PY_MAJOR_VERSION < 3
     0,                          /*nb_divide*/
+#endif
     0,                          /*nb_remainder*/
     0,                          /*nb_divmod*/
     0,                          /*nb_power*/
@@ -1870,9 +1934,15 @@
     0,                          /*nb_and*/
     0,                          /*nb_xor*/
     0,                          /*nb_or*/
+#if PY_MAJOR_VERSION < 3
     0,                          /*nb_coerce*/
+#endif
     (unaryfunc)cdata_int,       /*nb_int*/
+#if PY_MAJOR_VERSION < 3
     (unaryfunc)cdata_long,      /*nb_long*/
+#else
+    0,
+#endif
     (unaryfunc)cdata_float,     /*nb_float*/
     0,                          /*nb_oct*/
     0,                          /*nb_hex*/
@@ -2102,9 +2172,9 @@
             if (PyList_Check(init) || PyTuple_Check(init)) {
                 explicitlength = PySequence_Fast_GET_SIZE(init);
             }
-            else if (PyString_Check(init)) {
+            else if (PyBytes_Check(init)) {
                 /* from a string, we add the null terminator */
-                explicitlength = PyString_GET_SIZE(init) + 1;
+                explicitlength = PyBytes_GET_SIZE(init) + 1;
             }
             else if (PyUnicode_Check(init)) {
                 /* from a unicode, we add the null terminator */
@@ -2204,7 +2274,7 @@
                                  (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) {
         value = (Py_intptr_t)((CDataObject *)ob)->c_data;
     }
-    else if (PyString_Check(ob)) {
+    else if (PyText_Check(ob)) {
         if (ct->ct_flags & CT_IS_ENUM) {
             ob = convert_enum_string_to_int(ct, ob);
             if (ob == NULL)
@@ -2214,6 +2284,7 @@
             return cd;
         }
         else {
+#if PY_MAJOR_VERSION < 3
             if (PyString_GET_SIZE(ob) != 1) {
                 PyErr_Format(PyExc_TypeError,
                       "cannot cast string of length %zd to ctype '%s'",
@@ -2221,6 +2292,16 @@
                 return NULL;
             }
             value = (unsigned char)PyString_AS_STRING(ob)[0];
+#else
+            wchar_t ordinal;
+            if (_my_PyUnicode_AsSingleWideChar(ob, &ordinal) < 0) {
+                PyErr_Format(PyExc_TypeError,
+                             "cannot cast string of length %zd to ctype '%s'",
+                             PyUnicode_GET_SIZE(ob), ct->ct_name);
+                return NULL;
+            }
+            value = (long)ordinal;
+#endif
         }
     }
 #ifdef HAVE_WCHAR_H
@@ -2235,6 +2316,12 @@
         value = (long)ordinal;
     }
 #endif
+    else if (PyBytes_Check(ob)) {
+        int res = _convert_to_char(ob);
+        if (res < 0)
+            return NULL;
+        value = (unsigned char)res;
+    }
     else {
         value = _my_PyLong_AsUnsignedLongLong(ob, 0);
         if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
@@ -2298,12 +2385,12 @@
             Py_INCREF(io);
         }
 
-        if (PyString_Check(io)) {
-            if (PyString_GET_SIZE(io) != 1) {
+        if (PyBytes_Check(io)) {
+            if (PyBytes_GET_SIZE(io) != 1) {
                 Py_DECREF(io);
                 goto cannot_cast;
             }
-            value = (unsigned char)PyString_AS_STRING(io)[0];
+            value = (unsigned char)PyBytes_AS_STRING(io)[0];
         }
 #if HAVE_WCHAR_H
         else if (PyUnicode_Check(io)) {
@@ -2375,7 +2462,7 @@
 
 static PyObject *dl_repr(DynLibObject *dlobj)
 {
-    return PyString_FromFormat("<clibrary '%s'>", dlobj->dl_name);
+    return PyText_FromFormat("<clibrary '%s'>", dlobj->dl_name);
 }
 
 static PyObject *dl_load_function(DynLibObject *dlobj, PyObject *args)
@@ -2878,7 +2965,7 @@
         CFieldObject *cf;
 
         if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|ii:list item",
-                              &PyString_Type, &fname,
+                              &PyText_Type, &fname,
                               &CTypeDescr_Type, &ftype,
                               &fbitsize, &foffset))
             goto error;
@@ -2886,7 +2973,7 @@
         if (ftype->ct_size < 0) {
             PyErr_Format(PyExc_TypeError,
                          "field '%s.%s' has ctype '%s' of unknown size",
-                         ct->ct_name, PyString_AS_STRING(fname),
+                         ct->ct_name, PyText_AS_UTF8(fname),
                          ftype->ct_name);
             goto error;
         }
@@ -2928,7 +3015,7 @@
                     fbitsize == 0 ||
                     fbitsize > 8 * ftype->ct_size) {
                 PyErr_Format(PyExc_TypeError, "invalid bit field '%s'",
-                             PyString_AS_STRING(fname));
+                             PyText_AS_UTF8(fname));
                 goto error;
             }
             if (prev_bit_position > 0) {
@@ -2962,7 +3049,7 @@
         cf->cf_bitsize = fbitsize;
 
         Py_INCREF(fname);
-        PyString_InternInPlace(&fname);
+        PyText_InternInPlace(&fname);
         err = PyDict_SetItem(interned_fields, fname, (PyObject *)cf);
         Py_DECREF(fname);
         Py_DECREF(cf);
@@ -2971,7 +3058,7 @@
 
         if (PyDict_Size(interned_fields) != i + 1) {
             PyErr_Format(PyExc_KeyError, "duplicate field name '%s'",
-                         PyString_AS_STRING(fname));
+                         PyText_AS_UTF8(fname));
             goto error;
         }
 
@@ -3567,8 +3654,8 @@
     PyErr_WriteUnraisable(py_ob);
     if (SIGNATURE(1)->ct_size > 0) {
         py_rawerr = PyTuple_GET_ITEM(cb_args, 2);
-        memcpy(result, PyString_AS_STRING(py_rawerr),
-                       PyString_GET_SIZE(py_rawerr));
+        memcpy(result, PyBytes_AS_STRING(py_rawerr),
+                       PyBytes_GET_SIZE(py_rawerr));
     }
     goto done;
     }
@@ -3606,13 +3693,13 @@
     size = ctresult->ct_size;
     if (size < (Py_ssize_t)sizeof(ffi_arg))
         size = sizeof(ffi_arg);
-    py_rawerr = PyString_FromStringAndSize(NULL, size);
+    py_rawerr = PyBytes_FromStringAndSize(NULL, size);
     if (py_rawerr == NULL)
         return NULL;
-    memset(PyString_AS_STRING(py_rawerr), 0, size);
+    memset(PyBytes_AS_STRING(py_rawerr), 0, size);
     if (error_ob != Py_None) {
         if (convert_from_object_fficallback(
-                PyString_AS_STRING(py_rawerr), ctresult, error_ob) < 0) {
+                PyBytes_AS_STRING(py_rawerr), ctresult, error_ob) < 0) {
             Py_DECREF(py_rawerr);
             return NULL;
         }
@@ -3814,8 +3901,7 @@
 static PyObject *b_getcname(PyObject *self, PyObject *args)
 {
     CTypeDescrObject *ct;
-    char *replace_with, *p;
-    PyObject *s;
+    char *replace_with, *p, *s;
     Py_ssize_t namelen, replacelen;
 
     if (!PyArg_ParseTuple(args, "O!s:getcname",
@@ -3824,11 +3910,7 @@
 
     namelen = strlen(ct->ct_name);
     replacelen = strlen(replace_with);
-    s = PyString_FromStringAndSize(NULL, namelen + replacelen);
-    if (s == NULL)
-        return NULL;
-
-    p = PyString_AS_STRING(s);
+    s = p = alloca(namelen + replacelen + 1);
     memcpy(p, ct->ct_name, ct->ct_name_position);
     p += ct->ct_name_position;
     memcpy(p, replace_with, replacelen);
@@ -3836,7 +3918,7 @@
     memcpy(p, ct->ct_name + ct->ct_name_position,
            namelen - ct->ct_name_position);
 
-    return s;
+    return PyText_FromStringAndSize(s, namelen + replacelen);
 }
 
 static PyObject *b_string(PyObject *self, PyObject *args)
@@ -3857,7 +3939,7 @@
             if (s != NULL) {
                 PyErr_Format(PyExc_RuntimeError,
                              "cannot use string() on %s",
-                             PyString_AS_STRING(s));
+                             PyText_AS_UTF8(s));
                 Py_DECREF(s);
             }
             return NULL;
@@ -3875,7 +3957,7 @@
                 if (end != NULL)
                     length = end - start;
             }
-            return PyString_FromStringAndSize(start, length);
+            return PyBytes_FromStringAndSize(start, length);
         }
 #ifdef HAVE_WCHAR_H
         else if (cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR) {
@@ -3903,7 +3985,7 @@
                                      CT_PRIMITIVE_SIGNED |
                                      CT_PRIMITIVE_UNSIGNED)) {
         if (cd->c_type->ct_size == sizeof(char)) {
-            return PyString_FromStringAndSize(cd->c_data, 1);
+            return PyBytes_FromStringAndSize(cd->c_data, 1);
         }
 #ifdef HAVE_WCHAR_H
         else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) {
@@ -3945,7 +4027,17 @@
                      cd->c_type->ct_name);
         return NULL;
     }
+#if PY_MAJOR_VERSION < 3
     return PyBuffer_FromReadWriteMemory(cd->c_data, size);
+#else
+    {
+      Py_buffer view;
+      if (PyBuffer_FillInfo(&view, NULL, cd->c_data, size,
+                            /*readonly=*/0, PyBUF_WRITABLE) < 0)
+        return NULL;
+      return PyMemoryView_FromBuffer(&view);
+    }
+#endif
 }
 
 static PyObject *b_get_errno(PyObject *self, PyObject *noarg)
@@ -4171,7 +4263,7 @@
     {"get_errno", b_get_errno, METH_NOARGS},
     {"set_errno", b_set_errno, METH_VARARGS},
     {"_testfunc", b__testfunc, METH_VARARGS},
-    {NULL,     NULL}	/* Sentinel */
+    {NULL,     NULL}    /* Sentinel */
 };
 
 /************************************************************/
@@ -4179,8 +4271,8 @@
 
 static char *_cffi_to_c_char_p(PyObject *obj)
 {
-    if (PyString_Check(obj)) {
-        return PyString_AS_STRING(obj);
+    if (PyBytes_Check(obj)) {
+        return PyBytes_AS_STRING(obj);
     }
     if (CData_Check(obj)) {
         return ((CDataObject *)obj)->c_data;
@@ -4189,9 +4281,15 @@
     return NULL;
 }
 
+#if PY_MAJOR_VERSION < 3
+# define PyCffiInt_AsLong PyInt_AsLong
+#else
+# define PyCffiInt_AsLong PyLong_AsLong
+#endif
+
 #define _cffi_to_c_PRIMITIVE(TARGETNAME, TARGET)        \
 static TARGET _cffi_to_c_##TARGETNAME(PyObject *obj) {  \
-    long tmp = PyInt_AsLong(obj);                       \
+    long tmp = PyCffiInt_AsLong(obj);                   \
     if (tmp != (TARGET)tmp)                             \
         return (TARGET)_convert_overflow(obj, #TARGET); \
     return (TARGET)tmp;                                 \
@@ -4264,7 +4362,7 @@
 }
 
 static PyObject *_cffi_from_c_char(char x) {
-    return PyString_FromStringAndSize(&x, 1);
+    return PyBytes_FromStringAndSize(&x, 1);
 }
 
 #ifdef HAVE_WCHAR_H
@@ -4309,54 +4407,81 @@
 
 /************************************************************/
 
-void init_cffi_backend(void)
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef FFIBackendModuleDef = {
+  PyModuleDef_HEAD_INIT,
+  "_cffi_backend",
+  NULL,
+  -1,
+  FFIBackendMethods,
+  NULL, NULL, NULL, NULL
+};
+#define INITERROR return NULL
+
+PyMODINIT_FUNC
+PyInit__cffi_backend(void)
+#else
+#define INITERROR return
+
+PyMODINIT_FUNC
+init_cffi_backend(void)
+#endif
 {
     PyObject *m, *v;
 
     v = PySys_GetObject("version");
-    if (v == NULL || !PyString_Check(v) ||
-            strncmp(PyString_AS_STRING(v), PY_VERSION, 3) != 0) {
+    if (v == NULL || !PyText_Check(v) ||
+            strncmp(PyText_AS_UTF8(v), PY_VERSION, 3) != 0) {
         PyErr_Format(PyExc_ImportError,
                      "this module was compiled for Python %c%c%c",
                      PY_VERSION[0], PY_VERSION[1], PY_VERSION[2]);
-        return;
+        INITERROR;
     }
 
+#if PY_MAJOR_VERSION >= 3
+    m = PyModule_Create(&FFIBackendModuleDef);
+#else
     m = Py_InitModule("_cffi_backend", FFIBackendMethods);
+#endif
+
     if (m == NULL)
-        return;
+        INITERROR;
     if (PyType_Ready(&dl_type) < 0)
-        return;
+        INITERROR;
     if (PyType_Ready(&CTypeDescr_Type) < 0)
-        return;
+        INITERROR;
     if (PyType_Ready(&CField_Type) < 0)
-        return;
+        INITERROR;
     if (PyType_Ready(&CData_Type) < 0)
-        return;
+        INITERROR;
     if (PyType_Ready(&CDataOwning_Type) < 0)
-        return;
+        INITERROR;
     if (PyType_Ready(&CDataIter_Type) < 0)
-        return;
-
-    v = PyCObject_FromVoidPtr((void *)cffi_exports, NULL);
+        INITERROR;
+
+    v = PyCapsule_New((void *)cffi_exports, "cffi", NULL);
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
-        return;
-
-    v = PyString_FromString("0.3");
+        INITERROR;
+
+    v = PyText_FromString("0.3");
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
-        return;
+        INITERROR;
 
 #if defined(MS_WIN32) && !defined(_WIN64)
     v = PyInt_FromLong(FFI_STDCALL);
     if (v == NULL || PyModule_AddObject(m, "FFI_STDCALL", v) < 0)
-        return;
+        INITERROR;
 #endif
     v = PyInt_FromLong(FFI_DEFAULT_ABI);
     if (v == NULL || PyModule_AddObject(m, "FFI_DEFAULT_ABI", v) < 0)
-        return;
+        INITERROR;
     Py_INCREF(v);
     if (PyModule_AddObject(m, "FFI_CDECL", v) < 0)  /* win32 name */
-        return;
+        INITERROR;
 
     init_errno();
+
+#if PY_MAJOR_VERSION >= 3
+    return m;
+#endif
 }
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,24 @@
 
 # ____________________________________________________________
 
+if sys.version_info < (3,):
+    type_or_class = "type"
+    mandatory_b_prefix = ''
+    mandatory_u_prefix = 'u'
+    readbuf = str
+    bufchar = lambda x: x
+    bytechr = chr
+else:
+    type_or_class = "class"
+    long = int
+    unicode = str
+    unichr = chr
+    mandatory_b_prefix = 'b'
+    mandatory_u_prefix = ''
+    readbuf = lambda buf: buf.tobytes()
+    bufchar = ord
+    bytechr = lambda n: bytes([n])
+
 def size_of_int():
     BInt = new_primitive_type("int")
     return sizeof(BInt)
@@ -54,7 +72,7 @@
     p = new_primitive_type("signed char")
     x = cast(p, -65 + 17*256)
     assert repr(x) == "<cdata 'signed char' -65>"
-    assert repr(type(x)) == "<type '_cffi_backend.CData'>"
+    assert repr(type(x)) == "<%s '_cffi_backend.CData'>" % type_or_class
     assert int(x) == -65
     x = cast(p, -66 + (1<<199)*256)
     assert repr(x) == "<cdata 'signed char' -66>"
@@ -110,7 +128,7 @@
         assert bool(cast(p, -INF))
         assert int(cast(p, -150)) == -150
         assert int(cast(p, 61.91)) == 61
-        assert long(cast(p, 61.91)) == 61L
+        assert long(cast(p, 61.91)) == 61
         assert type(int(cast(p, 61.91))) is int
         assert type(int(cast(p, 1E22))) is long
         assert type(long(cast(p, 61.91))) is long
@@ -169,13 +187,13 @@
     assert bool(cast(p, '\x00'))
     assert cast(p, '\x00') != cast(p, -17*256)
     assert int(cast(p, 'A')) == 65
-    assert long(cast(p, 'A')) == 65L
+    assert long(cast(p, 'A')) == 65
     assert type(int(cast(p, 'A'))) is int
     assert type(long(cast(p, 'A'))) is long
     assert str(cast(p, 'A')) == repr(cast(p, 'A'))
-    assert repr(cast(p, 'A')) == "<cdata 'char' 'A'>"
-    assert repr(cast(p, 255)) == r"<cdata 'char' '\xff'>"
-    assert repr(cast(p, 0)) == r"<cdata 'char' '\x00'>"
+    assert repr(cast(p, 'A')) == "<cdata 'char' %s'A'>" % mandatory_b_prefix
+    assert repr(cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % mandatory_b_prefix
+    assert repr(cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % mandatory_b_prefix
 
 def test_pointer_type():
     p = new_primitive_type("int")
@@ -272,15 +290,17 @@
     py.test.raises(TypeError, newp, BChar, None)
     BPtr = new_pointer_type(BChar)
     p = newp(BPtr, None)
-    assert p[0] == '\x00'
-    p = newp(BPtr, 'A')
-    assert p[0] == 'A'
+    assert p[0] == b'\x00'
+    p = newp(BPtr, b'A')
+    assert p[0] == b'A'
     py.test.raises(TypeError, newp, BPtr, 65)
-    py.test.raises(TypeError, newp, BPtr, "foo")
-    c = cast(BChar, 'A')
+    py.test.raises(TypeError, newp, BPtr, b"foo")
+    py.test.raises(TypeError, newp, BPtr, u"foo")
+    c = cast(BChar, b'A')
     assert str(c) == repr(c)
-    assert int(c) == ord('A')
-    py.test.raises(TypeError, cast, BChar, 'foo')
+    assert int(c) == ord(b'A')
+    py.test.raises(TypeError, cast, BChar, b'foo')
+    py.test.raises(TypeError, cast, BChar, u'foo')
 
 def test_reading_pointer_to_pointer():
     BVoidP = new_pointer_type(new_void_type())
@@ -404,9 +424,9 @@
     assert repr(p2) == "<ctype 'int[][42]'>"
     #
     py.test.raises(OverflowError,
-                   new_array_type, new_pointer_type(p), sys.maxint+1)
+                   new_array_type, new_pointer_type(p), sys.maxsize+1)
     py.test.raises(OverflowError,
-                   new_array_type, new_pointer_type(p), sys.maxint // 3)
+                   new_array_type, new_pointer_type(p), sys.maxsize // 3)
 
 def test_array_instance():
     LENGTH = 1423
@@ -447,7 +467,7 @@
 def test_array_of_unknown_length_instance_with_initializer():
     p = new_primitive_type("int")
     p1 = new_array_type(new_pointer_type(p), None)
-    a = newp(p1, range(42))
+    a = newp(p1, list(range(42)))
     assert len(a) == 42
     a = newp(p1, tuple(range(142)))
     assert len(a) == 142
@@ -455,7 +475,7 @@
 def test_array_initializer():
     p = new_primitive_type("int")
     p1 = new_array_type(new_pointer_type(p), None)
-    a = newp(p1, range(100, 142))
+    a = newp(p1, list(range(100, 142)))
     for i in range(42):
         assert a[i] == 100 + i
     #
@@ -469,7 +489,7 @@
     p = new_primitive_type("int")
     p1 = new_array_type(new_pointer_type(p), 5)    # int[5]
     p2 = new_array_type(new_pointer_type(p1), 3)   # int[3][5]
-    a = newp(p2, [range(n, n+5) for n in [100, 200, 300]])
+    a = newp(p2, [list(range(n, n+5)) for n in [100, 200, 300]])
     assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % (
         3*5*size_of_int(),)
     assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x")
@@ -539,7 +559,7 @@
     p = new_primitive_type("char")
     p1 = new_pointer_type(p)
     n = newp(p1, cast(p, "A"))
-    assert n[0] == "A"
+    assert n[0] == b"A"
 
 def test_cast_between_pointers():
     BIntP = new_pointer_type(new_primitive_type("int"))
@@ -644,7 +664,7 @@
     s.a2 = 123
     assert s.a1 == 0
     assert s.a2 == 123
-    py.test.raises(OverflowError, "s.a1 = sys.maxint+1")
+    py.test.raises(OverflowError, "s.a1 = sys.maxsize+1")
     assert s.a1 == 0
     py.test.raises(AttributeError, "p.foobar")
     py.test.raises(AttributeError, "s.foobar")
@@ -846,12 +866,12 @@
                                        ('a2', BShort, -1)])
     BFunc7 = new_function_type((BStruct,), BShort, False)
     f = cast(BFunc7, _testfunc(7))
-    res = f({'a1': 'A', 'a2': -4042})
-    assert res == -4042 + ord('A')
+    res = f({'a1': b'A', 'a2': -4042})
+    assert res == -4042 + ord(b'A')
     #
-    x = newp(BStructPtr, {'a1': 'A', 'a2': -4042})
+    x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
     res = f(x[0])
-    assert res == -4042 + ord('A')
+    assert res == -4042 + ord(b'A')
 
 def test_call_function_20():
     BChar = new_primitive_type("char")
@@ -862,11 +882,11 @@
                                        ('a2', BShort, -1)])
     BFunc18 = new_function_type((BStructPtr,), BShort, False)
     f = cast(BFunc18, _testfunc(20))
-    x = newp(BStructPtr, {'a1': 'A', 'a2': -4042})
+    x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
     # test the exception that allows us to pass a 'struct foo' where the
     # function really expects a 'struct foo *'.
     res = f(x[0])
-    assert res == -4042 + ord('A')
+    assert res == -4042 + ord(b'A')
     assert res == f(x)
 
 def test_call_function_9():
@@ -902,7 +922,7 @@
     BCharA = new_array_type(BCharP, None)
     x = newp(BCharA, 42)
     assert len(x) == 42
-    x = newp(BCharA, "foobar")
+    x = newp(BCharA, b"foobar")
     assert len(x) == 7
 
 def test_load_and_call_function():
@@ -912,10 +932,10 @@
     BFunc = new_function_type((BCharP,), BLong, False)
     ll = find_and_load_library('c')
     strlen = ll.load_function(BFunc, "strlen")
-    input = newp(new_array_type(BCharP, None), "foobar")
+    input = newp(new_array_type(BCharP, None), b"foobar")
     assert strlen(input) == 6
     #
-    assert strlen("foobarbaz") == 9
+    assert strlen(b"foobarbaz") == 9
     #
     BVoidP = new_pointer_type(new_void_type())
     strlenaddr = ll.load_function(BVoidP, "strlen")
@@ -951,7 +971,8 @@
     f = make_callback()
     assert f(-142) == -141
     assert repr(f).startswith(
-        "<cdata 'int(*)(int)' calling <function cb at 0x")
+        "<cdata 'int(*)(int)' calling <function ")
+    assert "cb at 0x" in repr(f)
     e = py.test.raises(TypeError, f)
     assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0"
 
@@ -1071,18 +1092,20 @@
     BInt = new_primitive_type("int")
     BChar = new_primitive_type("char")
     def cb(n):
-        return chr(n)
+        return bytechr(n)
     BFunc = new_function_type((BInt,), BChar)
     f = callback(BFunc, cb)
-    assert f(0) == '\x00'
-    assert f(255) == '\xFF'
+    assert f(0) == b'\x00'
+    assert f(255) == b'\xFF'
 
 def test_callback_returning_wchar_t():
     BInt = new_primitive_type("int")
     BWChar = new_primitive_type("wchar_t")
     def cb(n):
-        if n < 0:
+        if n == -1:
             return u'\U00012345'
+        if n == -2:
+            raise ValueError
         return unichr(n)
     BFunc = new_function_type((BInt,), BWChar)
     f = callback(BFunc, cb)
@@ -1091,6 +1114,7 @@
     assert f(0x1234) == u'\u1234'
     if sizeof(BWChar) == 4:
         assert f(-1) == u'\U00012345'
+    assert f(-2) == u'\x00'   # and an exception printed to stderr
 
 def test_struct_with_bitfields():
     BLong = new_primitive_type("long")
@@ -1188,14 +1212,14 @@
     BChar = new_primitive_type("char")
     BArray1 = new_array_type(new_pointer_type(BChar), 5)
     BArray2 = new_array_type(new_pointer_type(BArray1), 5)
-    a = newp(BArray2, ["abc", "de", "ghij"])
-    assert string(a[1]) == "de"
-    assert string(a[2]) == "ghij"
-    a[2] = "."
-    assert string(a[2]) == "."
-    a[2] = "12345"
-    assert string(a[2]) == "12345"
-    e = py.test.raises(IndexError, 'a[2] = "123456"')
+    a = newp(BArray2, [b"abc", b"de", b"ghij"])
+    assert string(a[1]) == b"de"
+    assert string(a[2]) == b"ghij"
+    a[2] = b"."
+    assert string(a[2]) == b"."
+    a[2] = b"12345"
+    assert string(a[2]) == b"12345"
+    e = py.test.raises(IndexError, 'a[2] = b"123456"')
     assert 'char[5]' in str(e.value)
     assert 'got 6 characters' in str(e.value)
 
@@ -1214,13 +1238,13 @@
 def test_too_many_items():
     BChar = new_primitive_type("char")
     BArray = new_array_type(new_pointer_type(BChar), 5)
-    py.test.raises(IndexError, newp, BArray, ('1', '2', '3', '4', '5', '6'))
-    py.test.raises(IndexError, newp, BArray, ['1', '2', '3', '4', '5', '6'])
-    py.test.raises(IndexError, newp, BArray, '123456')
+    py.test.raises(IndexError, newp, BArray, tuple(b'123456'))
+    py.test.raises(IndexError, newp, BArray, list(b'123456'))
+    py.test.raises(IndexError, newp, BArray, b'123456')
     BStruct = new_struct_type("foo")
     complete_struct_or_union(BStruct, [])
-    py.test.raises(TypeError, newp, new_pointer_type(BStruct), '')
-    py.test.raises(ValueError, newp, new_pointer_type(BStruct), ['1'])
+    py.test.raises(TypeError, newp, new_pointer_type(BStruct), b'')
+    py.test.raises(ValueError, newp, new_pointer_type(BStruct), [b'1'])
 
 def test_more_type_errors():
     BInt = new_primitive_type("int")
@@ -1251,7 +1275,7 @@
     #
     BChar = new_primitive_type("char")
     p = newp(new_pointer_type(BChar), cast(BChar, '!'))
-    assert p[0] == '!'
+    assert p[0] == b'!'
     #
     BFloat = new_primitive_type("float")
     p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25))
@@ -1289,37 +1313,37 @@
 
 def test_string():
     BChar = new_primitive_type("char")
-    assert string(cast(BChar, 42)) == '*'
-    assert string(cast(BChar, 0)) == '\x00'
+    assert string(cast(BChar, 42)) == b'*'
+    assert string(cast(BChar, 0)) == b'\x00'
     BCharP = new_pointer_type(BChar)
     BArray = new_array_type(BCharP, 10)
-    a = newp(BArray, "hello")
+    a = newp(BArray, b"hello")
     assert len(a) == 10
-    assert string(a) == "hello"
+    assert string(a) == b"hello"
     p = a + 2
-    assert string(p) == "llo"
-    assert string(newp(new_array_type(BCharP, 4), "abcd")) == "abcd"
+    assert string(p) == b"llo"
+    assert string(newp(new_array_type(BCharP, 4), b"abcd")) == b"abcd"
     py.test.raises(RuntimeError, string, cast(BCharP, 0))
-    assert string(a, 4) == "hell"
-    assert string(a, 5) == "hello"
-    assert string(a, 6) == "hello"
+    assert string(a, 4) == b"hell"
+    assert string(a, 5) == b"hello"
+    assert string(a, 6) == b"hello"
 
 def test_string_byte():
     BByte = new_primitive_type("signed char")
-    assert string(cast(BByte, 42)) == '*'
-    assert string(cast(BByte, 0)) == '\x00'
+    assert string(cast(BByte, 42)) == b'*'
+    assert string(cast(BByte, 0)) == b'\x00'
     BArray = new_array_type(new_pointer_type(BByte), None)
     a = newp(BArray, [65, 66, 67])
-    assert type(string(a)) is str and string(a) == 'ABC'
+    assert type(string(a)) is bytes and string(a) == b'ABC'
     #
     BByte = new_primitive_type("unsigned char")
-    assert string(cast(BByte, 42)) == '*'
-    assert string(cast(BByte, 0)) == '\x00'
+    assert string(cast(BByte, 42)) == b'*'
+    assert string(cast(BByte, 0)) == b'\x00'
     BArray = new_array_type(new_pointer_type(BByte), None)
     a = newp(BArray, [65, 66, 67])
-    assert type(string(a)) is str and string(a) == 'ABC'
-    if 'PY_DOT_PY' not in globals():
-        assert string(a, 8).startswith('ABC')  # may contain additional garbage
+    assert type(string(a)) is bytes and string(a) == b'ABC'
+    if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
+        assert string(a, 8).startswith(b'ABC')  # may contain additional garbage
 
 def test_string_wchar():
     BWChar = new_primitive_type("wchar_t")
@@ -1329,7 +1353,7 @@
     BArray = new_array_type(new_pointer_type(BWChar), None)
     a = newp(BArray, [u'A', u'B', u'C'])
     assert type(string(a)) is unicode and string(a) == u'ABC'
-    if 'PY_DOT_PY' not in globals():
+    if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
         assert string(a, 8).startswith(u'ABC') # may contain additional garbage
 
 def test_string_typeerror():
@@ -1353,12 +1377,12 @@
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)])
     p = newp(BStructPtr, None)
-    assert string(p.a1) == ''
-    p.a1 = 'foo'
-    assert string(p.a1) == 'foo'
-    assert list(p.a1) == ['f', 'o', 'o'] + ['\x00'] * 7
-    p.a1 = ['x', 'y']
-    assert string(p.a1) == 'xyo'
+    assert string(p.a1) == b''
+    p.a1 = b'foo'
+    assert string(p.a1) == b'foo'
+    assert list(p.a1) == [b'f', b'o', b'o'] + [b'\x00'] * 7
+    p.a1 = [b'x', b'y']
+    assert string(p.a1) == b'xyo'
 
 def test_invalid_function_result_types():
     BFunc = new_function_type((), new_void_type())
@@ -1384,7 +1408,7 @@
     f = cast(BFunc10, _testfunc(10))
     s = f(40)
     assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>"
-    assert s.a1 == chr(40)
+    assert s.a1 == bytechr(40)
     assert s.a2 == 40 * 40
     #
     BStruct11 = new_struct_type("test11")
@@ -1483,11 +1507,14 @@
     BInt = new_primitive_type("int")
     pyuni4 = {1: True, 2: False}[len(u'\U00012345')]
     wchar4 = {2: False, 4: True}[sizeof(BWChar)]
-    assert str(cast(BWChar, 0x45)) == "<cdata 'wchar_t' u'E'>"
-    assert str(cast(BWChar, 0x1234)) == "<cdata 'wchar_t' u'\u1234'>"
+    assert str(cast(BWChar, 0x45)) == "<cdata 'wchar_t' %s'E'>" % (
+        mandatory_u_prefix,)
+    assert str(cast(BWChar, 0x1234)) == "<cdata 'wchar_t' %s'\u1234'>" % (
+        mandatory_u_prefix,)
     if wchar4:
         x = cast(BWChar, 0x12345)
-        assert str(x) == "<cdata 'wchar_t' u'\U00012345'>"
+        assert str(x) == "<cdata 'wchar_t' %s'\U00012345'>" % (
+            mandatory_u_prefix,)
         assert int(x) == 0x12345
     else:
         assert not pyuni4
@@ -1500,8 +1527,8 @@
     s = newp(BStructPtr)
     s.a1 = u'\x00'
     assert s.a1 == u'\x00'
-    py.test.raises(TypeError, "s.a1 = 'a'")
-    py.test.raises(TypeError, "s.a1 = '\xFF'")
+    py.test.raises(TypeError, "s.a1 = b'a'")
+    py.test.raises(TypeError, "s.a1 = bytechr(0xFF)")
     s.a1 = u'\u1234'
     assert s.a1 == u'\u1234'
     if pyuni4:
@@ -1541,17 +1568,17 @@
         py.test.raises(IndexError, 'a[4]')
     #
     w = cast(BWChar, 'a')
-    assert repr(w) == "<cdata 'wchar_t' u'a'>"
+    assert repr(w) == "<cdata 'wchar_t' %s'a'>" % mandatory_u_prefix
     assert str(w) == repr(w)
     assert string(w) == u'a'
     assert int(w) == ord('a')
     w = cast(BWChar, 0x1234)
-    assert repr(w) == "<cdata 'wchar_t' u'\u1234'>"
+    assert repr(w) == "<cdata 'wchar_t' %s'\u1234'>" % mandatory_u_prefix
     assert str(w) == repr(w)
     assert string(w) == u'\u1234'
     assert int(w) == 0x1234
     w = cast(BWChar, u'\u8234')
-    assert repr(w) == "<cdata 'wchar_t' u'\u8234'>"
+    assert repr(w) == "<cdata 'wchar_t' %s'\u8234'>" % mandatory_u_prefix
     assert str(w) == repr(w)
     assert string(w) == u'\u8234'
     assert int(w) == 0x8234
@@ -1559,7 +1586,8 @@
     assert repr(w) == "<cdata 'int' 4660>"
     if wchar4:
         w = cast(BWChar, u'\U00012345')
-        assert repr(w) == "<cdata 'wchar_t' u'\U00012345'>"
+        assert repr(w) == "<cdata 'wchar_t' %s'\U00012345'>" % (
+            mandatory_u_prefix,)
         assert str(w) == repr(w)
         assert string(w) == u'\U00012345'
         assert int(w) == 0x12345
@@ -1694,27 +1722,31 @@
     s = newp(new_pointer_type(BShort), 100)
     assert sizeof(s) == size_of_ptr()
     assert sizeof(BShort) == 2
-    assert len(str(buffer(s))) == 2
+    assert len(readbuf(buffer(s))) == 2
     #
     BChar = new_primitive_type("char")
     BCharArray = new_array_type(new_pointer_type(BChar), None)
-    c = newp(BCharArray, "hi there")
+    c = newp(BCharArray, b"hi there")
     buf = buffer(c)
-    assert str(buf) == "hi there\x00"
-    assert len(buf) == len("hi there\x00")
-    assert buf[0] == 'h'
-    assert buf[2] == ' '
-    assert list(buf) == ['h', 'i', ' ', 't', 'h', 'e', 'r', 'e', '\x00']
-    buf[2] = '-'
-    assert c[2] == '-'
-    assert str(buf) == "hi-there\x00"
-    buf[:2] = 'HI'
-    assert string(c) == 'HI-there'
-    assert buf[:4:2] == 'H-'
+    assert readbuf(buf) == b"hi there\x00"
+    assert len(buf) == len(b"hi there\x00")
+    assert buf[0] == bufchar('h')
+    assert buf[2] == bufchar(' ')
+    assert list(buf) == list(map(bufchar, "hi there\x00"))
+    buf[2] = bufchar('-')
+    assert c[2] == b'-'
+    assert readbuf(buf) == b"hi-there\x00"
+    c[2] = b'!'
+    assert buf[2] == bufchar('!')
+    assert readbuf(buf) == b"hi!there\x00"
+    c[2] = b'-'
+    buf[:2] = b'HI'
+    assert string(c) == b'HI-there'
+    assert buf[:4:2] == b'H-'
     if '__pypy__' not in sys.builtin_module_names:
         # XXX pypy doesn't support the following assignment so far
-        buf[:4:2] = 'XY'
-        assert string(c) == 'XIYthere'
+        buf[:4:2] = b'XY'
+        assert string(c) == b'XIYthere'
 
 def test_getcname():
     BUChar = new_primitive_type("unsigned char")
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -1,4 +1,4 @@
-import new
+import types
 
 class FFIError(Exception):
     pass
@@ -38,7 +38,7 @@
         if backend is None:
             try:
                 import _cffi_backend as backend
-            except ImportError, e:
+            except ImportError as e:
                 import warnings
                 warnings.warn("import _cffi_backend: %s\n"
                               "Falling back to the ctypes backend." % (e,))
@@ -47,8 +47,8 @@
         self._backend = backend
         self._parser = cparser.Parser()
         self._cached_btypes = {}
-        self._parsed_types = new.module('parsed_types').__dict__
-        self._new_types = new.module('new_types').__dict__
+        self._parsed_types = types.ModuleType('parsed_types').__dict__
+        self._new_types = types.ModuleType('new_types').__dict__
         self._function_caches = []
         self._cdefsources = []
         if hasattr(backend, 'set_ffi'):
@@ -113,7 +113,7 @@
         corresponding Python type: <class 'ffi.CData<...>'>.
         It can also be used on 'cdata' instance to get its C type.
         """
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             return self._typeof(cdecl)
         else:
             return self._backend.typeof(cdecl)
@@ -122,7 +122,7 @@
         """Return the size in bytes of the argument.  It can be a
         string naming a C type, or a 'cdata' instance.
         """
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             BType = self._typeof(cdecl)
             return self._backend.sizeof(BType)
         else:
@@ -132,7 +132,7 @@
         """Return the natural alignment size in bytes of the C type
         given as a string.
         """
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             cdecl = self._typeof(cdecl)
         return self._backend.alignof(cdecl)
 
@@ -140,7 +140,7 @@
         """Return the offset of the named field inside the given
         structure, which must be given as a C type name.
         """
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             cdecl = self._typeof(cdecl)
         return self._backend.offsetof(cdecl, fieldname)
 
@@ -167,7 +167,7 @@
         about that when copying the pointer to the memory somewhere
         else, e.g. into another structure.
         """
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             cdecl = self._typeof(cdecl)
         return self._backend.newp(cdecl, init)
 
@@ -176,7 +176,7 @@
         type initialized with the given 'source'.  The source is
         casted between integers or pointers of any type.
         """
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             cdecl = self._typeof(cdecl)
         return self._backend.cast(cdecl, source)
 
@@ -214,7 +214,7 @@
         """
         if not callable(python_callable):
             raise TypeError("the 'python_callable' argument is not callable")
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
         return self._backend.callback(cdecl, python_callable, error)
 
@@ -224,7 +224,7 @@
         extra text to append (or insert for more complicated C types), like
         a variable name, or '*' to get actually the C type 'pointer-to-cdecl'.
         """
-        if isinstance(cdecl, basestring):
+        if isinstance(cdecl, str):
             cdecl = self._typeof(cdecl)
         replace_with = replace_with.strip()
         if (replace_with.startswith('*')
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -1,5 +1,15 @@
 import ctypes, ctypes.util, operator, sys
 from . import model
+import sys
+
+if sys.version_info < (3,):
+    integer_types = (int, long)
+    bytechr = chr
+else:
+    unicode = str
+    integer_types = int
+    xrange = range
+    bytechr = lambda num: bytes([num])
 
 class CTypesData(object):
     __slots__ = ['__weakref__']
@@ -48,6 +58,7 @@
     @classmethod
     def _fix_class(cls):
         cls.__name__ = 'CData<%s>' % (cls._get_c_name(),)
+        cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),)
         cls.__module__ = 'ffi'
 
     def _get_own_repr(self):
@@ -165,7 +176,7 @@
             address = 0
         elif isinstance(source, CTypesData):
             address = source._cast_to_integer()
-        elif isinstance(source, (int, long)):
+        elif isinstance(source, integer_types):
             address = source
         else:
             raise TypeError("bad type for cast to %r: %r" %
@@ -190,6 +201,9 @@
 
     def __nonzero__(self):
         return bool(self._address)
+    
+    def __bool__(self):
+        return bool(self._address)
 
     @classmethod
     def _to_ctypes(cls, value):
@@ -324,11 +338,11 @@
             is_signed = (ctype(-1).value == -1)
         #
         def _cast_source_to_int(source):
-            if isinstance(source, (int, long, float)):
+            if isinstance(source, (integer_types, float)):
                 source = int(source)
             elif isinstance(source, CTypesData):
                 source = source._cast_to_integer()
-            elif isinstance(source, str):
+            elif isinstance(source, bytes):
                 source = ord(source)
             elif source is None:
                 source = 0
@@ -364,7 +378,7 @@
                 @classmethod
                 def _cast_from(cls, source):
                     source = _cast_source_to_int(source)
-                    source = chr(source & 0xFF)
+                    source = bytechr(source & 0xFF)
                     return cls(source)
                 def __int__(self):
                     return ord(self._value)
@@ -393,7 +407,7 @@
             if kind == 'int' or kind == 'byte':
                 @staticmethod
                 def _to_ctypes(x):
-                    if not isinstance(x, (int, long)):
+                    if not isinstance(x, integer_types):
                         if isinstance(x, CTypesData):
                             x = int(x)
                         else:
@@ -410,7 +424,7 @@
             if kind == 'char':
                 @staticmethod
                 def _to_ctypes(x):
-                    if isinstance(x, str) and len(x) == 1:
+                    if isinstance(x, bytes) and len(x) == 1:
                         return x
                     if isinstance(x, CTypesPrimitive):    # <CData <char>>
                         return x._value
@@ -420,7 +434,7 @@
             if kind == 'float':
                 @staticmethod
                 def _to_ctypes(x):
-                    if not isinstance(x, (int, long, float, CTypesData)):
+                    if not isinstance(x, (integer_types, float, CTypesData)):
                         raise TypeError("float expected, got %s" %
                                         type(x).__name__)
                     return ctype(x).value
@@ -455,6 +469,8 @@
         #
         class CTypesPtr(CTypesGenericPtr):
             __slots__ = ['_own']
+            if kind == 'charp':
+                __slots__ += ['__as_strbuf']
             _BItem = BItem
             if hasattr(BItem, '_ctype'):
                 _ctype = ctypes.POINTER(BItem._ctype)
@@ -468,20 +484,26 @@
 
             def __init__(self, init):
                 ctypeobj = BItem._create_ctype_obj(init)
-                self._as_ctype_ptr = ctypes.pointer(ctypeobj)
+                if kind == 'charp':
+                    self.__as_strbuf = ctypes.create_string_buffer(
+                        ctypeobj.value + b'\x00')
+                    self._as_ctype_ptr = ctypes.cast(
+                        self.__as_strbuf, self._ctype)
+                else:
+                    self._as_ctype_ptr = ctypes.pointer(ctypeobj)
                 self._address = ctypes.cast(self._as_ctype_ptr,
                                             ctypes.c_void_p).value
                 self._own = True
 
             def __add__(self, other):
-                if isinstance(other, (int, long)):
+                if isinstance(other, integer_types):
                     return self._new_pointer_at(self._address +
                                                 other * self._bitem_size)
                 else:
                     return NotImplemented
 
             def __sub__(self, other):
-                if isinstance(other, (int, long)):
+                if isinstance(other, integer_types):
                     return self._new_pointer_at(self._address -
                                                 other * self._bitem_size)
                 elif type(self) is type(other):
@@ -500,7 +522,7 @@
             if kind == 'charp':
                 @classmethod
                 def _arg_to_ctypes(cls, value):
-                    if isinstance(value, str):
+                    if isinstance(value, bytes):
                         return ctypes.c_char_p(value)
                     else:
                         return super(CTypesPtr, cls)._arg_to_ctypes(value)
@@ -508,13 +530,13 @@
             if kind == 'charp' or kind == 'bytep':
                 def _to_string(self, maxlen):
                     if maxlen < 0:
-                        maxlen = sys.maxint
+                        maxlen = sys.maxsize
                     p = ctypes.cast(self._as_ctype_ptr,
                                     ctypes.POINTER(ctypes.c_char))
                     n = 0
-                    while n < maxlen and p[n] != '\x00':
+                    while n < maxlen and p[n] != b'\x00':
                         n += 1
-                    return ''.join([p[i] for i in range(n)])
+                    return b''.join([p[i] for i in range(n)])
 
             def _get_own_repr(self):
                 if getattr(self, '_own', False):
@@ -556,13 +578,14 @@
 
             def __init__(self, init):
                 if length is None:
-                    if isinstance(init, (int, long)):
+                    if isinstance(init, integer_types):
                         len1 = init
                         init = None
+                    elif kind == 'char' and isinstance(init, bytes):
+                        len1 = len(init) + 1    # extra null
                     else:
-                        extra_null = (kind == 'char' and isinstance(init, str))
                         init = tuple(init)
-                        len1 = len(init) + extra_null
+                        len1 = len(init)
                     self._ctype = BItem._ctype * len1
                 self._blob = self._ctype()
                 self._own = True
@@ -571,7 +594,10 @@
 
             @staticmethod
             def _initialize(blob, init):
-                init = tuple(init)
+                if isinstance(init, bytes):
+                    init = [init[i:i+1] for i in range(len(init))]
+                else:
+                    init = tuple(init)
                 if len(init) > len(blob):
                     raise IndexError("too many initializers")
                 addr = ctypes.cast(blob, ctypes.c_void_p).value
@@ -601,9 +627,9 @@
                     p = ctypes.cast(self._blob,
                                     ctypes.POINTER(ctypes.c_char))
                     n = 0
-                    while n < maxlen and p[n] != '\x00':
+                    while n < maxlen and p[n] != b'\x00':
                         n += 1
-                    return ''.join([p[i] for i in range(n)])
+                    return b''.join([p[i] for i in range(n)])
 
             def _get_own_repr(self):
                 if getattr(self, '_own', False):
@@ -627,7 +653,7 @@
                 return CTypesPtr._arg_to_ctypes(value)
 
             def __add__(self, other):
-                if isinstance(other, (int, long)):
+                if isinstance(other, integer_types):
                     return CTypesPtr._new_pointer_at(
                         ctypes.addressof(self._blob) +
                         other * ctypes.sizeof(BItem._ctype))
@@ -697,7 +723,7 @@
                                     "only one supported (use a dict if needed)"
                                      % (len(init),))
             if not isinstance(init, dict):
-                if isinstance(init, str):
+                if isinstance(init, (bytes, unicode)):
                     raise TypeError("union initializer: got a str")
                 init = tuple(init)
                 if len(init) > len(fnames):
@@ -869,7 +895,8 @@
     def new_enum_type(self, name, enumerators, enumvalues):
         assert isinstance(name, str)
         mapping = dict(zip(enumerators, enumvalues))
-        reverse_mapping = dict(reversed(zip(enumvalues, enumerators)))
+        reverse_mapping = dict(zip(reversed(enumvalues),
+                                   reversed(enumerators)))
         CTypesInt = self.ffi._get_cached_btype(model.PrimitiveType('int'))
         #
         def forward_map(source):
@@ -924,6 +951,26 @@
         return b._to_string(maxlen)
 
     def buffer(self, bptr, size=-1):
+        if sys.version_info >= (3,):
+            # buf = bptr._as_ctype_ptr
+            # return memoryview(buf.contents)
+            if isinstance(bptr, CTypesGenericPtr):
+                buf = bptr._as_ctype_ptr
+                val = buf.contents
+            elif isinstance(bptr, CTypesGenericArray):
+                buf = bptr._blob
+                val = bptr._blob
+            else:
+                raise TypeError(bptr)
+            class Hack(ctypes.Union):
+                _fields_ = [('stupid', type(val))]
+            ptr = ctypes.cast(buf, ctypes.POINTER(Hack))
+            view = memoryview(ptr.contents)
+            if size >= 0:
+                return view.cast('B')[:size]
+            else:
+                return view.cast('B')
+
         # haaaaaaaaaaaack
         call = ctypes.pythonapi.PyBuffer_FromReadWriteMemory
         call.argtypes = (ctypes.c_void_p, ctypes.c_size_t)
@@ -988,7 +1035,7 @@
     def read_variable(self, BType, name):
         try:
             ctypes_obj = BType._ctype.in_dll(self.cdll, name)
-        except AttributeError, e:
+        except AttributeError as e:
             raise NotImplementedError(e)
         return BType._from_ctypes(ctypes_obj)
 
diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py
--- a/cffi/ffiplatform.py
+++ b/cffi/ffiplatform.py
@@ -54,7 +54,7 @@
     try:
         dist.run_command('build_ext')
     except (distutils.errors.CompileError,
-            distutils.errors.LinkError), e:
+            distutils.errors.LinkError) as e:
         raise VerificationError('%s: %s' % (e.__class__.__name__, e))
     #
     cmd_obj = dist.get_command_obj('build_ext')
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -182,7 +182,7 @@
         fldtypes = tuple(ffi._get_cached_btype(tp) for tp in self.fldtypes)
         #
         if self.fixedlayout is None:
-            lst = zip(self.fldnames, fldtypes, self.fldbitsize)
+            lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
             ffi._backend.complete_struct_or_union(BType, lst, self)
             #
         else:
@@ -213,7 +213,7 @@
                         "field '%s.%s' is declared as %d bytes, but is "
                         "really %d bytes" % (self.name, self.fldnames[i],
                                              bitemsize, fsize))
-            lst = zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)
+            lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs))
             ffi._backend.complete_struct_or_union(BType, lst, self,
                                                   totalsize, totalalignment)
         return BType
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -1,4 +1,4 @@
-import imp
+import sys, imp
 from . import model, ffiplatform
 
 
@@ -18,7 +18,7 @@
         self._generate("collecttype")
 
     def _prnt(self, what=''):
-        print >> self._f, what
+        self._f.write(what + '\n')
 
     def _gettypenum(self, type):
         # a KeyError here is a bug.  please report it! :-)
@@ -79,15 +79,35 @@
         #
         # standard init.
         modname = self.verifier.get_module_name()
+        if sys.version_info >= (3,):
+            prnt('static struct PyModuleDef _cffi_module_def = {')
+            prnt('  PyModuleDef_HEAD_INIT,')
+            prnt('  "%s",' % modname)
+            prnt('  NULL,')
+            prnt('  -1,')
+            prnt('  _cffi_methods,')
+            prnt('  NULL, NULL, NULL, NULL')
+            prnt('};')
+            prnt()
+            initname = 'PyInit_%s' % modname
+            createmod = 'PyModule_Create(&_cffi_module_def)'
+            errorcase = 'return NULL'
+            finalreturn = 'return lib'
+        else:
+            initname = 'init%s' % modname
+            createmod = 'Py_InitModule("%s", _cffi_methods)' % modname
+            errorcase = 'return'
+            finalreturn = 'return'
         prnt('PyMODINIT_FUNC')
-        prnt('init%s(void)' % modname)
+        prnt('%s(void)' % initname)
         prnt('{')
         prnt('  PyObject *lib;')
-        prnt('  lib = Py_InitModule("%s", _cffi_methods);' % modname)
+        prnt('  lib = %s;' % createmod)
         prnt('  if (lib == NULL || %s < 0)' % (
             self._chained_list_constants[False],))
-        prnt('    return;')
+        prnt('    %s;' % errorcase)
         prnt('  _cffi_init();')
+        prnt('  %s;' % finalreturn)
         prnt('}')
 
     def load_library(self):
@@ -96,7 +116,7 @@
         try:
             module = imp.load_dynamic(self.verifier.get_module_name(),
                                       self.verifier.modulefilename)
-        except ImportError, e:
+        except ImportError as e:
             error = "importing %r: %s" % (self.verifier.modulefilename, e)
             raise ffiplatform.VerificationError(error)
         #
@@ -109,7 +129,7 @@
         revmapping = dict([(value, key)
                            for (key, value) in self._typesdict.items()])
         lst = [revmapping[i] for i in range(len(revmapping))]
-        lst = map(self.ffi._get_cached_btype, lst)
+        lst = list(map(self.ffi._get_cached_btype, lst))
         #
         # build the FFILibrary class and instance and call _cffi_setup().
         # this will set up some fields like '_cffi_types', and only then
@@ -129,7 +149,7 @@
         return library
 
     def _generate(self, step_name):
-        for name, tp in self.ffi._parser._declarations.iteritems():
+        for name, tp in self.ffi._parser._declarations.items():
             kind, realname = name.split(' ', 1)
             try:
                 method = getattr(self, '_generate_cpy_%s_%s' % (kind,
@@ -140,7 +160,7 @@
             method(tp, realname)
 
     def _load(self, module, step_name, **kwds):
-        for name, tp in self.ffi._parser._declarations.iteritems():
+        for name, tp in self.ffi._parser._declarations.items():
             kind, realname = name.split(' ', 1)
             method = getattr(self, '_%s_cpy_%s' % (step_name, kind))
             method(tp, realname, module, **kwds)
@@ -616,6 +636,19 @@
 typedef unsigned __int64 uint64_t;
 #endif
 
+#if PY_MAJOR_VERSION < 3
+# undef PyCapsule_CheckExact
+# undef PyCapsule_GetPointer
+# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))
+# define PyCapsule_GetPointer(capsule, name) \
+    (PyCObject_AsVoidPtr(capsule))
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+# define PyInt_FromLong PyLong_FromLong
+# define PyInt_AsLong PyLong_AsLong
+#endif
+
 #define _cffi_from_c_double PyFloat_FromDouble
 #define _cffi_from_c_float PyFloat_FromDouble
 #define _cffi_from_c_signed_char PyInt_FromLong
@@ -729,11 +762,11 @@
     c_api_object = PyObject_GetAttrString(module, "_C_API");
     if (c_api_object == NULL)
         return;
-    if (!PyCObject_Check(c_api_object)) {
+    if (!PyCapsule_CheckExact(c_api_object)) {
         PyErr_SetNone(PyExc_ImportError);
         return;
     }
-    memcpy(_cffi_exports, PyCObject_AsVoidPtr(c_api_object),
+    memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"),
            _CFFI_NUM_EXPORTS * sizeof(void *));
 }
 
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -21,7 +21,7 @@
         pass      # not needed in the generic engine
 
     def _prnt(self, what=''):
-        print >> self._f, what
+        self._f.write(what + '\n')
 
     def write_source_to_f(self):
         prnt = self._prnt
@@ -60,7 +60,7 @@
         return library
 
     def _generate(self, step_name):
-        for name, tp in self.ffi._parser._declarations.iteritems():
+        for name, tp in self.ffi._parser._declarations.items():
             kind, realname = name.split(' ', 1)
             try:
                 method = getattr(self, '_generate_gen_%s_%s' % (kind,
@@ -71,7 +71,7 @@
             method(tp, realname)
 
     def _load(self, module, step_name, **kwds):
-        for name, tp in self.ffi._parser._declarations.iteritems():
+        for name, tp in self.ffi._parser._declarations.items():
             kind, realname = name.split(' ', 1)
             method = getattr(self, '_%s_gen_%s' % (step_name, kind))
             method(tp, realname, module, **kwds)
@@ -377,7 +377,10 @@
             function = module.load_function(BFunc, funcname)
             p = self.ffi.new("char[]", 256)
             if function(p) < 0:
-                raise ffiplatform.VerificationError(self.ffi.string(p))
+                error = self.ffi.string(p)
+                if sys.version_info >= (3,):
+                    error = str(error, 'utf-8')
+                raise ffiplatform.VerificationError(error)
 
     def _loaded_gen_enum(self, tp, name, module, library):
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -15,7 +15,7 @@
         self.kwds = kwds
         #
         key = '\x00'.join(['1', sys.version[:3], __version__, preamble] +
-                          ffi._cdefsources)
+                          ffi._cdefsources).encode('utf-8')
         k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff)
         k1 = k1.lstrip('0x').rstrip('L')
         k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff)
@@ -61,7 +61,10 @@
         return self._load_library()
 
     def get_module_name(self):
-        return os.path.splitext(os.path.basename(self.modulefilename))[0]
+        basename = os.path.basename(self.modulefilename)
+        # kill both the .so extension and the other .'s, as introduced
+        # by Python 3: 'basename.cpython-33m.so'
+        return basename.split('.', 1)[0]
 
     def get_extension(self):
         if self._status == 'init':
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -17,11 +17,11 @@
     try:
         p = subprocess.Popen(['pkg-config', option, 'libffi'],
                              stdout=subprocess.PIPE, stderr=open('/dev/null', 'w'))
-    except OSError, e:
+    except OSError as e:
         if e.errno != errno.ENOENT:
             raise
     else:
-        t = p.stdout.read().strip()
+        t = p.stdout.read().decode().strip()
         if p.wait() == 0:
             res = t.split()
             # '-I/usr/...' -> '/usr/...'
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -8,6 +8,10 @@
 SIZE_OF_PTR   = ctypes.sizeof(ctypes.c_void_p)
 SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
 
+if sys.version_info >= (3,):
+    unicode = str
+    long = int
+
 
 class BackendTests:
 
@@ -276,32 +280,32 @@
 
     def test_char(self):
         ffi = FFI(backend=self.Backend())
-        assert ffi.new("char*", "\xff")[0] == '\xff'
-        assert ffi.new("char*")[0] == '\x00'
+        assert ffi.new("char*", b"\xff")[0] == b'\xff'
+        assert ffi.new("char*")[0] == b'\x00'
         assert int(ffi.cast("char", 300)) == 300 - 256
         assert bool(ffi.cast("char", 0))
         py.test.raises(TypeError, ffi.new, "char*", 32)
         py.test.raises(TypeError, ffi.new, "char*", u"x")
-        py.test.raises(TypeError, ffi.new, "char*", "foo")
+        py.test.raises(TypeError, ffi.new, "char*", b"foo")
         #
-        p = ffi.new("char[]", ['a', 'b', '\x9c'])
+        p = ffi.new("char[]", [b'a', b'b', b'\x9c'])
         assert len(p) == 3
-        assert p[0] == 'a'
-        assert p[1] == 'b'
-        assert p[2] == '\x9c'
-        p[0] = '\xff'
-        assert p[0] == '\xff'
-        p = ffi.new("char[]", "abcd")
+        assert p[0] == b'a'
+        assert p[1] == b'b'
+        assert p[2] == b'\x9c'
+        p[0] = b'\xff'
+        assert p[0] == b'\xff'
+        p = ffi.new("char[]", b"abcd")
         assert len(p) == 5
-        assert p[4] == '\x00'    # like in C, with:  char[] p = "abcd";
+        assert p[4] == b'\x00'    # like in C, with:  char[] p = "abcd";
         #
-        p = ffi.new("char[4]", "ab")
+        p = ffi.new("char[4]", b"ab")
         assert len(p) == 4
-        assert [p[i] for i in range(4)] == ['a', 'b', '\x00', '\x00']
-        p = ffi.new("char[2]", "ab")
+        assert [p[i] for i in range(4)] == [b'a', b'b', b'\x00', b'\x00']
+        p = ffi.new("char[2]", b"ab")
         assert len(p) == 2
-        assert [p[i] for i in range(2)] == ['a', 'b']
-        py.test.raises(IndexError, ffi.new, "char[2]", "abc")
+        assert [p[i] for i in range(2)] == [b'a', b'b']
+        py.test.raises(IndexError, ffi.new, "char[2]", b"abc")
 
     def check_wchar_t(self, ffi):
         try:
@@ -313,7 +317,7 @@
         ffi = FFI(backend=self.Backend())
         self.check_wchar_t(ffi)
         assert ffi.new("wchar_t*", u'x')[0] == u'x'
-        assert ffi.new("wchar_t*", unichr(1234))[0] == unichr(1234)
+        assert ffi.new("wchar_t*", u'\u1234')[0] == u'\u1234'
         if SIZE_OF_WCHAR > 2:
             assert ffi.new("wchar_t*", u'\U00012345')[0] == u'\U00012345'
         else:
@@ -324,21 +328,21 @@
         py.test.raises(TypeError, ffi.new, "wchar_t*", 32)
         py.test.raises(TypeError, ffi.new, "wchar_t*", "foo")
         #
-        p = ffi.new("wchar_t[]", [u'a', u'b', unichr(1234)])
+        p = ffi.new("wchar_t[]", [u'a', u'b', u'\u1234'])
         assert len(p) == 3
         assert p[0] == u'a'
-        assert p[1] == u'b' and type(p[1]) is unicode
-        assert p[2] == unichr(1234)
+        assert p[1] == u'b' and type(p[1]) is type(u'')
+        assert p[2] == u'\u1234'
         p[0] = u'x'
-        assert p[0] == u'x' and type(p[0]) is unicode
-        p[1] = unichr(1357)
-        assert p[1] == unichr(1357)
+        assert p[0] == u'x' and type(p[0]) is type(u'')
+        p[1] = u'\u1357'
+        assert p[1] == u'\u1357'
         p = ffi.new("wchar_t[]", u"abcd")
         assert len(p) == 5
         assert p[4] == u'\x00'
         p = ffi.new("wchar_t[]", u"a\u1234b")
         assert len(p) == 4
-        assert p[1] == unichr(0x1234)
+        assert p[1] == u'\u1234'
         #
         p = ffi.new("wchar_t[]", u'\U00023456')
         if SIZE_OF_WCHAR == 2:
@@ -469,13 +473,13 @@
     def test_constructor_struct_of_array(self):
         ffi = FFI(backend=self.Backend())
         ffi.cdef("struct foo { int a[2]; char b[3]; };")
-        s = ffi.new("struct foo *", [[10, 11], ['a', 'b', 'c']])
+        s = ffi.new("struct foo *", [[10, 11], [b'a', b'b', b'c']])
         assert s.a[1] == 11
-        assert s.b[2] == 'c'
-        s.b[1] = 'X'
-        assert s.b[0] == 'a'
-        assert s.b[1] == 'X'
-        assert s.b[2] == 'c'
+        assert s.b[2] == b'c'
+        s.b[1] = b'X'
+        assert s.b[0] == b'a'
+        assert s.b[1] == b'X'
+        assert s.b[2] == b'c'
 
     def test_recursive_struct(self):
         ffi = FFI(backend=self.Backend())
@@ -512,16 +516,16 @@
     def test_union_initializer(self):
         ffi = FFI(backend=self.Backend())
         ffi.cdef("union foo { char a; int b; };")
-        py.test.raises(TypeError, ffi.new, "union foo*", 'A')
+        py.test.raises(TypeError, ffi.new, "union foo*", b'A')
         py.test.raises(TypeError, ffi.new, "union foo*", 5)
-        py.test.raises(ValueError, ffi.new, "union foo*", ['A', 5])
-        u = ffi.new("union foo*", ['A'])
-        assert u.a == 'A'
-        py.test.raises(TypeError, ffi.new, "union foo*", [5])
+        py.test.raises(ValueError, ffi.new, "union foo*", [b'A', 5])
+        u = ffi.new("union foo*", [b'A'])
+        assert u.a == b'A'
+        py.test.raises(TypeError, ffi.new, "union foo*", [1005])
         u = ffi.new("union foo*", {'b': 12345})
         assert u.b == 12345
         u = ffi.new("union foo*", [])
-        assert u.a == '\x00'
+        assert u.a == b'\x00'
         assert u.b == 0
 
     def test_sizeof_type(self):
@@ -552,10 +556,11 @@
 
     def test_string_from_char_pointer(self):
         ffi = FFI(backend=self.Backend())
-        x = ffi.new("char*", "x")
+        x = ffi.new("char*", b"x")
         assert str(x) == repr(x)
-        assert ffi.string(x) == "x"
-        assert ffi.string(ffi.new("char*", "\x00")) == ""
+        assert ffi.string(x) == b"x"
+        assert ffi.string(ffi.new("char*", b"\x00")) == b""
+        py.test.raises(TypeError, ffi.new, "char*", unicode("foo"))
 
     def test_unicode_from_wchar_pointer(self):
         ffi = FFI(backend=self.Backend())
@@ -567,20 +572,20 @@
 
     def test_string_from_char_array(self):
         ffi = FFI(backend=self.Backend())
-        p = ffi.new("char[]", "hello.")
-        p[5] = '!'
-        assert ffi.string(p) == "hello!"
-        p[6] = '?'
-        assert ffi.string(p) == "hello!?"
-        p[3] = '\x00'
-        assert ffi.string(p) == "hel"
-        assert ffi.string(p, 2) == "he"
-        py.test.raises(IndexError, "p[7] = 'X'")
+        p = ffi.new("char[]", b"hello.")
+        p[5] = b'!'
+        assert ffi.string(p) == b"hello!"
+        p[6] = b'?'
+        assert ffi.string(p) == b"hello!?"
+        p[3] = b'\x00'
+        assert ffi.string(p) == b"hel"
+        assert ffi.string(p, 2) == b"he"
+        py.test.raises(IndexError, "p[7] = b'X'")
         #
-        a = ffi.new("char[]", "hello\x00world")
+        a = ffi.new("char[]", b"hello\x00world")
         assert len(a) == 12
         p = ffi.cast("char *", a)
-        assert ffi.string(p) == 'hello'
+        assert ffi.string(p) == b'hello'
 
     def test_string_from_wchar_array(self):
         ffi = FFI(backend=self.Backend())
@@ -594,7 +599,7 @@
         p = ffi.new("wchar_t[]", u"hello.")
         p[5] = u'!'
         assert ffi.string(p) == u"hello!"
-        p[6] = unichr(1234)
+        p[6] = u'\u04d2'
         assert ffi.string(p) == u"hello!\u04d2"
         p[3] = u'\x00'
         assert ffi.string(p) == u"hel"
@@ -613,10 +618,10 @@
         # 'const' is ignored so far
         ffi = FFI(backend=self.Backend())
         ffi.cdef("struct foo { const char *name; };")
-        t = ffi.new("const char[]", "testing")
+        t = ffi.new("const char[]", b"testing")
         s = ffi.new("struct foo*", [t])
-        assert type(s.name) is not str
-        assert ffi.string(s.name) == "testing"
+        assert type(s.name) not in (bytes, str, unicode)
+        assert ffi.string(s.name) == b"testing"
         py.test.raises(TypeError, "s.name = None")
         s.name = ffi.NULL
         assert s.name == ffi.NULL
@@ -628,7 +633,7 @@
         ffi.cdef("struct foo { const wchar_t *name; };")
         t = ffi.new("const wchar_t[]", u"testing")
         s = ffi.new("struct foo*", [t])
-        assert type(s.name) not in (str, unicode)
+        assert type(s.name) not in (bytes, str, unicode)
         assert ffi.string(s.name) == u"testing"
         s.name = ffi.NULL
         assert s.name == ffi.NULL
@@ -660,6 +665,7 @@
         py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0)
         def cb(n):
             return n + 1
+        cb.__qualname__ = 'cb'
         p = ffi.callback("int(*)(int)", cb)
         res = p(41)     # calling an 'int(*)(int)', i.e. a function pointer
         assert res == 42 and type(res) is int
@@ -732,38 +738,38 @@
 
     def test_char_cast(self):
         ffi = FFI(backend=self.Backend())
-        p = ffi.cast("int", '\x01')
+        p = ffi.cast("int", b'\x01')
         assert ffi.typeof(p) is ffi.typeof("int")
         assert int(p) == 1
-        p = ffi.cast("int", ffi.cast("char", "a"))
+        p = ffi.cast("int", ffi.cast("char", b"a"))
         assert int(p) == ord("a")
-        p = ffi.cast("int", ffi.cast("char", "\x80"))
+        p = ffi.cast("int", ffi.cast("char", b"\x80"))
         assert int(p) == 0x80     # "char" is considered unsigned in this case
-        p = ffi.cast("int", "\x81")
+        p = ffi.cast("int", b"\x81")
         assert int(p) == 0x81
 
     def test_wchar_cast(self):
         ffi = FFI(backend=self.Backend())
         self.check_wchar_t(ffi)
-        p = ffi.cast("int", ffi.cast("wchar_t", unichr(1234)))
-        assert int(p) == 1234
+        p = ffi.cast("int", ffi.cast("wchar_t", u'\u1234'))
+        assert int(p) == 0x1234
         p = ffi.cast("long long", ffi.cast("wchar_t", -1))
         if SIZE_OF_WCHAR == 2:      # 2 bytes, unsigned
             assert int(p) == 0xffff
         else:                       # 4 bytes, signed
             assert int(p) == -1
-        p = ffi.cast("int", unichr(1234))
-        assert int(p) == 1234
+        p = ffi.cast("int", u'\u1234')
+        assert int(p) == 0x1234
 
     def test_cast_array_to_charp(self):
         ffi = FFI(backend=self.Backend())
         a = ffi.new("short int[]", [0x1234, 0x5678])
         p = ffi.cast("char*", a)
-        data = ''.join([p[i] for i in range(4)])
+        data = b''.join([p[i] for i in range(4)])
         if sys.byteorder == 'little':
-            assert data == '\x34\x12\x78\x56'
+            assert data == b'\x34\x12\x78\x56'
         else:
-            assert data == '\x12\x34\x56\x78'
+            assert data == b'\x12\x34\x56\x78'
 
     def test_cast_between_pointers(self):
         ffi = FFI(backend=self.Backend())
@@ -771,11 +777,11 @@
         p = ffi.cast("short*", a)
         p2 = ffi.cast("int*", p)
         q = ffi.cast("char*", p2)
-        data = ''.join([q[i] for i in range(4)])
+        data = b''.join([q[i] for i in range(4)])
         if sys.byteorder == 'little':
-            assert data == '\x34\x12\x78\x56'
+            assert data == b'\x34\x12\x78\x56'
         else:
-            assert data == '\x12\x34\x56\x78'
+            assert data == b'\x12\x34\x56\x78'
 
     def test_cast_pointer_and_int(self):
         ffi = FFI(backend=self.Backend())
@@ -828,8 +834,8 @@
             seen.append(ffi.string(argv[0]))
             seen.append(ffi.string(argv[1]))
         a = ffi.callback("void(*)(char *[])", cb)
-        a([ffi.new("char[]", "foobar"), ffi.new("char[]", "baz")])
-        assert seen == ["foobar", "baz"]
+        a([ffi.new("char[]", b"foobar"), ffi.new("char[]", b"baz")])
+        assert seen == [b"foobar", b"baz"]
 
     def test_cast_float(self):
         ffi = FFI(backend=self.Backend())
@@ -837,23 +843,23 @@
         assert float(a) == 12.0
         a = ffi.cast("float", 12.5)
         assert float(a) == 12.5
-        a = ffi.cast("float", "A")
+        a = ffi.cast("float", b"A")
         assert float(a) == ord("A")
         a = ffi.cast("int", 12.9)
         assert int(a) == 12
         a = ffi.cast("char", 66.9 + 256)
-        assert ffi.string(a) == "B"
+        assert ffi.string(a) == b"B"
         #
         a = ffi.cast("float", ffi.cast("int", 12))
         assert float(a) == 12.0
         a = ffi.cast("float", ffi.cast("double", 12.5))
         assert float(a) == 12.5
-        a = ffi.cast("float", ffi.cast("char", "A"))
+        a = ffi.cast("float", ffi.cast("char", b"A"))
         assert float(a) == ord("A")
         a = ffi.cast("int", ffi.cast("double", 12.9))
         assert int(a) == 12
         a = ffi.cast("char", ffi.cast("double", 66.9 + 256))
-        assert ffi.string(a) == "B"
+        assert ffi.string(a) == b"B"
 
     def test_enum(self):
         ffi = FFI(backend=self.Backend())
@@ -921,9 +927,9 @@
 
     def test_iterate_array(self):
         ffi = FFI(backend=self.Backend())
-        a = ffi.new("char[]", "hello")
-        assert list(a) == ["h", "e", "l", "l", "o", chr(0)]
-        assert list(iter(a)) == ["h", "e", "l", "l", "o", chr(0)]
+        a = ffi.new("char[]", b"hello")
+        assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
+        assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
         #
         py.test.raises(TypeError, iter, ffi.cast("char *", a))
         py.test.raises(TypeError, list, ffi.cast("char *", a))
@@ -969,10 +975,10 @@
         ffi.cdef("typedef struct { int a; } foo_t;")
         ffi.cdef("typedef struct { char b, c; } bar_t;")
         f = ffi.new("foo_t *", [12345])
-        b = ffi.new("bar_t *", ["B", "C"])
+        b = ffi.new("bar_t *", [b"B", b"C"])
         assert f.a == 12345
-        assert b.b == "B"
-        assert b.c == "C"
+        assert b.b == b"B"
+        assert b.c == b"C"
         assert repr(b).startswith("<cdata 'struct $bar_t *'")
 
     def test_struct_with_two_usages(self):
@@ -984,7 +990,7 @@
 
     def test_pointer_arithmetic(self):
         ffi = FFI(backend=self.Backend())
-        s = ffi.new("short[]", range(100, 110))
+        s = ffi.new("short[]", list(range(100, 110)))
         p = ffi.cast("short *", s)
         assert p[2] == 102
         assert p+1 == p+1
@@ -998,7 +1004,7 @@
 
     def test_pointer_comparison(self):
         ffi = FFI(backend=self.Backend())
-        s = ffi.new("short[]", range(100))
+        s = ffi.new("short[]", list(range(100)))
         p = ffi.cast("short *", s)
         assert (p <  s) is False
         assert (p <= s) is True
@@ -1061,57 +1067,75 @@
         ffi = FFI(backend=self.Backend())
         a = ffi.new("short *", 100)
         b = ffi.buffer(a)
-        assert type(b) is buffer
-        assert len(str(b)) == 2
+        if sys.version < '3':
+            assert type(b) is buffer
+            content = str(b)
+        else:
+            assert type(b) is memoryview
+            content = b.tobytes()
+        assert len(content) == 2
         if sys.byteorder == 'little':
-            assert str(b) == '\x64\x00'
-            b[0] = '\x65'
+            assert content == b'\x64\x00'
+            b[0] = b'\x65'[0]
         else:
-            assert str(b) == '\x00\x64'
-            b[1] = '\x65'
+            assert content == b'\x00\x64'
+            b[1] = b'\x65'[0]
         assert a[0] == 101
 
     def test_ffi_buffer_array(self):
         ffi = FFI(backend=self.Backend())
-        a = ffi.new("int[]", range(100, 110))
+        a = ffi.new("int[]", list(range(100, 110)))
         b = ffi.buffer(a)
-        assert type(b) is buffer
+        if sys.version < '3':
+            assert type(b) is buffer
+            content = str(b)
+        else:
+            assert type(b) is memoryview
+            content = b.tobytes()
         if sys.byteorder == 'little':
-            assert str(b).startswith('\x64\x00\x00\x00\x65\x00\x00\x00')
-            b[4] = '\x45'
+            assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00')
+            b[4] = b'\x45'[0]
         else:
-            assert str(b).startswith('\x00\x00\x00\x64\x00\x00\x00\x65')
-            b[7] = '\x45'
-        assert len(str(b)) == 4 * 10
+            assert content.startswith('\x00\x00\x00\x64\x00\x00\x00\x65')
+            b[7] = b'\x45'[0]
+        assert len(content) == 4 * 10
         assert a[1] == 0x45
 
     def test_ffi_buffer_ptr_size(self):
         ffi = FFI(backend=self.Backend())
         a = ffi.new("short *", 0x4243)
         b = ffi.buffer(a, 1)
-        assert type(b) is buffer
-        assert len(str(b)) == 1
+        if sys.version < '3':
+            assert type(b) is buffer
+            content = str(b)
+        else:
+            assert type(b) is memoryview
+            content = b.tobytes()
+        assert len(content) == 1
         if sys.byteorder == 'little':
-            assert str(b) == '\x43'
-            b[0] = '\x62'
+            assert content == b'\x43'
+            b[0] = b'\x62'[0]
             assert a[0] == 0x4262
         else:
-            assert str(b) == '\x42'
-            b[0] = '\x63'
+            assert content == b'\x42'
+            b[0] = b'\x63'[0]
             assert a[0] == 0x6343
 
     def test_ffi_buffer_array_size(self):
         ffi = FFI(backend=self.Backend())
-        a1 = ffi.new("int[]", range(100, 110))
-        a2 = ffi.new("int[]", range(100, 115))
-        assert str(ffi.buffer(a1)) == str(ffi.buffer(a2, 4*10))
+        a1 = ffi.new("int[]", list(range(100, 110)))
+        a2 = ffi.new("int[]", list(range(100, 115)))
+        if sys.version < '3':
+            assert str(ffi.buffer(a1)) == str(ffi.buffer(a2, 4*10))
+        else:
+            assert ffi.buffer(a1).tobytes() == ffi.buffer(a2, 4*10).tobytes()
 
     def test_ffi_buffer_with_file(self):
         ffi = FFI(backend=self.Backend())
         import tempfile, os, array
         fd, filename = tempfile.mkstemp()
         f = os.fdopen(fd, 'r+b')
-        a = ffi.new("int[]", range(1005))
+        a = ffi.new("int[]", list(range(1005)))
         f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
         f.seek(0)
         assert f.read() == array.array('i', range(1000)).tostring()
@@ -1192,13 +1216,13 @@
         # which is automatically replaced with the ptr-to-function type.
         ffi = FFI(backend=self.Backend())
         def cb(a, b):
-            return chr(ord(a) + ord(b))
+            return chr(ord(a) + ord(b)).encode()
         f = ffi.callback("char cb(char, char)", cb)
-        assert f('A', chr(1)) == 'B'
+        assert f(b'A', b'\x01') == b'B'
         def g(callback):
-            return callback('A', chr(1))
+            return callback(b'A', b'\x01')
         g = ffi.callback("char g(char cb(char, char))", g)
-        assert g(f) == 'B'
+        assert g(f) == b'B'
 
     def test_vararg_callback(self):
         py.test.skip("callback with '...'")
diff --git a/testing/test_function.py b/testing/test_function.py
--- a/testing/test_function.py
+++ b/testing/test_function.py
@@ -1,8 +1,13 @@
 import py
 from cffi import FFI
-import math, os, sys, StringIO
+import math, os, sys
 from cffi.backend_ctypes import CTypesBackend
 
+try:
+    from StringIO import StringIO
+except ImportError:
+    from io import StringIO
+
 
 class FdWriteCapture(object):
     """xxx limited to capture at most 512 bytes of output, according
@@ -85,11 +90,11 @@
         ffi.C = ffi.dlopen(None)
         ffi.C.puts   # fetch before capturing, for easier debugging
         with FdWriteCapture() as fd:
-            ffi.C.puts("hello")
-            ffi.C.puts("  world")
+            ffi.C.puts(b"hello")
+            ffi.C.puts(b"  world")
             ffi.C.fflush(ffi.NULL)
         res = fd.getvalue()
-        assert res == 'hello\n  world\n'
+        assert res == b'hello\n  world\n'
 
     def test_puts_without_const(self):
         ffi = FFI(backend=self.Backend())
@@ -100,11 +105,11 @@
         ffi.C = ffi.dlopen(None)
         ffi.C.puts   # fetch before capturing, for easier debugging
         with FdWriteCapture() as fd:
-            ffi.C.puts("hello")
-            ffi.C.puts("  world")
+            ffi.C.puts(b"hello")
+            ffi.C.puts(b"  world")
             ffi.C.fflush(ffi.NULL)
         res = fd.getvalue()
-        assert res == 'hello\n  world\n'
+        assert res == b'hello\n  world\n'
 
     def test_fputs(self):
         if not sys.platform.startswith('linux'):
@@ -116,9 +121,9 @@
         """)
         ffi.C = ffi.dlopen(None)
         with FdWriteCapture(2) as fd:
-            ffi.C.fputs("hello from stderr\n", ffi.C.stderr)
+            ffi.C.fputs(b"hello from stderr\n", ffi.C.stderr)
         res = fd.getvalue()
-        assert res == 'hello from stderr\n'
+        assert res == b'hello from stderr\n'
 
     def test_vararg(self):
         ffi = FFI(backend=self.Backend())
@@ -128,28 +133,28 @@
         """)
         ffi.C = ffi.dlopen(None)
         with FdWriteCapture() as fd:
-            ffi.C.printf("hello with no arguments\n")
-            ffi.C.printf("hello, %s!\n", ffi.new("char[]", "world"))
-            ffi.C.printf(ffi.new("char[]", "hello, %s!\n"),
-                         ffi.new("char[]", "world2"))
-            ffi.C.printf("hello int %d long %ld long long %lld\n",
+            ffi.C.printf(b"hello with no arguments\n")
+            ffi.C.printf(b"hello, %s!\n", ffi.new("char[]", b"world"))
+            ffi.C.printf(ffi.new("char[]", b"hello, %s!\n"),
+                         ffi.new("char[]", b"world2"))
+            ffi.C.printf(b"hello int %d long %ld long long %lld\n",
                          ffi.cast("int", 42),
                          ffi.cast("long", 84),
                          ffi.cast("long long", 168))
-            ffi.C.printf("hello %p\n", ffi.NULL)
+            ffi.C.printf(b"hello %p\n", ffi.NULL)
             ffi.C.fflush(ffi.NULL)
         res = fd.getvalue()
         if sys.platform == 'win32':
-            NIL = "00000000"
+            NIL = b"00000000"
         elif sys.platform.startswith('linux'):
-            NIL = "(nil)"
+            NIL = b"(nil)"
         else:
-            NIL = "0x0"    # OS/X at least
-        assert res == ("hello with no arguments\n"
-                       "hello, world!\n"
-                       "hello, world2!\n"
-                       "hello int 42 long 84 long long 168\n"
-                       "hello " + NIL + "\n")
+            NIL = b"0x0"    # OS/X at least
+        assert res == (b"hello with no arguments\n"
+                       b"hello, world!\n"
+                       b"hello, world2!\n"
+                       b"hello int 42 long 84 long long 168\n"
+                       b"hello " + NIL + b"\n")
 
     def test_must_specify_type_of_vararg(self):
         ffi = FFI(backend=self.Backend())
@@ -157,7 +162,7 @@
            int printf(const char *format, ...);
         """)
         ffi.C = ffi.dlopen(None)
-        e = py.test.raises(TypeError, ffi.C.printf, "hello %d\n", 42)
+        e = py.test.raises(TypeError, ffi.C.printf, b"hello %d\n", 42)
         assert str(e.value) == ("argument 2 passed in the variadic part "
                                 "needs to be a cdata object (got int)")
 
@@ -180,7 +185,7 @@
         fptr = ffi.callback("int(*)(const char *txt)", cb)
         assert fptr != ffi.callback("int(*)(const char *)", cb)
         assert repr(fptr) == "<cdata 'int(*)(char *)' calling %r>" % (cb,)
-        res = fptr("Hello")
+        res = fptr(b"Hello")
         assert res == 42
         #
         ffi.cdef("""
@@ -192,10 +197,10 @@
         assert fptr == ffi.C.puts
         assert repr(fptr).startswith("<cdata 'int(*)(char *)' 0x")
         with FdWriteCapture() as fd:
-            fptr("world")
+            fptr(b"world")
             ffi.C.fflush(ffi.NULL)
         res = fd.getvalue()
-        assert res == 'world\n'
+        assert res == b'world\n'
 
     def test_callback_returning_void(self):
         ffi = FFI(backend=self.Backend())
@@ -205,7 +210,7 @@
             fptr = ffi.callback("void(*)(void)", cb)
             old_stderr = sys.stderr
             try:
-                sys.stderr = StringIO.StringIO()
+                sys.stderr = StringIO()
                 returned = fptr()
                 printed = sys.stderr.getvalue()
             finally:
@@ -222,7 +227,7 @@
             int strlen(char[]);
         """)
         ffi.C = ffi.dlopen(None)
-        p = ffi.new("char[]", "hello")
+        p = ffi.new("char[]", b"hello")
         res = ffi.C.strlen(p)
         assert res == 5
 
@@ -242,11 +247,11 @@
         with FdWriteCapture(2) as fd:     # capturing stderr
             ffi.C.stdout = perr
             try:
-                ffi.C.puts("hello!") # goes to stdout, which is equal to stderr now
+                ffi.C.puts(b"hello!") # goes to stdout, which is equal to stderr now
             finally:
                 ffi.C.stdout = pout
         res = fd.getvalue()
-        assert res == "hello!\n"
+        assert res == b"hello!\n"
 
     def test_strchr(self):
         ffi = FFI(backend=self.Backend())
@@ -254,9 +259,9 @@
             char *strchr(const char *s, int c);
         """)
         ffi.C = ffi.dlopen(None)
-        p = ffi.new("char[]", "hello world!")
+        p = ffi.new("char[]", b"hello world!")
         q = ffi.C.strchr(p, ord('w'))
-        assert ffi.string(q) == "world!"
+        assert ffi.string(q) == b"world!"
 
     def test_function_with_struct_argument(self):
         if sys.platform == 'win32':
@@ -269,7 +274,7 @@
         ffi.C = ffi.dlopen(None)
         ina = ffi.new("struct in_addr *", [0x04040404])
         a = ffi.C.inet_ntoa(ina[0])
-        assert ffi.string(a) == '4.4.4.4'
+        assert ffi.string(a) == b'4.4.4.4'
 
     def test_function_typedef(self):
         py.test.skip("using really obscure C syntax")
diff --git a/testing/test_ownlib.py b/testing/test_ownlib.py
--- a/testing/test_ownlib.py
+++ b/testing/test_ownlib.py
@@ -72,10 +72,10 @@
         assert len(ownlib.my_array) == 7
         if self.Backend is CTypesBackend:
             py.test.skip("not supported by the ctypes backend")
-        ownlib.my_array = range(10, 17)
+        ownlib.my_array = list(range(10, 17))
         for i in range(7):
             assert ownlib.my_array[i] == 10 + i
-        ownlib.my_array = range(7)
+        ownlib.my_array = list(range(7))
         for i in range(7):
             assert ownlib.my_array[i] == i
 
@@ -92,9 +92,9 @@
         for i in range(7):
             assert ownlib.my_array[i] == i
         py.test.raises(TypeError, len, ownlib.my_array)
-        ownlib.my_array = range(10, 17)
+        ownlib.my_array = list(range(10, 17))
         for i in range(7):
             assert ownlib.my_array[i] == 10 + i
-        ownlib.my_array = range(7)
+        ownlib.my_array = list(range(7))
         for i in range(7):
             assert ownlib.my_array[i] == i
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -20,9 +20,9 @@
     ffi = FFI()
     lib = ffi.verify()
     if hasattr(lib, '_cffi_python_module'):
-        print 'verify got a PYTHON module'
+        print('verify got a PYTHON module')
     if hasattr(lib, '_cffi_generic_module'):
-        print 'verify got a GENERIC module'
+        print('verify got a GENERIC module')
     expected_generic = (cffi.verifier._FORCE_GENERIC_ENGINE or
                         '__pypy__' in sys.builtin_module_names)
     assert hasattr(lib, '_cffi_python_module') == (not expected_generic)
@@ -75,19 +75,19 @@
     ffi = FFI()
     ffi.cdef("size_t strlen(const char *s);")
     lib = ffi.verify("#include <string.h>")
-    assert lib.strlen("hi there!") == 9
+    assert lib.strlen(b"hi there!") == 9
 
 def test_strlen_approximate():
     ffi = FFI()
     ffi.cdef("int strlen(char *s);")
     lib = ffi.verify("#include <string.h>")
-    assert lib.strlen("hi there!") == 9
+    assert lib.strlen(b"hi there!") == 9
 
 def test_strlen_array_of_char():
     ffi = FFI()
     ffi.cdef("int strlen(char[]);")
     lib = ffi.verify("#include <string.h>")
-    assert lib.strlen("hello") == 5
+    assert lib.strlen(b"hello") == 5
 
 
 all_integer_types = ['short', 'int', 'long', 'long long',
@@ -115,7 +115,8 @@
         ffi.cdef("%s foo(%s);" % (typename, typename))
         lib = ffi.verify("%s foo(%s x) { return x+1; }" % (typename, typename))
         assert lib.foo(42) == 43
-        assert lib.foo(44L) == 45
+        if sys.version < '3':
+            assert lib.foo(long(44)) == 45
         assert lib.foo(ffi.cast(typename, 46)) == 47
         py.test.raises(TypeError, lib.foo, ffi.NULL)
         #
@@ -133,7 +134,7 @@
 def test_nonstandard_integer_types():
     ffi = FFI()
     lst = ffi._backend.nonstandard_integer_types().items()
-    lst.sort()
+    lst = sorted(lst)
     verify_lines = []
     for key, value in lst:
         ffi.cdef("static const int expected_%s;" % key)
@@ -148,7 +149,8 @@
     ffi = FFI()
     ffi.cdef("char foo(char);")
     lib = ffi.verify("char foo(char x) { return x+1; }")
-    assert lib.foo("A") == "B"
+    assert lib.foo(b"A") == b"B"
+    py.test.raises(TypeError, lib.foo, b"bar")
     py.test.raises(TypeError, lib.foo, "bar")
 
 def test_wchar_type():
@@ -380,7 +382,7 @@
     ffi.cdef("static char *const PP;")
     lib = ffi.verify('static char *const PP = "testing!";\n')
     assert ffi.typeof(lib.PP) == ffi.typeof("char *")
-    assert ffi.string(lib.PP) == "testing!"
+    assert ffi.string(lib.PP) == b"testing!"
 
 def test_nonfull_enum():
     ffi = FFI()
@@ -642,7 +644,7 @@
             return s.a - s.b;
         }
     """)
-    s = ffi.new("struct foo_s *", ['B', 1])
+    s = ffi.new("struct foo_s *", [b'B', 1])
     assert lib.foo(50, s[0]) == ord('A')
 
 def test_autofilled_struct_as_argument():
@@ -710,7 +712,7 @@
     """)
     foochar = ffi.cast("char *(*)(void)", lib.fooptr)
     s = foochar()
-    assert ffi.string(s) == "foobar"
+    assert ffi.string(s) == b"foobar"
 
 def test_funcptr_as_argument():
     ffi = FFI()
diff --git a/testing/test_version.py b/testing/test_version.py
--- a/testing/test_version.py
+++ b/testing/test_version.py
@@ -10,12 +10,12 @@
 def test_doc_version():
     parent = os.path.dirname(os.path.dirname(__file__))
     p = os.path.join(parent, 'doc', 'source', 'conf.py')
-    content = file(p).read()
+    content = open(p).read()
     #
     v = cffi.__version__
     assert ("version = '%s'\n" % v) in content
     assert ("release = '%s'\n" % v) in content
     #
     p = os.path.join(parent, 'doc', 'source', 'index.rst')
-    content = file(p).read()
+    content = open(p).read()
     assert ("release-%s.tar.bz2" % v) in content
diff --git a/testing/test_zdistutils.py b/testing/test_zdistutils.py
--- a/testing/test_zdistutils.py
+++ b/testing/test_zdistutils.py
@@ -1,4 +1,4 @@
-import sys, os, imp, math, StringIO, random
+import sys, os, imp, math, random
 import py
 from cffi import FFI, FFIError
 from cffi.verifier import Verifier, _locate_engine_class
@@ -26,7 +26,7 @@
         csrc = '/*hi there!*/\n#include <math.h>\n'
         v = Verifier(ffi, csrc, force_generic_engine=self.generic)
         v.write_source()
-        with file(v.sourcefilename, 'r') as f:
+        with open(v.sourcefilename, 'r') as f:
             data = f.read()
         assert csrc in data
 
@@ -38,7 +38,7 @@
         v.sourcefilename = filename = str(udir.join('write_source.c'))
         v.write_source()
         assert filename == v.sourcefilename
-        with file(filename, 'r') as f:
+        with open(filename, 'r') as f:
             data = f.read()
         assert csrc in data
 
@@ -47,7 +47,11 @@
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there!*/\n#include <math.h>\n'
         v = Verifier(ffi, csrc, force_generic_engine=self.generic)
-        f = StringIO.StringIO()
+        try:
+            from StringIO import StringIO
+        except ImportError:
+            from io import StringIO
+        f = StringIO()
         v.write_source(file=f)
         assert csrc in f.getvalue()
 
@@ -120,7 +124,7 @@
         lib = ffi.verify(csrc, force_generic_engine=self.generic)
         assert lib.sin(12.3) == math.sin(12.3)
         assert isinstance(ffi.verifier, Verifier)
-        with file(ffi.verifier.sourcefilename, 'r') as f:
+        with open(ffi.verifier.sourcefilename, 'r') as f:
             data = f.read()
         assert csrc in data
 
@@ -138,7 +142,7 @@
         assert lib.sin(12.3) == math.sin(12.3)
         v = ffi.verifier
         ext = v.get_extension()
-        assert str(ext.__class__) == 'distutils.extension.Extension'
+        assert 'distutils.extension.Extension' in str(ext.__class__)
         assert ext.sources == [v.sourcefilename]
         assert ext.name == v.get_module_name()
         assert ext.define_macros == [('TEST_EXTENSION_OBJECT', '1')]


More information about the pypy-commit mailing list