Hello community,
here is the log from the commit of package python-cffi for openSUSE:Factory checked in at 2018-03-05 13:35:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cffi (Old)
and /work/SRC/openSUSE:Factory/.python-cffi.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-cffi"
Mon Mar 5 13:35:18 2018 rev:21 rq:582163 version:1.11.5
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cffi/python-cffi.changes 2018-02-25 11:35:32.685470672 +0100
+++ /work/SRC/openSUSE:Factory/.python-cffi.new/python-cffi.changes 2018-03-05 13:35:23.273305877 +0100
@@ -1,0 +2,26 @@
+Fri Mar 2 23:14:41 UTC 2018 - arun@gmx.de
+
+- update to version 1.11.5:
+ * Issue #357: fix ffi.emit_python_code() which generated a buggy
+ Python file if you are using a struct with an anonymous union
+ field or vice-versa.
+ * Windows: ffi.dlopen() should now handle unicode filenames.
+ * ABI mode: implemented ffi.dlclose() for the in-line case (it used
+ to be present only in the out-of-line case).
+ * Fixed a corner case for setup.py install --record=xx --root=yy
+ with an out-of-line ABI module. Also fixed Issue #345.
+ * More hacks on Windows for running CFFI’s own setup.py.
+ * Issue #358: in embedding, to protect against (the rare case of)
+ Python initialization from several threads in parallel, we have to
+ use a spin-lock. On CPython 3 it is worse because it might
+ spin-lock for a long time (execution of Py_InitializeEx()). Sadly,
+ recent changes to CPython make that solution needed on CPython 2
+ too.
+ * CPython 3 on Windows: we no longer compile with Py_LIMITED_API by
+ default because such modules cannot be used with virtualenv. Issue
+ #350 mentions a workaround if you still want that and are not
+ concerned about virtualenv: pass a
+ define_macros=[("Py_LIMITED_API", None)] to the
+ ffibuilder.set_source() call.
+
+-------------------------------------------------------------------
Old:
----
cffi-1.11.4.tar.gz
New:
----
cffi-1.11.5.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-cffi.spec ++++++
--- /var/tmp/diff_new_pack.N9aYJS/_old 2018-03-05 13:35:24.713253766 +0100
+++ /var/tmp/diff_new_pack.N9aYJS/_new 2018-03-05 13:35:24.717253621 +0100
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-cffi
-Version: 1.11.4
+Version: 1.11.5
Release: 0
Summary: Foreign Function Interface for Python calling C code
License: MIT
++++++ cffi-1.11.4.tar.gz -> cffi-1.11.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/PKG-INFO new/cffi-1.11.5/PKG-INFO
--- old/cffi-1.11.4/PKG-INFO 2018-01-13 20:29:36.000000000 +0100
+++ new/cffi-1.11.5/PKG-INFO 2018-02-27 19:15:52.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.11.4
+Version: 1.11.5
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.11.4/c/_cffi_backend.c new/cffi-1.11.5/c/_cffi_backend.c
--- old/cffi-1.11.4/c/_cffi_backend.c 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/c/_cffi_backend.c 2018-02-27 19:15:41.000000000 +0100
@@ -2,7 +2,7 @@
#include
#include "structmember.h"
-#define CFFI_VERSION "1.11.4"
+#define CFFI_VERSION "1.11.5"
#ifdef MS_WIN32
#include
@@ -3794,27 +3794,29 @@
static int check_bytes_for_float_compatible(PyObject *io, double *out_value)
{
if (PyBytes_Check(io)) {
- if (PyBytes_GET_SIZE(io) != 1) {
- Py_DECREF(io);
- return -1;
- }
+ if (PyBytes_GET_SIZE(io) != 1)
+ goto error;
*out_value = (unsigned char)PyBytes_AS_STRING(io)[0];
return 1;
}
else if (PyUnicode_Check(io)) {
char ignored[80];
cffi_char32_t ordinal;
- if (_my_PyUnicode_AsSingleChar32(io, &ordinal, ignored) < 0) {
- Py_DECREF(io);
- return -1;
- }
+ if (_my_PyUnicode_AsSingleChar32(io, &ordinal, ignored) < 0)
+ goto error;
/* the signness of the 32-bit version of wide chars should not
* matter here, because 'ordinal' comes from a normal Python
* unicode string */
*out_value = ordinal;
return 1;
}
+ *out_value = 0; /* silence a gcc warning if this function is inlined */
return 0;
+
+ error:
+ Py_DECREF(io);
+ *out_value = 0; /* silence a gcc warning if this function is inlined */
+ return -1;
}
static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob)
@@ -3982,7 +3984,8 @@
static void dl_dealloc(DynLibObject *dlobj)
{
- dlclose(dlobj->dl_handle);
+ if (dlobj->dl_handle != NULL)
+ dlclose(dlobj->dl_handle);
free(dlobj->dl_name);
PyObject_Del(dlobj);
}
@@ -3992,6 +3995,17 @@
return PyText_FromFormat("", dlobj->dl_name);
}
+static int dl_check_closed(DynLibObject *dlobj)
+{
+ if (dlobj->dl_handle == NULL)
+ {
+ PyErr_Format(PyExc_ValueError, "library '%s' has already been closed",
+ dlobj->dl_name);
+ return -1;
+ }
+ return 0;
+}
+
static PyObject *dl_load_function(DynLibObject *dlobj, PyObject *args)
{
CTypeDescrObject *ct;
@@ -4002,6 +4016,9 @@
&CTypeDescr_Type, &ct, &funcname))
return NULL;
+ if (dl_check_closed(dlobj) < 0)
+ return NULL;
+
if (!(ct->ct_flags & (CT_FUNCTIONPTR | CT_POINTER | CT_ARRAY))) {
PyErr_Format(PyExc_TypeError,
"function or pointer or array cdata expected, got '%s'",
@@ -4034,6 +4051,9 @@
&CTypeDescr_Type, &ct, &varname))
return NULL;
+ if (dl_check_closed(dlobj) < 0)
+ return NULL;
+
dlerror(); /* clear error condition */
data = dlsym(dlobj->dl_handle, varname);
if (data == NULL) {
@@ -4059,6 +4079,9 @@
&CTypeDescr_Type, &ct, &varname, &value))
return NULL;
+ if (dl_check_closed(dlobj) < 0)
+ return NULL;
+
dlerror(); /* clear error condition */
data = dlsym(dlobj->dl_handle, varname);
if (data == NULL) {
@@ -4074,10 +4097,21 @@
return Py_None;
}
+static PyObject *dl_close_lib(DynLibObject *dlobj, PyObject *no_args)
+{
+ if (dl_check_closed(dlobj) < 0)
+ return NULL;
+ dlclose(dlobj->dl_handle);
+ dlobj->dl_handle = NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
static PyMethodDef dl_methods[] = {
{"load_function", (PyCFunction)dl_load_function, METH_VARARGS},
{"read_variable", (PyCFunction)dl_read_variable, METH_VARARGS},
{"write_variable", (PyCFunction)dl_write_variable, METH_VARARGS},
+ {"close_lib", (PyCFunction)dl_close_lib, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
@@ -4113,44 +4147,95 @@
dl_methods, /* tp_methods */
};
-static PyObject *b_load_library(PyObject *self, PyObject *args)
+static void *b_do_dlopen(PyObject *args, char **p_printable_filename,
+ PyObject **p_temp)
{
- char *filename_or_null, *printable_filename;
+ /* Logic to call the correct version of dlopen(). Returns NULL in case of error.
+ Otherwise, '*p_printable_filename' will point to a printable char version of
+ the filename (maybe utf-8-encoded). '*p_temp' will be set either to NULL or
+ to a temporary object that must be freed after looking at printable_filename.
+ */
void *handle;
- DynLibObject *dlobj;
+ char *filename_or_null;
int flags = 0;
-
+ *p_temp = NULL;
+
if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
PyObject *dummy;
if (!PyArg_ParseTuple(args, "|Oi:load_library",
&dummy, &flags))
return NULL;
filename_or_null = NULL;
+ *p_printable_filename = "<None>";
}
- else if (!PyArg_ParseTuple(args, "et|i:load_library",
- Py_FileSystemDefaultEncoding, &filename_or_null,
- &flags))
- return NULL;
+ else
+ {
+ PyObject *s = PyTuple_GET_ITEM(args, 0);
+#ifdef MS_WIN32
+ Py_UNICODE *filenameW;
+ if (PyArg_ParseTuple(args, "u|i:load_library", &filenameW, &flags))
+ {
+#if PY_MAJOR_VERSION < 3
+ s = PyUnicode_AsUTF8String(s);
+ if (s == NULL)
+ return NULL;
+ *p_temp = s;
+#endif
+ *p_printable_filename = PyText_AsUTF8(s);
+ if (*p_printable_filename == NULL)
+ return NULL;
+ handle = dlopenW(filenameW);
+ goto got_handle;
+ }
+ PyErr_Clear();
+#endif
+ if (!PyArg_ParseTuple(args, "et|i:load_library",
+ Py_FileSystemDefaultEncoding, &filename_or_null, &flags))
+ return NULL;
+
+ *p_printable_filename = PyText_AsUTF8(s);
+ if (*p_printable_filename == NULL)
+ return NULL;
+ }
if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
flags |= RTLD_NOW;
- printable_filename = filename_or_null ? filename_or_null : "<None>";
handle = dlopen(filename_or_null, flags);
+
+#ifdef MS_WIN32
+ got_handle:
+#endif
if (handle == NULL) {
const char *error = dlerror();
- PyErr_Format(PyExc_OSError, "cannot load library %s: %s",
- printable_filename, error);
+ PyErr_Format(PyExc_OSError, "cannot load library '%s': %s",
+ *p_printable_filename, error);
return NULL;
}
+ return handle;
+}
+
+static PyObject *b_load_library(PyObject *self, PyObject *args)
+{
+ char *printable_filename;
+ PyObject *temp;
+ void *handle;
+ DynLibObject *dlobj = NULL;
+
+ handle = b_do_dlopen(args, &printable_filename, &temp);
+ if (handle == NULL)
+ goto error;
dlobj = PyObject_New(DynLibObject, &dl_type);
if (dlobj == NULL) {
dlclose(handle);
- return NULL;
+ goto error;
}
dlobj->dl_handle = handle;
dlobj->dl_name = strdup(printable_filename);
+
+ error:
+ Py_XDECREF(temp);
return (PyObject *)dlobj;
}
@@ -4796,7 +4881,6 @@
if (PyText_GetSize(fname) == 0 &&
ftype->ct_flags & (CT_STRUCT|CT_UNION)) {
/* a nested anonymous struct or union */
- /* note: it seems we only get here with ffi.verify() */
CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra;
for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) {
/* broken complexity in the call to get_field_name(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/c/cdlopen.c new/cffi-1.11.5/c/cdlopen.c
--- old/cffi-1.11.4/c/cdlopen.c 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/c/cdlopen.c 2018-02-27 19:15:41.000000000 +0100
@@ -40,35 +40,18 @@
static PyObject *ffi_dlopen(PyObject *self, PyObject *args)
{
- char *filename_or_null, *printable_filename;
+ char *modname;
+ PyObject *temp, *result = NULL;
void *handle;
- int flags = 0;
- if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
- PyObject *dummy;
- if (!PyArg_ParseTuple(args, "|Oi:load_library",
- &dummy, &flags))
- return NULL;
- filename_or_null = NULL;
+ handle = b_do_dlopen(args, &modname, &temp);
+ if (handle != NULL)
+ {
+ result = (PyObject *)lib_internal_new((FFIObject *)self,
+ modname, handle);
}
- else if (!PyArg_ParseTuple(args, "et|i:load_library",
- Py_FileSystemDefaultEncoding, &filename_or_null,
- &flags))
- return NULL;
-
- if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
- flags |= RTLD_NOW;
- printable_filename = filename_or_null ? filename_or_null : "<None>";
-
- handle = dlopen(filename_or_null, flags);
- if (handle == NULL) {
- const char *error = dlerror();
- PyErr_Format(PyExc_OSError, "cannot load library '%s': %s",
- printable_filename, error);
- return NULL;
- }
- return (PyObject *)lib_internal_new((FFIObject *)self,
- printable_filename, handle);
+ Py_XDECREF(temp);
+ return result;
}
static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/c/misc_win32.h new/cffi-1.11.5/c/misc_win32.h
--- old/cffi-1.11.4/c/misc_win32.h 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/c/misc_win32.h 2018-02-27 19:15:41.000000000 +0100
@@ -192,7 +192,12 @@
static void *dlopen(const char *filename, int flag)
{
- return (void *)LoadLibrary(filename);
+ return (void *)LoadLibraryA(filename);
+}
+
+static void *dlopenW(const wchar_t *filename)
+{
+ return (void *)LoadLibraryW(filename);
}
static void *dlsym(void *handle, const char *symbol)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/c/realize_c_type.c new/cffi-1.11.5/c/realize_c_type.c
--- old/cffi-1.11.4/c/realize_c_type.c 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/c/realize_c_type.c 2018-02-27 19:15:41.000000000 +0100
@@ -737,13 +737,13 @@
return -1;
}
- if (fld->field_offset == (size_t)-1) {
+ if (ctf != NULL && fld->field_offset == (size_t)-1) {
/* unnamed struct, with field positions and sizes entirely
determined by complete_struct_or_union() and not checked.
Or, bitfields (field_size >= 0), similarly not checked. */
assert(fld->field_size == (size_t)-1 || fbitsize >= 0);
}
- else if (detect_custom_layout(ct, SF_STD_FIELD_POS,
+ else if (ctf == NULL || detect_custom_layout(ct, SF_STD_FIELD_POS,
ctf->ct_size, fld->field_size,
"wrong size for field '",
fld->name, "'") < 0) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/c/test_c.py new/cffi-1.11.5/c/test_c.py
--- old/cffi-1.11.4/c/test_c.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/c/test_c.py 2018-02-27 19:15:41.000000000 +0100
@@ -12,7 +12,7 @@
# ____________________________________________________________
import sys
-assert __version__ == "1.11.4", ("This test_c.py file is for testing a version"
+assert __version__ == "1.11.5", ("This test_c.py file is for testing a version"
" of cffi that differs from the one that we"
" get from 'import _cffi_backend'")
if sys.version_info < (3,):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/cffi/__init__.py new/cffi-1.11.5/cffi/__init__.py
--- old/cffi-1.11.4/cffi/__init__.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/cffi/__init__.py 2018-02-27 19:15:41.000000000 +0100
@@ -4,8 +4,8 @@
from .api import FFI
from .error import CDefError, FFIError, VerificationError, VerificationMissing
-__version__ = "1.11.4"
-__version_info__ = (1, 11, 4)
+__version__ = "1.11.5"
+__version_info__ = (1, 11, 5)
# 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.11.4/cffi/_embedding.h new/cffi-1.11.5/cffi/_embedding.h
--- old/cffi-1.11.4/cffi/_embedding.h 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/cffi/_embedding.h 2018-02-27 19:15:41.000000000 +0100
@@ -146,32 +146,6 @@
PyGILState_STATE state;
PyObject *pycode=NULL, *global_dict=NULL, *x;
-#if PY_MAJOR_VERSION >= 3
- /* see comments in _cffi_carefully_make_gil() about the
- Python2/Python3 difference
- */
-#else
- /* Acquire the GIL. We have no threadstate here. If Python is
- already initialized, it is possible that there is already one
- existing for this thread, but it is not made current now.
- */
- PyEval_AcquireLock();
-
- _cffi_py_initialize();
-
- /* The Py_InitializeEx() sometimes made a threadstate for us, but
- not always. Indeed Py_InitializeEx() could be called and do
- nothing. So do we have a threadstate, or not? We don't know,
- but we can replace it with NULL in all cases.
- */
- (void)PyThreadState_Swap(NULL);
-
- /* Now we can release the GIL and re-acquire immediately using the
- logic of PyGILState(), which handles making or installing the
- correct threadstate.
- */
- PyEval_ReleaseLock();
-#endif
state = PyGILState_Ensure();
/* Call the initxxx() function from the present module. It will
@@ -247,7 +221,7 @@
if (f != NULL && f != Py_None) {
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
- "\ncompiled with cffi version: 1.11.4"
+ "\ncompiled with cffi version: 1.11.5"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
@@ -278,16 +252,14 @@
that we don't hold the GIL before (if it exists), and we don't
hold it afterwards.
- What it really does is completely different in Python 2 and
- Python 3.
-
- Python 2
- ========
+ (What it really does used to be completely different in Python 2
+ and Python 3, with the Python 2 solution avoiding the spin-lock
+ around the Py_InitializeEx() call. However, after recent changes
+ to CPython 2.7 (issue #358) it no longer works. So we use the
+ Python 3 solution everywhere.)
- Initialize the GIL, without initializing the rest of Python,
- by calling PyEval_InitThreads().
-
- PyEval_InitThreads() must not be called concurrently at all.
+ This initializes Python by calling Py_InitializeEx().
+ Important: this must not be called concurrently at all.
So we use a global variable as a simple spin lock. This global
variable must be from 'libpythonX.Y.so', not from this
cffi-based extension module, because it must be shared from
@@ -297,18 +269,6 @@
string "ENDMARKER". We change it temporarily to point to the
next character in that string. (Yes, I know it's REALLY
obscure.)
-
- Python 3
- ========
-
- In Python 3, PyEval_InitThreads() cannot be called before
- Py_InitializeEx() any more. So this function calls
- Py_InitializeEx() first. It uses the same obscure logic to
- make sure we never call it concurrently.
-
- Arguably, this is less good on the spinlock, because
- Py_InitializeEx() takes much longer to run than
- PyEval_InitThreads(). But I didn't find a way around it.
*/
#ifdef WITH_THREAD
@@ -332,8 +292,7 @@
}
#endif
-#if PY_MAJOR_VERSION >= 3
- /* Python 3: call Py_InitializeEx() */
+ /* call Py_InitializeEx() */
{
PyGILState_STATE state = PyGILState_UNLOCKED;
if (!Py_IsInitialized())
@@ -344,17 +303,6 @@
PyEval_InitThreads();
PyGILState_Release(state);
}
-#else
- /* Python 2: call PyEval_InitThreads() */
-# ifdef WITH_THREAD
- if (!PyEval_ThreadsInitialized()) {
- PyEval_InitThreads(); /* makes the GIL */
- PyEval_ReleaseLock(); /* then release it */
- }
- /* else: there is already a GIL, but we still needed to do the
- spinlock dance to make sure that we see it as fully ready */
-# endif
-#endif
#ifdef WITH_THREAD
/* release the lock */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/cffi/api.py new/cffi-1.11.5/cffi/api.py
--- old/cffi-1.11.4/cffi/api.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/cffi/api.py 2018-02-27 19:15:41.000000000 +0100
@@ -143,6 +143,13 @@
self._libraries.append(lib)
return lib
+ def dlclose(self, lib):
+ """Close a library obtained with ffi.dlopen(). After this call,
+ access to functions or variables from the library will fail
+ (possibly with a segmentation fault).
+ """
+ type(lib).__cffi_close__(lib)
+
def _typeof_locked(self, cdecl):
# call me with the lock!
key = cdecl
@@ -898,6 +905,9 @@
return addressof_var(name)
raise AttributeError("cffi library has no function or "
"global variable named '%s'" % (name,))
+ def __cffi_close__(self):
+ backendlib.close_lib()
+ self.__dict__.clear()
#
if libname is not None:
try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/cffi/model.py new/cffi-1.11.5/cffi/model.py
--- old/cffi-1.11.4/cffi/model.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/cffi/model.py 2018-02-27 19:15:41.000000000 +0100
@@ -352,21 +352,20 @@
self.fldquals = fldquals
self.build_c_name_with_marker()
- def has_anonymous_struct_fields(self):
- if self.fldtypes is None:
- return False
- for name, type in zip(self.fldnames, self.fldtypes):
- if name == '' and isinstance(type, StructOrUnion):
- return True
- return False
+ def anonymous_struct_fields(self):
+ if self.fldtypes is not None:
+ for name, type in zip(self.fldnames, self.fldtypes):
+ if name == '' and isinstance(type, StructOrUnion):
+ yield type
- def enumfields(self):
+ def enumfields(self, expand_anonymous_struct_union=True):
fldquals = self.fldquals
if fldquals is None:
fldquals = (0,) * len(self.fldnames)
for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
self.fldbitsize, fldquals):
- if name == '' and isinstance(type, StructOrUnion):
+ if (name == '' and isinstance(type, StructOrUnion)
+ and expand_anonymous_struct_union):
# nested anonymous struct/union
for result in type.enumfields():
yield result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/cffi/recompiler.py new/cffi-1.11.5/cffi/recompiler.py
--- old/cffi-1.11.4/cffi/recompiler.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/cffi/recompiler.py 2018-02-27 19:15:41.000000000 +0100
@@ -836,6 +836,10 @@
def _struct_collecttype(self, tp):
self._do_collect_type(tp)
+ if self.target_is_python:
+ # also requires nested anon struct/unions in ABI mode, recursively
+ for fldtype in tp.anonymous_struct_fields():
+ self._struct_collecttype(fldtype)
def _struct_decl(self, tp, cname, approxname):
if tp.fldtypes is None:
@@ -884,7 +888,7 @@
named_ptr not in self.ffi._parser._included_declarations)):
if tp.fldtypes is None:
pass # opaque
- elif tp.partial or tp.has_anonymous_struct_fields():
+ elif tp.partial or any(tp.anonymous_struct_fields()):
pass # field layout obtained silently from the C compiler
else:
flags.append("_CFFI_F_CHECK_FIELDS")
@@ -896,7 +900,8 @@
flags = '|'.join(flags) or '0'
c_fields = []
if reason_for_not_expanding is None:
- enumfields = list(tp.enumfields())
+ expand_anonymous_struct_union = not self.target_is_python
+ enumfields = list(tp.enumfields(expand_anonymous_struct_union))
for fldname, fldtype, fbitsize, fqual in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
self._check_not_opaque(fldtype,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/cffi/setuptools_ext.py new/cffi-1.11.5/cffi/setuptools_ext.py
--- old/cffi-1.11.4/cffi/setuptools_ext.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/cffi/setuptools_ext.py 2018-02-27 19:15:41.000000000 +0100
@@ -148,8 +148,8 @@
def _add_py_module(dist, ffi, module_name):
from distutils.dir_util import mkpath
- from distutils.command.build_py import build_py
- from distutils.command.build_ext import build_ext
+ from setuptools.command.build_py import build_py
+ from setuptools.command.build_ext import build_ext
from distutils import log
from cffi import recompiler
@@ -169,6 +169,17 @@
generate_mod(os.path.join(self.build_lib, *module_path))
dist.cmdclass['build_py'] = build_py_make_mod
+ # distutils and setuptools have no notion I could find of a
+ # generated python module. If we don't add module_name to
+ # dist.py_modules, then things mostly work but there are some
+ # combination of options (--root and --record) that will miss
+ # the module. So we add it here, which gives a few apparently
+ # harmless warnings about not finding the file outside the
+ # build directory.
+ if dist.py_modules is None:
+ dist.py_modules = []
+ dist.py_modules.append(module_name)
+
# the following is only for "build_ext -i"
base_class_2 = dist.cmdclass.get('build_ext', build_ext)
class build_ext_make_mod(base_class_2):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/cffi.egg-info/PKG-INFO new/cffi-1.11.5/cffi.egg-info/PKG-INFO
--- old/cffi-1.11.4/cffi.egg-info/PKG-INFO 2018-01-13 20:29:36.000000000 +0100
+++ new/cffi-1.11.5/cffi.egg-info/PKG-INFO 2018-02-27 19:15:52.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.11.4
+Version: 1.11.5
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.11.4/doc/source/cdef.rst new/cffi-1.11.5/doc/source/cdef.rst
--- old/cffi-1.11.4/doc/source/cdef.rst 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/doc/source/cdef.rst 2018-02-27 19:15:41.000000000 +0100
@@ -560,7 +560,13 @@
``NAME.cpython-35m-x86_64-linux-gnu.so``. You can manually rename it to
``NAME.abi3.so``, or use setuptools version 26 or later. Also, note
that compiling with a debug version of Python will not actually define
-``Py_LIMITED_API``, as doing so makes ``Python.h`` unhappy.
+``Py_LIMITED_API``, as doing so makes ``Python.h`` unhappy. Finally,
+``Py_LIMITED_API`` is not defined on Windows, because this makes
+modules which cannot be used with ``virtualenv`` (issues `#355`__ and
+`#350`__).
+
+.. __: https://bitbucket.org/cffi/cffi/issues/355/importerror-dll-load-failed-on-wi...
+.. __: https://bitbucket.org/cffi/cffi/issues/350/issue-with-py_limited_api-on-wind...
**ffibuilder.compile(tmpdir='.', verbose=False, debug=None):**
explicitly generate the .py or .c file,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/doc/source/conf.py new/cffi-1.11.5/doc/source/conf.py
--- old/cffi-1.11.4/doc/source/conf.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/doc/source/conf.py 2018-02-27 19:15:41.000000000 +0100
@@ -47,7 +47,7 @@
# The short X.Y version.
version = '1.11'
# The full version, including alpha/beta/rc tags.
-release = '1.11.4'
+release = '1.11.5'
# 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.11.4/doc/source/installation.rst new/cffi-1.11.5/doc/source/installation.rst
--- old/cffi-1.11.4/doc/source/installation.rst 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/doc/source/installation.rst 2018-02-27 19:15:41.000000000 +0100
@@ -53,7 +53,7 @@
* https://pypi.python.org/pypi/cffi
-* Checksums of the "source" package version 1.11.4:
+* Checksums of the "source" package version 1.11.5:
- MD5: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/doc/source/whatsnew.rst new/cffi-1.11.5/doc/source/whatsnew.rst
--- old/cffi-1.11.4/doc/source/whatsnew.rst 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/doc/source/whatsnew.rst 2018-02-27 19:15:41.000000000 +0100
@@ -2,6 +2,42 @@
What's New
======================
+
+v1.11.5
+=======
+
+* `Issue #357`_: fix ``ffi.emit_python_code()`` which generated a buggy
+ Python file if you are using a ``struct`` with an anonymous ``union``
+ field or vice-versa.
+
+* Windows: ``ffi.dlopen()`` should now handle unicode filenames.
+
+* ABI mode: implemented ``ffi.dlclose()`` for the in-line case (it used
+ to be present only in the out-of-line case).
+
+* Fixed a corner case for ``setup.py install --record=xx --root=yy``
+ with an out-of-line ABI module. Also fixed `Issue #345`_.
+
+* More hacks on Windows for running CFFI's own ``setup.py``.
+
+* `Issue #358`_: in embedding, to protect against (the rare case of)
+ Python initialization from several threads in parallel, we have to use
+ a spin-lock. On CPython 3 it is worse because it might spin-lock for
+ a long time (execution of ``Py_InitializeEx()``). Sadly, recent
+ changes to CPython make that solution needed on CPython 2 too.
+
+* CPython 3 on Windows: we no longer compile with ``Py_LIMITED_API``
+ by default because such modules cannot be used with virtualenv.
+ `Issue #350`_ mentions a workaround if you still want that and are not
+ concerned about virtualenv: pass a ``define_macros=[("Py_LIMITED_API",
+ None)]`` to the ``ffibuilder.set_source()`` call.
+
+.. _`Issue #345`: https://bitbucket.org/cffi/cffi/issues/345/
+.. _`Issue #350`: https://bitbucket.org/cffi/cffi/issues/350/
+.. _`Issue #358`: https://bitbucket.org/cffi/cffi/issues/358/
+.. _`Issue #357`: https://bitbucket.org/cffi/cffi/issues/357/
+
+
v1.11.4
=======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/setup.py new/cffi-1.11.5/setup.py
--- old/cffi-1.11.4/setup.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/setup.py 2018-02-27 19:15:41.000000000 +0100
@@ -2,6 +2,10 @@
import subprocess
import errno
+# on Windows we give up and always import setuptools early to fix things for us
+if sys.platform == "win32":
+ import setuptools
+
sources = ['c/_cffi_backend.c']
libraries = ['ffi']
@@ -186,7 +190,7 @@
`Mailing list https://groups.google.com/forum/#!forum/python-cffi`_
""",
- version='1.11.4',
+ version='1.11.5',
packages=['cffi'] if cpython else [],
package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h',
'_embedding.h', '_cffi_errors.h']}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/testing/cffi0/test_function.py new/cffi-1.11.5/testing/cffi0/test_function.py
--- old/cffi-1.11.4/testing/cffi0/test_function.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/testing/cffi0/test_function.py 2018-02-27 19:15:41.000000000 +0100
@@ -499,3 +499,23 @@
""")
m = ffi.dlopen(lib_m)
assert dir(m) == ['MYE1', 'MYE2', 'MYFOO', 'myconst', 'myfunc', 'myvar']
+
+ def test_dlclose(self):
+ if self.Backend is CTypesBackend:
+ py.test.skip("not with the ctypes backend")
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("int foobar(void); int foobaz;")
+ lib = ffi.dlopen(lib_m)
+ ffi.dlclose(lib)
+ e = py.test.raises(ValueError, ffi.dlclose, lib)
+ assert str(e.value).startswith("library '")
+ assert str(e.value).endswith("' has already been closed")
+ e = py.test.raises(ValueError, getattr, lib, 'foobar')
+ assert str(e.value).startswith("library '")
+ assert str(e.value).endswith("' has already been closed")
+ e = py.test.raises(ValueError, getattr, lib, 'foobaz')
+ assert str(e.value).startswith("library '")
+ assert str(e.value).endswith("' has already been closed")
+ e = py.test.raises(ValueError, setattr, lib, 'foobaz', 42)
+ assert str(e.value).startswith("library '")
+ assert str(e.value).endswith("' has already been closed")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/testing/cffi0/test_ownlib.py new/cffi-1.11.5/testing/cffi0/test_ownlib.py
--- old/cffi-1.11.4/testing/cffi0/test_ownlib.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/testing/cffi0/test_ownlib.py 2018-02-27 19:15:41.000000000 +0100
@@ -114,8 +114,12 @@
if sys.platform == 'win32':
import os
# did we already build it?
- if os.path.exists(str(udir.join('testownlib.dll'))):
- cls.module = str(udir.join('testownlib.dll'))
+ if cls.Backend is CTypesBackend:
+ dll_path = str(udir) + '\\testownlib1.dll' # only ascii for the ctypes backend
+ else:
+ dll_path = str(udir) + '\\' + (u+'testownlib\u03be.dll') # non-ascii char
+ if os.path.exists(dll_path):
+ cls.module = dll_path
return
# try (not too hard) to find the version used to compile this python
# no mingw
@@ -135,8 +139,9 @@
if os.path.isfile(vcvarsall):
cmd = '"%s" %s' % (vcvarsall, arch) + ' & cl.exe testownlib.c ' \
' /LD /Fetestownlib.dll'
- subprocess.check_call(cmd, cwd = str(udir), shell=True)
- cls.module = str(udir.join('testownlib.dll'))
+ subprocess.check_call(cmd, cwd = str(udir), shell=True)
+ os.rename(str(udir) + '\\testownlib.dll', dll_path)
+ cls.module = dll_path
else:
subprocess.check_call(
'cc testownlib.c -shared -fPIC -o testownlib.so',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/testing/cffi1/test_re_python.py new/cffi-1.11.5/testing/cffi1/test_re_python.py
--- old/cffi-1.11.4/testing/cffi1/test_re_python.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/testing/cffi1/test_re_python.py 2018-02-27 19:15:41.000000000 +0100
@@ -1,8 +1,9 @@
-import sys
+import sys, os
import py
from cffi import FFI
from cffi import recompiler, ffiplatform, VerificationMissing
from testing.udir import udir
+from testing.support import u
def setup_module(mod):
@@ -35,6 +36,13 @@
'globalconst42', 'globalconsthello']
)
outputfilename = ffiplatform.compile(str(tmpdir), ext)
+ if sys.platform == "win32":
+ # test with a non-ascii char
+ outputfn1 = outputfilename
+ ofn, oext = os.path.splitext(outputfn1)
+ outputfilename = ofn + (u+'\u03be') + oext
+ #print(repr(outputfn1) + ' ==> ' + repr(outputfilename))
+ os.rename(outputfn1, outputfilename)
mod.extmod = outputfilename
mod.tmpdir = tmpdir
#
@@ -55,6 +63,9 @@
typedef struct bar_s { int x; signed char a[]; } bar_t;
enum foo_e { AA, BB, CC };
int strlen(const char *);
+ struct with_union { union { int a; char b; }; };
+ union with_struct { struct { int a; char b; }; };
+ struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; };
""")
ffi.set_source('re_python_pysrc', None)
ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py')))
@@ -104,12 +115,16 @@
from re_python_pysrc import ffi
lib = ffi.dlopen(extmod)
ffi.dlclose(lib)
+ if type(extmod) is not str: # unicode, on python 2
+ str_extmod = extmod.encode('utf-8')
+ else:
+ str_extmod = extmod
e = py.test.raises(ffi.error, ffi.dlclose, lib)
assert str(e.value).startswith(
- "library '%s' is already closed" % (extmod,))
+ "library '%s' is already closed" % (str_extmod,))
e = py.test.raises(ffi.error, getattr, lib, 'add42')
assert str(e.value) == (
- "library '%s' has been closed" % (extmod,))
+ "library '%s' has been closed" % (str_extmod,))
def test_constant_via_lib():
from re_python_pysrc import ffi
@@ -212,3 +227,23 @@
ffi.set_source('test_partial_enum', None)
py.test.raises(VerificationMissing, ffi.emit_python_code,
str(tmpdir.join('test_partial_enum.py')))
+
+def test_anonymous_union_inside_struct():
+ # based on issue #357
+ from re_python_pysrc import ffi
+ INT = ffi.sizeof("int")
+ assert ffi.offsetof("struct with_union", "a") == 0
+ assert ffi.offsetof("struct with_union", "b") == 0
+ assert ffi.sizeof("struct with_union") == INT
+ #
+ assert ffi.offsetof("union with_struct", "a") == 0
+ assert ffi.offsetof("union with_struct", "b") == INT
+ assert ffi.sizeof("union with_struct") >= INT + 1
+ #
+ FLOAT = ffi.sizeof("float")
+ assert ffi.sizeof("struct NVGcolor") == FLOAT * 4
+ assert ffi.offsetof("struct NVGcolor", "rgba") == 0
+ assert ffi.offsetof("struct NVGcolor", "r") == 0
+ assert ffi.offsetof("struct NVGcolor", "g") == FLOAT
+ assert ffi.offsetof("struct NVGcolor", "b") == FLOAT * 2
+ assert ffi.offsetof("struct NVGcolor", "a") == FLOAT * 3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.11.4/testing/cffi1/test_recompiler.py new/cffi-1.11.5/testing/cffi1/test_recompiler.py
--- old/cffi-1.11.4/testing/cffi1/test_recompiler.py 2018-01-13 20:28:57.000000000 +0100
+++ new/cffi-1.11.5/testing/cffi1/test_recompiler.py 2018-02-27 19:15:41.000000000 +0100
@@ -2297,3 +2297,11 @@
else:
assert lib.__loader__ is None
assert lib.__spec__ is None
+
+def test_realize_struct_error():
+ ffi = FFI()
+ ffi.cdef("""typedef ... foo_t; struct foo_s { void (*x)(foo_t); };""")
+ lib = verify(ffi, "test_realize_struct_error", """
+ typedef int foo_t; struct foo_s { void (*x)(foo_t); };
+ """)
+ py.test.raises(TypeError, ffi.new, "struct foo_s *")