Python bindings: patch, documentation, examples

David Osguthorpe david.osguthorpe at gmail.com
Sat May 10 03:22:45 EDT 2014


Interestingly one of the extensions Im using gets the budget - as you say
its not available in current bindings - dont know about Future Transactions
- to get the budget needed some fixups to swig bindings
Ive attached my 2 extension scripts plus the binding patches ( this is to
2.6 version)
The budget extensions require re-running swig so you would need to build
gnucash - although it would be possible to access the budget using ctypes
without recompilation

Theres a little script showing usage of budget functions

Ill leave the pyguile/schemepy for now

David


On Fri, May 9, 2014 at 11:06 PM, Marc Shapiro <marcnshap at gmail.com> wrote:

> On 05/09/2014 06:37 PM, David Osguthorpe wrote:
>
>> On Thu, May 08, 2014 at 11:47:34PM -0700, mshapiro wrote:
>>
>>> David Osguthorpe wrote
>>>
>>>> I have a very hacky implementation in gnucash to call python from guile
>>>> and
>>>> return results to guile - I found existing libraries to do both
>>>> (no updates to gnucash required - just a user prototype.scm file)
>>>>
>>> Can you post what libraries you used, where you got them, how to use them
>>> and your prototype.scm file.  Also, any pointers to useful documentation
>>> for
>>> using the Python bindings would be greatly appreciated.  I am primarily
>>> interested (at the moment) in accessing budgeting information and future
>>> transactions, as well as accounts, since I would like to do more
>>> forecasting
>>> than the standard reports provide.
>>>
>>>  it is really hacky - and I still had crashes when attempting to create
>> real reports
>> so its very, very alpha
>> but if you wish to pursue it here are the details
>>
> I have the feeling that I will be better off to just write a standalone
> python script.  This is not really a problem.  A program to do forecasting
> can be done outside gnucash just fine.  Except that I still need to find a
> way to access the future transactions and the budget information.  I
> haven't seen either of these in any of the example reports for the python
> bindings.  Does anyone know of any info on how to use the python bindings
> to access these?
>
>  note this does not use any of the python bindings - as far as I can tell
>> they only work for
>> non-gui standalone scripts - well its the only Ive used them
>> - you would write a script to access your gnucash database (xml or SQL)
>> and use any python
>> modules to format the data for a new report completely outside of gnucash
>> for the moment I would say you would be better just writing command line
>> scripts
>> using the python bindings to generate HTML or whatever reports
>>
>> here are some details
>>
>> 1. you need pyguile - a module for calling guile version of scheme from
>> python
>> - unfortunately the available source has not been udpated for years so
>> needed quite
>> a bit of patching to build (I run under macports on OSX mainly)
>> - one patch I did have to add was the ability to return so called SCM
>> (scheme) objects
>> back to guile
>>
>> 2. you need schemepy - which has a module for calling python from guile
>> version of scheme
>> - again the available source has not been udpated for years so needed
>> some patching to get running
>>
>> Then you have the prototype.scm (simply not bothered to change name)
>> which sets up
>> to call python where you could write your report.
>>
>>
>> My initial goal was to write reports in python - Im primarily writing in
>> this now
>> and although I had tried scheme for a multiple stock price scatter plot
>> report every time I went
>> back trying to re-think in scheme was a pain
>>
> I tried to write my report in scheme, and I can't really say that I
> failed.  Just that I never got it finished.  I took the Balance Sheet , the
> Budget Report and the Future Transactions Report and tried to put them
> together.  I was able to successfully combine all of the required options
> so that they can be input on a singe screen.  Then it simply runs the
> Balance Sheet.  If I could figure out how to access the future transactions
> and budgeting data and update the accounts on the Balance Sheet before
> displaying them then I would be all set.  But, so far, I have not been able
> to wrap my head around that much scheme.  As a co-worker says of LISP (he
> uses it in AutoCad) I find myself Lost In Stupid Parenthesis.  It makes my
> head hurt.
>
>  The major problem I ran across is that when analysing the GUI report
>> system in gnucash
>> I discovered it was not done in pure gtk but some of the gui is actually
>> written in scheme
>> by calling gtk gunctions via swig wrapped functions involving gtk
>> - to directly call python reports would need re-writing most of this GUI
>> scheme stuff using
>> the python gtk library - not difficult but seemed like a lot of work
>> I had hoped to find a report function where I could plugin in a call to
>> python so could then
>> do the report in python (python has the ctypes module which allows
>> calling C functions
>> in  arbitrary C shared libraries such as gnucash uses) - pygtk allows
>> direct use of gtk functions
>> in python
>> I did this around 2.4.7 and am looking to review it now at 2.6.3
>>
>> from that analysis as far as I could tell the final report result is an
>> html text string which is
>> written to a file - again these components using scheme coding
>>
>>
>> If you really want the files let me know
>>
> Yes.  If you can post the files, or links to them, then I will have them
> if I decide to try and go down that route.  If not, well, it won't hurt to
> have them and maybe it can help someone else.
>
>  as you have discovered there isnt much documentation of the python
>> bindings
>>
> Yes.  If I had proper documentation then I would have just written the
> standalone report and been done with it.  As it stands, I have no actual
> proof that the bindings will give me access to the budgeting and future
> transactions.  That may never have been included in them, but since no one
> actually seems to have documented what is, or is not, included (let alone
> how to use it) it makes it kind of difficult.
>
> Marc
>
>
> _______________________________________________
> gnucash-devel mailing list
> gnucash-devel at gnucash.org
> https://lists.gnucash.org/mailman/listinfo/gnucash-devel
>
-------------- next part --------------
--- src/base-typemaps.i.orig	2013-12-28 11:46:49.000000000 -0800
+++ src/base-typemaps.i	2014-01-26 12:57:22.000000000 -0800
@@ -161,8 +161,12 @@
     }
 }
 
-%typemap(out) GList *, CommodityList *, SplitList *, AccountList *, LotList *,
-    MonetaryList *, PriceList *, EntryList * {
+/* 
+ * move specific type lists into separate functions
+ * leaving a single generic GList function
+ */
+
+%typemap(out) GList * {
     guint i;
     gpointer data;
     PyObject *list = PyList_New(0);
@@ -197,11 +201,107 @@
             PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncJob, 0));
         else if (GNC_IS_TAXTABLE(data))
             PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p__gncTaxTable, 0));
-        else if ($1_descriptor == $descriptor(MonetaryList *))
-            PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(gnc_monetary *), 0));
+        else if (GNC_IS_BUDGET(data))
+            PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(GncBudget *), 0));
         else
             PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_void, 0));
     }
     $result = list;
 }
+
+%typemap(out) EntryList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(Entry *), 0));
+    }
+    $result = list;
+}
+
+%typemap(out) PriceList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(GNCPrice *), 0));
+    }
+    $result = list;
+}
+
+%typemap(out) LotList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(GNCLot *), 0));
+    }
+    $result = list;
+}
+
+%typemap(out) AccountList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(Account *), 0));
+    }
+    $result = list;
+}
+
+%typemap(out) SplitList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(Split *), 0));
+    }
+    $result = list;
+}
+
+%typemap(out) CommodityList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(gnc_commodity *), 0));
+    }
+    $result = list;
+}
+
+%typemap(out) MonetaryList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(gnc_monetary *), 0));
+    }
+    $result = list;
+}
+
+%typemap(out) GncTaxTableEntryList * {
+    guint i;
+    gpointer data;
+    PyObject *list = PyList_New(0);
+    for (i = 0; i < g_list_length($1); i++)
+    {
+        data = g_list_nth_data($1, i);
+        PyList_Append(list, SWIG_NewPointerObj(data, $descriptor(GncTaxTableEntry *), 0));
+    }
+    $result = list;
+}
 #endif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: gnucash_ext.py
Type: text/x-python-script
Size: 13562 bytes
Desc: not available
URL: <http://lists.gnucash.org/pipermail/gnucash-devel/attachments/20140510/c55ead73/attachment-0003.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: gnucash_ctypes.py
Type: text/x-python-script
Size: 12007 bytes
Desc: not available
URL: <http://lists.gnucash.org/pipermail/gnucash-devel/attachments/20140510/c55ead73/attachment-0004.bin>
-------------- next part --------------

--- src/optional/python-bindings/Makefile.am.orig	2013-12-28 11:46:50.000000000 -0800
+++ src/optional/python-bindings/Makefile.am	2014-01-07 18:27:27.000000000 -0800
@@ -1,6 +1,6 @@
 SUBDIRS = . tests
 
-SWIG_FILES = gnucash_core.i timespec.i
+SWIG_FILES = gnucash_core.i timespec.i gdate.i
 
 pkgpyexec_DATA = \
   __init__.py \


--- src/optional/python-bindings/gnucash_core.i.orig	2013-12-28 11:46:50.000000000 -0800
+++ src/optional/python-bindings/gnucash_core.i	2014-01-08 15:59:40.000000000 -0800
@@ -82,6 +82,8 @@
 #include "app-utils/gnc-prefs-utils.h"
 %}
 
+%include <gdate.i>
+
 %include <timespec.i>
 
 %include <base-typemaps.i>


--- src/optional/python-bindings/gdate.i.orig	2014-01-08 16:47:56.000000000 -0800
+++ src/optional/python-bindings/gdate.i	2014-01-08 16:46:28.000000000 -0800
@@ -0,0 +1,76 @@
+/*
+ * gdate.i -- SWIG interface file for type translation of GDate types
+ *
+ */
+
+
+// well cant include this
+//%include "/opt/local/include/glib-2.0/glib/gdate.h"
+
+// but this starts getting there
+
+// this is a dummy definition
+// this tells swig we have this class but nothing is known about it
+// note that if we map these to python types on input/output python
+// never needs to know about GDate internals
+struct GDate { };
+
+%extend GDate {
+    GDate() {
+        return g_date_new();
+    }
+    ~GDate() {
+        g_date_free($self);
+    }
+}
+
+// A typemap for converting python dates to GDate in functions that
+// require GDate as an argument
+// not clear any functions in gnucash pass GDate objects - always pointers to objects
+%typemap(in) GDate {
+    PyDateTime_IMPORT;
+    g_date_set_day(&($1),PyDateTime_GET_DAY($input));
+    g_date_set_month(&($1),PyDateTime_GET_MONTH($input));
+    g_date_set_year(&($1),PyDateTime_GET_YEAR($input));
+}
+
+//
+// need to fix for julian dates??
+// dont think so - looks like GDate interconverts between dmy and julian
+// depending on how called
+// issue with this is what about freeing GDates??
+// use the freearg typemap
+%typemap(in) GDate * (GDate *ts) {
+    PyDateTime_IMPORT;
+    ts = g_date_new_dmy(PyDateTime_GET_DAY($input),
+                          PyDateTime_GET_MONTH($input),
+                          PyDateTime_GET_YEAR($input) );
+    $1 = ts;
+}
+
+%typemap(freearg) GDate * {
+  g_date_free($1);
+}
+
+// A typemap for converting GDate values returned from functions to
+// python dates.
+// need to fix for julian dates??
+// dont think so - looks like GDate interconverts between dmy and julian
+// depending on how called
+%typemap(out) GDate * {
+    int year, month, day;
+    PyDateTime_IMPORT;
+    day = g_date_get_day($1);
+    month = g_date_get_month($1);
+    year = g_date_get_year($1);
+    $result = PyDate_FromDate(year, month, day);
+}
+
+%typemap(out) GDate {
+    int year, month, day;
+    PyDateTime_IMPORT;
+    day = g_date_get_day(&($1));
+    month = g_date_get_month(&($1));
+    year = g_date_get_year(&($1));
+    $result = PyDate_FromDate(year, month, day);
+}
-------------- next part --------------

--- src/optional/python-bindings/Makefile.in.orig.save	2013-12-28 11:47:34.000000000 -0800
+++ src/optional/python-bindings/Makefile.in	2014-01-07 18:42:36.000000000 -0800
@@ -1016,7 +1016,7 @@
 
 
 @BUILDING_FROM_SCM_TRUE at gnucash_core.c: $(SWIG_FILES) ${top_srcdir}/src/base-typemaps.i ${top_srcdir}/src/engine/engine-common.i $(_gnucash_core_c_includes)
- at BUILDING_FROM_SCM_TRUE@	swig -python -Wall -Werror \
+ at BUILDING_FROM_SCM_TRUE@	/opt/local/bin/swig -python -Wall -Werror \
 @BUILDING_FROM_SCM_TRUE@	-I$(top_srcdir)/src -I$(top_srcdir)/src/engine \
 @BUILDING_FROM_SCM_TRUE@	-I$(top_srcdir)/src/app-utils -I${top_srcdir}/src/libqof/qof \
 @BUILDING_FROM_SCM_TRUE@	-o $@ $<


--- src/optional/python-bindings/gnucash_core.i.orig	2013-04-20 14:07:10.000000000 -0700
+++ src/optional/python-bindings/gnucash_core.i	2014-01-07 15:41:48.000000000 -0800
@@ -74,6 +74,8 @@
 #include "gncTaxTable.h"
 #include "gncIDSearch.h"
 #include "engine/gnc-pricedb.h"
+#include "Recurrence.h"
+#include "engine/gnc-budget.h"
 %}
 
 %include <timespec.i>
@@ -194,6 +196,10 @@
 %include <gncTaxTable.h>
 %include <gncIDSearch.h>
 
+// Budget include
+%include "Recurrence.h"
+%include <gnc-budget.h>
+
 // Commodity prices includes and stuff
 %include <gnc-pricedb.h>
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: add_budget.py
Type: text/x-python-script
Size: 11096 bytes
Desc: not available
URL: <http://lists.gnucash.org/pipermail/gnucash-devel/attachments/20140510/c55ead73/attachment-0005.bin>


More information about the gnucash-devel mailing list