From c45eec02185b425e353f5fc477b04567d9627fcb Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Tue, 30 Mar 2021 07:54:42 +0200 Subject: Fix regression in marshalling partial() objects In a4880dbc4575fadc0e3 a special case for partial() was added to handle gtk4 template callbacks. This in turn broken normal usage of partial objects. To work around that add a special marker in the gtk template code for now until we find a better fix. Also adds a test so this doesn't happen again. Fixes #464 --- gi/_gtktemplate.py | 7 +++++-- gi/pygi-struct-marshal.c | 2 +- tests/test_gi.py | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/gi/_gtktemplate.py b/gi/_gtktemplate.py index a631a6eb..925aa0dd 100644 --- a/gi/_gtktemplate.py +++ b/gi/_gtktemplate.py @@ -78,9 +78,12 @@ def define_builder_scope(): handler, args = _extract_handler_and_args(current_object, handler_name) if obj: - return partial(handler, *args, swap_data=obj) + p = partial(handler, *args, swap_data=obj) + else: + p = partial(handler, *args) - return partial(handler, *args) + p.__gtk_template__ = True + return p return BuilderScope diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c index 0e190b8e..a3eb2802 100644 --- a/gi/pygi-struct-marshal.c +++ b/gi/pygi-struct-marshal.c @@ -191,7 +191,7 @@ pygi_arg_gclosure_from_py_marshal (PyObject *py_arg, Py_DECREF (functools); } - if (partial && PyObject_IsInstance (py_arg, partial) > 0) { + if (partial && PyObject_IsInstance (py_arg, partial) > 0 && PyObject_HasAttrString (py_arg, "__gtk_template__")) { PyObject *partial_func; PyObject *partial_args; PyObject *partial_keywords; diff --git a/tests/test_gi.py b/tests/test_gi.py index f6552665..5979d5d0 100644 --- a/tests/test_gi.py +++ b/tests/test_gi.py @@ -1692,6 +1692,22 @@ class TestGClosure(unittest.TestCase): def test_in(self): GIMarshallingTests.gclosure_in(lambda: 42) + def test_in_partial(self): + from functools import partial + + called_args = [] + called_kwargs = {} + + def callback(*args, **kwargs): + called_args.extend(args) + called_kwargs.update(kwargs) + return 42 + + func = partial(callback, 1, 2, 3, foo=42) + GIMarshallingTests.gclosure_in(func) + assert called_args == [1, 2, 3] + assert called_kwargs["foo"] == 42 + def test_pass(self): # test passing a closure between two C calls closure = GIMarshallingTests.gclosure_return() -- cgit v1.2.1