Hello community,
here is the log from the commit of package python3-cffi for openSUSE:Factory checked in at 2015-06-16 14:05:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-cffi (Old)
and /work/SRC/openSUSE:Factory/.python3-cffi.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python3-cffi"
Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-cffi/python3-cffi.changes 2015-06-02 10:04:07.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python3-cffi.new/python3-cffi.changes 2015-06-16 14:05:59.000000000 +0200
@@ -1,0 +2,18 @@
+Mon Jun 15 02:13:07 UTC 2015 - arun@gmx.de
+
+- update to version 1.1.2:
+ * ffi.gc(): fixed a race condition in multithreaded programs
+ introduced in 1.1.1
+
+- changes from version 1.1.1:
+ * Out-of-line mode: ffi.string(), ffi.buffer() and ffi.getwinerror()
+ didn't accept their arguments as keyword arguments, unlike their
+ in-line mode equivalent. (It worked in PyPy.)
+ * Out-of-line ABI mode: documented a restriction of ffi.dlopen()
+ when compared to the in-line mode.
+ * ffi.gc(): when called several times with equal pointers, it was
+ accidentally registering only the last destructor, or even none at
+ all depending on details. (It was correctly registering all of
+ them only in PyPy, and only with the out-of-line FFIs.)
+
+-------------------------------------------------------------------
Old:
----
cffi-1.1.0.tar.gz
New:
----
cffi-1.1.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python3-cffi.spec ++++++
--- /var/tmp/diff_new_pack.eQaebf/_old 2015-06-16 14:06:00.000000000 +0200
+++ /var/tmp/diff_new_pack.eQaebf/_new 2015-06-16 14:06:00.000000000 +0200
@@ -17,7 +17,7 @@
Name: python3-cffi
-Version: 1.1.0
+Version: 1.1.2
Release: 0
Summary: Foreign Function Interface for Python calling C code
License: MIT
++++++ cffi-1.1.0.tar.gz -> cffi-1.1.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/PKG-INFO new/cffi-1.1.2/PKG-INFO
--- old/cffi-1.1.0/PKG-INFO 2015-05-30 21:48:01.000000000 +0200
+++ new/cffi-1.1.2/PKG-INFO 2015-06-09 12:04:16.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.1.0
+Version: 1.1.2
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/_cffi_backend.c new/cffi-1.1.2/c/_cffi_backend.c
--- old/cffi-1.1.0/c/_cffi_backend.c 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/c/_cffi_backend.c 2015-06-09 12:04:10.000000000 +0200
@@ -5158,12 +5158,14 @@
return PyText_FromStringAndSize(s, namelen + replacelen);
}
-static PyObject *b_string(PyObject *self, PyObject *args)
+static PyObject *b_string(PyObject *self, PyObject *args, PyObject *kwds)
{
CDataObject *cd;
Py_ssize_t maxlen = -1;
- if (!PyArg_ParseTuple(args, "O!|n:string",
- &CData_Type, &cd, &maxlen))
+ static char *keywords[] = {"cdata", "maxlen", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:string", keywords,
+ &CData_Type, &cd, &maxlen))
return NULL;
if (cd->c_type->ct_itemdescr != NULL &&
@@ -5246,12 +5248,14 @@
return NULL;
}
-static PyObject *b_buffer(PyObject *self, PyObject *args)
+static PyObject *b_buffer(PyObject *self, PyObject *args, PyObject *kwds)
{
CDataObject *cd;
Py_ssize_t size = -1;
- if (!PyArg_ParseTuple(args, "O!|n:buffer",
- &CData_Type, &cd, &size))
+ static char *keywords[] = {"cdata", "size", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:buffer", keywords,
+ &CData_Type, &cd, &size))
return NULL;
if (cd->c_type->ct_flags & CT_POINTER) {
@@ -5351,6 +5355,12 @@
return NULL;
}
x = (PyObject *)(raw + 42);
+ if (Py_REFCNT(x) <= 0) {
+ Py_FatalError("ffi.from_handle() detected that the address passed "
+ "points to garbage. If it is really the result of "
+ "ffi.new_handle(), then the Python object has already "
+ "been garbage collected");
+ }
Py_INCREF(x);
return x;
}
@@ -5790,15 +5800,15 @@
{"typeoffsetof", b_typeoffsetof, METH_VARARGS},
{"rawaddressof", b_rawaddressof, METH_VARARGS},
{"getcname", b_getcname, METH_VARARGS},
- {"string", b_string, METH_VARARGS},
- {"buffer", b_buffer, METH_VARARGS},
+ {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS},
+ {"buffer", (PyCFunction)b_buffer, METH_VARARGS | METH_KEYWORDS},
{"get_errno", b_get_errno, METH_NOARGS},
{"set_errno", b_set_errno, METH_O},
{"newp_handle", b_newp_handle, METH_VARARGS},
{"from_handle", b_from_handle, METH_O},
{"from_buffer", b_from_buffer, METH_VARARGS},
#ifdef MS_WIN32
- {"getwinerror", b_getwinerror, METH_VARARGS},
+ {"getwinerror", (PyCFunction)b_getwinerror, METH_VARARGS | METH_KEYWORDS},
#endif
{"_get_types", b__get_types, METH_NOARGS},
{"_testfunc", b__testfunc, METH_VARARGS},
@@ -6053,7 +6063,7 @@
if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
INITERROR;
- v = PyText_FromString("1.1.0");
+ v = PyText_FromString("1.1.2");
if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
INITERROR;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/cgc.c new/cffi-1.1.2/c/cgc.c
--- old/cffi-1.1.0/c/cgc.c 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/c/cgc.c 2015-06-09 12:04:07.000000000 +0200
@@ -2,79 +2,121 @@
/* translated to C from cffi/gc_weakref.py */
-static PyObject *const_name_pop;
-
-static PyObject *gc_wref_remove(PyObject *ffi_wref_data, PyObject *arg)
+static PyObject *gc_wref_remove(PyObject *ffi_wref_tup, PyObject *key)
{
- PyObject *destructor, *cdata, *x;
- PyObject *res = PyObject_CallMethodObjArgs(ffi_wref_data,
- const_name_pop, arg, NULL);
- if (res == NULL)
- return NULL;
-
- assert(PyTuple_Check(res));
- destructor = PyTuple_GET_ITEM(res, 0);
- cdata = PyTuple_GET_ITEM(res, 1);
- x = PyObject_CallFunctionObjArgs(destructor, cdata, NULL);
- Py_DECREF(res);
- if (x == NULL)
- return NULL;
- Py_DECREF(x);
-
- Py_INCREF(Py_None);
- return Py_None;
+ FFIObject *ffi;
+ PyObject *indexobj, *destructor, *cdata, *freelist, *result;
+ Py_ssize_t index;
+
+ /* here, tup is a 4-tuple (ffi, destructor, cdata, index) */
+ if (!PyTuple_Check(ffi_wref_tup))
+ goto oops; /* should never occur */
+
+ ffi = (FFIObject *)PyTuple_GET_ITEM(ffi_wref_tup, 0);
+ destructor = PyTuple_GET_ITEM(ffi_wref_tup, 1);
+ cdata = PyTuple_GET_ITEM(ffi_wref_tup, 2);
+ indexobj = PyTuple_GET_ITEM(ffi_wref_tup, 3);
+
+ index = PyInt_AsSsize_t(indexobj);
+ if (index < 0)
+ goto oops; /* should never occur */
+
+ /* assert gc_wrefs[index] is key */
+ if (PyList_GET_ITEM(ffi->gc_wrefs, index) != key)
+ goto oops; /* should never occur */
+
+ /* gc_wrefs[index] = freelist */
+ /* transfer ownership of 'freelist' to 'gc_wrefs[index]' */
+ freelist = ffi->gc_wrefs_freelist;
+ PyList_SET_ITEM(ffi->gc_wrefs, index, freelist);
+
+ /* freelist = index */
+ ffi->gc_wrefs_freelist = indexobj;
+ Py_INCREF(indexobj);
+
+ /* destructor(cdata) */
+ result = PyObject_CallFunctionObjArgs(destructor, cdata, NULL);
+
+ Py_DECREF(key); /* free the reference that was in 'gc_wrefs[index]' */
+ return result;
+
+ oops:
+ PyErr_SetString(PyExc_SystemError, "cgc: internal inconsistency");
+ /* random leaks may follow */
+ return NULL;
}
static PyMethodDef remove_callback = {
"gc_wref_remove", (PyCFunction)gc_wref_remove, METH_O
};
-static PyObject *gc_weakrefs_build(FFIObject *ffi, CDataObject *cd,
+static PyObject *gc_weakrefs_build(FFIObject *ffi, CDataObject *cdata,
PyObject *destructor)
{
- PyObject *new_cdata, *ref = NULL, *tup = NULL;
+ PyObject *new_cdata, *ref = NULL, *tup = NULL, *remove_fn = NULL;
+ Py_ssize_t index;
+ PyObject *datalist;
if (ffi->gc_wrefs == NULL) {
/* initialize */
- PyObject *data;
-
- if (const_name_pop == NULL) {
- const_name_pop = PyText_InternFromString("pop");
- if (const_name_pop == NULL)
- return NULL;
- }
- data = PyDict_New();
- if (data == NULL)
- return NULL;
- ffi->gc_wrefs = PyCFunction_New(&remove_callback, data);
- Py_DECREF(data);
- if (ffi->gc_wrefs == NULL)
+ datalist = PyList_New(0);
+ if (datalist == NULL)
return NULL;
+ ffi->gc_wrefs = datalist;
+ assert(ffi->gc_wrefs_freelist == NULL);
+ ffi->gc_wrefs_freelist = Py_None;
+ Py_INCREF(Py_None);
}
- new_cdata = do_cast(cd->c_type, (PyObject *)cd);
+ /* new_cdata = self.ffi.cast(typeof(cdata), cdata) */
+ new_cdata = do_cast(cdata->c_type, (PyObject *)cdata);
if (new_cdata == NULL)
goto error;
- ref = PyWeakref_NewRef(new_cdata, ffi->gc_wrefs);
- if (ref == NULL)
+ /* if freelist is None: */
+ datalist = ffi->gc_wrefs;
+ if (ffi->gc_wrefs_freelist == Py_None) {
+ /* index = len(gc_wrefs) */
+ index = PyList_GET_SIZE(datalist);
+ /* gc_wrefs.append(None) */
+ if (PyList_Append(datalist, Py_None) < 0)
+ goto error;
+ tup = Py_BuildValue("OOOn", ffi, destructor, cdata, index);
+ }
+ else {
+ /* index = freelist */
+ index = PyInt_AsSsize_t(ffi->gc_wrefs_freelist);
+ if (index < 0)
+ goto error; /* should not occur */
+ tup = PyTuple_Pack(4, ffi, destructor, cdata, ffi->gc_wrefs_freelist);
+ }
+ if (tup == NULL)
goto error;
- tup = PyTuple_Pack(2, destructor, cd);
- if (tup == NULL)
+ remove_fn = PyCFunction_New(&remove_callback, tup);
+ if (remove_fn == NULL)
goto error;
- /* the 'self' of the function 'gc_wrefs' is actually the data dict */
- if (PyDict_SetItem(PyCFunction_GET_SELF(ffi->gc_wrefs), ref, tup) < 0)
+ ref = PyWeakref_NewRef(new_cdata, remove_fn);
+ if (ref == NULL)
goto error;
+ /* freelist = gc_wrefs[index] (which is None if we just did append(None)) */
+ /* transfer ownership of 'datalist[index]' into gc_wrefs_freelist */
+ Py_DECREF(ffi->gc_wrefs_freelist);
+ ffi->gc_wrefs_freelist = PyList_GET_ITEM(datalist, index);
+ /* gc_wrefs[index] = ref */
+ /* transfer ownership of 'ref' into 'datalist[index]' */
+ PyList_SET_ITEM(datalist, index, ref);
+ Py_DECREF(remove_fn);
Py_DECREF(tup);
- Py_DECREF(ref);
+
return new_cdata;
error:
Py_XDECREF(new_cdata);
Py_XDECREF(ref);
Py_XDECREF(tup);
+ Py_XDECREF(remove_fn);
return NULL;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/ffi_obj.c new/cffi-1.1.2/c/ffi_obj.c
--- old/cffi-1.1.0/c/ffi_obj.c 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/c/ffi_obj.c 2015-06-09 12:04:07.000000000 +0200
@@ -23,7 +23,7 @@
struct FFIObject_s {
PyObject_HEAD
- PyObject *gc_wrefs;
+ PyObject *gc_wrefs, *gc_wrefs_freelist;
struct _cffi_parse_info_s info;
char ctx_is_static, ctx_is_nonempty;
builder_c_t types_builder;
@@ -51,6 +51,7 @@
return NULL;
}
ffi->gc_wrefs = NULL;
+ ffi->gc_wrefs_freelist = NULL;
ffi->info.ctx = &ffi->types_builder.ctx;
ffi->info.output = internal_output;
ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
@@ -63,6 +64,7 @@
{
PyObject_GC_UnTrack(ffi);
Py_XDECREF(ffi->gc_wrefs);
+ Py_XDECREF(ffi->gc_wrefs_freelist);
free_builder_c(&ffi->types_builder, ffi->ctx_is_static);
@@ -140,6 +142,38 @@
#define ACCEPT_ALL (ACCEPT_STRING | ACCEPT_CTYPE | ACCEPT_CDATA)
#define CONSIDER_FN_AS_FNPTR 8
+static CTypeDescrObject *_ffi_bad_type(FFIObject *ffi, char *input_text)
+{
+ size_t length = strlen(input_text);
+ char *extra;
+
+ if (length > 500) {
+ extra = "";
+ }
+ else {
+ char *p;
+ size_t i, num_spaces = ffi->info.error_location;
+ extra = alloca(length + num_spaces + 4);
+ p = extra;
+ *p++ = '\n';
+ for (i = 0; i < length; i++) {
+ if (' ' <= input_text[i] && input_text[i] < 0x7f)
+ *p++ = input_text[i];
+ else if (input_text[i] == '\t' || input_text[i] == '\n')
+ *p++ = ' ';
+ else
+ *p++ = '?';
+ }
+ *p++ = '\n';
+ memset(p, ' ', num_spaces);
+ p += num_spaces;
+ *p++ = '^';
+ *p++ = 0;
+ }
+ PyErr_Format(FFIError, "%s%s", ffi->info.error_message, extra);
+ return NULL;
+}
+
static CTypeDescrObject *_ffi_type(FFIObject *ffi, PyObject *arg,
int accept)
{
@@ -153,15 +187,9 @@
if (x == NULL) {
char *input_text = PyText_AS_UTF8(arg);
int err, index = parse_c_type(&ffi->info, input_text);
- if (index < 0) {
- size_t num_spaces = ffi->info.error_location;
- char *spaces = alloca(num_spaces + 1);
- memset(spaces, ' ', num_spaces);
- spaces[num_spaces] = '\0';
- PyErr_Format(FFIError, "%s\n%s\n%s^", ffi->info.error_message,
- input_text, spaces);
- return NULL;
- }
+ if (index < 0)
+ return _ffi_bad_type(ffi, input_text);
+
x = realize_c_type_or_func(&ffi->types_builder,
ffi->info.output, index);
if (x == NULL)
@@ -774,7 +802,7 @@
static PyMethodDef ffi_methods[] = {
{"addressof", (PyCFunction)ffi_addressof, METH_VARARGS, ffi_addressof_doc},
{"alignof", (PyCFunction)ffi_alignof, METH_O, ffi_alignof_doc},
- {"buffer", (PyCFunction)ffi_buffer, METH_VARARGS, ffi_buffer_doc},
+ {"buffer", (PyCFunction)ffi_buffer, METH_VKW, ffi_buffer_doc},
{"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc},
{"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc},
{"dlclose", (PyCFunction)ffi_dlclose, METH_VARARGS, ffi_dlclose_doc},
@@ -784,14 +812,14 @@
{"gc", (PyCFunction)ffi_gc, METH_VKW, ffi_gc_doc},
{"getctype", (PyCFunction)ffi_getctype, METH_VKW, ffi_getctype_doc},
#ifdef MS_WIN32
- {"getwinerror",(PyCFunction)ffi_getwinerror,METH_VARARGS, ffi_getwinerror_doc},
+ {"getwinerror",(PyCFunction)ffi_getwinerror,METH_VKW, ffi_getwinerror_doc},
#endif
{"integer_const",(PyCFunction)ffi_int_const,METH_VKW, ffi_int_const_doc},
{"new", (PyCFunction)ffi_new, METH_VKW, ffi_new_doc},
{"new_handle", (PyCFunction)ffi_new_handle, METH_O, ffi_new_handle_doc},
{"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS, ffi_offsetof_doc},
{"sizeof", (PyCFunction)ffi_sizeof, METH_O, ffi_sizeof_doc},
- {"string", (PyCFunction)ffi_string, METH_VARARGS, ffi_string_doc},
+ {"string", (PyCFunction)ffi_string, METH_VKW, ffi_string_doc},
{"typeof", (PyCFunction)ffi_typeof, METH_O, ffi_typeof_doc},
{NULL}
};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/lib_obj.c new/cffi-1.1.2/c/lib_obj.c
--- old/cffi-1.1.0/c/lib_obj.c 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/c/lib_obj.c 2015-06-09 12:04:07.000000000 +0200
@@ -300,7 +300,7 @@
case _CFFI_OP_GLOBAL_VAR:
{
/* global variable of the exact type specified here */
- size_t g_size = (size_t)g->size_or_direct_fn;
+ Py_ssize_t g_size = (Py_ssize_t)g->size_or_direct_fn;
ct = realize_c_type(types_builder, types_builder->ctx.types,
_CFFI_GETARG(g->type_op));
if (ct == NULL)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/misc_win32.h new/cffi-1.1.2/c/misc_win32.h
--- old/cffi-1.1.0/c/misc_win32.h 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/c/misc_win32.h 2015-06-09 12:04:07.000000000 +0200
@@ -82,14 +82,15 @@
}
#if PY_MAJOR_VERSION >= 3
-static PyObject *b_getwinerror(PyObject *self, PyObject *args)
+static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
{
int err = -1;
int len;
WCHAR *s_buf = NULL; /* Free via LocalFree */
PyObject *v, *message;
+ static char *keywords[] = {"code", NULL};
- if (!PyArg_ParseTuple(args, "|i", &err))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err))
return NULL;
if (err == -1) {
@@ -129,7 +130,7 @@
return v;
}
#else
-static PyObject *b_getwinerror(PyObject *self, PyObject *args)
+static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
{
int err = -1;
int len;
@@ -137,8 +138,9 @@
char *s_buf = NULL; /* Free via LocalFree */
char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */
PyObject *v;
+ static char *keywords[] = {"code", NULL};
- if (!PyArg_ParseTuple(args, "|i", &err))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err))
return NULL;
if (err == -1) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/realize_c_type.c new/cffi-1.1.2/c/realize_c_type.c
--- old/cffi-1.1.0/c/realize_c_type.c 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/c/realize_c_type.c 2015-06-09 12:04:07.000000000 +0200
@@ -60,7 +60,7 @@
static void free_builder_c(builder_c_t *builder, int ctx_is_static)
{
if (!ctx_is_static) {
- int i;
+ size_t i;
const void *mem[] = {builder->ctx.types,
builder->ctx.globals,
builder->ctx.struct_unions,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/test_c.py new/cffi-1.1.2/c/test_c.py
--- old/cffi-1.1.0/c/test_c.py 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/c/test_c.py 2015-06-09 12:04:10.000000000 +0200
@@ -3346,4 +3346,4 @@
def test_version():
# this test is here mostly for PyPy
- assert __version__ == "1.1.0"
+ assert __version__ == "1.1.2"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/__init__.py new/cffi-1.1.2/cffi/__init__.py
--- old/cffi-1.1.0/cffi/__init__.py 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/cffi/__init__.py 2015-06-09 12:04:10.000000000 +0200
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.1.0"
-__version_info__ = (1, 1, 0)
+__version__ = "1.1.2"
+__version_info__ = (1, 1, 2)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/gc_weakref.py new/cffi-1.1.2/cffi/gc_weakref.py
--- old/cffi-1.1.0/cffi/gc_weakref.py 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/cffi/gc_weakref.py 2015-06-09 12:04:07.000000000 +0200
@@ -2,18 +2,23 @@
class GcWeakrefs(object):
- # code copied and adapted from WeakKeyDictionary.
-
def __init__(self, ffi):
self.ffi = ffi
- self.data = data = {}
- def remove(k):
- destructor, cdata = data.pop(k)
- destructor(cdata)
- self.remove = remove
+ self.data = {}
+ self.nextindex = 0
def build(self, cdata, destructor):
# make a new cdata of the same type as the original one
new_cdata = self.ffi.cast(self.ffi._backend.typeof(cdata), cdata)
- self.data[ref(new_cdata, self.remove)] = destructor, cdata
+ #
+ def remove(key):
+ # careful, this function is not protected by any lock
+ old_key = self.data.pop(index)
+ assert old_key is key
+ destructor(cdata)
+ #
+ key = ref(new_cdata, remove)
+ index = self.nextindex
+ self.nextindex = index + 1 # we're protected by the lock here
+ self.data[index] = key
return new_cdata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/recompiler.py new/cffi-1.1.2/cffi/recompiler.py
--- old/cffi-1.1.0/cffi/recompiler.py 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/cffi/recompiler.py 2015-06-09 12:04:10.000000000 +0200
@@ -775,7 +775,8 @@
try:
if ftype.is_integer_type() or fbitsize >= 0:
# accept all integers, but complain on float or double
- prnt(' (void)((p->%s) << 1);' % fname)
+ prnt(" (void)((p->%s) << 1); /* check that '%s.%s' is "
+ "an integer */" % (fname, cname, fname))
continue
# only accept exactly the type declared, except that '[]'
# is interpreted as a '*' and so will match any array length.
@@ -949,7 +950,7 @@
prnt('{')
prnt(' int n = (%s) <= 0;' % (name,))
prnt(' *o = (unsigned long long)((%s) << 0);'
- ' /* check that we get an integer */' % (name,))
+ ' /* check that %s is an integer */' % (name, name))
if check_value is not None:
if check_value > 0:
check_value = '%dU' % (check_value,)
@@ -1088,8 +1089,9 @@
self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index)
def _emit_bytecode_UnknownIntegerType(self, tp, index):
- s = '_cffi_prim_int(sizeof(%s), (((%s)-1) << 0) <= 0)' % (
- tp.name, tp.name)
+ s = ('_cffi_prim_int(sizeof(%s), (\n'
+ ' ((%s)-1) << 0 /* check that %s is an integer type */\n'
+ ' ) <= 0)' % (tp.name, tp.name, tp.name))
self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
def _emit_bytecode_RawFunctionType(self, tp, index):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/setuptools_ext.py new/cffi-1.1.2/cffi/setuptools_ext.py
--- old/cffi-1.1.0/cffi/setuptools_ext.py 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/cffi/setuptools_ext.py 2015-06-09 12:04:07.000000000 +0200
@@ -18,7 +18,9 @@
# __init__.py files may already try to import the file that
# we are generating.
with open(filename) as f:
- code = compile(f.read(), filename, 'exec')
+ src = f.read()
+ src += '\n' # Python 2.6 compatibility
+ code = compile(src, filename, 'exec')
exec(code, glob, glob)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/vengine_gen.py new/cffi-1.1.2/cffi/vengine_gen.py
--- old/cffi-1.1.0/cffi/vengine_gen.py 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/cffi/vengine_gen.py 2015-06-09 12:04:07.000000000 +0200
@@ -402,12 +402,16 @@
else:
assert tp is not None
assert check_value is None
- prnt(tp.get_c_name(' %s(void)' % funcname, name),)
- prnt('{')
if category == 'var':
ampersand = '&'
else:
ampersand = ''
+ extra = ''
+ if category == 'const' and isinstance(tp, model.StructOrUnion):
+ extra = 'const *'
+ ampersand = '&'
+ prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name))
+ prnt('{')
prnt(' return (%s%s);' % (ampersand, name))
prnt('}')
prnt()
@@ -436,9 +440,14 @@
value += (1 << (8*self.ffi.sizeof(BLongLong)))
else:
assert check_value is None
- BFunc = self.ffi._typeof_locked(tp.get_c_name('(*)(void)', name))[0]
+ fntypeextra = '(*)(void)'
+ if isinstance(tp, model.StructOrUnion):
+ fntypeextra = '*' + fntypeextra
+ BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0]
function = module.load_function(BFunc, funcname)
value = function()
+ if isinstance(tp, model.StructOrUnion):
+ value = value[0]
return value
def _loaded_gen_constant(self, tp, name, module, library):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi.egg-info/PKG-INFO new/cffi-1.1.2/cffi.egg-info/PKG-INFO
--- old/cffi-1.1.0/cffi.egg-info/PKG-INFO 2015-05-30 21:48:01.000000000 +0200
+++ new/cffi-1.1.2/cffi.egg-info/PKG-INFO 2015-06-09 12:04:15.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.1.0
+Version: 1.1.2
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/cdef.rst new/cffi-1.1.2/doc/source/cdef.rst
--- old/cffi-1.1.0/doc/source/cdef.rst 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/doc/source/cdef.rst 2015-06-09 12:04:10.000000000 +0200
@@ -278,6 +278,18 @@
needed. (Alternatively, the out-of-line FFIs have a method
``ffi.dlclose(lib)``.)
+.. _dlopen-note:
+
+Note: the old version of ``ffi.dlopen()`` from the in-line ABI mode
+tries to use ``ctypes.util.find_library()`` if it cannot directly find
+the library. The newer out-of-line ``ffi.dlopen()`` no longer does it
+automatically; it simply passes the argument it receives to the
+underlying ``dlopen()`` or ``LoadLibrary()`` function. If needed, it
+is up to you to use ``ctypes.util.find_library()`` or any other way to
+look for the library's filename. This also means that
+``ffi.dlopen(None)`` no longer work on Windows; try instead
+``ffi.dlopen(ctypes.util.find_library('c'))``.
+
ffi.set_source(): preparing out-of-line modules
-----------------------------------------------
@@ -375,7 +387,7 @@
* *New in version 1.1:* integer types: the syntax "``typedef
int... foo_t;``" declares the type ``foo_t`` as an integer type
- whose exact size and signness is not specified. The compiler will
+ whose exact size and signedness is not specified. The compiler will
figure it out. (Note that this requires ``set_source()``; it does
not work with ``verify()``.) The ``int...`` can be replaced with
``long...`` or ``unsigned long long...`` or any other primitive
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/conf.py new/cffi-1.1.2/doc/source/conf.py
--- old/cffi-1.1.0/doc/source/conf.py 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/doc/source/conf.py 2015-06-09 12:04:10.000000000 +0200
@@ -47,7 +47,7 @@
# The short X.Y version.
version = '1.1'
# The full version, including alpha/beta/rc tags.
-release = '1.1.0'
+release = '1.1.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/installation.rst new/cffi-1.1.2/doc/source/installation.rst
--- old/cffi-1.1.0/doc/source/installation.rst 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/doc/source/installation.rst 2015-06-09 12:04:10.000000000 +0200
@@ -51,7 +51,7 @@
Download and Installation:
-* http://pypi.python.org/packages/source/c/cffi/cffi-1.1.0.tar.gz
+* http://pypi.python.org/packages/source/c/cffi/cffi-1.1.2.tar.gz
- Or grab the most current version by following the instructions below.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/overview.rst new/cffi-1.1.2/doc/source/overview.rst
--- old/cffi-1.1.0/doc/source/overview.rst 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/doc/source/overview.rst 2015-06-09 12:04:07.000000000 +0200
@@ -82,9 +82,21 @@
from _simple_example import ffi
- lib = ffi.dlopen(None) # or path to a library
+ lib = ffi.dlopen(None) # Unix: open the standard C library
+ #import ctypes.util # or, try this on Windows:
+ #lib = ffi.dlopen(ctypes.util.find_library("c"))
+
lib.printf(b"hi there, number %d\n", ffi.cast("int", 2))
+Note that this ``ffi.dlopen()``, unlike the one from in-line mode,
+does not invoke any additional magic to locate the library: it must be
+a path name (with or without a directory), as required by the C
+``dlopen()`` or ``LoadLibrary()`` functions. This means that
+``ffi.dlopen("libfoo.so")`` is ok, but ``ffi.dlopen("foo")`` is not.
+In the latter case, you could replace it with
+``ffi.dlopen(ctypes.util.find_library("foo"))``. Also, None is only
+recognized on Unix to open the standard C library.
+
For distribution purposes, remember that there is a new
``_simple_example.py`` file generated. You can either include it
statically within your project's source files, or, with Setuptools,
@@ -202,6 +214,13 @@
.. _struct: http://docs.python.org/library/struct.html
.. _array: http://docs.python.org/library/array.html
+This example also admits an out-of-line equivalent. It is similar to
+`Out-of-line example (ABI level, out-of-line)`_ above, but without any
+call to ``ffi.dlopen()``. In the main program, you write ``from
+_simple_example import ffi`` and then the same content as the in-line
+example above starting from the line ``image = ffi.new("pixel_t[]",
+800*600)``.
+
.. _performance:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/whatsnew.rst new/cffi-1.1.2/doc/source/whatsnew.rst
--- old/cffi-1.1.0/doc/source/whatsnew.rst 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/doc/source/whatsnew.rst 2015-06-09 12:04:10.000000000 +0200
@@ -3,11 +3,36 @@
======================
+1.1.2
+=====
+
+* ``ffi.gc()``: fixed a race condition in multithreaded programs
+ introduced in 1.1.1
+
+
+1.1.1
+=====
+
+* Out-of-line mode: ``ffi.string()``, ``ffi.buffer()`` and
+ ``ffi.getwinerror()`` didn't accept their arguments as keyword
+ arguments, unlike their in-line mode equivalent. (It worked in PyPy.)
+
+* Out-of-line ABI mode: documented a restriction__ of ``ffi.dlopen()``
+ when compared to the in-line mode.
+
+* ``ffi.gc()``: when called several times with equal pointers, it was
+ accidentally registering only the last destructor, or even none at
+ all depending on details. (It was correctly registering all of them
+ only in PyPy, and only with the out-of-line FFIs.)
+
+.. __: cdef.html#dlopen-note
+
+
1.1.0
=====
* Out-of-line API mode: we can now declare integer types with
- ``typedef int... foo_t;``. The exact size and signness of ``foo_t``
+ ``typedef int... foo_t;``. The exact size and signedness of ``foo_t``
is figured out by the compiler.
* Out-of-line API mode: we can now declare multidimensional arrays
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/setup.py new/cffi-1.1.2/setup.py
--- old/cffi-1.1.0/setup.py 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/setup.py 2015-06-09 12:04:10.000000000 +0200
@@ -144,7 +144,7 @@
`Mailing list https://groups.google.com/forum/#!forum/python-cffi`_
""",
- version='1.1.0',
+ version='1.1.2',
packages=['cffi'] if cpython else [],
package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h']}
if cpython else {},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi0/backend_tests.py new/cffi-1.1.2/testing/cffi0/backend_tests.py
--- old/cffi-1.1.0/testing/cffi0/backend_tests.py 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/testing/cffi0/backend_tests.py 2015-06-09 12:04:07.000000000 +0200
@@ -1457,6 +1457,63 @@
import gc; gc.collect(); gc.collect(); gc.collect()
assert seen == [1]
+ def test_gc_2(self):
+ ffi = FFI(backend=self.Backend())
+ p = ffi.new("int *", 123)
+ seen = []
+ q1 = ffi.gc(p, lambda p: seen.append(1))
+ q2 = ffi.gc(q1, lambda p: seen.append(2))
+ import gc; gc.collect()
+ assert seen == []
+ del q1, q2
+ import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
+ assert seen == [2, 1]
+
+ def test_gc_3(self):
+ ffi = FFI(backend=self.Backend())
+ p = ffi.new("int *", 123)
+ r = ffi.new("int *", 123)
+ seen = []
+ seen_r = []
+ q1 = ffi.gc(p, lambda p: seen.append(1))
+ s1 = ffi.gc(r, lambda r: seen_r.append(4))
+ q2 = ffi.gc(q1, lambda p: seen.append(2))
+ s2 = ffi.gc(s1, lambda r: seen_r.append(5))
+ q3 = ffi.gc(q2, lambda p: seen.append(3))
+ import gc; gc.collect()
+ assert seen == []
+ assert seen_r == []
+ del q1, q2, q3, s2, s1
+ import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
+ assert seen == [3, 2, 1]
+ assert seen_r == [5, 4]
+
+ def test_gc_4(self):
+ ffi = FFI(backend=self.Backend())
+ p = ffi.new("int *", 123)
+ seen = []
+ q1 = ffi.gc(p, lambda p: seen.append(1))
+ q2 = ffi.gc(q1, lambda p: seen.append(2))
+ q3 = ffi.gc(q2, lambda p: seen.append(3))
+ import gc; gc.collect()
+ assert seen == []
+ del q1, q3 # q2 remains, and has a hard ref to q1
+ import gc; gc.collect(); gc.collect(); gc.collect()
+ assert seen == [3]
+
+ def test_gc_finite_list(self):
+ ffi = FFI(backend=self.Backend())
+ p = ffi.new("int *", 123)
+ keepalive = []
+ for i in range(10):
+ keepalive.append(ffi.gc(p, lambda p: None))
+ assert len(ffi.gc_weakrefs.data) == i + 1 #should be a private attr
+ del keepalive[:]
+ import gc; gc.collect(); gc.collect()
+ for i in range(10):
+ keepalive.append(ffi.gc(p, lambda p: None))
+ assert len(ffi.gc_weakrefs.data) == 10
+
def test_CData_CType(self):
ffi = FFI(backend=self.Backend())
assert isinstance(ffi.cast("int", 0), ffi.CData)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi0/test_verify.py new/cffi-1.1.2/testing/cffi0/test_verify.py
--- old/cffi-1.1.0/testing/cffi0/test_verify.py 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/testing/cffi0/test_verify.py 2015-06-09 12:04:07.000000000 +0200
@@ -2227,3 +2227,11 @@
ffi.cdef("static const int FOO = 123;")
e = py.test.raises(VerificationError, ffi.verify, "#define FOO 124")
assert str(e.value).endswith("FOO has the real value 124, not 123")
+
+def test_const_struct_global():
+ ffi = FFI()
+ ffi.cdef("typedef struct { int x; ...; } T; const T myglob;")
+ lib = ffi.verify("typedef struct { double y; int x; } T;"
+ "const T myglob = { 0.1, 42 };")
+ assert ffi.typeof(lib.myglob) == ffi.typeof("T")
+ assert lib.myglob.x == 42
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi0/test_zintegration.py new/cffi-1.1.2/testing/cffi0/test_zintegration.py
--- old/cffi-1.1.0/testing/cffi0/test_zintegration.py 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/testing/cffi0/test_zintegration.py 2015-06-09 12:04:07.000000000 +0200
@@ -1,5 +1,4 @@
import py, os, sys, shutil
-import imp
import subprocess
from testing.udir import udir
@@ -15,28 +14,12 @@
except OSError as e:
py.test.skip("Cannot execute virtualenv: %s" % (e,))
- try:
- deepcopy = os.symlink
- except:
- import shutil, errno
- def deepcopy(src, dst):
- try:
- shutil.copytree(src, dst)
- except OSError as e:
- if e.errno in (errno.ENOTDIR, errno.EINVAL):
- shutil.copy(src, dst)
- else:
- print('got errno')
- print(e.errno)
- print('not')
- print(errno.ENOTDIR)
- raise
-
site_packages = None
for dirpath, dirnames, filenames in os.walk(str(tmpdir)):
if os.path.basename(dirpath) == 'site-packages':
site_packages = dirpath
break
+ paths = ""
if site_packages:
try:
from cffi import _pycparser
@@ -49,15 +32,22 @@
pass
else:
modules += ('ply',) # needed for older versions of pycparser
+ paths = []
for module in modules:
- target = imp.find_module(module)[1]
- deepcopy(target, os.path.join(site_packages,
- os.path.basename(target)))
- return tmpdir
+ target = __import__(module, None, None, [])
+ src = os.path.abspath(target.__file__)
+ for end in ['__init__.pyc', '__init__.pyo', '__init__.py']:
+ if src.lower().endswith(end):
+ src = src[:-len(end)-1]
+ break
+ paths.append(os.path.dirname(src))
+ paths = os.pathsep.join(paths)
+ return tmpdir, paths
SNIPPET_DIR = py.path.local(__file__).join('..', 'snippets')
-def really_run_setup_and_program(dirname, venv_dir, python_snippet):
+def really_run_setup_and_program(dirname, venv_dir_and_paths, python_snippet):
+ venv_dir, paths = venv_dir_and_paths
def remove(dir):
dir = str(SNIPPET_DIR.join(dirname, dir))
shutil.rmtree(dir, ignore_errors=True)
@@ -75,9 +65,11 @@
else:
bindir = 'bin'
vp = str(venv_dir.join(bindir).join('python'))
- subprocess.check_call((vp, 'setup.py', 'clean'))
- subprocess.check_call((vp, 'setup.py', 'install'))
- subprocess.check_call((vp, str(python_f)))
+ env = os.environ.copy()
+ env['PYTHONPATH'] = paths
+ subprocess.check_call((vp, 'setup.py', 'clean'), env=env)
+ subprocess.check_call((vp, 'setup.py', 'install'), env=env)
+ subprocess.check_call((vp, str(python_f)), env=env)
finally:
os.chdir(olddir)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_ffi_obj.py new/cffi-1.1.2/testing/cffi1/test_ffi_obj.py
--- old/cffi-1.1.0/testing/cffi1/test_ffi_obj.py 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/testing/cffi1/test_ffi_obj.py 2015-06-09 12:04:07.000000000 +0200
@@ -1,4 +1,4 @@
-import py
+import py, sys
import _cffi_backend as _cffi1_backend
@@ -65,6 +65,7 @@
ffi = _cffi1_backend.FFI()
p = ffi.new("char[]", init=b"foobar\x00baz")
assert ffi.string(p) == b"foobar"
+ assert ffi.string(cdata=p, maxlen=3) == b"foo"
def test_ffi_errno():
# xxx not really checking errno, just checking that we can read/write it
@@ -157,11 +158,19 @@
assert str(e.value) == ("undefined struct/union name\n"
"struct never_heard_of_s\n"
" ^")
+ e = py.test.raises(ffi.error, ffi.cast, "\t\n\x01\x1f~\x7f\x80\xff", 0)
+ marks = "?" if sys.version_info < (3,) else "??"
+ assert str(e.value) == ("identifier expected\n"
+ " ??~?%s%s\n"
+ " ^" % (marks, marks))
+ e = py.test.raises(ffi.error, ffi.cast, "X" * 600, 0)
+ assert str(e.value) == ("undefined type name")
def test_ffi_buffer():
ffi = _cffi1_backend.FFI()
a = ffi.new("signed char[]", [5, 6, 7])
assert ffi.buffer(a)[:] == b'\x05\x06\x07'
+ assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06'
def test_ffi_from_buffer():
import array
@@ -178,3 +187,11 @@
ffi = _cffi1_backend.FFI()
assert isinstance(ffi.cast("int", 42), CData)
assert isinstance(ffi.typeof("int"), CType)
+
+def test_ffi_getwinerror():
+ if sys.platform != "win32":
+ py.test.skip("for windows")
+ ffi = _cffi1_backend.FFI()
+ n = (1 << 29) + 42
+ code, message = ffi.getwinerror(code=n)
+ assert code == n
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_new_ffi_1.py new/cffi-1.1.2/testing/cffi1/test_new_ffi_1.py
--- old/cffi-1.1.0/testing/cffi1/test_new_ffi_1.py 2015-05-30 21:45:20.000000000 +0200
+++ new/cffi-1.1.2/testing/cffi1/test_new_ffi_1.py 2015-06-09 12:04:07.000000000 +0200
@@ -32,7 +32,9 @@
struct ab { int a, b; };
struct abc { int a, b, c; };
- enum foq { A0, B0, CC0, D0 };
+ /* don't use A0, B0, CC0, D0 because termios.h might be included
+ and it has its own #defines for these names */
+ enum foq { cffiA0, cffiB0, cffiCC0, cffiD0 };
enum bar { A1, B1=-2, CC1, D1, E1 };
enum baz { A2=0x1000, B2=0x2000 };
enum foo2 { A3, B3, C3, D3 };
@@ -878,9 +880,9 @@
def test_enum(self):
# enum foq { A0, B0, CC0, D0 };
- assert ffi.string(ffi.cast("enum foq", 0)) == "A0"
- assert ffi.string(ffi.cast("enum foq", 2)) == "CC0"
- assert ffi.string(ffi.cast("enum foq", 3)) == "D0"
+ assert ffi.string(ffi.cast("enum foq", 0)) == "cffiA0"
+ assert ffi.string(ffi.cast("enum foq", 2)) == "cffiCC0"
+ assert ffi.string(ffi.cast("enum foq", 3)) == "cffiD0"
assert ffi.string(ffi.cast("enum foq", 4)) == "4"
# enum bar { A1, B1=-2, CC1, D1, E1 };
assert ffi.string(ffi.cast("enum bar", 0)) == "A1"
@@ -1407,6 +1409,47 @@
import gc; gc.collect(); gc.collect(); gc.collect()
assert seen == [1]
+ def test_gc_2(self):
+ p = ffi.new("int *", 123)
+ seen = []
+ q1 = ffi.gc(p, lambda p: seen.append(1))
+ q2 = ffi.gc(q1, lambda p: seen.append(2))
+ import gc; gc.collect()
+ assert seen == []
+ del q1, q2
+ import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
+ assert seen == [2, 1]
+
+ def test_gc_3(self):
+ p = ffi.new("int *", 123)
+ r = ffi.new("int *", 123)
+ seen = []
+ seen_r = []
+ q1 = ffi.gc(p, lambda p: seen.append(1))
+ s1 = ffi.gc(r, lambda r: seen_r.append(4))
+ q2 = ffi.gc(q1, lambda p: seen.append(2))
+ s2 = ffi.gc(s1, lambda r: seen_r.append(5))
+ q3 = ffi.gc(q2, lambda p: seen.append(3))
+ import gc; gc.collect()
+ assert seen == []
+ assert seen_r == []
+ del q1, q2, q3, s2, s1
+ import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
+ assert seen == [3, 2, 1]
+ assert seen_r == [5, 4]
+
+ def test_gc_4(self):
+ p = ffi.new("int *", 123)
+ seen = []
+ q1 = ffi.gc(p, lambda p: seen.append(1))
+ q2 = ffi.gc(q1, lambda p: seen.append(2))
+ q3 = ffi.gc(q2, lambda p: seen.append(3))
+ import gc; gc.collect()
+ assert seen == []
+ del q1, q3 # q2 remains, and has a hard ref to q1
+ import gc; gc.collect(); gc.collect(); gc.collect()
+ assert seen == [3]
+
def test_CData_CType(self):
assert isinstance(ffi.cast("int", 0), ffi.CData)
assert isinstance(ffi.new("int *"), ffi.CData)
@@ -1533,8 +1576,8 @@
assert p.a == -52525
#
p = ffi.cast("enum foq", 2)
- assert ffi.string(p) == "CC0"
- assert ffi2.sizeof("char[CC0]") == 2
+ assert ffi.string(p) == "cffiCC0"
+ assert ffi2.sizeof("char[cffiCC0]") == 2
#
p = ffi.new("anon_foo_t *", [-52526])
assert p.a == -52526
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_re_python.py new/cffi-1.1.2/testing/cffi1/test_re_python.py
--- old/cffi-1.1.0/testing/cffi1/test_re_python.py 2015-05-30 21:45:50.000000000 +0200
+++ new/cffi-1.1.2/testing/cffi1/test_re_python.py 2015-06-09 12:04:07.000000000 +0200
@@ -7,6 +7,7 @@
def setup_module(mod):
SRC = """
+ #include