diff --git a/configure.in b/configure.in index c3e79d4c97..5d19aa16ed 100644 --- a/configure.in +++ b/configure.in @@ -1543,6 +1543,7 @@ AC_CONFIG_FILES(po/Makefile.in src/import-export/hbci/test/Makefile src/optional/Makefile src/optional/python-bindings/Makefile + src/optional/python-bindings/tests/Makefile src/optional/xsl/Makefile src/pixmaps/Makefile src/quotes/Makefile diff --git a/src/base-typemaps.i b/src/base-typemaps.i index 9b17c91a06..8878bfb44a 100644 --- a/src/base-typemaps.i +++ b/src/base-typemaps.i @@ -1,30 +1,17 @@ -%typemap(in) gboolean "$1 = SCM_NFALSEP($input) ? TRUE : FALSE;" -%typemap(out) gboolean "$result = $1 ? SCM_BOOL_T : SCM_BOOL_F;" - -%typemap(in) Timespec "$1 = gnc_timepair2timespec($input);" -%typemap(out) Timespec "$result = gnc_timespec2timepair($1);" - -%typemap(in) GUID "$1 = gnc_scm2guid($input);" -%typemap(out) GUID "$result = gnc_guid2scm($1);" -%typemap(in) GUID * (GUID g) " g = gnc_scm2guid($input); $1 = &g; " -%typemap(out) GUID * " $result = ($1) ? gnc_guid2scm(*($1)): SCM_UNDEFINED; " - -%typemap(in) gnc_numeric "$1 = gnc_scm_to_numeric($input);" -%typemap(out) gnc_numeric "$result = gnc_numeric_to_scm($1);" - -%typemap(in) gint64 " $1 = gnc_scm_to_gint64($input); " -%typemap(out) gint64 " $result = gnc_gint64_to_scm($1); " - /* Not sure why SWIG doesn't figure this out. */ -typedef void * gpointer; typedef int gint; typedef int time_t; typedef unsigned int guint; typedef double gdouble; +typedef float gfloat; typedef char * URLType; -typedef char gchar; +typedef void * gpointer; %typemap(newfree) gchar * "g_free($1);" + +#if defined(SWIGGUILE) +typedef char gchar; + %typemap (out) char * { $result = scm_makfrom0str((const char *)$1); if (!SCM_NFALSEP($result)) { @@ -34,6 +21,22 @@ typedef char gchar; %typemap(in) GNCPrintAmountInfo "$1 = gnc_scm2printinfo($input);" %typemap(out) GNCPrintAmountInfo "$result = gnc_printinfo2scm($1);" +%typemap(in) gboolean "$1 = SCM_NFALSEP($input) ? TRUE : FALSE;" +%typemap(out) gboolean "$result = $1 ? SCM_BOOL_T : SCM_BOOL_F;" + +%typemap(in) Timespec "$1 = gnc_timepair2timespec($input);" +%typemap(out) Timespec "$result = gnc_timespec2timepair($1);" + +%typemap(in) GUID "$1 = gnc_scm2guid($input);" +%typemap(out) GUID "$result = gnc_guid2scm($1);" +%typemap(in) GUID * (GUID g) " g = gnc_scm2guid($input); $1 = &g; " +%typemap(out) GUID * " $result = ($1) ? gnc_guid2scm(*($1)): SCM_UNDEFINED; " + +%typemap(in) gnc_numeric "$1 = gnc_scm_to_numeric($input);" +%typemap(out) gnc_numeric "$result = gnc_numeric_to_scm($1);" + +%typemap(in) gint64 " $1 = gnc_scm_to_gint64($input); " +%typemap(out) gint64 " $result = gnc_gint64_to_scm($1); " %define GLIST_HELPER_INOUT(ListType, ElemSwigType) %typemap(in) ListType * { @@ -66,5 +69,87 @@ typedef char gchar; $result = scm_reverse(list); } %enddef +#elif defined(SWIGPYTHON) /* Typemaps for Python */ +%typemap(in) gint8, gint16, gint32, gint64, gshort, glong { + $1 = ($1_type)PyInt_AsLong($input); +} +%typemap(out) gint8, gint16, gint32, gint64, gshort, glong { + $result = PyInt_FromLong($1); +} +%typemap(in) guint8, guint16, guint32, guint64, gushort, gulong { + $1 = ($1_type)PyLong_AsUnsignedLong($input); +} + +%typemap(out) guint8, guint16, guint32, guint64, gushort, gulong { + $result = PyLong_FromUnsignedLong($1); +} + +%typemap(in) gchar * { + $1 = ($1_type)PyString_AsString($input); +} + +%typemap(out) gchar * { + $result = PyString_FromString($1); +} + +%typemap(in) gboolean { + if ($input == Py_True) + $1 = TRUE; + else if ($input == Py_False) + $1 = FALSE; + else + { + PyErr_SetString( + PyExc_ValueError, + "Python object passed to a gboolean argument was not True " + "or False" ); + return NULL; + } +} + +%typemap(out) gboolean { + if ($1 == TRUE) + { + Py_INCREF(Py_True); + $result = Py_True; + } + else if ($1 == FALSE) + { + Py_INCREF(Py_False); + $result = Py_False; + } + else + { + PyErr_SetString( + PyExc_ValueError, + "function returning gboolean returned a value that wasn't " + "TRUE or FALSE."); + return NULL; + } +} + +%typemap(out) GList *, CommodityList *, SplitList *, AccountList *, 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); + if (GNC_IS_ACCOUNT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Account, 0)); + else if (GNC_IS_SPLIT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Split, 0)); + else if (GNC_IS_TRANSACTION(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Transaction, 0)); + else if (GNC_IS_COMMODITY(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_gnc_commodity, 0)); + else if (GNC_IS_LOT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_GNCLot, 0)); + else + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_void, 0)); + } + $result = list; +} +#endif diff --git a/src/engine/engine-common.i b/src/engine/engine-common.i new file mode 100644 index 0000000000..9b7ad76c79 --- /dev/null +++ b/src/engine/engine-common.i @@ -0,0 +1,31 @@ +%inline %{ +static const GUID * gncSplitGetGUID(Split *x) +{ return qof_instance_get_guid(QOF_INSTANCE(x)); } +static const GUID * gncTransGetGUID(Transaction *x) +{ return qof_instance_get_guid(QOF_INSTANCE(x)); } +static const GUID * gncAccountGetGUID(Account *x) +{ return qof_instance_get_guid(QOF_INSTANCE(x)); } +%} + +%typemap(newfree) AccountList * "g_list_free($1);" +%typemap(newfree) SplitList * "g_list_free($1);" +%typemap(newfree) TransList * "g_list_free($1);" +%typemap(newfree) PriceList * "g_list_free($1);" +%typemap(newfree) LotList * "g_list_free($1);" +%typemap(newfree) CommodityList * "g_list_free($1);" + +%include + +AccountList * gnc_account_get_children (const Account *account); +AccountList * gnc_account_get_children_sorted (const Account *account); +AccountList * gnc_account_get_descendants (const Account *account); +AccountList * gnc_account_get_descendants_sorted (const Account *account); +%ignore gnc_account_get_children; +%ignore gnc_account_get_children_sorted; +%ignore gnc_account_get_descendants; +%ignore gnc_account_get_descendants_sorted; +%include + +%include + +%include diff --git a/src/engine/engine.i b/src/engine/engine.i index d43047f2ea..59d06281ee 100644 --- a/src/engine/engine.i +++ b/src/engine/engine.i @@ -23,35 +23,22 @@ SCM scm_init_sw_engine_module (void); %import "base-typemaps.i" - -GLIST_HELPER_INOUT(SplitList, SWIGTYPE_p_Split); -GLIST_HELPER_INOUT(TransList, SWIGTYPE_p_Transaction); -GLIST_HELPER_INOUT(LotList, SWIGTYPE_p_GNCLot); -GLIST_HELPER_INOUT(AccountList, SWIGTYPE_p_Account); -GLIST_HELPER_INOUT(PriceList, SWIGTYPE_p_GNCPrice); -// TODO: free PriceList? -GLIST_HELPER_INOUT(CommodityList, SWIGTYPE_p_gnc_commodity); - +%include "engine-common.i" %inline %{ -static const GUID * gncSplitGetGUID(Split *x) -{ return qof_instance_get_guid(QOF_INSTANCE(x)); } -static const GUID * gncTransGetGUID(Transaction *x) -{ return qof_instance_get_guid(QOF_INSTANCE(x)); } -static const GUID * gncAccountGetGUID(Account *x) -{ return qof_instance_get_guid(QOF_INSTANCE(x)); } static const GUID * gncPriceGetGUID(GNCPrice *x) { return qof_instance_get_guid(QOF_INSTANCE(x)); } static const GUID * gncBudgetGetGUID(GncBudget *x) { return qof_instance_get_guid(QOF_INSTANCE(x)); } %} -%typemap(newfree) AccountList * "g_list_free($1);" -%typemap(newfree) SplitList * "g_list_free($1);" -%typemap(newfree) TransList * "g_list_free($1);" -%typemap(newfree) PriceList * "g_list_free($1);" -%typemap(newfree) LotList * "g_list_free($1);" -%typemap(newfree) CommodityList * "g_list_free($1);" +GLIST_HELPER_INOUT(SplitList, SWIGTYPE_p_Split); +GLIST_HELPER_INOUT(TransList, SWIGTYPE_p_Transaction); +GLIST_HELPER_INOUT(LotList, SWIGTYPE_p_GNCLot); +GLIST_HELPER_INOUT(AccountList, SWIGTYPE_p_Account); +GLIST_HELPER_INOUT(PriceList, SWIGTYPE_p_GNCPrice); +// TODO: free PriceList? +GLIST_HELPER_INOUT(CommodityList, SWIGTYPE_p_gnc_commodity); %typemap(newfree) gchar * "g_free($1);" @@ -83,18 +70,7 @@ functions. */ static QofIdType QOF_ID_BOOK_SCM (void) { return QOF_ID_BOOK; } } -%include %include -AccountList * gnc_account_get_children (const Account *account); -AccountList * gnc_account_get_children_sorted (const Account *account); -AccountList * gnc_account_get_descendants (const Account *account); -AccountList * gnc_account_get_descendants_sorted (const Account *account); -%ignore gnc_account_get_children; -%ignore gnc_account_get_children_sorted; -%ignore gnc_account_get_descendants; -%ignore gnc_account_get_descendants_sorted; -%include -%include %include QofSession * qof_session_new (void); @@ -193,7 +169,6 @@ void gnc_quote_source_set_fq_installed (GList *sources_list); %ignore gnc_quote_source_set_fq_installed; %include -%include %include void gnc_hook_add_scm_dangler (const gchar *name, SCM proc); void gnc_hook_run (const gchar *name, gpointer data); diff --git a/src/optional/python-bindings/Makefile.am b/src/optional/python-bindings/Makefile.am index 9b0f56cb05..4a4c8156d2 100644 --- a/src/optional/python-bindings/Makefile.am +++ b/src/optional/python-bindings/Makefile.am @@ -1,15 +1,18 @@ +SUBDIRS = . tests + BUILT_SOURCES = gnucash_core.c SWIG_SOURCES = gnucash_core.i pkgpython_PYTHON = __init__.py function_class.py \ -gnucash_core.py gnucash_core_c.py +gnucash_core.py gnucash_core_c.py gnucash_business.py pkgpyexec_LTLIBRARIES = _gnucash_core_c.la _gnucash_core_c_la_SOURCES = $(BUILT_SOURCES) $(SWIG_SOURCES) _gnucash_core_c_la_CPPFLAGS = $(PYTHON_CPPFLAGS) \ -I$(top_srcdir)/src $(QOF_CFLAGS) \ $(GLIB_CFLAGS) $(GUILE_INCS) \ - -I$(top_srcdir)/src/engine + -I$(top_srcdir)/src/engine \ + -I$(top_srcdir)/src/business/business-core # Suppress all warnings for now, but we really only need to -Wno-implicit AM_CFLAGS = -w @@ -17,9 +20,11 @@ AM_CFLAGS = -w _gnucash_core_c_la_LDFLAGS = -avoid-version -module _gnucash_core_c_la_LIBADD = ${QOF_LIBS} ${GUILE_LIBS} ${GLIB_LIBS} \ ${top_builddir}/src/gnc-module/libgnc-module.la \ - ${top_builddir}/src/engine/libgncmod-engine.la + ${top_builddir}/src/engine/libgncmod-engine.la \ + ${top_builddir}/src/business/business-core/libgncmod-business-core.la gnucash_core.c : $(SWIG_SOURCES) - $(SWIG) $(SWIG_PYTHON_OPT) -Wall -Werror \ + swig $(SWIG_PYTHON_OPT) -Wall -Werror \ -I$(top_srcdir)/src -I$(top_srcdir)/src/engine \ + -I$(top_srcdir)/src/business/business-core \ $(QOF_CFLAGS) -o $@ $< diff --git a/src/optional/python-bindings/example_scripts/simple_test.py b/src/optional/python-bindings/example_scripts/simple_test.py index 5ed0a18184..1bf8a2ec8a 100644 --- a/src/optional/python-bindings/example_scripts/simple_test.py +++ b/src/optional/python-bindings/example_scripts/simple_test.py @@ -1,49 +1,78 @@ #!/usr/bin/env python +# Creates a basic set of accounts and a couple of transactions -from gnucash import \ - Session, Account, Transaction, Split, GncCommodity, GncNumeric - +import gnucash FILE_1 = "/tmp/example.xac" session = None -session = Session("file:%s" % FILE_1, True) +session = gnucash.Session("file:%s" % FILE_1, True) book = session.book -root_account = book.get_root_account() -acct1 = Account(book) -acct2 = Account(book) -trans = Transaction(book) -split1 = Split(book) -split2 = Split(book) -comm = GncCommodity(book, "Canadian Dollars", "CURRENCY", "CAD", None, 100) -debit_num = GncNumeric(4, 1) -credit_num = debit_num.neg() - -acct1.SetCommodity(comm) -acct1.SetName("Savings") -root_account.append_child(acct1) - -acct2.SetCommodity(comm) -acct2.SetName("Food expenses") -root_account.append_child(acct2) - -split1.SetValue(credit_num) -split1.SetAccount(acct1) -split1.SetParent(trans) - -split2.SetValue(debit_num) -split2.SetAccount(acct2) -split2.SetParent(trans) - -trans.SetCurrency(comm) -trans.SetDescription("Groceries") +root_acct = gnucash.Account(book) +expenses_acct = gnucash.Account(book) +savings_acct = gnucash.Account(book) +opening_acct = gnucash.Account(book) +trans1 = gnucash.Transaction(book) +trans2 = gnucash.Transaction(book) +split1 = gnucash.Split(book) +split3 = gnucash.Split(book) +comm = gnucash.GncCommodity(book, "Canadian Dollars", "CURRENCY", "CAD", None, 100) +num1 = gnucash.GncNumeric(4, 1) +num2 = gnucash.GncNumeric(100, 1) + +#Set new root account +book.set_root_account(root_acct) + +#Set up root account and add sub-accounts +root_acct.SetName("Root") +root_acct.SetType(13) #ACCT_TYPE_ROOT = 13 +root_acct.append_child(expenses_acct) +root_acct.append_child(savings_acct) +root_acct.append_child(opening_acct) + +#Set up Expenses account +expenses_acct.SetCommodity(comm) +expenses_acct.SetName("Expenses") +expenses_acct.SetType(9) #ACCT_TYPE_EXPENSE = 9 + +#Set up Savings account +savings_acct.SetCommodity(comm) +savings_acct.SetName("Savings") +savings_acct.SetType(0) #ACCT_TYPE_BANK = 0 + +#Set up Opening Balance account +opening_acct.SetCommodity(comm) +opening_acct.SetName("Opening Balance") +opening_acct.SetType(10) #ACCT_TYPE_EQUITY = 10 + +split1.SetValue(num1) +split1.SetAccount(expenses_acct) +split1.SetParent(trans1) + +split3.SetValue(num2) +split3.SetAccount(savings_acct) +split3.SetParent(trans2) + +trans1.SetCurrency(comm) +trans1.SetDescription("Groceries") + +trans2.SetCurrency(comm) +trans2.SetDescription("Opening Savings Balance") + +split2 = split1.GetOtherSplit() +split2.SetAccount(savings_acct) + +split4 = split3.GetOtherSplit() +split4.SetAccount(opening_acct) book.print_dirty() book.mark_saved() book.mark_closed() +book.print_dirty() + session.save() session.end() session.destroy() diff --git a/src/optional/python-bindings/function_class.py b/src/optional/python-bindings/function_class.py index 215608c281..88fd28f2fc 100644 --- a/src/optional/python-bindings/function_class.py +++ b/src/optional/python-bindings/function_class.py @@ -165,3 +165,12 @@ def extract_attributes_with_prefix(obj, prefix): if attr_name.startswith(prefix): after_prefix = attr_name[ len(prefix): ] yield attr_name, attr_value, after_prefix + +def methods_return_instance(cls, function_dict): + """Iterates through a dictionary of function name strings and instance names + and sets the function to return the associated instance + """ + for func_name, instance_name in function_dict.iteritems(): + setattr(cls, func_name, + method_function_returns_instance( getattr(cls, func_name), instance_name)) + diff --git a/src/optional/python-bindings/glib.i b/src/optional/python-bindings/glib.i index f9638a4bcb..db02f4c221 100644 --- a/src/optional/python-bindings/glib.i +++ b/src/optional/python-bindings/glib.i @@ -90,3 +90,26 @@ return NULL; } } + +%typemap(out) GList *, CommodityList *, SplitList *, AccountList *, 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); + if (GNC_IS_ACCOUNT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Account, 0)); + else if (GNC_IS_SPLIT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Split, 0)); + else if (GNC_IS_TRANSACTION(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_Transaction, 0)); + else if (GNC_IS_COMMODITY(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_gnc_commodity, 0)); + else if (GNC_IS_LOT(data)) + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_GNCLot, 0)); + else + PyList_Append(list, SWIG_NewPointerObj(data, SWIGTYPE_p_gpointer, 0)); + } + $result = list; +} diff --git a/src/optional/python-bindings/gnucash_business.py b/src/optional/python-bindings/gnucash_business.py new file mode 100644 index 0000000000..559e7767f8 --- /dev/null +++ b/src/optional/python-bindings/gnucash_business.py @@ -0,0 +1,92 @@ +# gnucash_business.py -- High level python wrapper classes for the business +# parts of GnuCash +# +# Copyright (C) 2008 ParIT Worker Co-operative +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact: +# Free Software Foundation Voice: +1-617-542-5942 +# 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 +# Boston, MA 02110-1301, USA gnu@gnu.org +# +# @author Mark Jenkins, ParIT Worker Co-operative +# @author Jeff Green, ParIT Worker Co-operative + +import gnucash_core_c + +from function_class import \ + ClassFromFunctions, extract_attributes_with_prefix, \ + default_arguments_decorator, method_function_returns_instance, \ + methods_return_instance + +from gnucash_core import \ + GnuCashCoreClass, GncNumeric, GncCommodity, Transaction, \ + Split, Book + +class Customer(GnuCashCoreClass): pass + +class Employee(GnuCashCoreClass): pass + +class Vendor(GnuCashCoreClass): pass + +class Address(GnuCashCoreClass): pass + +class BillTerm(GnuCashCoreClass): pass + +# Customer +Customer.add_constructor_and_methods_with_prefix('gncCustomer', 'Create') + +customer_dict = { + 'GetAddr' : Address, + 'GetShipAddr' : Address, + 'GetDiscount' : GncNumeric, + 'GetCredit' : GncNumeric, + 'GetTerms' : BillTerm, + 'GetCurrency' : GncCommodity + } +methods_return_instance(Customer, customer_dict) + +# Employee +Employee.add_constructor_and_methods_with_prefix('gncEmployee', 'Create') + +employee_dict = { + 'GetBook' : Book, + 'GetAddr' : Address, + 'GetWorkday' : GncNumeric, + 'GetRate' : GncNumeric, + 'GetCurrency' : GncCommodity + } +methods_return_instance(Employee, employee_dict) + +# Vendor +Vendor.add_constructor_and_methods_with_prefix('gncVendor', 'Create') + +vendor_dict = { + 'GetAddr' : Address, + 'GetTerms' : BillTerm, + 'GetCurrency' : GncCommodity + } +methods_return_instance(Vendor, vendor_dict) + +# Address +Address.add_constructor_and_methods_with_prefix('gncAddress', 'Create') + +# BillTerm +BillTerm.add_constructor_and_methods_with_prefix('gncBillTerm', 'Create') + +billterm_dict = { + 'LookupByName' : BillTerm, + 'GetDiscount' : GncNumeric, + 'GetParent' : BillTerm, + 'ReturnChild' : BillTerm + } +methods_return_instance(BillTerm, billterm_dict) diff --git a/src/optional/python-bindings/gnucash_core.i b/src/optional/python-bindings/gnucash_core.i index 0071e1c7b9..0a10633c40 100644 --- a/src/optional/python-bindings/gnucash_core.i +++ b/src/optional/python-bindings/gnucash_core.i @@ -32,18 +32,27 @@ #include "qofsession.h" #include "qofbook.h" #include "qofbackend.h" -#include "gnc-commodity.h" -#include "gnc-lot.h" -#include "gnc-numeric.h" +#include "qofid.h" +#include "guid.h" #include "Transaction.h" #include "Split.h" #include "Account.h" +#include "gnc-commodity.h" +#include "gnc-lot.h" +#include "gnc-numeric.h" +#include "gncCustomer.h" +#include "gncEmployee.h" +#include "gncVendor.h" +#include "gncAddress.h" +#include "gncBillTerm.h" #include %} %include -%include +%include + +%include %include @@ -54,9 +63,15 @@ %include -%include +%include + +/* SWIG doesn't like this macro, so redefine it to simply mean const */ +#define G_CONST_RETURN const +%include + +/* %include %include -%include +%include */ //Ignored because it is unimplemented %ignore gnc_numeric_convert_with_error; @@ -64,7 +79,14 @@ %include -%include +/* %include */ + +//business-core includes +%include +%include +%include +%include +%include %init %{ diff --git a/src/optional/python-bindings/gnucash_core.py b/src/optional/python-bindings/gnucash_core.py index b1dc2d5555..10fa31a2b4 100644 --- a/src/optional/python-bindings/gnucash_core.py +++ b/src/optional/python-bindings/gnucash_core.py @@ -25,7 +25,8 @@ import gnucash_core_c from function_class import \ ClassFromFunctions, extract_attributes_with_prefix, \ - default_arguments_decorator, method_function_returns_instance + default_arguments_decorator, method_function_returns_instance, \ + methods_return_instance class GnuCashCoreClass(ClassFromFunctions): _module = gnucash_core_c @@ -118,9 +119,7 @@ class GncCommodity(GnuCashCoreClass): def __init__(self, book, name=None, namespace=None, mnemonic=None, cusip=None, fraction=1, **kargs): GnuCashCoreClass.__init__(self, book, name, namespace, mnemonic, cusip, fraction, **kargs) -class GncCommodityTable(GnuCashCoreClass): - def __init__(self, book, **kargs): - GnuCashCoreClass.__init__(self, book, **kargs) +class GncCommodityTable(GnuCashCoreClass): pass class GncLot(GnuCashCoreClass): def __init__(self, book, **kargs): @@ -128,12 +127,19 @@ class GncLot(GnuCashCoreClass): class Transaction(GnuCashCoreClass): _new_instance = 'xaccMallocTransaction' + def GetNthSplit(self, n): + return self.GetSplitList().pop(n) class Split(GnuCashCoreClass): _new_instance = 'xaccMallocSplit' class Account(GnuCashCoreClass): _new_instance = 'xaccMallocAccount' + def GetNthChild(self, n): + return self.get_children().pop(n) + +class GUID(GnuCashCoreClass): + _new_instance = 'guid_new_return' # Session Session.add_constructor_and_methods_with_prefix('qof_session_', 'new') @@ -158,43 +164,32 @@ for error_name, error_value, error_name_after_prefix in \ #Book Book.add_constructor_and_methods_with_prefix('qof_book_', 'new') Book.add_method('gnc_book_get_root_account', 'get_root_account') +Book.add_method('gnc_book_set_root_account', 'set_root_account') #Functions that return Account Book.get_root_account = method_function_returns_instance( Book.get_root_account, Account ) # GncNumeric GncNumeric.add_constructor_and_methods_with_prefix('gnc_numeric_', 'create') -#Functions that return GncNumeric -GncNumeric.same = method_function_returns_instance( - GncNumeric.same, GncNumeric ) -GncNumeric.add = method_function_returns_instance( - GncNumeric.add, GncNumeric ) -GncNumeric.sub = method_function_returns_instance( - GncNumeric.sub, GncNumeric ) -GncNumeric.mul = method_function_returns_instance( - GncNumeric.mul, GncNumeric ) -GncNumeric.div = method_function_returns_instance( - GncNumeric.div, GncNumeric ) -GncNumeric.neg = method_function_returns_instance( - GncNumeric.neg, GncNumeric ) -GncNumeric.abs = method_function_returns_instance( - GncNumeric.abs, GncNumeric ) -GncNumeric.add_fixed = method_function_returns_instance( - GncNumeric.add_fixed, GncNumeric ) -GncNumeric.sub_fixed = method_function_returns_instance( - GncNumeric.sub_fixed, GncNumeric ) -GncNumeric.add_with_error = method_function_returns_instance( - GncNumeric.add_with_error, GncNumeric ) -GncNumeric.sub_with_error = method_function_returns_instance( - GncNumeric.sub_with_error, GncNumeric ) -GncNumeric.mul_with_error = method_function_returns_instance( - GncNumeric.mul_with_error, GncNumeric ) -GncNumeric.div_with_error = method_function_returns_instance( - GncNumeric.div_with_error, GncNumeric ) -GncNumeric.convert = method_function_returns_instance( - GncNumeric.convert, GncNumeric ) -GncNumeric.reduce = method_function_returns_instance( - GncNumeric.reduce, GncNumeric ) + +gncnumeric_dict = { + 'same' : GncNumeric, + 'add' : GncNumeric, + 'sub' : GncNumeric, + 'mul' : GncNumeric, + 'div' : GncNumeric, + 'neg' : GncNumeric, + 'abs' : GncNumeric, + 'add_fixed' : GncNumeric, + 'sub_fixed' : GncNumeric, + 'add_with_error' : GncNumeric, + 'sub_with_error' : GncNumeric, + 'mul_with_error' : GncNumeric, + 'div_with_error' : GncNumeric, + 'convert' : GncNumeric, + 'reduce' : GncNumeric + } +methods_return_instance(GncNumeric, gncnumeric_dict) # GncCommodity GncCommodity.add_constructor_and_methods_with_prefix('gnc_commodity_', 'new') @@ -204,105 +199,69 @@ GncCommodity.clone = method_function_returns_instance( # GncCommodityTable GncCommodityTable.add_constructor_and_methods_with_prefix('gnc_commodity_table_', 'get_table') -#Functions that return GncCommodity -GncCommodityTable.lookup = method_function_returns_instance( - GncCommodityTable.lookup, GncCommodity ) -GncCommodityTable.lookup_unique = method_function_returns_instance( - GncCommodityTable.lookup_unique, GncCommodity ) -GncCommodityTable.find_full = method_function_returns_instance( - GncCommodityTable.find_full, GncCommodity ) -GncCommodityTable.insert = method_function_returns_instance( - GncCommodityTable.insert, GncCommodity ) + +commoditytable_dict = { + 'lookup' : GncCommodity, + 'lookup_unique' : GncCommodity, + 'find_full' : GncCommodity, + 'insert' : GncCommodity + } +methods_return_instance(GncCommodityTable, commoditytable_dict) # GncLot GncLot.add_constructor_and_methods_with_prefix('gnc_lot_', 'new') -#Functions that return Account -GncLot.get_account = method_function_returns_instance( - GncLot.get_account, Account ) -#Functions that return Book -GncLot.get_book = method_function_returns_instance( - GncLot.get_book, Book ) -#Functions that return Split -GncLot.get_earliest_split = method_function_returns_instance( - GncLot.get_earliest_split, Split ) -GncLot.get_latest_split = method_function_returns_instance( - GncLot.get_latest_split, Split ) -#Functions that return GncNumeric -GncLot.get_balance = method_function_returns_instance( - GncLot.get_balance, GncNumeric ) -#Functions that return GncLot -GncLot.lookup = method_function_returns_instance( - GncLot.lookup, GncLot ) -GncLot.make_default = method_function_returns_instance( - GncLot.make_default, GncLot ) +gnclot_dict = { + 'get_account' : Account, + 'get_book' : Book, + 'get_earliest_split' : Split, + 'get_latest_split' : Split, + 'get_balance' : GncNumeric, + 'lookup' : GncLot, + 'make_default' : GncLot + } +methods_return_instance(GncLot, gnclot_dict) # Transaction Transaction.add_methods_with_prefix('xaccTrans') -#Functions that return Split -Transaction.GetSplit = method_function_returns_instance( - Transaction.GetSplit, Split ) -Transaction.FindSplitByAccount = method_function_returns_instance( - Transaction.FindSplitByAccount, Split ) -#Functions that return Transaction -Transaction.Clone = method_function_returns_instance( - Transaction.Clone, Transaction ) -Transaction.Reverse = method_function_returns_instance( - Transaction.Reverse, Transaction ) -Transaction.GetReversedBy = method_function_returns_instance( - Transaction.GetReversedBy, Transaction ) -#Functions that return GncCommodity -Transaction.GetCurrency = method_function_returns_instance( - Transaction.GetCurrency, GncCommodity ) -#Functions that return GncNumeric -Transaction.GetImbalance = method_function_returns_instance( - Transaction.GetImbalance, GncNumeric ) -Transaction.GetAccountValue = method_function_returns_instance( - Transaction.GetAccountValue, GncNumeric ) -Transaction.GetAccountAmount = method_function_returns_instance( - Transaction.GetAccountAmount, GncNumeric ) -Transaction.GetAccountConvRate = method_function_returns_instance( - Transaction.GetAccountConvRate, GncNumeric ) -Transaction.GetAccountBalance = method_function_returns_instance( - Transaction.GetAccountBalance, GncNumeric ) + +trans_dict = { + 'GetSplit': Split, + 'FindSplitByAccount': Split, + 'GetNthSplit': Split, + 'Clone': Transaction, + 'Reverse': Transaction, + 'GetReversedBy': Transaction, + 'GetImbalance': GncNumeric, + 'GetAccountValue': GncNumeric, + 'GetAccountAmount': GncNumeric, + 'GetAccountConvRate': GncNumeric, + 'GetAccountBalance': GncNumeric, + 'GetCurrency': GncCommodity + } +methods_return_instance(Transaction, trans_dict) # Split Split.add_methods_with_prefix('xaccSplit') -#Functions that return Book -Split.GetBook = method_function_returns_instance( - Split.GetBook, Book ) -#Functions that return Account -Split.GetAccount = method_function_returns_instance( - Split.GetAccount, Account ) -#Functions that return Transaction -Split.GetParent = method_function_returns_instance( - Split.GetParent, Transaction ) -#Functions that return Split -Split.Lookup = method_function_returns_instance( - Split.Lookup, Split ) -Split.GetOtherSplit = method_function_returns_instance( - Split.GetOtherSplit, Split ) -#Functions that return GncNumeric -Split.GetAmount = method_function_returns_instance( - Split.GetAmount, GncNumeric ) -Split.GetValue = method_function_returns_instance( - Split.GetValue, GncNumeric ) -Split.GetSharePrice = method_function_returns_instance( - Split.GetSharePrice, GncNumeric ) -Split.ConvertAmount = method_function_returns_instance( - Split.ConvertAmount, GncNumeric ) -Split.GetBaseValue = method_function_returns_instance( - Split.GetBaseValue, GncNumeric ) -Split.GetBalance = method_function_returns_instance( - Split.GetBalance, GncNumeric ) -Split.GetClearedBalance = method_function_returns_instance( - Split.GetClearedBalance, GncNumeric ) -Split.GetReconciledBalance = method_function_returns_instance( - Split.GetReconciledBalance, GncNumeric ) -Split.VoidFormerAmount = method_function_returns_instance( - Split.VoidFormerAmount, GncNumeric ) -Split.VoidFormerValue = method_function_returns_instance( - Split.VoidFormerValue, GncNumeric ) + +split_dict = { + 'GetBook': Book, + 'GetAccount': Account, + 'GetParent': Transaction, + 'Lookup': Split, + 'GetOtherSplit': Split, + 'GetAmount': GncNumeric, + 'GetValue': GncNumeric, + 'GetSharePrice': GncNumeric, + 'ConvertAmount': GncNumeric, + 'GetBaseValue': GncNumeric, + 'GetBalance': GncNumeric, + 'GetClearedBalance': GncNumeric, + 'GetReconciledBalance': GncNumeric, + 'VoidFormerAmount': GncNumeric, + 'VoidFormerValue': GncNumeric + } +methods_return_instance(Split, split_dict) Split.account = property( Split.GetAccount, Split.SetAccount ) Split.parent = property( Split.GetParent, Split.SetParent ) @@ -310,65 +269,41 @@ Split.parent = property( Split.GetParent, Split.SetParent ) # Account Account.add_methods_with_prefix('xaccAccount') Account.add_methods_with_prefix('gnc_account_') -#Functions that return Book -Account.get_book = method_function_returns_instance( - Account.get_book, Book ) -#Functions that return Account -Account.Lookup = method_function_returns_instance( - Account.Lookup, Account ) -Account.get_parent = method_function_returns_instance( - Account.get_parent, Account ) -Account.get_root = method_function_returns_instance( - Account.get_root, Account ) -Account.nth_child = method_function_returns_instance( - Account.nth_child, Account ) -Account.lookup_by_name = method_function_returns_instance( - Account.lookup_by_name, Account ) -Account.lookup_by_full_name = method_function_returns_instance( - Account.lookup_by_full_name, Account ) -#Functions that return Transaction -Account.FindTransByDesc = method_function_returns_instance( - Account.FindTransByDesc, Transaction ) -#Functions that return Split -Account.FindSplitByDesc = method_function_returns_instance( - Account.FindSplitByDesc, Split ) -#Functions that return GncNumeric -Account.get_start_balance = method_function_returns_instance( - Account.get_start_balance, GncNumeric ) -Account.get_start_cleared_balance = method_function_returns_instance( - Account.get_start_cleared_balance, GncNumeric ) -Account.GetBalance = method_function_returns_instance( - Account.GetBalance, GncNumeric ) -Account.GetClearedBalance = method_function_returns_instance( - Account.GetClearedBalance, GncNumeric ) -Account.GetReconciledBalance = method_function_returns_instance( - Account.GetReconciledBalance, GncNumeric ) -Account.GetPresentBalance = method_function_returns_instance( - Account.GetPresentBalance, GncNumeric ) -Account.GetProjectedMinimumBalance = method_function_returns_instance( - Account.GetProjectedMinimumBalance, GncNumeric ) -Account.GetBalanceAsOfDate = method_function_returns_instance( - Account.GetBalanceAsOfDate, GncNumeric ) -Account.ConvertBalanceToCurrency = method_function_returns_instance( - Account.ConvertBalanceToCurrency, GncNumeric ) -Account.ConvertBalanceToCurrencyAsOfDate = method_function_returns_instance( - Account.ConvertBalanceToCurrencyAsOfDate, GncNumeric ) -Account.GetBalanceInCurrency = method_function_returns_instance( - Account.GetBalanceInCurrency, GncNumeric ) -Account.GetClearedBalanceInCurrency = method_function_returns_instance( - Account.GetClearedBalanceInCurrency, GncNumeric ) -Account.GetReconciledBalanceInCurrency = method_function_returns_instance( - Account.GetReconciledBalanceInCurrency, GncNumeric ) -Account.GetPresentBalanceInCurrency = method_function_returns_instance( - Account.GetPresentBalanceInCurrency, GncNumeric ) -Account.GetProjectedMinimumBalanceInCurrency = method_function_returns_instance( - Account.GetProjectedMinimumBalanceInCurrency, GncNumeric ) -Account.GetBalanceAsOfDateInCurrency = method_function_returns_instance( - Account.GetBalanceInCurrency, GncNumeric ) -Account.GetBalanceChangeForPeriod = method_function_returns_instance( - Account.GetBalanceChangeForPeriod, GncNumeric ) -#Functions that return GncCommodity -Account.GetCommodity = method_function_returns_instance( - Account.GetCommodity, GncCommodity ) + +account_dict = { + 'get_book' : Book, + 'Lookup' : Account, + 'get_parent' : Account, + 'get_root' : Account, + 'nth_child' : Account, + 'lookup_by_name' : Account, + 'lookup_by_full_name' : Account, + 'GetNthChild' : Account, + 'FindTransByDesc' : Transaction, + 'FindSplitByDesc' : Split, + 'get_start_balance' : GncNumeric, + 'get_start_cleared_balance' : GncNumeric, + 'GetBalance' : GncNumeric, + 'GetClearedBalance' : GncNumeric, + 'GetReconciledBalance' : GncNumeric, + 'GetPresentBalance' : GncNumeric, + 'GetProjectedMinimumBalance' : GncNumeric, + 'GetBalanceAsOfDate' : GncNumeric, + 'ConvertBalanceToCurrency' : GncNumeric, + 'ConvertBalanceToCurrencyAsOfDate' : GncNumeric, + 'GetBalanceInCurrency' : GncNumeric, + 'GetClearedBalanceInCurrency' : GncNumeric, + 'GetReconciledBalanceInCurrency' : GncNumeric, + 'GetPresentBalanceInCurrency' : GncNumeric, + 'GetProjectedMinimumBalanceInCurrency' : GncNumeric, + 'GetBalanceAsOfDateInCurrency' : GncNumeric, + 'GetBalanceChangeForPeriod' : GncNumeric, + 'GetCommodity' : GncCommodity + } +methods_return_instance(Account, account_dict) Account.name = property( Account.GetName, Account.SetName ) + +#GUID +GUID.add_methods_with_prefix('guid_') + diff --git a/src/optional/python-bindings/tests/Makefile.am b/src/optional/python-bindings/tests/Makefile.am new file mode 100644 index 0000000000..4a6bbe5a4d --- /dev/null +++ b/src/optional/python-bindings/tests/Makefile.am @@ -0,0 +1,5 @@ +TESTS_ENVIRONMENT = $(top_srcdir)/src/bin/gnucash-env $(PYTHON) +TESTS = runTests.py + +clean-local: + rm -f translog.* diff --git a/src/optional/python-bindings/tests/runTests.py b/src/optional/python-bindings/tests/runTests.py new file mode 100644 index 0000000000..2c28854f0e --- /dev/null +++ b/src/optional/python-bindings/tests/runTests.py @@ -0,0 +1,14 @@ +import unittest + +from test import test_support + +from test_book import TestBook +from test_account import TestAccount +from test_split import TestSplit +from test_transaction import TestTransaction + +def test_main(): + test_support.run_unittest(TestBook, TestAccount, TestSplit, TestTransaction) + +if __name__ == '__main__': + test_main() diff --git a/src/optional/python-bindings/tests/test_account.py b/src/optional/python-bindings/tests/test_account.py new file mode 100644 index 0000000000..6488406d5d --- /dev/null +++ b/src/optional/python-bindings/tests/test_account.py @@ -0,0 +1,26 @@ +from unittest import main + +from gnucash import Book, Account, Split + +from test_book import BookSession + +class AccountSession( BookSession ): + def setUp(self): + BookSession.setUp(self) + self.account = Account(self.book) + +class TestAccount( AccountSession ): + def test_name(self): + NAME = "Money" + self.assertEquals( '', self.account.GetName() ) + self.account.SetName(NAME) + self.assertEquals( NAME, self.account.GetName() ) + + def test_split(self): + SPLIT = Split(self.book) + self.assertTrue(self.account.insert_split(SPLIT)) + self.assertTrue(self.account.find_split(SPLIT)) + self.assertTrue(self.account.remove_split(SPLIT)) + +if __name__ == '__main__': + main() diff --git a/src/optional/python-bindings/tests/test_book.py b/src/optional/python-bindings/tests/test_book.py new file mode 100644 index 0000000000..ac98dd7b0f --- /dev/null +++ b/src/optional/python-bindings/tests/test_book.py @@ -0,0 +1,14 @@ +from unittest import TestCase, main + +from gnucash import Book + +class BookSession( TestCase ): + def setUp(self): + self.book = Book() + +class TestBook( BookSession ): + def test_markclosed(self): + self.book.mark_closed() + +if __name__ == '__main__': + main() diff --git a/src/optional/python-bindings/tests/test_split.py b/src/optional/python-bindings/tests/test_split.py new file mode 100644 index 0000000000..ee3c6662a3 --- /dev/null +++ b/src/optional/python-bindings/tests/test_split.py @@ -0,0 +1,35 @@ +from unittest import main + +from gnucash import Book, Account, Split, Transaction + +from test_book import BookSession + +class SplitSession( BookSession ): + def setUp(self): + BookSession.setUp(self) + self.split = Split(self.book) + +class TestSplit( SplitSession ): + def test_memo(self): + MEMO = "cookie monster" + self.assertEquals( '', self.split.GetMemo() ) + self.split.SetMemo(MEMO) + self.assertEquals( MEMO, self.split.GetMemo() ) + + def test_account(self): + ACCT = Account(self.book) + self.split.SetAccount(ACCT) + self.assertTrue( ACCT.Equal(self.split.GetAccount(), True) ) + + def test_transaction(self): + TRANS = Transaction(self.book) + self.split.SetParent(TRANS) + TRANS.SetDescription("Foo") + self.assertEquals( TRANS.GetDescription(), self.split.GetParent().GetDescription() ) + + def test_equal(self): + COPY = self.split + self.assertTrue( self.split.Equal(COPY, True, False, False) ) + +if __name__ == '__main__': + main() diff --git a/src/optional/python-bindings/tests/test_transaction.py b/src/optional/python-bindings/tests/test_transaction.py new file mode 100644 index 0000000000..b5f9d5281a --- /dev/null +++ b/src/optional/python-bindings/tests/test_transaction.py @@ -0,0 +1,97 @@ +from unittest import main + +from gnucash import Transaction, Book, Account, Split + +from test_book import BookSession + +class TransactionSession( BookSession ): + def setUp(self): + BookSession.setUp(self) + self.trans = Transaction(self.book) + #Evil bug means we must set a split for the transaction before making + #any other changes (is slightly useful for later tests) + self.split = Split(self.book) + self.split.SetParent(self.trans) + ############ + +class TestTransaction( TransactionSession ): + def test_equal(self): + TRANS = self.trans + self.assertTrue( TRANS.Equal(self.trans, True, False, False, False) ) + + def test_clone(self): + TRANS = self.trans.Clone() + #Clone and original should have different GUIDs + self.assertFalse( TRANS.Equal(self.trans, True, False, False, False) ) + #Clone and original should have the same balance + self.assertTrue( TRANS.Equal(self.trans, False, False, True, False) ) + + def test_edit(self): + self.assertFalse( self.trans.IsOpen() ) + self.trans.BeginEdit() + self.assertTrue( self.trans.IsOpen() ) + self.trans.CommitEdit() + self.assertFalse( self.trans.IsOpen() ) + + def test_rollback(self): + self.assertEquals( '', self.trans.GetDescription() ) + self.trans.BeginEdit() + DESC = 'Food' + self.trans.SetDescription(DESC) + self.assertEquals( DESC, self.trans.GetDescription() ) + self.trans.RollbackEdit() + self.assertEquals( '', self.trans.GetDescription() ) + + def test_findsplit(self): + ACCT = Account(self.book) + self.split.SetAccount( ACCT ) + SPLIT = self.trans.FindSplitByAccount( ACCT ) + self.assertTrue( SPLIT.Equal(self.split, True, False, False) ) + + def test_getsplit(self): + SPLIT = self.trans.GetSplit(0) + self.assertTrue( SPLIT.Equal(self.split, True, False, False) ) + + def test_getsplitindex(self): + self.assertEquals( 0, self.trans.GetSplitIndex(self.split) ) + + def test_countsplits(self): + self.assertEquals( 1, self.trans.CountSplits() ) + + def test_readonly(self): + self.assertEquals( None, self.trans.GetReadOnly() ) + REASON = 'none' + self.trans.SetReadOnly(REASON) + self.assertEquals( REASON, self.trans.GetReadOnly() ) + self.trans.ClearReadOnly() + self.assertEquals( None, self.trans.GetReadOnly() ) + + def test_txntype(self): + self.assertEquals( '\x00', self.trans.GetTxnType() ) + TYPE = 'I' + self.trans.SetTxnType(TYPE) + self.assertEquals( TYPE, self.trans.GetTxnType() ) + TYPE = 'P' + self.trans.SetTxnType(TYPE) + self.assertEquals( TYPE, self.trans.GetTxnType() ) + + def test_num(self): + NUM = '5' + self.assertEquals( '', self.trans.GetNum() ) + self.trans.SetNum(NUM) + self.assertEquals( NUM, self.trans.GetNum() ) + + def test_description(self): + DESCR = 'Groceries' + self.assertEquals( '', self.trans.GetDescription() ) + self.trans.SetDescription(DESCR) + self.assertEquals( DESCR, self.trans.GetDescription() ) + + def test_notes(self): + NOTE = 'For dinner party' + self.assertEquals( None, self.trans.GetNotes() ) + self.trans.SetNotes(NOTE) + self.assertEquals( NOTE, self.trans.GetNotes() ) + +if __name__ == '__main__': + main()