diff --exclude=.svn -urN gnucash-trunk/src/optional/Makefile.am gnucash-python-binding-clean/src/optional/Makefile.am --- gnucash-trunk/src/optional/Makefile.am 2008-06-05 15:42:42.000000000 -0500 +++ gnucash-python-binding-clean/src/optional/Makefile.am 2008-06-05 15:42:01.000000000 -0500 @@ -1 +1 @@ -SUBDIRS = xsl +SUBDIRS = xsl ${PYTHON_DIR} diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/example_scripts/simple_book.py gnucash-python-binding-clean/src/optional/python-bindings/example_scripts/simple_book.py --- gnucash-trunk/src/optional/python-bindings/example_scripts/simple_book.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/example_scripts/simple_book.py 2008-06-05 15:42:00.000000000 -0500 @@ -0,0 +1,13 @@ +#!/usr/bin/env python +from gnucash import Book + +book = Book() + +#Call some methods that produce output to show that Book works +print "New book:" +book.print_dirty() +book.mark_saved() +print "\nBook marked saved:" +book.print_dirty() + +book.destroy() diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/example_scripts/simple_session.py gnucash-python-binding-clean/src/optional/python-bindings/example_scripts/simple_session.py --- gnucash-trunk/src/optional/python-bindings/example_scripts/simple_session.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/example_scripts/simple_session.py 2008-06-05 15:42:00.000000000 -0500 @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +from gnucash import \ + Session, GnuCashBackendException, \ + ERR_BACKEND_LOCKED, ERR_FILEIO_FILE_NOT_FOUND + +FILE_1 = "/tmp/not_there.xac" +FILE_2 = "/tmp/example_file.xac" + +# open a file that isn't there, detect the error +session = None +try: + session = Session("file:%s" % FILE_1) +except GnuCashBackendException, backend_exception: + assert( ERR_FILEIO_FILE_NOT_FOUND in backend_exception.errors) + + +# create a new file +session = Session("file:%s" % FILE_2, True) +session.save() +session.end() +session.destroy() + +# open the new file, try to open it a second time, detect the lock +session = Session("file:%s" % FILE_2) +try: + session_2 = Session("file:%s" % FILE_2) +except GnuCashBackendException, backend_exception: + assert( ERR_BACKEND_LOCKED in backend_exception.errors ) +session.end() +session.destroy() + + diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/example_scripts/simple_test.py gnucash-python-binding-clean/src/optional/python-bindings/example_scripts/simple_test.py --- gnucash-trunk/src/optional/python-bindings/example_scripts/simple_test.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/example_scripts/simple_test.py 2008-06-05 15:42:00.000000000 -0500 @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# Creates a basic set of accounts and a couple of transactions + +import gnucash + +FILE_1 = "/tmp/example.xac" + +session = None +session = gnucash.Session("file:%s" % FILE_1, True) + +book = session.book +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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/function_class.py gnucash-python-binding-clean/src/optional/python-bindings/function_class.py --- gnucash-trunk/src/optional/python-bindings/function_class.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/function_class.py 2008-06-05 15:42:01.000000000 -0500 @@ -0,0 +1,176 @@ +# function_class.py -- Library for making python classes from a set +# of functions. +# +# 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 + +INSTANCE_ARGUMENT = "instance" + +class ClassFromFunctions(object): + """Inherit this class to give yourself a python class that wraps a set of + functions that together consitute the methods of the class. + + The method functions must all have as a first argument an object + holding the instance data. There must also be a function that + returns a new instance of the class, the constructor. + + Your subclass must define + _module - The module where the method functions, including the + constructor can be found + _new_instance - The name of a function that serves as a constructor, + returning the instance data. + + To access the instance data, use the read-only property instance. + + To add some functions from _module as methods, call classmethods like + add_method and add_methods_with_prefix. + """ + def __new__(cls, *args, **kargs): + # why reimpliment __new__? Because later on we're going to + # use new to avoid creating new instances when existing instances + # already exist with the same __instance value, or equivlent __instance + # values, where this is desirable... + return super(ClassFromFunctions, cls).__new__(cls, *args, **kargs) + + def __init__(self, *args, **kargs): + """Construct a new instance, using either the function + self._module[self._new_instance] or using existing instance + data. (specified with the keyword argument, instance) + + Pass the arguments that should be passed on to + self._module[self._new_instance] . Any arguments of that + are instances of ClassFromFunctions will be switched with the instance + data. (by calling the .instance property) + """ + if INSTANCE_ARGUMENT in kargs: + self.__instance = kargs[INSTANCE_ARGUMENT] + else: + self.__instance = getattr(self._module, self._new_instance)( + *process_list_convert_to_instance(args) ) + + def get_instance(self): + """Get the instance data. + + You can also call the instance property + """ + return self.__instance + + instance = property(get_instance) + + # CLASS METHODS + + @classmethod + def add_method(cls, function_name, method_name): + """Add the function, method_name to this class as a method named name + """ + def method_function(self, *meth_func_args): + return getattr(self._module, function_name)( + self.instance, + *process_list_convert_to_instance(meth_func_args) ) + + setattr(cls, method_name, method_function) + setattr(method_function, "__name__", method_name) + return method_function + + @classmethod + def add_methods_with_prefix(cls, prefix): + """Add a group of functions with the same prefix + """ + for function_name, function_value, after_prefix in \ + extract_attributes_with_prefix(cls._module, prefix): + cls.add_method(function_name, after_prefix) + + @classmethod + def add_constructor_and_methods_with_prefix(cls, prefix, constructor): + """Add a group of functions with the same prefix, and set the + _new_instance attribute to prefix + constructor + """ + cls.add_methods_with_prefix(prefix) + cls._new_instance = prefix + constructor + + @classmethod + def decorate_functions(cls, decorator, *args): + for function_name in args: + setattr( cls, function_name, + decorator( getattr(cls, function_name) ) ) + +def method_function_returns_instance(method_function, cls): + """A function decorator that is used to decorates method functions that + return instance data, to return instances instead. + + You can't use this decorator with @, because this function has a second + argument. + """ + assert( 'instance' == INSTANCE_ARGUMENT ) + def new_function(*args): + kargs = { INSTANCE_ARGUMENT : method_function(*args) } + return cls( **kargs ) + + return new_function + +def default_arguments_decorator(function, *args): + """Decorates a function to give it default, positional arguments + + You can't use this decorator with @, because this function has more + than one argument. + """ + def new_function(*function_args): + new_argset = list(function_args) + new_argset.extend( args[ len(function_args): ] ) + return function( *new_argset ) + return new_function + +def return_instance_if_value_has_it(value): + """Return value.instance if value is an instance of ClassFromFunctions, + else return value + """ + if isinstance(value, ClassFromFunctions): + return value.instance + else: + return value + +def process_list_convert_to_instance( value_list ): + """Return a list built from value_list, where if a value is in an instance + of ClassFromFunctions, we put value.instance in the list instead. + + Things that are not instances of ClassFromFunctions are returned to + the new list unchanged. + """ + return [ return_instance_if_value_has_it(value) + for value in value_list ] + +def extract_attributes_with_prefix(obj, prefix): + """Generator that iterates through the attributes of an object and + for any attribute that matches a prefix, this yields + the attribute name, the attribute value, and the text that appears + after the prefix in the name + """ + for attr_name, attr_value in obj.__dict__.iteritems(): + 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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/glib.i gnucash-python-binding-clean/src/optional/python-bindings/glib.i --- gnucash-trunk/src/optional/python-bindings/glib.i 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/glib.i 2008-06-05 15:42:01.000000000 -0500 @@ -0,0 +1,115 @@ +/* + * glib.i -- SWIG interface file for type translation of glib types + * + * 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 + */ + +%typemap(in) gint8, gint16, gint32, gint64, gint, gshort, glong { + $1 = ($1_type)PyInt_AsLong($input); +} + +%typemap(out) gint8, gint16, gint32, gint64, gint, gshort, glong { + $result = PyInt_FromLong($1); +} + +%typemap(in) guint8, guint16, guint32, guint64, guint, gushort, gulong { + $1 = ($1_type)PyLong_AsUnsignedLong($input); +} + +%typemap(out) guint8, guint16, guint32, guint64, guint, gushort, gulong { + $result = PyLong_FromUnsignedLong($1); +} + +%typemap(in) gfloat, gdouble { + $1 = ($1_type)PyFloat_AsDouble($input); +} + +%typemap(out) gfloat, gdouble { + $result = PyFloat_FromDouble($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_gpointer, 0)); + } + $result = list; +} diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/gnucash_business.py gnucash-python-binding-clean/src/optional/python-bindings/gnucash_business.py --- gnucash-trunk/src/optional/python-bindings/gnucash_business.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/gnucash_business.py 2008-06-05 15:42:01.000000000 -0500 @@ -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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/gnucash_core.i gnucash-python-binding-clean/src/optional/python-bindings/gnucash_core.i --- gnucash-trunk/src/optional/python-bindings/gnucash_core.i 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/gnucash_core.i 2008-06-05 15:42:01.000000000 -0500 @@ -0,0 +1,98 @@ +/* + * gnucash_core.i -- SWIG interface file for the core 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 + */ + +%module(package="gnucash") gnucash_core_c + +%{ +#include "config.h" +#include +#include "qofsession.h" +#include "qofbook.h" +#include "qofbackend.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 + +// this function is defined in qofsession.h, but isnt found in the libraries, +// ignoroed because SWIG attempts to link against (to create language bindings) +%ignore qof_session_not_saved; +%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 */ + +//Ignored because it is unimplemented +%ignore gnc_numeric_convert_with_error; +%include + +%include + +/* %include */ + +//business-core includes +%include +%include +%include +%include +%include + +%init %{ + +g_type_init(); +scm_init_guile(); +gnc_module_load("gnucash/engine", 0); +gnc_module_load("gnucash/business-core-file", 0); + +%} diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/gnucash_core.py gnucash-python-binding-clean/src/optional/python-bindings/gnucash_core.py --- gnucash-trunk/src/optional/python-bindings/gnucash_core.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/gnucash_core.py 2008-06-05 15:42:01.000000000 -0500 @@ -0,0 +1,309 @@ +# gnucash_core.py -- High level python wrapper classes for the core 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 + +class GnuCashCoreClass(ClassFromFunctions): + _module = gnucash_core_c + +class GnuCashBackendException(Exception): + def __init__(self, msg, errors): + Exception.__init__(self, msg) + self.errors = errors + +class Session(GnuCashCoreClass): + def __init__(self, book_uri=None, is_new=False): + """A convienent contructor that allows you to specify a book URI, + begin the session, and load the book. + + This can give you the power of calling + qof_session_new, qof_session_begin, and qof_session_load all in one! + + book_uri can be None to skip the calls to qof_session_begin and + qof_session_load, or it can be a string like "file:/test.xac" + + qof_session_load is only called if is_new is set to False + + is_new is passed to qof_session_begin as the + argument create_if_nonexistent + + This function can raise a GnuCashBackendException. If it does, + you don't need to cleanup and call end() and destroy(), that is handled + for you, and the exception is raised. + """ + GnuCashCoreClass.__init__(self) + if book_uri is not None: + try: + self.begin(book_uri, False, is_new) + if not is_new: + self.load() + except GnuCashBackendException, backend_exception: + self.end() + self.destroy() + raise + + def raise_backend_errors(self, called_function="qof_session function"): + """Raises a GnuCashBackendException if there are outstanding + QOF_BACKEND errors. + + set called_function to name the function that was last called + """ + errors = self.pop_all_errors() + if errors != (): + raise GnuCashBackendException( + "call to %s resulted in the " + "following errors, %s" % (called_function, errors), + errors ) + + def generate_errors(self): + """A generator that yeilds any outstanding QofBackend errors + """ + while self.get_error() is not ERR_BACKEND_NO_ERR: + error = self.pop_error() + yield error + + def pop_all_errors(self): + """Returns any accumulated qof backend errors as a tuple + """ + return tuple( self.generate_errors() ) + + # STATIC METHODS + @staticmethod + def raise_backend_errors_after_call(function): + """A function decorator that results in a call to + raise_backend_errors after execution. + """ + def new_function(self, *args): + return_value = function(self, *args) + self.raise_backend_errors(function.__name__) + return return_value + return new_function + +class Book(GnuCashCoreClass): pass + +class GncNumeric(GnuCashCoreClass): + def __init__(self, num=0, denom=0, **kargs): + GnuCashCoreClass.__init__(self, num, denom, **kargs) + #if INSTANCE_ARG in kargs: + # GnuCashCoreClass.__init__(**kargs) + #else: + # self.set_denom(denom) # currently undefined + # self.set_num(num) # currently undefined + +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): pass + +class GncLot(GnuCashCoreClass): + def __init__(self, book, **kargs): + GnuCashCoreClass.__init__(self, book, **kargs) + +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') + +def one_arg_default_none(function): + return default_arguments_decorator(function, None, None) +Session.decorate_functions(one_arg_default_none, "load", "save") + +Session.decorate_functions( Session.raise_backend_errors_after_call, + "begin", "load", "save", "end") +Session.get_book = method_function_returns_instance( + Session.get_book, Book ) + +Session.book = property( Session.get_book ) + +# import all of the session backend error codes into this module +this_module_dict = globals() +for error_name, error_value, error_name_after_prefix in \ + extract_attributes_with_prefix(gnucash_core_c, 'ERR_'): + this_module_dict[ error_name ] = error_value + +#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') + +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') +#Functions that return GncCommodity +GncCommodity.clone = method_function_returns_instance( + GncCommodity.clone, GncCommodity ) + +# GncCommodityTable +GncCommodityTable.add_constructor_and_methods_with_prefix('gnc_commodity_table_', 'get_table') + +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') + +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') + +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') + +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 ) + +# Account +Account.add_methods_with_prefix('xaccAccount') +Account.add_methods_with_prefix('gnc_account_') + +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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/__init__.py gnucash-python-binding-clean/src/optional/python-bindings/__init__.py --- gnucash-trunk/src/optional/python-bindings/__init__.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/__init__.py 2008-06-05 15:42:01.000000000 -0500 @@ -0,0 +1,6 @@ +# import all the symbols from gnucash_core, so basic gnucash stuff can be +# loaded with: +# >>> from gnucash import thingy +# instead of +# >>> from gnucash.gnucash_core import thingy +from gnucash_core import * diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/Makefile.am gnucash-python-binding-clean/src/optional/python-bindings/Makefile.am --- gnucash-trunk/src/optional/python-bindings/Makefile.am 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/Makefile.am 2008-06-05 15:42:01.000000000 -0500 @@ -0,0 +1,30 @@ +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_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/business/business-core + +# Suppress all warnings for now, but we really only need to -Wno-implicit +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/business/business-core/libgncmod-business-core.la + +gnucash_core.c : $(SWIG_SOURCES) + 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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/tests/Makefile.am gnucash-python-binding-clean/src/optional/python-bindings/tests/Makefile.am --- gnucash-trunk/src/optional/python-bindings/tests/Makefile.am 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/tests/Makefile.am 2008-06-05 15:42:00.000000000 -0500 @@ -0,0 +1,5 @@ +TESTS_ENVIRONMENT = $(top_srcdir)/src/bin/gnucash-env $(PYTHON) +TESTS = runTests.py + +clean-local: + rm -f translog.* diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/tests/runTests.py gnucash-python-binding-clean/src/optional/python-bindings/tests/runTests.py --- gnucash-trunk/src/optional/python-bindings/tests/runTests.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/tests/runTests.py 2008-06-05 15:42:00.000000000 -0500 @@ -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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/tests/test_account.py gnucash-python-binding-clean/src/optional/python-bindings/tests/test_account.py --- gnucash-trunk/src/optional/python-bindings/tests/test_account.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/tests/test_account.py 2008-06-05 15:42:00.000000000 -0500 @@ -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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/tests/test_book.py gnucash-python-binding-clean/src/optional/python-bindings/tests/test_book.py --- gnucash-trunk/src/optional/python-bindings/tests/test_book.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/tests/test_book.py 2008-06-05 15:42:00.000000000 -0500 @@ -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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/tests/test_split.py gnucash-python-binding-clean/src/optional/python-bindings/tests/test_split.py --- gnucash-trunk/src/optional/python-bindings/tests/test_split.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/tests/test_split.py 2008-06-05 15:42:00.000000000 -0500 @@ -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 --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/tests/test_transaction.py gnucash-python-binding-clean/src/optional/python-bindings/tests/test_transaction.py --- gnucash-trunk/src/optional/python-bindings/tests/test_transaction.py 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/tests/test_transaction.py 2008-06-05 15:42:00.000000000 -0500 @@ -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() diff --exclude=.svn -urN gnucash-trunk/src/optional/python-bindings/timespec.i gnucash-python-binding-clean/src/optional/python-bindings/timespec.i --- gnucash-trunk/src/optional/python-bindings/timespec.i 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/optional/python-bindings/timespec.i 2008-06-05 15:42:01.000000000 -0500 @@ -0,0 +1,67 @@ +/* + * timespec.i -- SWIG interface file for type translation of Timespec types + * + * 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 + */ + +// A typemap for converting python dates to Timespec in functions that +// require Timespec as an argument +%typemap(in) Timespec { + PyDateTime_IMPORT; + $1 = gnc_dmy2timespec(PyDateTime_GET_DAY($input), + PyDateTime_GET_MONTH($input), + PyDateTime_GET_YEAR($input) ); +} + +// A typemap for converting python dates to Timespec *, for fuctions that +// requires a Timespec * as an argument. BIG ASSUMPTION, the function +// recieving this pointer is going to make a copy of the data. After the +// function call, the memory for the Timespec used to perform this conversion +// is going to be lost, so make damn sure that the recipiant of this pointer +// is NOT going dereference it sometime after this function call takes place. +// +// As far as I know, the xaccTransSetDate[Posted|Entered|Due]TS functions +// from Transaction.h are the only functions with Timespec * that we re +// actually using. I have personaly verifyed in the source that the pointer +// being produced by this typemap is being deferenced, and the data copied +// in all three functions. +// +// The memory for the Timespec used for this conversion is allocated on the +// stack. (SWIG will name the variables ts1, ts2, ts3...) +// +// Mark Jenkins +%typemap(in) Timespec * (Timespec ts) { + PyDateTime_IMPORT; + ts = gnc_dmy2timespec(PyDateTime_GET_DAY($input), + PyDateTime_GET_MONTH($input), + PyDateTime_GET_YEAR($input) ); + $1 = &ts; +} + +// A typemap for converting Timespec values returned from functions to +// python dates. +%typemap(out) Timespec { + int year, month, day; + gnc_timespec2dmy($1, &day, &month, &year); + PyDateTime_IMPORT; + $result = PyDate_FromDate(year, month, day); +} --- gnucash-trunk/configure.in 2008-06-05 15:44:22.000000000 -0500 +++ gnucash-python-binding-clean/configure.in 2008-06-05 15:44:50.000000000 -0500 @@ -1322,6 +1322,28 @@ fi AC_SUBST(LC_MESSAGES_ENUM) +###-------------------------------------------------------- +### Make Python bindings optional +###-------------------------------------------------------- +enable_python=false + +AC_ARG_ENABLE(python-bindings, + [ --enable-python-bindings enable python bindings], + [case "${enableval}" in + yes) enable_python=true ;; + no) enable_python=false ;; + *) enable_python=true ;; + esac] + ) +if test x${enable_python} = "xtrue" +then + PYTHON_DIR=python-bindings + AM_PATH_PYTHON(2.4) + AC_PYTHON_DEVEL(>= '2.4') + SWIG_PYTHON +fi +AC_SUBST(PYTHON_DIR) + ###------------------------------------------------------------------------- ### Additional compiler warnings (or not) if we're running GCC ###------------------------------------------------------------------------- @@ -1513,6 +1534,8 @@ src/import-export/hbci/schemas/Makefile 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 @@ -1578,6 +1601,9 @@ if test x${HBCI_DIR} != x; then components="$components hbci" fi +if test x${PYTHON_DIR} != x; then +components="$components python-bindings" +fi AC_MSG_RESULT([ Options detected/selected diff --exclude=.svn -urN gnucash-trunk/src/engine/engine-common.i gnucash-python-binding-clean/src/engine/engine-common.i --- gnucash-trunk/src/engine/engine-common.i 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/src/engine/engine-common.i 2008-06-05 15:43:06.000000000 -0500 @@ -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 --exclude=.svn -urN gnucash-trunk/src/engine/engine.i gnucash-python-binding-clean/src/engine/engine.i --- gnucash-trunk/src/engine/engine.i 2008-06-05 15:43:18.000000000 -0500 +++ gnucash-python-binding-clean/src/engine/engine.i 2008-06-05 15:43:06.000000000 -0500 @@ -23,35 +23,22 @@ %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 @@ 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); @@ -192,7 +168,6 @@ %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 --exclude=.svn -urN gnucash-trunk/macros/ac_python_devel.m4 gnucash-python-binding-clean/macros/ac_python_devel.m4 --- gnucash-trunk/macros/ac_python_devel.m4 1969-12-31 18:00:00.000000000 -0600 +++ gnucash-python-binding-clean/macros/ac_python_devel.m4 2008-06-05 15:44:49.000000000 -0500 @@ -0,0 +1,64 @@ +dnl @synopsis AC_PYTHON_DEVEL +dnl +dnl Checks for Python and tries to get the include path to 'Python.h'. +dnl It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS) output +dnl variable. +dnl +dnl @category InstalledPackages +dnl @author Sebastian Huber +dnl @author Alan W. Irwin +dnl @author Rafael Laboissiere +dnl @author Andrew Collier +dnl @version 2004-07-14 +dnl @license GPLWithACException + +AC_DEFUN([AC_PYTHON_DEVEL],[ + # + # should allow for checking of python version here... + # + AC_REQUIRE([AM_PATH_PYTHON]) + + # Check for Python include path + AC_MSG_CHECKING([for Python include path]) + python_path=`echo $PYTHON | sed "s,/bin.*$,,"` + for i in "$python_path/include/python$PYTHON_VERSION/" "$python_path/include/python/" "$python_path/" ; do + python_path=`find $i -type f -name Python.h -print | sed "1q"` + if test -n "$python_path" ; then + break + fi + done + python_path=`echo $python_path | sed "s,/Python.h$,,"` + AC_MSG_RESULT([$python_path]) + if test -z "$python_path" ; then + AC_MSG_ERROR([cannot find Python include path]) + fi + AC_SUBST([PYTHON_CPPFLAGS],[-I$python_path]) + + # Check for Python library path + AC_MSG_CHECKING([for Python library path]) + python_path=`echo $PYTHON | sed "s,/bin.*$,,"` + for i in "$python_path/lib/python$PYTHON_VERSION/config/" "$python_path/lib/python$PYTHON_VERSION/" "$python_path/lib/python/config/" "$python_path/lib/python/" "$python_path/" ; do + python_path=`find $i -type f -name libpython$PYTHON_VERSION.* -print | sed "1q"` + if test -n "$python_path" ; then + break + fi + done + python_path=`echo $python_path | sed "s,/libpython.*$,,"` + AC_MSG_RESULT([$python_path]) + if test -z "$python_path" ; then + AC_MSG_ERROR([cannot find Python library path]) + fi + AC_SUBST([PYTHON_LDFLAGS],["-L$python_path -lpython$PYTHON_VERSION"]) + # + python_site=`echo $python_path | sed "s/config/site-packages/"` + AC_SUBST([PYTHON_SITE_PKG],[$python_site]) + # + # libraries which must be linked in when embedding + # + AC_MSG_CHECKING(python extra libraries) + PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \ + conf = distutils.sysconfig.get_config_var; \ + print conf('LOCALMODLIBS')+' '+conf('LIBS')" + AC_MSG_RESULT($PYTHON_EXTRA_LIBS)` + AC_SUBST(PYTHON_EXTRA_LIBS) +]) --- gnucash-trunk/src/base-typemaps.i 2008-06-05 15:43:21.000000000 -0500 +++ gnucash-python-binding-clean/src/base-typemaps.i 2008-06-05 15:43:10.000000000 -0500 @@ -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 @@ %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 @@ $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