From e4ec72c97c80559db9ef4aa7d07eea37a9021dd5 Mon Sep 17 00:00:00 2001 From: Noah R Date: Fri, 6 Mar 2026 12:35:35 -0800 Subject: [PATCH] [python-bindings] Add SWIG typemap compatibility layer for wrapper objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add GNC_ACCEPT_WRAPPER macro that generates %typemap(in) entries for all core engine and business pointer types. These typemaps accept both raw SWIG pointers (zero-overhead fast path) and ClassFromFunctions wrapper objects (fallback path that extracts .instance). This is pure infrastructure for an upcoming change that fixes missing return-type wrapping in gnucash_core.py. Once methods like GncPriceDB.nth_price() return proper GncPrice wrapper objects instead of raw SwigPyObjects, existing code that passes those objects to gnucash_core_c C functions would break. These typemaps prevent that breakage: the C functions transparently unwrap the .instance pointer. Covered types: Core: Account, Split, Transaction, GNCLot, gnc_commodity, gnc_commodity_namespace, gnc_commodity_table, GNCPrice, GNCPriceDB, QofBook, QofSession, GncGUID Business: GncCustomer, GncEmployee, GncVendor, GncJob, GncAddress, GncBillTerm, GncTaxTable, GncInvoice, GncEntry GncOwner is excluded — it has its own custom type-dispatching typemaps. --- bindings/python/gnucash_core.i | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/bindings/python/gnucash_core.i b/bindings/python/gnucash_core.i index 667b2a8c36..1dbef8413d 100644 --- a/bindings/python/gnucash_core.i +++ b/bindings/python/gnucash_core.i @@ -88,6 +88,78 @@ %include +/* GNC_ACCEPT_WRAPPER: Generate input typemaps that accept both raw SWIG + * pointers and Python wrapper objects (ClassFromFunctions subclasses). + * + * The Python bindings use a two-layer architecture: + * - gnucash_core_c (SWIG-generated): exposes C functions with raw pointers + * - gnucash_core.py: wraps selected methods to return Python objects + * + * When gnucash_core.py wraps return types (via methods_return_instance), + * the returned Python objects store the raw SWIG pointer in a .instance + * attribute. Without these typemaps, passing such a wrapper object to a + * gnucash_core_c function fails because SWIG only recognizes its own + * pointer wrappers. + * + * These typemaps fix that: they try normal SWIG conversion first (zero + * overhead for the common case), and fall back to extracting .instance + * if needed. + */ +%define GNC_ACCEPT_WRAPPER(CType) +%typemap(in) CType * (void *argp = NULL) { + int res = SWIG_ConvertPtr($input, &argp, $1_descriptor, 0); + if (SWIG_IsOK(res)) { + $1 = %reinterpret_cast(argp, $1_ltype); + } else { + PyObject *instance = PyObject_GetAttrString($input, "instance"); + if (instance != NULL) { + res = SWIG_ConvertPtr(instance, &argp, $1_descriptor, 0); + Py_DECREF(instance); + if (SWIG_IsOK(res)) { + /* TODO: Add DeprecationWarning once return-type + * wrapping is fixed (PR 2). */ + $1 = %reinterpret_cast(argp, $1_ltype); + } else { + SWIG_exception_fail(SWIG_TypeError, + "in method '$symname', argument $argnum:" + " .instance is not a " #CType " *"); + } + } else { + PyErr_Clear(); + SWIG_exception_fail(SWIG_TypeError, + "in method '$symname', argument $argnum:" + " expected " #CType " * or wrapper object"); + } + } +} +%apply CType * { const CType * }; +%enddef + +/* Core engine types */ +GNC_ACCEPT_WRAPPER(Account) +GNC_ACCEPT_WRAPPER(Split) +GNC_ACCEPT_WRAPPER(Transaction) +GNC_ACCEPT_WRAPPER(GNCLot) +GNC_ACCEPT_WRAPPER(gnc_commodity) +GNC_ACCEPT_WRAPPER(gnc_commodity_namespace) +GNC_ACCEPT_WRAPPER(gnc_commodity_table) +GNC_ACCEPT_WRAPPER(GNCPrice) +GNC_ACCEPT_WRAPPER(GNCPriceDB) +GNC_ACCEPT_WRAPPER(QofBook) +GNC_ACCEPT_WRAPPER(QofSession) +GNC_ACCEPT_WRAPPER(GncGUID) + +/* Business types */ +GNC_ACCEPT_WRAPPER(GncCustomer) +GNC_ACCEPT_WRAPPER(GncEmployee) +GNC_ACCEPT_WRAPPER(GncVendor) +GNC_ACCEPT_WRAPPER(GncJob) +GNC_ACCEPT_WRAPPER(GncAddress) +GNC_ACCEPT_WRAPPER(GncBillTerm) +GNC_ACCEPT_WRAPPER(GncTaxTable) +GNC_ACCEPT_WRAPPER(GncInvoice) +GNC_ACCEPT_WRAPPER(GncEntry) + %include %include