diff options
-rw-r--r-- | c/_cffi_backend.c | 144 | ||||
-rw-r--r-- | c/ffi_obj.c | 2 | ||||
-rw-r--r-- | c/test_c.py | 62 | ||||
-rw-r--r-- | cffi/__init__.py | 4 | ||||
-rw-r--r-- | cffi/_embedding.h | 2 | ||||
-rw-r--r-- | cffi/recompiler.py | 18 | ||||
-rw-r--r-- | cffi/verifier.py | 3 | ||||
-rw-r--r-- | doc/source/conf.py | 2 | ||||
-rw-r--r-- | doc/source/installation.rst | 8 | ||||
-rw-r--r-- | doc/source/whatsnew.rst | 18 | ||||
-rw-r--r-- | setup.py | 6 | ||||
-rw-r--r-- | setup_base.py | 1 | ||||
-rw-r--r-- | testing/cffi0/test_ffi_backend.py | 1 | ||||
-rw-r--r-- | testing/cffi0/test_version.py | 7 | ||||
-rw-r--r-- | testing/cffi1/test_re_python.py | 5 |
15 files changed, 226 insertions, 57 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c index 440be7e..208f933 100644 --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -2,7 +2,7 @@ #include <Python.h> #include "structmember.h" -#define CFFI_VERSION "1.14.3" +#define CFFI_VERSION "1.14.5" #ifdef MS_WIN32 #include <windows.h> @@ -147,32 +147,42 @@ typedef unsigned long long int uintmax_t; * should not be open to the fork() bug. * * This is also used on macOS, provided we are executing on macOS 10.15 or - * above. + * above. It's a mess because it needs runtime checks in that case. */ #ifdef __NetBSD__ # define CFFI_CHECK_FFI_CLOSURE_ALLOC 1 +# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1 # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 1 +# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1 # define CFFI_CHECK_FFI_PREP_CIF_VAR 0 +# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0 #elif defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) # define CFFI_CHECK_FFI_CLOSURE_ALLOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) +# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1 # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) +# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1 # define CFFI_CHECK_FFI_PREP_CIF_VAR __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) - -# include "malloc_closure.h" +# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 1 #else # define CFFI_CHECK_FFI_CLOSURE_ALLOC 0 +# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 0 # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 0 +# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 0 # define CFFI_CHECK_FFI_PREP_CIF_VAR 0 - -# include "malloc_closure.h" +# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0 #endif +/* always includes this, even if it turns out not to be used on NetBSD + because calls are behind "if (0)" */ +#include "malloc_closure.h" + + #if PY_MAJOR_VERSION >= 3 # define STR_OR_BYTES "bytes" # define PyText_Type PyUnicode_Type @@ -232,6 +242,10 @@ typedef unsigned long long int uintmax_t; # define Py_SET_REFCNT(obj, val) (Py_REFCNT(obj) = (val)) #endif +#if PY_VERSION_HEX >= 0x03080000 +# define USE_WRITEUNRAISABLEMSG +#endif + /************************************************************/ /* base type flag: exactly one of the following: */ @@ -1975,11 +1989,12 @@ static void cdataowninggc_dealloc(CDataObject *cd) ffi_closure *closure = ((CDataObject_closure *)cd)->closure; PyObject *args = (PyObject *)(closure->user_data); Py_XDECREF(args); +#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { ffi_closure_free(closure); - } else { + } else +#endif cffi_closure_free(closure); - } } else { Py_FatalError("cdata CDataOwningGC_Type with unexpected type flags"); @@ -4582,14 +4597,18 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, if (PyUnicode_Check(s)) { s = PyUnicode_AsUTF8String(s); - if (s == NULL) + if (s == NULL) { + PyMem_Free(filename_or_null); return NULL; + } *p_temp = s; } #endif *p_printable_filename = PyText_AsUTF8(s); - if (*p_printable_filename == NULL) + if (*p_printable_filename == NULL) { + PyMem_Free(filename_or_null); return NULL; + } } if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0) flags |= RTLD_NOW; @@ -4608,6 +4627,7 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, #endif handle = dlopen(filename_or_null, flags); + PyMem_Free(filename_or_null); #ifdef MS_WIN32 got_handle: @@ -5921,8 +5941,7 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs, char *buffer; cif_description_t *cif_descr; struct funcbuilder_s funcbuffer; - ffi_status status; - char did_prep_cif_var = 0; + ffi_status status = (ffi_status)-1; funcbuffer.nb_bytes = 0; funcbuffer.bufferp = NULL; @@ -5947,16 +5966,17 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs, cif_descr = (cif_description_t *)buffer; /* use `ffi_prep_cif_var` if necessary and available */ +#if CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE if (variadic_nargs_declared >= 0) { if (CFFI_CHECK_FFI_PREP_CIF_VAR) { status = ffi_prep_cif_var(&cif_descr->cif, fabi, variadic_nargs_declared, funcbuffer.nargs, funcbuffer.rtype, funcbuffer.atypes); - did_prep_cif_var = 1; } } +#endif - if (!did_prep_cif_var) { + if (status == (ffi_status)-1) { status = ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs, funcbuffer.rtype, funcbuffer.atypes); } @@ -6133,6 +6153,43 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, char *extra_error_line) { /* like PyErr_WriteUnraisable(), but write a full traceback */ +#ifdef USE_WRITEUNRAISABLEMSG + + /* PyErr_WriteUnraisable actually writes the full traceback anyway + from Python 3.4, but we can't really get the formatting of the + custom text to be what we want. We can do better from Python + 3.8 by calling the new _PyErr_WriteUnraisableMsg(). + Luckily it's also Python 3.8 that adds new functionality that + people might want: the new sys.unraisablehook(). + */ + PyObject *s; + int first_char; + assert(objdescr != NULL && objdescr[0] != 0); /* non-empty */ + first_char = objdescr[0]; + if (first_char >= 'A' && first_char <= 'Z') + first_char += 'a' - 'A'; /* lower() the very first character */ + if (extra_error_line == NULL) + extra_error_line = ""; + + if (obj != NULL) + s = PyUnicode_FromFormat("%c%s%R%s", + first_char, objdescr + 1, obj, extra_error_line); + else + s = PyUnicode_FromFormat("%c%s%s", + first_char, objdescr + 1, extra_error_line); + + PyErr_Restore(t, v, tb); + if (s != NULL) { + _PyErr_WriteUnraisableMsg(PyText_AS_UTF8(s), NULL); + Py_DECREF(s); + } + else + PyErr_WriteUnraisable(obj); /* best effort */ + PyErr_Clear(); + +#else + + /* version for Python 2.7 and < 3.8 */ PyObject *f; #if PY_MAJOR_VERSION >= 3 /* jump through hoops to ensure the tb is attached to v, on Python 3 */ @@ -6157,6 +6214,8 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, Py_XDECREF(t); Py_XDECREF(v); Py_XDECREF(tb); + +#endif } static void general_invoke_callback(int decode_args_from_libffi, @@ -6206,7 +6265,11 @@ static void general_invoke_callback(int decode_args_from_libffi, goto error; if (convert_from_object_fficallback(result, SIGNATURE(1), py_res, decode_args_from_libffi) < 0) { +#ifdef USE_WRITEUNRAISABLEMSG + extra_error_line = ", trying to convert the result back to C"; +#else extra_error_line = "Trying to convert the result back to C:\n"; +#endif goto error; } done: @@ -6258,10 +6321,16 @@ static void general_invoke_callback(int decode_args_from_libffi, _my_PyErr_WriteUnraisable(exc1, val1, tb1, "From cffi callback ", py_ob, extra_error_line); +#ifdef USE_WRITEUNRAISABLEMSG + _my_PyErr_WriteUnraisable(exc2, val2, tb2, + "during handling of the above exception by 'onerror'", + NULL, NULL); +#else extra_error_line = ("\nDuring the call to 'onerror', " "another exception occurred:\n\n"); _my_PyErr_WriteUnraisable(exc2, val2, tb2, NULL, NULL, extra_error_line); +#endif _cffi_stop_error_capture(ecap); } } @@ -6340,6 +6409,17 @@ static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct, return infotuple; } +/* messily try to silence a gcc/clang deprecation warning for + ffi_prep_closure. Don't miss the "pragma pop" after the function. + This is done around the whole function because very old GCCs don't + support it inside a function. */ +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif static PyObject *b_callback(PyObject *self, PyObject *args) { CTypeDescrObject *ct; @@ -6359,9 +6439,12 @@ static PyObject *b_callback(PyObject *self, PyObject *args) if (infotuple == NULL) return NULL; +#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec); - } else { + } else +#endif + { closure = cffi_closure_alloc(); closure_exec = closure; } @@ -6382,8 +6465,8 @@ static PyObject *b_callback(PyObject *self, PyObject *args) cd->head.c_type = ct; cd->head.c_data = (char *)closure_exec; cd->head.c_weakreflist = NULL; + closure->user_data = NULL; cd->closure = closure; - PyObject_GC_Track(cd); cif_descr = (cif_description_t *)ct->ct_extra; if (cif_descr == NULL) { @@ -6393,30 +6476,20 @@ static PyObject *b_callback(PyObject *self, PyObject *args) goto error; } +#if CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE if (CFFI_CHECK_FFI_PREP_CLOSURE_LOC) { status = ffi_prep_closure_loc(closure, &cif_descr->cif, invoke_callback, infotuple, closure_exec); } - else { + else +#endif + { #if defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) && !FFI_LEGACY_CLOSURE_API PyErr_Format(PyExc_SystemError, "ffi_prep_closure_loc() is missing"); goto error; #else -/* messily try to silence a gcc/clang deprecation warning here */ -# if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -# elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -# endif status = ffi_prep_closure(closure, &cif_descr->cif, invoke_callback, infotuple); -# if defined(__clang__) -# pragma clang diagnostic pop -# elif defined(__GNUC__) -# pragma GCC diagnostic pop -# endif #endif } @@ -6440,23 +6513,30 @@ static PyObject *b_callback(PyObject *self, PyObject *args) "different from the 'ffi.h' file seen at compile-time)"); goto error; } + PyObject_GC_Track(cd); return (PyObject *)cd; error: closure->user_data = NULL; if (cd == NULL) { +#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { ffi_closure_free(closure); } - else { + else +#endif cffi_closure_free(closure); - } } else Py_DECREF(cd); Py_XDECREF(infotuple); return NULL; } +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif static PyObject *b_new_enum_type(PyObject *self, PyObject *args) { diff --git a/c/ffi_obj.c b/c/ffi_obj.c index 05c3a6d..f154146 100644 --- a/c/ffi_obj.c +++ b/c/ffi_obj.c @@ -1070,10 +1070,10 @@ static PyObject *ffi_init_once(FFIObject *self, PyObject *args, PyObject *kwds) if (res != NULL) { tup = PyTuple_Pack(2, Py_True, res); if (tup == NULL || PyDict_SetItem(cache, tag, tup) < 0) { - Py_XDECREF(tup); Py_DECREF(res); res = NULL; } + Py_XDECREF(tup); } } diff --git a/c/test_c.py b/c/test_c.py index 95ca812..788500e 100644 --- a/c/test_c.py +++ b/c/test_c.py @@ -17,7 +17,7 @@ from _cffi_backend import __version__ # ____________________________________________________________ import sys -assert __version__ == "1.14.3", ("This test_c.py file is for testing a version" +assert __version__ == "1.14.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,): @@ -1331,7 +1331,9 @@ def test_callback_exception(): except ImportError: import io as cStringIO # Python 3 import linecache - def matches(istr, ipattern): + def matches(istr, ipattern, ipattern38): + if sys.version_info >= (3, 8): + ipattern = ipattern38 str, pattern = istr, ipattern while '$' in pattern: i = pattern.index('$') @@ -1375,6 +1377,14 @@ Traceback (most recent call last): File "$", line $, in check_value $ ValueError: 42 +""", """\ +Exception ignored from cffi callback <function$Zcb1 at 0x$>: +Traceback (most recent call last): + File "$", line $, in Zcb1 + $ + File "$", line $, in check_value + $ +ValueError: 42 """) sys.stderr = cStringIO.StringIO() bigvalue = 20000 @@ -1383,6 +1393,12 @@ ValueError: 42 From cffi callback <function$Zcb1 at 0x$>: Trying to convert the result back to C: OverflowError: integer 60000 does not fit 'short' +""", """\ +Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: +Traceback (most recent call last): + File "$", line $, in test_callback_exception + $ +OverflowError: integer 60000 does not fit 'short' """) sys.stderr = cStringIO.StringIO() bigvalue = 20000 @@ -1420,6 +1436,17 @@ OverflowError: integer 60000 does not fit 'short' During the call to 'onerror', another exception occurred: TypeError: $integer$ +""", """\ +Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: +Traceback (most recent call last): + File "$", line $, in test_callback_exception + $ +OverflowError: integer 60000 does not fit 'short' +Exception ignored during handling of the above exception by 'onerror': +Traceback (most recent call last): + File "$", line $, in test_callback_exception + $ +TypeError: $integer$ """) # sys.stderr = cStringIO.StringIO() @@ -1436,6 +1463,17 @@ Traceback (most recent call last): File "$", line $, in oops $ AttributeError: 'str' object has no attribute 'append' +""", """\ +Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: +Traceback (most recent call last): + File "$", line $, in test_callback_exception + $ +OverflowError: integer 60000 does not fit 'short' +Exception ignored during handling of the above exception by 'onerror': +Traceback (most recent call last): + File "$", line $, in oops + $ +AttributeError: 'str' object has no attribute 'append' """) finally: sys.stderr = orig_stderr @@ -1470,7 +1508,7 @@ def test_a_lot_of_callbacks(): def make_callback(m): def cb(n): return n + m - return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope + return callback(BFunc, cb, 42) # 'cb' goes out of scope # flist = [make_callback(i) for i in range(BIGNUM)] for i, f in enumerate(flist): @@ -3974,6 +4012,20 @@ def test_from_buffer_types(): with pytest.raises(ValueError): release(pv[0]) +def test_issue483(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BIntA = new_array_type(BIntP, None) + lst = list(range(25)) + bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ') + p1 = from_buffer(BIntA, bytestring) # int[] + assert len(buffer(p1)) == 25 * size_of_int() + assert sizeof(p1) == 25 * size_of_int() + # + p2 = from_buffer(BIntP, bytestring) + assert sizeof(p2) == size_of_ptr() + assert len(buffer(p2)) == size_of_int() # first element only, by default + def test_memmove(): Short = new_primitive_type("short") ShortA = new_array_type(new_pointer_type(Short), None) @@ -4515,5 +4567,5 @@ def test_unaligned_types(): pbuf1 = cast(new_pointer_type(p), pbuf + 1) pbuf1[0] = num assert pbuf1[0] == num - assert buf[0] == '\x00' - assert buf[1 + size] == '\x00' + assert buf[0] == b'\x00' + assert buf[1 + size] == b'\x00' diff --git a/cffi/__init__.py b/cffi/__init__.py index 264afa1..b79c21f 100644 --- a/cffi/__init__.py +++ b/cffi/__init__.py @@ -5,8 +5,8 @@ from .api import FFI from .error import CDefError, FFIError, VerificationError, VerificationMissing from .error import PkgConfigError -__version__ = "1.14.3" -__version_info__ = (1, 14, 3) +__version__ = "1.14.5" +__version_info__ = (1, 14, 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 --git a/cffi/_embedding.h b/cffi/_embedding.h index fdce222..c36d793 100644 --- a/cffi/_embedding.h +++ b/cffi/_embedding.h @@ -224,7 +224,7 @@ static int _cffi_initialize_python(void) if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.14.3" + "\ncompiled with cffi version: 1.14.5" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff --git a/cffi/recompiler.py b/cffi/recompiler.py index 457d6f9..5369722 100644 --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -193,6 +193,17 @@ class Recompiler: assert isinstance(op, CffiOp) self.cffi_types = tuple(self.cffi_types) # don't change any more + def _enum_fields(self, tp): + # When producing C, expand all anonymous struct/union fields. + # That's necessary to have C code checking the offsets of the + # individual fields contained in them. When producing Python, + # don't do it and instead write it like it is, with the + # corresponding fields having an empty name. Empty names are + # recognized at runtime when we import the generated Python + # file. + expand_anonymous_struct_union = not self.target_is_python + return tp.enumfields(expand_anonymous_struct_union) + def _do_collect_type(self, tp): if not isinstance(tp, model.BaseTypeByIdentity): if isinstance(tp, tuple): @@ -206,7 +217,7 @@ class Recompiler: elif isinstance(tp, model.StructOrUnion): if tp.fldtypes is not None and ( tp not in self.ffi._parser._included_declarations): - for name1, tp1, _, _ in tp.enumfields(): + for name1, tp1, _, _ in self._enum_fields(tp): self._do_collect_type(self._field_type(tp, name1, tp1)) else: for _, x in tp._get_items(): @@ -864,7 +875,7 @@ class Recompiler: prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') - for fname, ftype, fbitsize, fqual in tp.enumfields(): + for fname, ftype, fbitsize, fqual in self._enum_fields(tp): try: if ftype.is_integer_type() or fbitsize >= 0: # accept all integers, but complain on float or double @@ -920,8 +931,7 @@ class Recompiler: flags = '|'.join(flags) or '0' c_fields = [] if reason_for_not_expanding is None: - expand_anonymous_struct_union = not self.target_is_python - enumfields = list(tp.enumfields(expand_anonymous_struct_union)) + enumfields = list(self._enum_fields(tp)) for fldname, fldtype, fbitsize, fqual in enumfields: fldtype = self._field_type(tp, fldname, fldtype) self._check_not_opaque(fldtype, diff --git a/cffi/verifier.py b/cffi/verifier.py index 84fc8b5..c445675 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -50,7 +50,8 @@ class Verifier(object): if tag: raise TypeError("can't specify both 'modulename' and 'tag'") else: - key = '\x00'.join([sys.version[:3], __version_verifier_modules__, + key = '\x00'.join(['%d.%d' % sys.version_info[:2], + __version_verifier_modules__, preamble, flattened_kwds] + ffi._cdefsources) if sys.version_info >= (3,): diff --git a/doc/source/conf.py b/doc/source/conf.py index 2315b93..2a7e353 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -47,7 +47,7 @@ copyright = u'2012-2018, Armin Rigo, Maciej Fijalkowski' # The short X.Y version. version = '1.14' # The full version, including alpha/beta/rc tags. -release = '1.14.3' +release = '1.14.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/installation.rst b/doc/source/installation.rst index 3c010bc..ebd2a34 100644 --- a/doc/source/installation.rst +++ b/doc/source/installation.rst @@ -52,13 +52,13 @@ Download and Installation: * https://pypi.python.org/pypi/cffi -* Checksums of the "source" package version 1.14.3: +* Checksums of the "source" package version 1.14.5: - - MD5: c2a47ffd5d183b193ac8ed3414dcfd07 + - MD5: 272cb183bf0365530e3c0d8f446cd89d - - SHA: 7199374653c1927e8d3c523b6498b149acdb6f7e + - SHA1: 21cdeccd7b7b121d35eae1b8e91d78f9ec83da98 - - SHA256: f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591 + - SHA256: fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c * Or grab the most current version from the `Heptapod page`_: ``hg clone https://foss.heptapod.net/pypy/cffi`` diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst index 0658e0d..f6111d5 100644 --- a/doc/source/whatsnew.rst +++ b/doc/source/whatsnew.rst @@ -3,6 +3,24 @@ What's New ====================== +v1.14.5 +======= + +* Source fix for old gcc versions + +* This and future releases should include wheels on more platforms, + thanks to our new release managers Matt and Matt! + +v1.14.4 +======= + +Release done for pip reasons. + +v1.14.3 +======= + +Release done for pip reasons. + v1.14.2 ======= @@ -76,10 +76,6 @@ def get_config(): config = Distribution().get_command_obj('config') return config -def macosx_deployment_target(): - from distutils.sysconfig import get_config_var - return tuple(map(int, get_config_var("MACOSX_DEPLOYMENT_TARGET").split('.'))) - def ask_supports_thread(): config = get_config() ok = (sys.platform != 'win32' and @@ -196,7 +192,7 @@ Contact `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ """, - version='1.14.3', + version='1.14.5', packages=['cffi'] if cpython else [], package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', '_embedding.h', '_cffi_errors.h']} diff --git a/setup_base.py b/setup_base.py index 667c7d5..4cf6ea5 100644 --- a/setup_base.py +++ b/setup_base.py @@ -8,6 +8,7 @@ from setup import library_dirs, extra_compile_args, extra_link_args if __name__ == '__main__': from distutils.core import setup from distutils.extension import Extension + standard = '__pypy__' not in sys.builtin_module_names setup(packages=['cffi'], requires=['pycparser'], diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py index 3552196..8e29bc4 100644 --- a/testing/cffi0/test_ffi_backend.py +++ b/testing/cffi0/test_ffi_backend.py @@ -179,6 +179,7 @@ class TestBitfield: setters = ['case %d: s.%s = value; break;' % iname for iname in enumerate(fnames)] lib = ffi1.verify(""" + #include <string.h> struct s1 { %s }; struct sa { char a; struct s1 b; }; #define Gofs_y offsetof(struct s1, y) diff --git a/testing/cffi0/test_version.py b/testing/cffi0/test_version.py index 9325685..d380b98 100644 --- a/testing/cffi0/test_version.py +++ b/testing/cffi0/test_version.py @@ -36,7 +36,12 @@ def test_doc_version_file(): v = cffi.__version__.replace('+', '') p = os.path.join(parent, 'doc', 'source', 'installation.rst') content = open(p).read() - assert (" package version %s:" % v) in content + if " package version %s:" % v not in content: + for i in range(5): + if " package version %s-%d:" % (v, i) in content: + break + else: + assert 0, "doc/source/installation.rst needs updating" def test_setup_version(): parent = os.path.dirname(os.path.dirname(cffi.__file__)) diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py index dce4f40..2ae0dd1 100644 --- a/testing/cffi1/test_re_python.py +++ b/testing/cffi1/test_re_python.py @@ -74,6 +74,7 @@ def setup_module(mod): int strlen(const char *); struct with_union { union { int a; char b; }; }; union with_struct { struct { int a; char b; }; }; + struct with_struct_with_union { struct { union { int x; }; } cp; }; struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; }; typedef struct selfref { struct selfref *next; } *selfref_ptr_t; """) @@ -248,6 +249,10 @@ def test_anonymous_union_inside_struct(): assert ffi.offsetof("union with_struct", "b") == INT assert ffi.sizeof("union with_struct") >= INT + 1 # + assert ffi.sizeof("struct with_struct_with_union") == INT + p = ffi.new("struct with_struct_with_union *") + assert p.cp.x == 0 + # FLOAT = ffi.sizeof("float") assert ffi.sizeof("struct NVGcolor") == FLOAT * 4 assert ffi.offsetof("struct NVGcolor", "rgba") == 0 |