Amaury Forgeot d'Arc avatar Amaury Forgeot d'Arc committed 203dc42

An attempt to port cffi to python3.
Most tests are passing, yeah!

Comments (0)

Files changed (12)

c/_cffi_backend.c

 # define USE__THREAD
 #endif
 
+#if PY_MAJOR_VERSION >= 3
+# define PyText_Type PyUnicode_Type
+# define PyText_Check PyUnicode_Check
+# define PyText_FromFormat PyUnicode_FromFormat
+# define PyText_AsUTF8 PyUnicode_AsUTF8
+# define PyText_GetSize PyUnicode_GetSize
+# define PyText_FromString PyUnicode_FromString
+# define PyText_FromStringAndSize PyUnicode_FromStringAndSize
+# define PyText_InternInPlace PyUnicode_InternInPlace
+#else
+# define PyText_Type PyString_Type
+# define PyText_Check PyString_Check
+# define PyText_FromFormat PyString_FromFormat
+# define PyText_AsUTF8 PyString_AsString
+# 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: */
 static PyObject *
 ctypedescr_repr(CTypeDescrObject *ct)
 {
-    return PyString_FromFormat("<ctype '%s'>", ct->ct_name);
+    return PyText_FromFormat("<ctype '%s'>", ct->ct_name);
 }
 
 static void
     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;
 }
 #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
        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 {
         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 {
        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;
         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 {
 {
     PyObject *d_value;
 
-    if (PyString_AS_STRING(ob)[0] == '#') {
-        char *number = PyString_AS_STRING(ob) + 1;   /* strip initial '#' */
-        PyObject *ob2 = PyString_FromString(number);
+    if (PyText_AsUTF8(ob)[0] == '#') {
+        char *number = PyText_AsUTF8(ob) + 1;   /* strip initial '#' */
+        PyObject *ob2 = PyText_FromString(number);
         if (ob2 == NULL)
             return NULL;
 
         d_value = PyDict_GetItem(PyTuple_GET_ITEM(ct->ct_stuff, 0), ob);
         if (d_value == NULL) {
             PyErr_Format(PyExc_ValueError,
-                         "'%s' is not an enumerator for %s",
-                         PyString_AS_STRING(ob),
-                         ct->ct_name);
+                         "%R is not an enumerator for %s",
+                         ob, ct->ct_name);
             return NULL;
         }
         Py_INCREF(d_value);
             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)
     }
     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);
     s = PyObject_Str(init);
     if (s == NULL)
         return -1;
-    PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'",
-                 PyString_AS_STRING(s), ct_name);
+    PyErr_Format(PyExc_OverflowError, "integer %S does not fit '%s'",
+                 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 PY_MAJOR_VERSION >= 3
+    if (PyLong_Check(init)) {
+        long value = PyLong_AsLong(init);
+        if (value >= 0 && value < 256) {
+            return (unsigned char)value;
+        }
+    }
+#endif
     if (CData_Check(init) &&
            (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) &&
            (((CDataObject *)init)->c_type->ct_size == sizeof(char))) {
         return *(unsigned char *)((CDataObject *)init)->c_data;
     }
     PyErr_Format(PyExc_TypeError,
-                 "initializer for ctype 'char' must be a string of length 1, "
+                 "initializer for ctype 'char' must be a bytes string of length 1, "
                  "not %.200s", Py_TYPE(init)->tp_name);
     return -1;
 }
             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 = "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' "
                 }
                 if (n != ct->ct_length)
                     n++;
-                srcdata = PyString_AS_STRING(init);
+                srcdata = PyBytes_AS_STRING(init);
                 memcpy(data, srcdata, n);
                 return 0;
             }
             else {
                 PyObject *ob;
                 PyErr_Clear();
-                if (!PyString_Check(init)) {
+                if (!PyText_Check(init)) {
                     expected = "str or int";
                     goto cannot_convert;
                 }
         sfmax = PyObject_Str(lfmax);
         if (sfmax == NULL) goto skip;
         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));
+                     "value %S outside the range allowed by the "
+                     "bit field width: %S <= x <= %S",
+                     svalue, sfmin, sfmax);
        skip:
         Py_XDECREF(svalue);
         Py_XDECREF(sfmin);
         Py_DECREF(o);
         if (s == NULL)
             return NULL;
-        p = PyString_AS_STRING(s);
+        p = PyText_AsUTF8(s);
     }
     else {
         if (cd->c_data != NULL) {
-            s = PyString_FromFormat("%p", cd->c_data);
+            s = PyText_FromFormat("%p", cd->c_data);
             if (s == NULL)
                 return NULL;
-            p = PyString_AS_STRING(s);
+            p = PyText_AsUTF8(s);
         }
         else
             p = "NULL";
         extra = " &";
     else
         extra = "";
-    result = PyString_FromFormat("<cdata '%s%s' %s>",
-                                 cd->c_type->ct_name, extra, p);
+    result = PyText_FromFormat("<cdata '%s%s' %s>",
+                               cd->c_type->ct_name, extra, p);
     Py_XDECREF(s);
     return result;
 }
 
-static PyObject *cdata_str(CDataObject *cd)
+static PyObject *cdata_get_value(CDataObject *cd)
 {
     if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR &&
         cd->c_type->ct_size == sizeof(char)) {
-        return PyString_FromStringAndSize(cd->c_data, 1);
+        return PyBytes_FromStringAndSize(cd->c_data, 1);
     }
     else if (cd->c_type->ct_itemdescr != NULL &&
              cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR &&
                 PyObject *s = cdata_repr(cd);
                 if (s != NULL) {
                     PyErr_Format(PyExc_RuntimeError,
-                                 "cannot use str() on %s",
-                                 PyString_AS_STRING(s));
+                                 "cannot use str() on %S", s);
                     Py_DECREF(s);
                 }
                 return NULL;
             length = strlen(cd->c_data);
         }
 
-        return PyString_FromStringAndSize(cd->c_data, length);
+        return PyBytes_FromStringAndSize(cd->c_data, length);
     }
-    else if (cd->c_type->ct_flags & CT_IS_ENUM)
-        return convert_to_object(cd->c_data, cd->c_type);
-    else
-        return Py_TYPE(cd)->tp_repr((PyObject *)cd);
-}
-
 #ifdef HAVE_WCHAR_H
-static PyObject *cdata_unicode(CDataObject *cd)
-{
-    if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR &&
+    else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR &&
         cd->c_type->ct_size == sizeof(wchar_t)) {
         return _my_PyUnicode_FromWideChar((wchar_t *)cd->c_data, 1);
     }
                 PyObject *s = cdata_repr(cd);
                 if (s != NULL) {
                     PyErr_Format(PyExc_RuntimeError,
-                                 "cannot use unicode() on %s",
-                                 PyString_AS_STRING(s));
+                                 "cannot use unicode() on %S", s);
                     Py_DECREF(s);
                 }
                 return NULL;
 
         return _my_PyUnicode_FromWideChar((wchar_t *)cd->c_data, length);
     }
+#endif
+    else {
+        Py_INCREF(cd);
+        return (PyObject *)cd;
+    }
+}
+
+static PyObject *cdata_str(CDataObject *cd)
+{
+    if (cd->c_type->ct_flags & CT_IS_ENUM)
+        return convert_to_object(cd->c_data, cd->c_type);
     else
         return Py_TYPE(cd)->tp_repr((PyObject *)cd);
 }
-#endif
 
 static PyObject *cdataowning_repr(CDataObject *cd)
 {
     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:
     {
         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;
     }
     }
     else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) {
         PyObject *o = convert_to_object(cd->c_data, cd->c_type);
+#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;
     }
     return NULL;
 }
 
+#if PY_MAJOR_VERSION < 3
 static PyObject *cdata_long(CDataObject *cd)
 {
     PyObject *res = cdata_int(cd);
     }
     return res;
 }
+#endif
 
 static PyObject *cdata_float(CDataObject *cd)
 {
             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);
             }
             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;
         if ((argtype->ct_flags & CT_POINTER) &&
             (argtype->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR)) {
             if (argtype->ct_itemdescr->ct_size == sizeof(char)) {
-                if (PyString_Check(obj)) {
+                if (PyText_Check(obj)) {
                     /* special case: Python string -> cdata 'char *' */
-                    *(char **)data = PyString_AS_STRING(obj);
+                    *(char **)data = PyText_AsUTF8(obj);
                     continue;
                 }
             }
     (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*/
     0,                          /*nb_and*/
     0,                          /*nb_xor*/
     0,                          /*nb_or*/
+#if PY_MAJOR_VERSION < 3
     0,                          /*nb_coerce*/
+    (unaryfunc)cdata_long,      /*nb_long*/
+#else
     (unaryfunc)cdata_int,       /*nb_int*/
-    (unaryfunc)cdata_long,      /*nb_long*/
+    0,                          /*nb_reserved*/
+#endif
     (unaryfunc)cdata_float,     /*nb_float*/
-    0,                          /*nb_oct*/
-    0,                          /*nb_hex*/
 };
 
 static PyMappingMethods CData_as_mapping = {
 };
 
 static PyMethodDef CData_methods[] = {
-    {"__unicode__",     (PyCFunction)cdata_unicode,  METH_NOARGS},
     {NULL,              NULL}           /* sentinel */
 };
 
+static PyGetSetDef CData_getset[] = {
+    {"value", (getter)cdata_get_value, NULL, NULL},
+    {0}
+};
+
 static PyTypeObject CData_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "_cffi_backend.CData",
     (getiterfunc)cdata_iter,                    /* tp_iter */
     0,                                          /* tp_iternext */
     CData_methods,                              /* tp_methods */
+    0,                                          /* tp_members */
+    CData_getset,                               /* tp_getset */
 };
 
 static PyTypeObject CDataOwning_Type = {
             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 */
                                  (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)
             return cd;
         }
         else {
-            if (PyString_GET_SIZE(ob) != 1) {
+#if PY_MAJOR_VERSION < 3
+            if (PyString_GetSize(ob) != 1) {
                 PyErr_Format(PyExc_TypeError,
                       "cannot cast string of length %zd to ctype '%s'",
-                             PyString_GET_SIZE(ob), ct->ct_name);
+                             PyString_GetSize(ob), ct->ct_name);
                 return NULL;
             }
-            value = (unsigned char)PyString_AS_STRING(ob)[0];
+            value = (unsigned char)PyString_AsString(ob)[0];
+#else
+            wchar_t ordinal;
+            if (_my_PyUnicode_AsSingleWideChar(ob, &ordinal) < 0) {
+                PyErr_Format(PyExc_TypeError,
+                             "cannot cast unicode of length %zd to ctype '%s'",
+                             PyUnicode_GET_SIZE(ob), ct->ct_name);
+                return NULL;
+            }
+            value = (long)ordinal;
+#endif
         }
     }
 #ifdef HAVE_WCHAR_H
         value = (long)ordinal;
     }
 #endif
+    else if (PyBytes_Check(ob)) {
+      value = (unsigned char)_convert_to_char(ob);
+    }
     else {
         value = _my_PyLong_AsUnsignedLongLong(ob, 0);
         if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
             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];
         }
         else {
             value = PyFloat_AsDouble(io);
 
 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)
         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;
 
         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),
+                         "field '%s.%S' has ctype '%s' of unknown size",
+                         ct->ct_name, fname,
                          ftype->ct_name);
             goto error;
         }
 #endif
                     fbitsize == 0 ||
                     fbitsize > 8 * ftype->ct_size) {
-                PyErr_Format(PyExc_TypeError, "invalid bit field '%s'",
-                             PyString_AS_STRING(fname));
+                PyErr_Format(PyExc_TypeError, "invalid bit field %R",
+                             fname);
                 goto error;
             }
             if (prev_bit_position > 0) {
         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);
             goto error;
 
         if (PyDict_Size(interned_fields) != i + 1) {
-            PyErr_Format(PyExc_KeyError, "duplicate field name '%s'",
-                         PyString_AS_STRING(fname));
+            PyErr_Format(PyExc_KeyError, "duplicate field name %R",
+                         fname);
             goto error;
         }
 
     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;
     }
     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);
     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;
         }
 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",
 
     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);
     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_buffer(PyObject *self, PyObject *args)
                      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)
     {"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 */
 };
 
 /************************************************************/
 
 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;
     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;                                 \
 }
 
 static PyObject *_cffi_from_c_char(char x) {
-    return PyString_FromStringAndSize(&x, 1);
+    return PyBytes_FromStringAndSize(&x, 1);
 }
 
 #ifdef HAVE_WCHAR_H
 
 /************************************************************/
 
+#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
+
+PyObject *
+PyInit__cffi_backend(void)
+#else
+#define INITERROR return
+
 void 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_AsUTF8(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.2.1");
+        INITERROR;
+
+    v = PyText_FromString("0.2.1");
     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
 }
-import new
+import types
 
 class FFIError(Exception):
     pass
         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,))
         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'):
         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)
         """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:
         """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)
 
         """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)
 
         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)
 
         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)
 
         """
         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)
 
         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('*')

cffi/backend_ctypes.py

 import ctypes, ctypes.util, operator
 from . import model
+import sys
+
+if sys.version < '3':
+    integer_types = (int, long)
+    bytes = str
+else:
+    integer_types = (int,)
+    xrange = range
 
 class CTypesData(object):
     __slots__ = []
     @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):
             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" %
 
     def __nonzero__(self):
         return bool(self._address)
+    
+    def __bool__(self):
+        return bool(self._address)
 
     @classmethod
     def _to_ctypes(cls, value):
             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
                 @classmethod
                 def _cast_from(cls, source):
                     source = _cast_source_to_int(source)
-                    source = chr(source & 0xFF)
+                    source = chr(source & 0xFF).encode('latin1')
                     return cls(source)
                 def __int__(self):
                     return ord(self._value)
-                def __str__(self):
+                @property
+                def value(self):
                     return self._value
 
             if kind == 'float':
             if kind == 'int':
                 @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:
             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
+                    if sys.version >= '3' and isinstance(x, int):
+                        return x
                     raise TypeError("character expected, got %s" %
                                     type(x).__name__)
 
             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
                 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):
                 self._as_ctype_ptr[index] = BItem._to_ctypes(value)
 
             if kind == 'charp':
-                def __str__(self):
+                @property
+                def value(self):
                     n = 0
-                    while self._as_ctype_ptr[n] != '\x00':
+                    while self._as_ctype_ptr[n] != b'\x00':
                         n += 1
-                    return ''.join([self._as_ctype_ptr[i] for i in range(n)])
+                    chars = [self._as_ctype_ptr[i] for i in range(n)]
+                    return b''.join(chars)
                 @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)
 
             def __init__(self, init):
                 if length is None:
-                    if isinstance(init, (int, long)):
+                    if isinstance(init, integer_types):
                         len1 = init
                         init = None
                     else:
-                        extra_null = (kind == 'char' and isinstance(init, str))
+                        extra_null = (kind == 'char' and isinstance(init, bytes))
                         init = tuple(init)
                         len1 = len(init) + extra_null
                     self._ctype = BItem._ctype * len1
                 self._blob[index] = BItem._to_ctypes(value)
 
             if kind == 'char':
-                def __str__(self):
-                    s = ''.join(self._blob)
+                @property
+                def value(self):
+                    s = b''.join(self._blob)
                     try:
-                        s = s[:s.index('\x00')]
+                        s = s[:s.index(b'\x00')]
                     except ValueError:
                         pass
                     return s
                 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))
                                     "only one supported (use a dict if needed)"
                                      % (len(init),))
             if not isinstance(init, dict):
-                if isinstance(init, str):
+                if isinstance(init, (bytes, str)):
                     raise TypeError("union initializer: got a str")
                 init = tuple(init)
                 if len(init) > len(fnames):
                 p = ctypes.cast(addr + offset, PTR)
                 BField._initialize(p.contents, value)
         is_union = CTypesStructOrUnion._kind == 'union'
-        name2fieldtype = dict(zip(fnames, zip(btypes, bitfields)))
+        name2fieldtype = dict(zip(fnames, list(zip(btypes, bitfields))))
         #
         for fname, BField, bitsize in fields:
             if hasattr(CTypesStructOrUnion, fname):
     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):
         ctypes.set_errno(value)
 
     def buffer(self, bptr, size=-1):
+        if sys.version >= '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:
+                buf = bptr.XXX
+            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)

cffi/ffiplatform.py

     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')
         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:
                         "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
+from __future__ import print_function
 import sys, os, hashlib, imp, shutil
 from . import model, ffiplatform
 from . import __version__
         self.kwds = kwds
         #
         m = hashlib.md5('\x00'.join([sys.version[:3], __version__, preamble] +
-                                    ffi._cdefsources))
+                                    ffi._cdefsources).encode())
         modulename = '_cffi_%s' % m.hexdigest()
         suffix = _get_so_suffix()
         self.sourcefilename = os.path.join(_TMPDIR, modulename + '.c')
         return self._load_library()
 
     def get_module_name(self):
-        return os.path.splitext(os.path.basename(self.modulefilename))[0]
+        return os.path.basename(self.modulefilename).split('.', 1)[0]
 
     def get_extension(self):
         if self._status == 'init':
         self._collect_types()
         self._status = 'module'
 
-    def _prnt(self, what=''):
-        print >> self._f, what
+    def print(self, what=''):
+        print(what, file=self._f)
 
     def _gettypenum(self, type):
         # a KeyError here is a bug.  please report it! :-)
         # call to do, if any.
         self._chained_list_constants = ['0', '0']
         #
-        prnt = self._prnt
+        print = self.print
         # first paste some standard set of lines that are mostly '#define'
-        prnt(cffimod_header)
-        prnt()
+        print(cffimod_header)
+        print()
         # then paste the C source given by the user, verbatim.
-        prnt(self.preamble)
-        prnt()
+        print(self.preamble)
+        print()
         #
         # call generate_cpy_xxx_decl(), for every xxx found from
         # ffi._parser._declarations.  This generates all the functions.
         # implement the function _cffi_setup_custom() as calling the
         # head of the chained list.
         self._generate_setup_custom()
-        prnt()
+        print()
         #
         # produce the method table, including the entries for the
         # generated Python->C function wrappers, which are done
         # by generate_cpy_function_method().
-        prnt('static PyMethodDef _cffi_methods[] = {')
+        print('static PyMethodDef _cffi_methods[] = {')
         self._generate("method")
-        prnt('  {"_cffi_setup", _cffi_setup, METH_VARARGS},')
-        prnt('  {NULL, NULL}    /* Sentinel */')
-        prnt('};')
-        prnt()
+        print('  {"_cffi_setup", _cffi_setup, METH_VARARGS},')
+        print('  {NULL, NULL}    /* Sentinel */')
+        print('};')
+        print()
         #
         # standard init.
         modname = self.get_module_name()
-        prnt('PyMODINIT_FUNC')
-        prnt('init%s(void)' % modname)
-        prnt('{')
-        prnt('  PyObject *lib;')
-        prnt('  lib = Py_InitModule("%s", _cffi_methods);' % modname)
-        prnt('  if (lib == NULL || %s < 0)' % (
-            self._chained_list_constants[False],))
-        prnt('    return;')
-        prnt('  _cffi_init();')
-        prnt('}')
+        if sys.version < '3':
+            print('PyMODINIT_FUNC')
+            print('init%s(void)' % modname)
+            print('{')
+            print('  PyObject *lib;')
+            print('  lib = Py_InitModule("%s", _cffi_methods);' % modname)
+            print('  if (lib == NULL || %s < 0)' % (
+                    self._chained_list_constants[False],))
+            print('    return;')
+            print('  _cffi_init();')
+            print('}')
+        else:
+            print('static struct PyModuleDef _cffi_module_def = {')
+            print('  PyModuleDef_HEAD_INIT,')
+            print('  "%s",' % modname)
+            print('  NULL,')
+            print('  -1,')
+            print('  _cffi_methods,')
+            print('  NULL, NULL, NULL, NULL')
+            print('};')
+            print('')
+            print('PyMODINIT_FUNC')
+            print('PyInit_%s(void)' % modname)
+            print('{')
+            print('  PyObject *lib;')
+            print('  lib = PyModule_Create(&_cffi_module_def);')
+            print('  if (lib == NULL || %s < 0)' % (
+                    self._chained_list_constants[False],))
+            print('    return NULL;')
+            print('  _cffi_init();')
+            print('  return lib;')
+            print('}')
 
     def _compile_module(self):
         # compile this C source
         try:
             module = imp.load_dynamic(self.get_module_name(),
                                       self.modulefilename)
-        except ImportError, e:
+        except ImportError as e:
             error = "importing %r: %s" % (self.modulefilename, e)
             raise ffiplatform.VerificationError(error)
         #
         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
         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,
             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)
         #
         elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
             # a struct (not a struct pointer) as a function argument
-            self._prnt('  if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
+            self.print('  if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
                       % (tovar, self._gettypenum(tp), fromvar))
-            self._prnt('    %s;' % errcode)
+            self.print('    %s;' % errcode)
             return
         #
         elif isinstance(tp, model.FunctionPtrType):
         else:
             raise NotImplementedError(tp)
         #
-        self._prnt('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
-        self._prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
+        self.print('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
+        self.print('  if (%s == (%s)%s && PyErr_Occurred())' % (
             tovar, tp.get_c_name(''), errvalue))
-        self._prnt('    %s;' % errcode)
+        self.print('    %s;' % errcode)
 
     def _convert_expr_from_c(self, tp, var):
         if isinstance(tp, model.PrimitiveType):
             # constant function pointer (no CPython wrapper)
             self._generate_cpy_const(False, name, tp)
             return
-        prnt = self._prnt
+        print = self.print
         numargs = len(tp.args)
         if numargs == 0:
             argname = 'no_arg'
             argname = 'arg0'
         else:
             argname = 'args'
-        prnt('static PyObject *')
-        prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
-        prnt('{')
+        print('static PyObject *')
+        print('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
+        print('{')
         #
         for i, type in enumerate(tp.args):
-            prnt('  %s;' % type.get_c_name(' x%d' % i))
+            print('  %s;' % type.get_c_name(' x%d' % i))
         if not isinstance(tp.result, model.VoidType):
             result_code = 'result = '
-            prnt('  %s;' % tp.result.get_c_name(' result'))
+            print('  %s;' % tp.result.get_c_name(' result'))
         else:
             result_code = ''
         #
         if len(tp.args) > 1:
             rng = range(len(tp.args))
             for i in rng:
-                prnt('  PyObject *arg%d;' % i)
-            prnt()
-            prnt('  if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
+                print('  PyObject *arg%d;' % i)
+            print()
+            print('  if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
                 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
-            prnt('    return NULL;')
-        prnt()
+            print('    return NULL;')
+        print()
         #
         for i, type in enumerate(tp.args):
             self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
                                        'return NULL')
-            prnt()
+            print()
         #
-        prnt('  _cffi_restore_errno();')
-        prnt('  { %s%s(%s); }' % (
+        print('  _cffi_restore_errno();')
+        print('  { %s%s(%s); }' % (
             result_code, name,
             ', '.join(['x%d' % i for i in range(len(tp.args))])))
-        prnt('  _cffi_save_errno();')
-        prnt()
+        print('  _cffi_save_errno();')
+        print()
         #
         if result_code:
-            prnt('  return %s;' %
+            print('  return %s;' %
                  self._convert_expr_from_c(tp.result, 'result'))
         else:
-            prnt('  Py_INCREF(Py_None);')
-            prnt('  return Py_None;')
-        prnt('}')
-        prnt()
+            print('  Py_INCREF(Py_None);')
+            print('  return Py_None;')
+        print('}')
+        print()
 
     def _generate_cpy_function_method(self, tp, name):
         if tp.ellipsis:
             meth = 'METH_O'
         else:
             meth = 'METH_VARARGS'
-        self._prnt('  {"%s", _cffi_f_%s, %s},' % (name, name, meth))
+        self.print('  {"%s", _cffi_f_%s, %s},' % (name, name, meth))
 
     _loading_cpy_function = _loaded_noop
 
         layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
         cname = ('%s %s' % (prefix, name)).strip()
         #
-        prnt = self._prnt
-        prnt('static void %s(%s *p)' % (checkfuncname, cname))
-        prnt('{')
-        prnt('  /* only to generate compile-time warnings or errors */')
+        print = self.print
+        print('static void %s(%s *p)' % (checkfuncname, cname))
+        print('{')
+        print('  /* only to generate compile-time warnings or errors */')
         for i in range(len(tp.fldnames)):
             fname = tp.fldnames[i]
             ftype = tp.fldtypes[i]
             if (isinstance(ftype, model.PrimitiveType)
                 and ftype.is_integer_type()):
                 # accept all integers, but complain on float or double
-                prnt('  (void)((p->%s) << 1);' % fname)
+                print('  (void)((p->%s) << 1);' % fname)
             else:
                 # only accept exactly the type declared.  Note the parentheses
                 # around the '*tmp' below.  In most cases they are not needed
                 # but don't hurt --- except test_struct_array_field.
-                prnt('  { %s = &p->%s; (void)tmp; }' % (
+                print('  { %s = &p->%s; (void)tmp; }' % (
                     ftype.get_c_name('(*tmp)'), fname))
-        prnt('}')
-        prnt('static PyObject *')
-        prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
-        prnt('{')
-        prnt('  struct _cffi_aligncheck { char x; %s y; };' % cname)
+        print('}')
+        print('static PyObject *')
+        print('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
+        print('{')
+        print('  struct _cffi_aligncheck { char x; %s y; };' % cname)
         if tp.partial:
-            prnt('  static Py_ssize_t nums[] = {')
-            prnt('    sizeof(%s),' % cname)
-            prnt('    offsetof(struct _cffi_aligncheck, y),')
+            print('  static Py_ssize_t nums[] = {')
+            print('    sizeof(%s),' % cname)
+            print('    offsetof(struct _cffi_aligncheck, y),')
             for fname in tp.fldnames:
-                prnt('    offsetof(%s, %s),' % (cname, fname))
-                prnt('    sizeof(((%s *)0)->%s),' % (cname, fname))
-            prnt('    -1')
-            prnt('  };')
-            prnt('  return _cffi_get_struct_layout(nums);')
+                print('    offsetof(%s, %s),' % (cname, fname))
+                print('    sizeof(((%s *)0)->%s),' % (cname, fname))
+            print('    -1')
+            print('  };')
+            print('  return _cffi_get_struct_layout(nums);')
         else:
             ffi = self.ffi
             BStruct = ffi._get_cached_btype(tp)
                         cname, fname, ffi.offsetof(BStruct, fname)),
                     'sizeof(((%s *)0)->%s) != %d' % (
                         cname, fname, ffi.sizeof(BField))]
-            prnt('  if (%s ||' % conditions[0])
+            print('  if (%s ||' % conditions[0])
             for i in range(1, len(conditions)-1):
-                prnt('      %s ||' % conditions[i])
-            prnt('      %s) {' % conditions[-1])
-            prnt('    Py_INCREF(Py_False);')
-            prnt('    return Py_False;')
-            prnt('  }')
-            prnt('  else {')
-            prnt('    Py_INCREF(Py_True);')
-            prnt('    return Py_True;')
-            prnt('  }')
-        prnt('  /* the next line is not executed, but compiled */')
-        prnt('  %s(0);' % (checkfuncname,))
-        prnt('}')
-        prnt()
+                print('      %s ||' % conditions[i])
+            print('      %s) {' % conditions[-1])
+            print('    Py_INCREF(Py_False);')
+            print('    return Py_False;')
+            print('  }')
+            print('  else {')
+            print('    Py_INCREF(Py_True);')
+            print('    return Py_True;')
+            print('  }')
+        print('  /* the next line is not executed, but compiled */')
+        print('  %s(0);' % (checkfuncname,))
+        print('}')
+        print()
 
     def _generate_struct_or_union_method(self, tp, prefix, name):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
         layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
-        self._prnt('  {"%s", %s, METH_NOARGS},' % (layoutfuncname,
+        self.print('  {"%s", %s, METH_NOARGS},' % (layoutfuncname,
                                                    layoutfuncname))
 
     def _loading_struct_or_union(self, tp, prefix, name, module):
 
     def _generate_cpy_const(self, is_int, name, tp=None, category='const',
                             vartp=None, delayed=True):
-        prnt = self._prnt
+        print = self.print
         funcname = '_cffi_%s_%s' % (category, name)
-        prnt('static int %s(PyObject *lib)' % funcname)
-        prnt('{')
-        prnt('  PyObject *o;')
-        prnt('  int res;')
+        print('static int %s(PyObject *lib)' % funcname)
+        print('{')
+        print('  PyObject *o;')
+        print('  int res;')
         if not is_int:
-            prnt('  %s;' % (vartp or tp).get_c_name(' i'))
+            print('  %s;' % (vartp or tp).get_c_name(' i'))
         else:
             assert category == 'const'
         #
                 realexpr = '&' + name
             else:
                 realexpr = name
-            prnt('  i = (%s);' % (realexpr,))
-            prnt('  o = %s;' % (self._convert_expr_from_c(tp, 'i'),))
+            print('  i = (%s);' % (realexpr,))
+            print('  o = %s;' % (self._convert_expr_from_c(tp, 'i'),))
             assert delayed
         else:
-            prnt('  if (LONG_MIN <= (%s) && (%s) <= LONG_MAX)' % (name, name))
-            prnt('    o = PyInt_FromLong((long)(%s));' % (name,))
-            prnt('  else if ((%s) <= 0)' % (name,))
-            prnt('    o = PyLong_FromLongLong((long long)(%s));' % (name,))
-            prnt('  else')
-            prnt('    o = PyLong_FromUnsignedLongLong('
+            print('  if (LONG_MIN <= (%s) && (%s) <= LONG_MAX)' % (name, name))
+            print('    o = PyInt_FromLong((long)(%s));' % (name,))
+            print('  else if ((%s) <= 0)' % (name,))
+            print('    o = PyLong_FromLongLong((long long)(%s));' % (name,))
+            print('  else')
+            print('    o = PyLong_FromUnsignedLongLong('
                  '(unsigned long long)(%s));' % (name,))
-        prnt('  if (o == NULL)')
-        prnt('    return -1;')
-        prnt('  res = PyObject_SetAttrString(lib, "%s", o);' % name)
-        prnt('  Py_DECREF(o);')
-        prnt('  if (res < 0)')
-        prnt('    return -1;')
-        prnt('  return %s;' % self._chained_list_constants[delayed])
+        print('  if (o == NULL)')
+        print('    return -1;')
+        print('  res = PyObject_SetAttrString(lib, "%s", o);' % name)
+        print('  Py_DECREF(o);')
+        print('  if (res < 0)')
+        print('    return -1;')
+        print('  return %s;' % self._chained_list_constants[delayed])
         self._chained_list_constants[delayed] = funcname + '(lib)'
-        prnt('}')
-        prnt()
+        print('}')
+        print()
 
     def _generate_cpy_constant_collecttype(self, tp, name):
         is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
             return
         #
         funcname = '_cffi_enum_%s' % name
-        prnt = self._prnt
-        prnt('static int %s(PyObject *lib)' % funcname)
-        prnt('{')
+        print = self.print
+        print('static int %s(PyObject *lib)' % funcname)
+        print('{')
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
-            prnt('  if (%s != %d) {' % (enumerator, enumvalue))
-            prnt('    PyErr_Format(_cffi_VerificationError,')
-            prnt('                 "in enum %s: %s has the real value %d, '
+            print('  if (%s != %d) {' % (enumerator, enumvalue))
+            print('    PyErr_Format(_cffi_VerificationError,')
+            print('                 "in enum %s: %s has the real value %d, '
                  'not %d",')
-            prnt('                 "%s", "%s", (int)%s, %d);' % (
+            print('                 "%s", "%s", (int)%s, %d);' % (
                 name, enumerator, enumerator, enumvalue))
-            prnt('    return -1;')
-            prnt('  }')
-        prnt('  return %s;' % self._chained_list_constants[True])
+            print('    return -1;')
+            print('  }')
+        print('  return %s;' % self._chained_list_constants[True])
         self._chained_list_constants[True] = funcname + '(lib)'
-        prnt('}')
-        prnt()
+        print('}')
+        print()
 
     _generate_cpy_enum_collecttype = _generate_nothing
     _generate_cpy_enum_method = _generate_nothing
     # ----------
 
     def _generate_setup_custom(self):
-        prnt = self._prnt
-        prnt('static PyObject *_cffi_setup_custom(PyObject *lib)')
-        prnt('{')
-        prnt('  if (%s < 0)' % self._chained_list_constants[True])
-        prnt('    return NULL;')
-        prnt('  Py_INCREF(Py_None);')
-        prnt('  return Py_None;')
-        prnt('}')
+        print = self.print
+        print('static PyObject *_cffi_setup_custom(PyObject *lib)')
+        print('{')
+        print('  if (%s < 0)' % self._chained_list_constants[True])
+        print('    return NULL;')
+        print('  Py_INCREF(Py_None);')
+        print('  return Py_None;')
+        print('}')
 
 cffimod_header = r'''
 #include <Python.h>
 #include <stddef.h>
 
+#if PY_MAJOR_VERSION < 3
+# 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
     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 *));
 }
 
     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/...'

testing/backend_tests.py

         assert int(p) == min
         p = ffi.cast(c_decl, max)
         assert int(p) == max
-        p = ffi.cast(c_decl, long(max))
-        assert int(p) == max
         q = ffi.cast(c_decl, min - 1)
         assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
-        q = ffi.cast(c_decl, long(min - 1))
-        assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
+        if sys.version < '3':
+            p = ffi.cast(c_decl, long(max))
+            assert int(p) == max
+            q = ffi.cast(c_decl, long(min - 1))
+            assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
         assert q != p
         assert int(q) == int(p)
         assert hash(q) != hash(p)   # unlikely
         c_decl_ptr = '%s *' % c_decl
         py.test.raises(OverflowError, ffi.new, c_decl_ptr, min - 1)
         py.test.raises(OverflowError, ffi.new, c_decl_ptr, max + 1)
-        py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1))
-        py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1))
         assert ffi.new(c_decl_ptr, min)[0] == min
         assert ffi.new(c_decl_ptr, max)[0] == max
-        assert ffi.new(c_decl_ptr, long(min))[0] == min
-        assert ffi.new(c_decl_ptr, long(max))[0] == max
+        if sys.version < '3':
+            py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1))
+            py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1))
+            assert ffi.new(c_decl_ptr, long(min))[0] == min
+            assert ffi.new(c_decl_ptr, long(max))[0] == max
 
     def test_new_unsupported_type(self):
         ffi = FFI(backend=self.Backend())
 
     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)
+        if sys.version < '3':
+            py.test.raises(TypeError, ffi.new, "char*", 32)
+        else:
+            assert ffi.new("char*", 32)[0] == b' '
         py.test.raises(TypeError, ffi.new, "char*", u"x")
         py.test.raises(TypeError, ffi.new, "char*", "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:
         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:
         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:
     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())
     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):
 
     def test_str_from_char_pointer(self):
         ffi = FFI(backend=self.Backend())
-        assert str(ffi.new("char*", "x")) == "x"
-        assert str(ffi.new("char*", "\x00")) == ""
+        assert ffi.new("char*", b"x").value == b"x"
+        assert ffi.new("char*", b"\x00").value == b""
 
     def test_unicode_from_wchar_pointer(self):
         ffi = FFI(backend=self.Backend())
         self.check_wchar_t(ffi)
-        assert unicode(ffi.new("wchar_t*", u"x")) == u"x"
-        assert unicode(ffi.new("wchar_t*", u"\x00")) == u""
+        assert ffi.new("wchar_t*", u"x").value == u"x"
+        assert ffi.new("wchar_t*", u"\x00").value == u""
         x = ffi.new("wchar_t*", u"\x00")
         assert str(x) == repr(x)
 
     def test_string_from_char_array(self):
         ffi = FFI(backend=self.Backend())
-        assert str(ffi.cast("char", "x")) == "x"
-        p = ffi.new("char[]", "hello.")
-        p[5] = '!'
-        assert str(p) == "hello!"
-        p[6] = '?'
-        assert str(p) == "hello!?"
-        p[3] = '\x00'
-        assert str(p) == "hel"
-        py.test.raises(IndexError, "p[7] = 'X'")
+        assert ffi.cast("char", b"x").value == b"x"
+        p = ffi.new("char[]", b"hello.")
+        p[5] = b'!'
+        assert p.value == b"hello!"
+        p[6] = b'?'
+        assert p.value == b"hello!?"
+        p[3] = b'\x00'
+        assert p.value == b"hel"
+        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 str(p) == 'hello'
+        assert p.value == b'hello'
 
     def test_string_from_wchar_array(self):
         ffi = FFI(backend=self.Backend())
         self.check_wchar_t(ffi)
-        assert unicode(ffi.cast("wchar_t", "x")) == u"x"
-        assert unicode(ffi.cast("wchar_t", u"x")) == u"x"
+        assert ffi.cast("wchar_t", b"x").value == u"x"
+        assert ffi.cast("wchar_t", u"x").value == u"x"
         x = ffi.cast("wchar_t", "x")
         assert str(x) == repr(x)
         #
         p = ffi.new("wchar_t[]", u"hello.")
         p[5] = u'!'
-        assert unicode(p) == u"hello!"
-        p[6] = unichr(1234)
-        assert unicode(p) == u"hello!\u04d2"
+        assert p.value == u"hello!"
+        p[6] = u'\u1234'
+        assert p.value == u"hello!\u1234"
         p[3] = u'\x00'
-        assert unicode(p) == u"hel"
+        assert p.value == u"hel"
         py.test.raises(IndexError, "p[7] = u'X'")
         #
         a = ffi.new("wchar_t[]", u"hello\x00world")
         assert len(a) == 12
         p = ffi.cast("wchar_t *", a)
-        assert unicode(p) == u'hello'
+        assert p.value == u'hello'
 
     def test_fetch_const_char_p_field(self):
         # '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 str(s.name) == "testing"
+        assert s.name.value == b"testing"
         py.test.raises(TypeError, "s.name = None")
         s.name = ffi.NULL
         assert s.name == ffi.NULL
         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 unicode(s.name) == u"testing"
+        if sys.version < '3':
+            assert type(s.name) not in (str, unicode)
+        else:
+            assert type(s.name) not in (bytes, str)
+        assert s.name.value == u"testing"
         s.name = ffi.NULL
         assert s.name == ffi.NULL
 
         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
 
     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())
         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())
         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 str(a) == "B"
+        assert a.value == 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 str(a) == "B"
+        assert a.value == b"B"
 
     def test_enum(self):
         ffi = FFI(backend=self.Backend())
 
     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))
         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):
 
     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
 
     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
         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)