From b61b47e37f2631c0e2e7dd718e2f0f789c9dd2b0c383cc8eba30bee618fc2f9d Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Sat, 31 Aug 2024 12:55:13 +0000 Subject: [PATCH] - update to 1.17.0: * Add support for Python 3.13. * In API mode, when you get a function from a C library by writing `fn = lib.myfunc`, you get an object of a special type for performance reasons, instead of a ``. Before version 1.17 you could only call such objects. You could write `ffi.addressof(lib, "myfunc")` in order to get a real `` object, based on the idea that in these cases in C you'd usually write `&myfunc` instead of `myfunc`. In version 1.17, the special object `lib.myfunc` can now be passed in many places where CFFI expects a regular `` object. For example, you can now pass it as a callback to a C function call, or write it inside a C structure field of the correct pointer-to-function type, or use `ffi.cast()` or `ffi.typeof()` on it. - drop py313-compat.patch, py313-use-format-unraisable.patch, py313-use-hashpointer.patch (upstream) OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-cffi?expand=0&rev=99 --- cffi-1.16.0.tar.gz | 3 - cffi-1.17.0.tar.gz | 3 + py313-compat.patch | 302 ------------------------------ py313-use-format-unraisable.patch | 30 --- py313-use-hashpointer.patch | 32 ---- python-cffi.changes | 21 +++ python-cffi.spec | 5 +- 7 files changed, 25 insertions(+), 371 deletions(-) delete mode 100644 cffi-1.16.0.tar.gz create mode 100644 cffi-1.17.0.tar.gz delete mode 100644 py313-compat.patch delete mode 100644 py313-use-format-unraisable.patch delete mode 100644 py313-use-hashpointer.patch diff --git a/cffi-1.16.0.tar.gz b/cffi-1.16.0.tar.gz deleted file mode 100644 index 4754c49..0000000 --- a/cffi-1.16.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 -size 512873 diff --git a/cffi-1.17.0.tar.gz b/cffi-1.17.0.tar.gz new file mode 100644 index 0000000..5c2ab2f --- /dev/null +++ b/cffi-1.17.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76 +size 516073 diff --git a/py313-compat.patch b/py313-compat.patch deleted file mode 100644 index ef756e4..0000000 --- a/py313-compat.patch +++ /dev/null @@ -1,302 +0,0 @@ -From 14723b0bbd127790c450945099db31018d80fa83 Mon Sep 17 00:00:00 2001 -From: Matt Davis <6775756+nitzmahone@users.noreply.github.com> -Date: Thu, 30 Nov 2023 18:27:52 -0800 -Subject: [PATCH] Python 3.13 compatibility (#24) - -* fix obsolete private API aliases for 3.13 compat - -* update unraisable tests to use sys.unraisablehook - -* assert shape of calls to unraisablehook and sanity check traceback contents instead of (varying) stderr output from default unraisablehook impl ---- - src/c/_cffi_backend.c | 4 +- - src/c/misc_thread_common.h | 4 +- - src/c/test_c.py | 217 ++++++++++++------------------------- - 3 files changed, 74 insertions(+), 151 deletions(-) - -diff --git a/src/c/_cffi_backend.c b/src/c/_cffi_backend.c -index 5e284e00..7c72ffe0 100644 ---- a/src/c/_cffi_backend.c -+++ b/src/c/_cffi_backend.c -@@ -134,8 +134,8 @@ - # define PyText_Check PyUnicode_Check - # define PyTextAny_Check PyUnicode_Check - # define PyText_FromFormat PyUnicode_FromFormat --# define PyText_AsUTF8 _PyUnicode_AsString /* PyUnicode_AsUTF8 in Py3.3 */ --# define PyText_AS_UTF8 _PyUnicode_AsString -+# define PyText_AsUTF8 PyUnicode_AsUTF8 -+# define PyText_AS_UTF8 PyUnicode_AsUTF8 - # if PY_VERSION_HEX >= 0x03030000 - # define PyText_GetSize PyUnicode_GetLength - # else -diff --git a/src/c/misc_thread_common.h b/src/c/misc_thread_common.h -index ead9c83c..7d29634b 100644 ---- a/src/c/misc_thread_common.h -+++ b/src/c/misc_thread_common.h -@@ -331,7 +331,9 @@ PyAPI_DATA(void *volatile) _PyThreadState_Current; - - static PyThreadState *get_current_ts(void) - { --#if PY_VERSION_HEX >= 0x03060000 -+#if PY_VERSION_HEX >= 0x030D0000 -+ return PyThreadState_GetUnchecked(); -+#elif PY_VERSION_HEX >= 0x03060000 - return _PyThreadState_UncheckedGet(); - #elif defined(_Py_atomic_load_relaxed) - return (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); -diff --git a/src/c/test_c.py b/src/c/test_c.py -index 1cdab10f..10cc35cf 100644 ---- a/src/c/test_c.py -+++ b/src/c/test_c.py -@@ -1,5 +1,12 @@ -+from __future__ import annotations -+ -+import contextlib -+import traceback -+import unittest.mock -+ - import pytest - import sys -+import typing as t - - is_musl = False - if sys.platform == 'linux': -@@ -1337,27 +1344,37 @@ def cb(n): - e = pytest.raises(TypeError, f) - assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0" - -+@contextlib.contextmanager -+def _assert_unraisable(error_type: type[Exception] | None, message: str = '', traceback_tokens: list[str] | None = None): -+ """Assert that a given sys.unraisablehook interaction occurred (or did not occur, if error_type is None) while this context was active""" -+ raised_errors: list[Exception] = [] -+ raised_traceback: str = '' -+ -+ # sys.unraisablehook is called more than once for chained exceptions; accumulate the errors and tracebacks for inspection -+ def _capture_unraisable_hook(ur_args): -+ nonlocal raised_traceback -+ raised_errors.append(ur_args.exc_value) -+ -+ # NB: need to use the old etype/value/tb form until 3.10 is the minimum -+ raised_traceback += (ur_args.err_msg or '' + '\n') + ''.join(traceback.format_exception(None, ur_args.exc_value, ur_args.exc_traceback)) -+ -+ -+ with pytest.MonkeyPatch.context() as mp: -+ mp.setattr(sys, 'unraisablehook', _capture_unraisable_hook) -+ yield -+ -+ if error_type is None: -+ assert not raised_errors -+ assert not raised_traceback -+ return -+ -+ assert any(type(raised_error) is error_type for raised_error in raised_errors) -+ assert any(message in str(raised_error) for raised_error in raised_errors) -+ for t in traceback_tokens or []: -+ assert t in raised_traceback -+ -+ - def test_callback_exception(): -- try: -- import cStringIO -- except ImportError: -- import io as cStringIO # Python 3 -- import linecache -- def matches(istr, ipattern, ipattern38, ipattern311=None): -- if sys.version_info >= (3, 8): -- ipattern = ipattern38 -- if sys.version_info >= (3, 11): -- ipattern = ipattern311 or ipattern38 -- str, pattern = istr, ipattern -- while '$' in pattern: -- i = pattern.index('$') -- assert str[:i] == pattern[:i] -- j = str.find(pattern[i+1], i) -- assert i + 1 <= j <= str.find('\n', i) -- str = str[j:] -- pattern = pattern[i+1:] -- assert str == pattern -- return True - def check_value(x): - if x == 10000: - raise ValueError(42) -@@ -1366,148 +1383,52 @@ def Zcb1(x): - return x * 3 - BShort = new_primitive_type("short") - BFunc = new_function_type((BShort,), BShort, False) -+ - f = callback(BFunc, Zcb1, -42) -- # - seen = [] - oops_result = None - def oops(*args): - seen.append(args) - return oops_result - ff = callback(BFunc, Zcb1, -42, oops) -- # -- orig_stderr = sys.stderr -- orig_getline = linecache.getline -- try: -- linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests -- sys.stderr = cStringIO.StringIO() -- if hasattr(sys, '__unraisablehook__'): # work around pytest -- sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons -+ with _assert_unraisable(None): - assert f(100) == 300 -- assert sys.stderr.getvalue() == '' -+ with _assert_unraisable(ValueError, '42', ['in Zcb1', 'in check_value']): - assert f(10000) == -42 -- assert matches(sys.stderr.getvalue(), """\ --From cffi callback : --Traceback (most recent call last): -- File "$", line $, in Zcb1 -- $ -- File "$", line $, in check_value -- $ --ValueError: 42 --""", """\ --Exception ignored from cffi callback : --Traceback (most recent call last): -- File "$", line $, in Zcb1 -- $ -- File "$", line $, in check_value -- $ --ValueError: 42 --""") -- sys.stderr = cStringIO.StringIO() -- bigvalue = 20000 -+ -+ bigvalue = 20000 -+ with _assert_unraisable(OverflowError, "integer 60000 does not fit 'short'", ['callback', 'Zcb1']): - assert f(bigvalue) == -42 -- assert matches(sys.stderr.getvalue(), """\ --From cffi callback : --Trying to convert the result back to C: --OverflowError: integer 60000 does not fit 'short' --""", """\ --Exception ignored from cffi callback , 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 -- assert len(seen) == 0 -+ assert len(seen) == 0 -+ -+ with _assert_unraisable(None): - assert ff(bigvalue) == -42 -- assert sys.stderr.getvalue() == "" -- assert len(seen) == 1 -- exc, val, tb = seen[0] -- assert exc is OverflowError -- assert str(val) == "integer 60000 does not fit 'short'" -- # -- sys.stderr = cStringIO.StringIO() -- bigvalue = 20000 -- del seen[:] -- oops_result = 81 -+ assert len(seen) == 1 -+ exc, val, tb = seen[0] -+ assert exc is OverflowError -+ assert str(val) == "integer 60000 does not fit 'short'" -+ -+ del seen[:] -+ oops_result = 81 -+ with _assert_unraisable(None): - assert ff(bigvalue) == 81 -- oops_result = None -- assert sys.stderr.getvalue() == "" -- assert len(seen) == 1 -- exc, val, tb = seen[0] -- assert exc is OverflowError -- assert str(val) == "integer 60000 does not fit 'short'" -- # -- sys.stderr = cStringIO.StringIO() -- bigvalue = 20000 -- del seen[:] -- oops_result = "xy" # not None and not an int! -+ -+ assert len(seen) == 1 -+ exc, val, tb = seen[0] -+ assert exc is OverflowError -+ assert str(val) == "integer 60000 does not fit 'short'" -+ -+ del seen[:] -+ oops_result = "xy" # not None and not an int! -+ -+ with _assert_unraisable(TypeError, "an integer is required", ["integer 60000 does not fit 'short'"]): - assert ff(bigvalue) == -42 -- oops_result = None -- assert matches(sys.stderr.getvalue(), """\ --From cffi callback : --Trying to convert the result back to C: --OverflowError: integer 60000 does not fit 'short' -- --During the call to 'onerror', another exception occurred: -- --TypeError: $integer$ --""", """\ --Exception ignored from cffi callback , 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() -- seen = "not a list" # this makes the oops() function crash -+ -+ seen = "not a list" # this makes the oops() function crash -+ oops_result = None -+ with _assert_unraisable(AttributeError, "'str' object has no attribute 'append", ['Zcb1', 'ff', 'oops']): - assert ff(bigvalue) == -42 -- # the $ after the AttributeError message are for the suggestions that -- # will be added in Python 3.10 -- assert matches(sys.stderr.getvalue(), """\ --From cffi callback : --Trying to convert the result back to C: --OverflowError: integer 60000 does not fit 'short' -- --During the call to 'onerror', another exception occurred: -- --Traceback (most recent call last): -- File "$", line $, in oops -- $ --AttributeError: 'str' object has no attribute 'append$ --""", """\ --Exception ignored from cffi callback , 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$ --""", """\ --Exception ignored from cffi callback , 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 -- linecache.getline = orig_getline -+ - - def test_callback_return_type(): - for rettype in ["signed char", "short", "int", "long", "long long", diff --git a/py313-use-format-unraisable.patch b/py313-use-format-unraisable.patch deleted file mode 100644 index 656dd04..0000000 --- a/py313-use-format-unraisable.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 49127c6929bfc7186fbfd3819dd5e058ad888de4 Mon Sep 17 00:00:00 2001 -From: Victor Stinner -Date: Thu, 16 Nov 2023 17:26:12 +0100 -Subject: [PATCH] Use PyErr_FormatUnraisable() on Python 3.13 (#34) - -Use the new public PyErr_FormatUnraisable() on Python 3.13. - -The private _PyErr_WriteUnraisableMsg() function was removed in -Python 3.13: -https://github.com/python/cpython/pull/111643 ---- - src/c/_cffi_backend.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/c/_cffi_backend.c b/src/c/_cffi_backend.c -index 76ed8f09..5e284e00 100644 ---- a/src/c/_cffi_backend.c -+++ b/src/c/_cffi_backend.c -@@ -6118,7 +6118,11 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, - - PyErr_Restore(t, v, tb); - if (s != NULL) { -+#if PY_VERSION_HEX >= 0x030D0000 -+ PyErr_FormatUnraisable("Exception ignored %S", s); -+#else - _PyErr_WriteUnraisableMsg(PyText_AS_UTF8(s), NULL); -+#endif - Py_DECREF(s); - } - else diff --git a/py313-use-hashpointer.patch b/py313-use-hashpointer.patch deleted file mode 100644 index 0ee0159..0000000 --- a/py313-use-hashpointer.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c27335f0f8e1e4436082236e92ddabe1b8324d22 Mon Sep 17 00:00:00 2001 -From: Matt Davis <6775756+nitzmahone@users.noreply.github.com> -Date: Wed, 7 Feb 2024 09:12:08 -0800 -Subject: [PATCH] use public Py_HashPointer API on 3.13+ (#52) - -* use public Py_HashPointer API on 3.13+ - -* Wrong direction in the conditional - ---------- - -Co-authored-by: Armin Rigo ---- - src/c/_cffi_backend.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/c/_cffi_backend.c b/src/c/_cffi_backend.c -index cb82e16d..14fe9106 100644 ---- a/src/c/_cffi_backend.c -+++ b/src/c/_cffi_backend.c -@@ -2466,7 +2466,11 @@ static Py_hash_t cdata_hash(PyObject *v) - } - Py_DECREF(vv); - } -+#if PY_VERSION_HEX < 0x030D0000 - return _Py_HashPointer(((CDataObject *)v)->c_data); -+#else -+ return Py_HashPointer(((CDataObject *)v)->c_data); -+#endif - } - - static Py_ssize_t diff --git a/python-cffi.changes b/python-cffi.changes index f7b6608..e6b87db 100644 --- a/python-cffi.changes +++ b/python-cffi.changes @@ -1,3 +1,24 @@ +------------------------------------------------------------------- +Sat Aug 31 12:39:52 UTC 2024 - Dirk Müller + +- update to 1.17.0: + * Add support for Python 3.13. + * In API mode, when you get a function from a C library by writing + `fn = lib.myfunc`, you get an object of a special type for + performance reasons, instead of a ``. + Before version 1.17 you could only call such objects. + You could write `ffi.addressof(lib, "myfunc")` in order to get + a real `` object, based on the idea that in these cases + in C you'd usually write `&myfunc` instead of `myfunc`. In + version 1.17, the special object `lib.myfunc` can now be passed + in many places where CFFI expects + a regular `` object. For example, you can now pass + it as a callback to a C function call, or write it inside a C + structure field of the correct pointer-to-function type, or use + `ffi.cast()` or `ffi.typeof()` on it. +- drop py313-compat.patch, py313-use-format-unraisable.patch, + py313-use-hashpointer.patch (upstream) + ------------------------------------------------------------------- Sun Jun 30 21:26:53 UTC 2024 - Dirk Müller diff --git a/python-cffi.spec b/python-cffi.spec index cccba51..4148b64 100644 --- a/python-cffi.spec +++ b/python-cffi.spec @@ -18,16 +18,13 @@ %{?sle15_python_module_pythons} Name: python-cffi -Version: 1.16.0 +Version: 1.17.0 Release: 0 Summary: Foreign Function Interface for Python calling C code License: MIT URL: https://cffi.readthedocs.org Source0: https://files.pythonhosted.org/packages/source/c/cffi/cffi-%{version}.tar.gz Source1: python-cffi-rpmlintrc -Patch1: https://github.com/python-cffi/cffi/commit/49127c6929bfc7186fbfd3819dd5e058ad888de4.patch#/py313-use-format-unraisable.patch -Patch2: https://github.com/python-cffi/cffi/commit/14723b0bbd127790c450945099db31018d80fa83.patch#/py313-compat.patch -Patch3: https://github.com/python-cffi/cffi/commit/c27335f0f8e1e4436082236e92ddabe1b8324d22.patch#/py313-use-hashpointer.patch BuildRequires: %{python_module devel} BuildRequires: %{python_module pip} BuildRequires: %{python_module pycparser}