[python-bindings] Add SWIG typemap compatibility layer for wrapper objects

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.
pull/2186/head
Noah R 1 month ago
parent 8538dcf9ac
commit e4ec72c97c

@ -88,6 +88,78 @@
%include <base-typemaps.i>
/* 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 <engine-common.i>
%include <qofbackend.h>

Loading…
Cancel
Save