Ahh, finally.

Attached are patches to the python bindings that I've actually had for awhile. Sending them upstream was somebody else's responsibility for so long that they were out of my field of attention once responsibility changed.

Today I opened up ParIT's svn repository, so if we're ever foolishly hoarding things again, you guys can just pull from us
http://svn.parit.ca/financial/gnucash

Our python binding work is in
http://svn.parit.ca/financial/gnucash/branches/python-bindings-2009-trunk

Apparently there's more work sitting in a working copy on the hard drive of a former colleague, some of which might even be the .i redundancy work that Derek suggested we engage in. I've this guy as another reminder that I'd really like to get my hands on that work, polish it, and get it here upstream where it belongs.


So, the patches are (in order of application)

python_GetNthChild_remove.patch
remove the redundant GetNthChild code, gnc_account_nth_child supported

python_more_GUID.patch
Improve support for GUID


python_better_commodity.patch
* Removed custom __init__ from GncCommodity, not only is it wrong but the one
from GnuCashCoreClass is just fine.

* Supported the get_table method For Book

* Removed support for direct instantiation of GncCommodityTable. (via
gnc_commodity_table_new() ). Only methods and not the constructor
function are added to the class now. Python binding users can access a
GncCommodityTable instance via Book.get_table() and have no need to use
gnc_commodity_table_new(), which the apis advise is for internal use
only.


python_GncLot.patch
* included gnc-lot.h in gnucash_core.i again

* Made GncLot class use superclass __init__, it doesn't need its own.


python_more_documentation.patch
Documentation strings for many classes, which can be viewed in source and with python's help() mechanism.


python_business_module_load.patch
load the business module, not the business module specific backend


python_example_scripts.py
example scripts improved, new one added. This new script originally came from this post:
http://lists.gnucash.org/pipermail/gnucash-devel/2008-July/023618.html


python_authors_update.patch
added Legal Aid Manitoba to credit line for Mark Jenkins


My funding is coming from Legal Aid Manitoba, which has a very successful free software deployment. They are looking forward to adding GnuCash to their mix.
http://www.informit.com/articles/article.aspx?p=30590

I'd like to know if anyone has any trouble using --enable-python-bindings. Remember to use gnucash-env and to include the directory containing the python gnucash module directory in your PYTHONPATH.


Mark Jenkins
Member
ParIT Worker Co-operative

cc Scott Balneaves, Legal Aid Manitoba
cc fellow ParITistas
Index: src/optional/python-bindings/gnucash_core.py
===================================================================
--- src/optional/python-bindings/gnucash_core.py	(revision 380)
+++ src/optional/python-bindings/gnucash_core.py	(revision 381)
@@ -135,8 +135,6 @@
 
 class Account(GnuCashCoreClass):
     _new_instance = 'xaccMallocAccount'
-    def GetNthChild(self, n):
-        return self.get_children().pop(n)
 
 class GUID(GnuCashCoreClass):
     _new_instance = 'guid_new_return'
@@ -278,7 +276,6 @@
                     'nth_child' : Account, 
                     'lookup_by_name' : Account, 
                     'lookup_by_full_name' : Account, 
-                    'GetNthChild' : Account, 
                     'FindTransByDesc' : Transaction, 
                     'FindSplitByDesc' : Split, 
                     'get_start_balance' : GncNumeric, 
Index: src/optional/python-bindings/gnucash_core.py
===================================================================
--- src/optional/python-bindings/gnucash_core.py	(revision 381)
+++ src/optional/python-bindings/gnucash_core.py	(revision 382)
@@ -222,6 +222,7 @@
 
 # Transaction
 Transaction.add_methods_with_prefix('xaccTrans')
+Transaction.add_method('gncTransGetGUID', 'GetGUID');
 
 trans_dict =    {
                     'GetSplit': Split, 
@@ -235,12 +236,14 @@
                     'GetAccountAmount': GncNumeric, 
                     'GetAccountConvRate': GncNumeric, 
                     'GetAccountBalance': GncNumeric, 
-                    'GetCurrency': GncCommodity 
+                    'GetCurrency': GncCommodity,
+                    'GetGUID': GUID
                 }
 methods_return_instance(Transaction, trans_dict)
 
 # Split
 Split.add_methods_with_prefix('xaccSplit')
+Split.add_method('gncSplitGetGUID', 'GetGUID');
 
 split_dict =    {
                     'GetBook': Book, 
@@ -257,7 +260,8 @@
                     'GetClearedBalance': GncNumeric, 
                     'GetReconciledBalance': GncNumeric, 
                     'VoidFormerAmount': GncNumeric, 
-                    'VoidFormerValue': GncNumeric 
+                    'VoidFormerValue': GncNumeric,
+                    'GetGUID': GUID
                 }
 methods_return_instance(Split, split_dict)
 
@@ -267,6 +271,7 @@
 # Account
 Account.add_methods_with_prefix('xaccAccount')
 Account.add_methods_with_prefix('gnc_account_')
+Account.add_method('gncAccountGetGUID', 'GetGUID');
 
 account_dict =  {   
                     'get_book' : Book, 
@@ -295,7 +300,8 @@
                     'GetProjectedMinimumBalanceInCurrency' : GncNumeric, 
                     'GetBalanceAsOfDateInCurrency' : GncNumeric, 
                     'GetBalanceChangeForPeriod' : GncNumeric, 
-                    'GetCommodity' : GncCommodity 
+                    'GetCommodity' : GncCommodity,
+                    'GetGUID': GUID 
                 }
 methods_return_instance(Account, account_dict)
 
@@ -303,4 +309,15 @@
 
 #GUID
 GUID.add_methods_with_prefix('guid_')
+GUID.add_method('xaccAccountLookup', 'AccountLookup')
+GUID.add_method('xaccTransLookup', 'TransLookup')
+GUID.add_method('xaccSplitLookup', 'SplitLookup')
 
+guid_dict = {
+                'copy' : GUID,
+                'TransLookup': Transaction,
+                'AccountLookup': Account,
+                'SplitLookup': Split
+            }
+methods_return_instance(GUID, guid_dict)
+                
Index: src/optional/python-bindings/gnucash_core.py
===================================================================
--- src/optional/python-bindings/gnucash_core.py	(revision 382)
+++ src/optional/python-bindings/gnucash_core.py	(revision 383)
@@ -115,9 +115,7 @@
         #    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 GncCommodity(GnuCashCoreClass): pass
 
 class GncCommodityTable(GnuCashCoreClass): pass
 
@@ -163,9 +161,13 @@
 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')
+Book.add_method('gnc_commodity_table_get_table', 'get_table')
 #Functions that return Account
 Book.get_root_account = method_function_returns_instance(
     Book.get_root_account, Account )
+#Functions that return GncCommodityTable
+Book.get_table = method_function_returns_instance(
+    Book.get_table, GncCommodityTable ) 
 
 # GncNumeric
 GncNumeric.add_constructor_and_methods_with_prefix('gnc_numeric_', 'create')
@@ -196,8 +198,7 @@
     GncCommodity.clone, GncCommodity )
 
 # GncCommodityTable
-GncCommodityTable.add_constructor_and_methods_with_prefix('gnc_commodity_table_', 'get_table')
-
+GncCommodityTable.add_methods_with_prefix('gnc_commodity_table_')
 commoditytable_dict =   { 
                             'lookup' : GncCommodity, 
                             'lookup_unique' : GncCommodity, 
Index: src/optional/python-bindings/gnucash_core.i
===================================================================
--- src/optional/python-bindings/gnucash_core.i	(revision 383)
+++ src/optional/python-bindings/gnucash_core.i	(revision 384)
@@ -79,7 +79,7 @@
 
 %include <gnc-commodity.h>
 
-/* %include <gnc-lot.h> */
+%include <gnc-lot.h>
 
 //business-core includes
 %include <gncCustomer.h>
Index: src/optional/python-bindings/gnucash_core.py
===================================================================
--- src/optional/python-bindings/gnucash_core.py	(revision 383)
+++ src/optional/python-bindings/gnucash_core.py	(revision 384)
@@ -120,8 +120,7 @@
 class GncCommodityTable(GnuCashCoreClass): pass
 
 class GncLot(GnuCashCoreClass):
-    def __init__(self, book, **kargs):
-        GnuCashCoreClass.__init__(self, book, **kargs)
+    pass
 
 class Transaction(GnuCashCoreClass):
     _new_instance = 'xaccMallocTransaction'
Index: src/optional/python-bindings/gnucash_core.py
===================================================================
--- src/optional/python-bindings/gnucash_core.py	(revision 384)
+++ src/optional/python-bindings/gnucash_core.py	(revision 385)
@@ -37,6 +37,18 @@
         self.errors = errors
 
 class Session(GnuCashCoreClass):
+    """A GnuCash book editing session
+
+    To commit changes to the session you may need to call save,
+    (this is allways the case with the file backend).
+    
+    When you're down with a session you may need to call end()
+
+    Every Session has a Book in the book attribute, which you'll definetely
+    be interested in, as every GnuCash entity (Transaction, Split, Vendor,
+    Invoice..) is associated with a particular book where it is stored.
+    """
+
     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.
@@ -104,10 +116,37 @@
             return return_value
         return new_function
 
-class Book(GnuCashCoreClass): pass
+class Book(GnuCashCoreClass):
+    """A Book encapsulates all of the GnuCash data, it is the place where
+    all GnuCash entities (Transaction, Split, Vendor, Invoice...), are
+    stored. You'll notice that all of the constructors for those entities
+    need a book to be associated with.
 
+    The most common way to get a book is through the book property in the
+    Session class, that is, create a session that connects to some storage,
+    such as through 'my_session = Session('file:my_books.xac')', and access
+    the book via the book property, 'my_session.book'
+
+    If you would like to create a Book without any backing storage, call the
+    Book constructor wihout any parameters, 'Book()'. You can later merge
+    such a book into a book with actual store by using merge_init.
+
+    Methods of interest
+    get_root_account -- Returns the root level Account
+    get_table -- Returns a commodity lookup table, of type GncCommodityTable
+    """
+    pass
+
 class GncNumeric(GnuCashCoreClass):
-    def __init__(self, num=0, denom=0, **kargs):
+    """Object used by GnuCash to store all numbers. Always consists of a
+    numerator and denominator.
+    """
+
+    def __init__(self, num=0, denom=1, **kargs):
+        """Constructor that allows you to set the numerator and denominator or
+        leave them blank with a default value of 0 (not a good idea since there
+        is currently no way to alter the value after instantiation)
+        """
         GnuCashCoreClass.__init__(self, num, denom, **kargs)
         #if INSTANCE_ARG in kargs:
         #    GnuCashCoreClass.__init__(**kargs)
@@ -117,20 +156,57 @@
 
 class GncCommodity(GnuCashCoreClass): pass
 
-class GncCommodityTable(GnuCashCoreClass): pass
+class GncCommodityTable(GnuCashCoreClass):
+    """A CommodityTable provides a way to store and lookup commoditys.
+    Commoditys are primarily currencies, but other tradable things such as
+    stocks, mutual funds, and material substances are posible.
 
+    Users of this library should not create thier own CommodityTable, instead
+    the get_table method from the Book class should be used.
+
+    This table is automatically populated with the GnuCash default commodity's
+    which includes most of the world's currencies.
+    """
+    pass
+
 class GncLot(GnuCashCoreClass):
     pass
 
 class Transaction(GnuCashCoreClass):
+    """A GnuCash Transaction
+    
+    Consists of at least one (generally two) splits to represent a transaction
+    between two accounts.
+    """
     _new_instance = 'xaccMallocTransaction'
     def GetNthSplit(self, n):
         return self.GetSplitList().pop(n)
 
 class Split(GnuCashCoreClass):
+    """A GnuCash Split
+
+    The most basic representation of a movement of currency from one account to
+    another.
+    """
     _new_instance = 'xaccMallocSplit'
 
 class Account(GnuCashCoreClass):
+    """A GnuCash Account.
+
+    A fundamental entity in accounting, an Account provides representation
+    for a financial object, such as a BANK account, an ASSET (like a building),
+    a LIABILITY (such as a bank loan), a summary of some type of EXPENSE, or
+    a summary of some source of INCOME.
+
+    The words in upper case are the constants that GnuCash and this library uses
+    to describe account type. Here is the full list:
+    BANK, CASH, CREDIT, ASSET, LIABILITY, STOCK, MUTUAL
+    CURRENCY, INCOME, EXPENSE, EQUITY, RECEIVABLE, PAYABLE, 
+    CHECKING, SAVINGS, MONEYMRKT, CREDITLINE
+
+    These are not strings, they are attributes you can import from this
+    module
+    """
     _new_instance = 'xaccMallocAccount'
 
 class GUID(GnuCashCoreClass):
Index: src/optional/python-bindings/gnucash_core.i
===================================================================
--- src/optional/python-bindings/gnucash_core.i	(revision 385)
+++ src/optional/python-bindings/gnucash_core.i	(revision 386)
@@ -93,6 +93,6 @@
 g_type_init();
 scm_init_guile();
 gnc_module_load("gnucash/engine", 0);
-gnc_module_load("gnucash/business-core-file", 0);
+gnc_module_load("gnucash/business-core", 0);
 
 %}
Index: src/optional/python-bindings/example_scripts/simple_test.py
===================================================================
--- src/optional/python-bindings/example_scripts/simple_test.py	(revision 387)
+++ src/optional/python-bindings/example_scripts/simple_test.py	(revision 388)
@@ -1,26 +1,27 @@
 #!/usr/bin/env python
 # Creates a basic set of accounts and a couple of transactions
 
-import gnucash
+from gnucash import Session, Account, Transaction, Split, GncNumeric
 
-FILE_1 = "/tmp/example.xac"
+FILE_1 = "/tmp/example.gnucash"
 
-session = None
-session = gnucash.Session("file:%s" % FILE_1, True)
+session = Session("xml:%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)
+root_acct = Account(book)
+expenses_acct = Account(book)
+savings_acct = Account(book)
+opening_acct = Account(book)
+trans1 = Transaction(book)
+trans2 = Transaction(book)
+split1 = Split(book)
+split3 = Split(book)
+comm_table = book.get_table()
+cad = comm_table.lookup("CURRENCY", "CAD")
 
+num1 = GncNumeric(4, 1)
+num2 = GncNumeric(100, 1)
+
 #Set new root account
 book.set_root_account(root_acct)
 
@@ -32,17 +33,17 @@
 root_acct.append_child(opening_acct)
 
 #Set up Expenses account
-expenses_acct.SetCommodity(comm)
+expenses_acct.SetCommodity(cad)
 expenses_acct.SetName("Expenses")
 expenses_acct.SetType(9) #ACCT_TYPE_EXPENSE = 9
 
 #Set up Savings account
-savings_acct.SetCommodity(comm)
+savings_acct.SetCommodity(cad)
 savings_acct.SetName("Savings")
 savings_acct.SetType(0) #ACCT_TYPE_BANK = 0
 
 #Set up Opening Balance account
-opening_acct.SetCommodity(comm)
+opening_acct.SetCommodity(cad)
 opening_acct.SetName("Opening Balance")
 opening_acct.SetType(10) #ACCT_TYPE_EQUITY = 10
 
@@ -54,10 +55,10 @@
 split3.SetAccount(savings_acct)
 split3.SetParent(trans2)
 
-trans1.SetCurrency(comm)
+trans1.SetCurrency(cad)
 trans1.SetDescription("Groceries")
 
-trans2.SetCurrency(comm)
+trans2.SetCurrency(cad)
 trans2.SetDescription("Opening Savings Balance")
 
 split2 = split1.GetOtherSplit()
Index: src/optional/python-bindings/example_scripts/change_tax_code.py
===================================================================
--- src/optional/python-bindings/example_scripts/change_tax_code.py	(revision 0)
+++ src/optional/python-bindings/example_scripts/change_tax_code.py	(revision 388)
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+from gnucash import Session, Account
+
+# choose the account code to select
+TARGET_ACCOUNT_CODE = '1234'
+
+def mark_account_with_code_as_tax_related(account, target_code):
+    """Looks at account to see if it has the target_account_code, if so
+    set the account tax related flag to True and return True.
+    If not, recursively tries to do the same to all children accounts
+    of account.
+    Returns False when recursion fails to find it.
+    """
+    if account.GetCode() == target_code:
+        account.SetTaxRelated(True)
+        return True
+    else:
+        for child in account.get_children():
+            child = Account(instance=child)
+            if mark_account_with_code_as_tax_related(child, target_code):
+                return True
+        return False
+            
+# Change this path to your own
+gnucash_session = Session("xml:/home/mark/python-bindings-help/test.xac")
+
+mark_account_with_code_as_tax_related(
+    gnucash_session.book.get_root_account(),
+    TARGET_ACCOUNT_CODE)
+
+gnucash_session.save()
+gnucash_session.end()
Index: src/optional/python-bindings/example_scripts/simple_session.py
===================================================================
--- src/optional/python-bindings/example_scripts/simple_session.py	(revision 387)
+++ src/optional/python-bindings/example_scripts/simple_session.py	(revision 388)
@@ -10,21 +10,21 @@
 # open a file that isn't there, detect the error
 session = None
 try:
-    session = Session("file:%s" % FILE_1)
+    session = Session("xml:%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 = Session("xml:%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)
+session = Session("xml:%s" % FILE_2)
 try:
-    session_2 = Session("file:%s" % FILE_2)
+    session_2 = Session("xml:%s" % FILE_2)
 except GnuCashBackendException, backend_exception:
     assert( ERR_BACKEND_LOCKED in backend_exception.errors )
 session.end()
Index: AUTHORS
===================================================================
--- AUTHORS	(revision 388)
+++ AUTHORS	(revision 389)
@@ -174,7 +174,7 @@
 Edward J. Huff <ejh...@huff20may77.us> Date handling in reports, quarterly option
 Tomokazu Iwashita <iwash...@center.nitech.ac.jp> Japanese translation of xea
 David Jafferian <david.jaffer...@east.sun.com> Delete account query code.
-Mark Jenkins <m...@parit.ca> Python bindings, with grant funding from Assiniboine Credit Union (http://assiniboine.mb.ca/)
+Mark Jenkins <m...@parit.ca> Python bindings, with grant funding from Assiniboine Credit Union (http://assiniboine.mb.ca/) and Legal Aid Manitoba (http://www.legalaid.mb.ca/)
 Miquel Jordana Vilamitjana <jjv...@mundomail.net> Spanish translation of manual
 Prakash Kailasa <praka...@bigfoot.com> for gnome build fixes
 Alexey Kakunin <sm...@arcadia.spb.ru> quickfill patch for Cyrillic
_______________________________________________
gnucash-devel mailing list
gnucash-devel@gnucash.org
https://lists.gnucash.org/mailman/listinfo/gnucash-devel

Reply via email to