Python bindings for the gnucash API.

Submitted by Mark Jenkins on 2008-03-25 to gnucash-devel.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@17263 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Christian Stimming 2008-07-07 19:18:26 +00:00
parent 0c9ce6d1f2
commit 4fa2e87962
14 changed files with 996 additions and 1 deletions

View File

@ -150,6 +150,7 @@ Ron Forrester <rjf@aracnet.com> for gnome patches
Dave Freese <DFreese@osc.uscg.mil> for leap-year fix
Todd T. Fries <todd@flare.fries.net> OpenBSD fix
John Goerzen <jgoerzen@complete.org> file i/o fix for 64-bit architectures
Jeff Green <jmgreen7@gmail.com> Python bindings
Hans de Graaff <hans@degraaff.org> XML patches
Daniel Hagerty <hag@linnaean.org> patch to balance sheet report
Mitsuo Hamada <mhamada@redhat.com> messages Japanese translations
@ -166,6 +167,7 @@ Péter Hosszú <hosszu@web.de> Hungarian translation
Edward J. Huff <ejhuff@huff20may77.us> Date handling in reports, quarterly option
Tomokazu Iwashita <iwashita@center.nitech.ac.jp> Japanese translation of xea
David Jafferian <david.jafferian@east.sun.com> Delete account query code.
Mark Jenkins <mark@parit.ca> Python bindings
Miquel Jordana Vilamitjana <jjvmjv@mundomail.net> Spanish translation of manual
Prakash Kailasa <PrakashK@bigfoot.com> for gnome build fixes
Alexey Kakunin <small@arcadia.spb.ru> quickfill patch for Cyrillic

View File

@ -1329,6 +1329,28 @@ else
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
###-------------------------------------------------------------------------
@ -1520,6 +1542,7 @@ AC_CONFIG_FILES(po/Makefile.in
src/import-export/hbci/schemas/Makefile
src/import-export/hbci/test/Makefile
src/optional/Makefile
src/optional/python-bindings/Makefile
src/optional/xsl/Makefile
src/pixmaps/Makefile
src/quotes/Makefile
@ -1585,6 +1608,9 @@ fi
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

64
macros/ac_python_devel.m4 Normal file
View File

@ -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 <sebastian-huber@web.de>
dnl @author Alan W. Irwin <irwin@beluga.phys.uvic.ca>
dnl @author Rafael Laboissiere <laboissiere@psy.mpg.de>
dnl @author Andrew Collier <colliera@nu.ac.za>
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)
])

View File

@ -1 +1,2 @@
SUBDIRS = xsl
SUBDIRS = xsl ${PYTHON_DIR}
DIST_SUBDIRS = xsl python-bindings

View File

@ -0,0 +1,25 @@
BUILT_SOURCES = gnucash_core.c
SWIG_SOURCES = gnucash_core.i
pkgpython_PYTHON = __init__.py function_class.py \
gnucash_core.py gnucash_core_c.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
# 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
gnucash_core.c : $(SWIG_SOURCES)
$(SWIG) $(SWIG_PYTHON_OPT) -Wall -Werror \
-I$(top_srcdir)/src -I$(top_srcdir)/src/engine \
$(QOF_CFLAGS) -o $@ $<

View File

@ -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 *

View File

@ -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()

View File

@ -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()

View File

@ -0,0 +1,49 @@
#!/usr/bin/env python
from gnucash import \
Session, Account, Transaction, Split, GncCommodity, GncNumeric
FILE_1 = "/tmp/example.xac"
session = None
session = 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")
book.print_dirty()
book.mark_saved()
book.mark_closed()
session.save()
session.end()
session.destroy()

View File

@ -0,0 +1,167 @@
# function_class.py -- Library for making python classes from a set
# of functions.
#
# Copyright (C) 2008 ParIT Worker Co-operative <paritinfo@parit.ca>
# 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 <mark@parit.ca>
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

View File

@ -0,0 +1,92 @@
/*
* glib.i -- SWIG interface file for type translation of glib types
*
* Copyright (C) 2008 ParIT Worker Co-operative <paritinfo@parit.ca>
*
* 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 <mark@parit.ca>
*/
%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;
}
}

View File

@ -0,0 +1,76 @@
/*
* gnucash_core.i -- SWIG interface file for the core parts of GnuCash
*
* Copyright (C) 2008 ParIT Worker Co-operative <paritinfo@parit.ca>
*
* 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 <mark@parit.ca>
* @author Jeff Green, ParIT Worker Co-operative <jeff@parit.ca>
*/
%module(package="gnucash") gnucash_core_c
%{
#include "config.h"
#include <datetime.h>
#include "qofsession.h"
#include "qofbook.h"
#include "qofbackend.h"
#include "gnc-commodity.h"
#include "gnc-lot.h"
#include "gnc-numeric.h"
#include "Transaction.h"
#include "Split.h"
#include "Account.h"
#include <guile/gh.h>
%}
%include <timespec.i>
%include <glib.i>
%include <qofbackend.h>
// 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 <qofsession.h>
%include <qofbook.h>
%include <Transaction.h>
%include <Split.h>
%include <Account.h>
//Ignored because it is unimplemented
%ignore gnc_numeric_convert_with_error;
%include <gnc-numeric.h>
%include <gnc-commodity.h>
%include <gnc-lot.h>
%init %{
g_type_init();
scm_init_guile();
gnc_module_load("gnucash/engine", 0);
gnc_module_load("gnucash/business-core-file", 0);
%}

View File

@ -0,0 +1,374 @@
# gnucash_core.py -- High level python wrapper classes for the core parts
# of GnuCash
#
# Copyright (C) 2008 ParIT Worker Co-operative <paritinfo@parit.ca>
# 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 <mark@parit.ca>
# @author Jeff Green, ParIT Worker Co-operative <jeff@parit.ca>
import gnucash_core_c
from function_class import \
ClassFromFunctions, extract_attributes_with_prefix, \
default_arguments_decorator, method_function_returns_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):
def __init__(self, book, **kargs):
GnuCashCoreClass.__init__(self, book, **kargs)
class GncLot(GnuCashCoreClass):
def __init__(self, book, **kargs):
GnuCashCoreClass.__init__(self, book, **kargs)
class Transaction(GnuCashCoreClass):
_new_instance = 'xaccMallocTransaction'
class Split(GnuCashCoreClass):
_new_instance = 'xaccMallocSplit'
class Account(GnuCashCoreClass):
_new_instance = 'xaccMallocAccount'
# 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')
#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 )
# 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')
#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 )
# 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 )
# 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 )
# 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.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_')
#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.name = property( Account.GetName, Account.SetName )

View File

@ -0,0 +1,67 @@
/*
* timespec.i -- SWIG interface file for type translation of Timespec types
*
* Copyright (C) 2008 ParIT Worker Co-operative <paritinfo@parit.ca>
*
* 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 <mark@parit.ca>
*/
// 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 <mark@parit.ca>
%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);
}