#********************************************************************** # Gnu Cash to OpenOffice.org (gnuc2ooo.py) # # Macros for the download of GnuCash Data to OpenOffice.org Base # # Macro SetGnuCashFilePaths: # Set or change the filepaths of the (GnuCash) data source # and of the new OpenOffice.org database that will be created # in this macro though still empty # # Macro fillGnuCashDB: # Download data from the GnuCash data source to OpenOffice.org # Base # # #********************************************************************** # Copyright (c) 2008 Knut Gerwens # gnuc2ooo@alice-dsl.net # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # See: https://www.gnu.org/licenses/lgpl.html # #********************************************************************** # Acknowledgements: Special thanks go to the authors on OpenOffice.org # macro programming Roberto Benitez(http://www.baseprogramming.com) and # Andrew Pitonyak (http://www.pitonyak.org) #********************************************************************** # Changes # Knut Gerwens, 2008-09-16: # Bugfix: locale.getlocale() -> locale.getdefaultlocale() # Extension: field description in table TRN from 256 to 512 Bytes # # Knut Gerwens, 2008-09-20: # try/unconditional except for read input, so Windows XP-Users can use # the program with unzipped GnuCashFiles (no valid gzip module). # try/except for sort on hierarchy (accounttree), because python 2.3.4 # does not support keyword argument in sort. # Infobox/Success-message at end of FillGnuCashDB # # Knut Gerwens, 2008-09-29: # Improved Errorhandling. Errors are intercepted, Some Error and # Trace-Information is written to logfile GnuCashFilePaths.txt # # Knut Gerwens, 2008-10-02: # Checkpoint-Statement at the end added, so tables are actually stored # in database and not only as logfile # # Knut Gerwens, 2008-10-04: # Improved memory-mangement. Writing to disc is enforced every 1000 rows # import uno, unohelper import gzip import xml.sax as sax import os.path, locale import time # ********************** OPENOFFICE.ORG-API ******************************* # Component Context und Service Manager ctx = uno.getComponentContext() smgr = ctx.ServiceManager # create database context Context = smgr.createInstanceWithContext( "com.sun.star.sdb.DatabaseContext", ctx) # Star Desktop Desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx) # user directory PathSettings = smgr.createInstanceWithContext( "com.sun.star.util.PathSettings", ctx) # ************************** PROLOG *************************************** from com.sun.star.ui.dialogs.TemplateDescription import FILEOPEN_SIMPLE, FILESAVE_AUTOEXTENSION lcodec = locale.getdefaultlocale()[1] set_macro = "SetGnuCashFilePaths" settings_textentrance = "#This file was generated by OpenOfficeMacro: " settings_textinp = "GnuCashDatafile: " settings_textoutp = "Registered Database in Openoffice.org: " # Trace / Error - Information global crout crout = 'main' last_input_getDBFilename = 'not available' last_input_createDB = 'not available' last_input_createdelete = 'not available' last_input_eval_fraction = 'not available' last_input_view_all_transactions = 'not available' last_input___init__ = 'not available' last_input_startElement = 'not available' last_input_endElement = 'not available' last_input_insert_statement = 'not available' last_input_characters = 'not available' last_input_MessageBox = 'not available' insert_ct = 0 maxmemory = 1000 def settings_filepath(): userdir_url = PathSettings.UserConfig userdir = unohelper.fileUrlToSystemPath(userdir_url) userfile = os.path.join(userdir, 'GnuCashFilePaths.txt') return userfile def getGCFilename(): global crout crout = 'getGCFilename' fp_read.Title = "Pick Output Data File of GnuCash Program" fp_read.initialize((FILEOPEN_SIMPLE,)) fp_read.MultiSelectionMode = False if fp_read.execute(): return fp_read.Files[0] def getDBFilename(default): global crout crout = 'getDBFilename' global last_input_getDBFilename ## last_input_getDBFilename = str(default) + '\n' fp_write.Title = "Enter Database Filename" fp_write.MultiSelectionMode = False try: fp_write.appendFilter("Base Files (*.odb)", "*.odb") except: fp_write.setCurrentFilter("Base Files (*.odb)") fp_write.initialize((FILESAVE_AUTOEXTENSION,)) fp_write.setDefaultName(default) if fp_write.execute(): return fp_write.Files[0] def createDB(db_defaultname): global crout crout = 'createDB' global last_input_createDB ## last_input_createDB = str(db_defaultname) fileurl=getDBFilename(db_defaultname) if fileurl: DB = Context.createInstance() DB.URL = "sdbc:embedded:hsqldb" DB.DatabaseDocument.storeAsURL(fileurl, ()) filepath = unohelper.fileUrlToSystemPath(fileurl) filename = os.path.basename(filepath) datasource = Context.getByName(fileurl) dbname = filename[:-4] Context.registerObject(dbname, datasource) return dbname else: return None def exec_SetGnuCashFilePaths(): """ Definition of data source and target files, creation of empty database """ global fp_read, fp_write global crout crout = 'SetGnuCashFilePaths' # uno service for filepickers # There was a bug under ubuntu 8.04 when I took the normal, # i.e. Gnom FilePicker, so I had to take the Office File Picker fp_read = smgr.createInstanceWithContext( "com.sun.star.ui.dialogs.OfficeFilePicker", ctx) fp_write = smgr.createInstanceWithContext( "com.sun.star.ui.dialogs.OfficeFilePicker", ctx) GCFileURL = getGCFilename() if GCFileURL: GCFile = unohelper.fileUrlToSystemPath(GCFileURL) else: return None settings = open(settings_filepath(), 'w') entrance_line = settings_textentrance + set_macro + '\n' settings.write(entrance_line) settings.write(settings_textinp) settings.write(GCFile.encode(lcodec) + '\n') gcfilename = os.path.basename(GCFile) dbname = createDB(gcfilename) if dbname: settings.write(settings_textoutp) settings.write(dbname.encode(lcodec) + '\n') else: return None settings.close() MessageBox('A new Openoffice.org database has been created.\n' + 'To fill with data please run macro "fillGnuCashDB."', MsgType="infobox") def read_filepaths(): global crout crout = 'read_filepaths' try: settings = open(settings_filepath(), 'r') except IOError: return [] gcfile = "" dbname = "" for line in settings: lineparts = line.split(": ") if lineparts[0] == settings_textinp[:-2]: gcfile = lineparts[1].rstrip().decode(lcodec) elif lineparts[0] == settings_textoutp[:-2]: dbname = lineparts[1].rstrip().decode(lcodec) else: pass settings.close() if gcfile == "" or dbname == "": return [] else: return [gcfile, dbname] # *********************** TABLES ooo-DB ********************************** # Three definitions for account: must be kept in sync create_account = """CREATE TABLE ACCOUNT ( NAME VARCHAR(256), ID VARCHAR(256), TYPE VARCHAR(256), DESCRIPTION VARCHAR(256), PARENT VARCHAR(256)) """ insert_account = """INSERT INTO ACCOUNT( NAME, ID, TYPE, DESCRIPTION, PARENT) VALUES (?, ?, ?, ?, ?)""" ## """ def init_account(): global crout crout = 'init_account' account0 = {}.fromkeys(['name', 'id', 'type', 'description', 'parent'], '') return account0 # Definitions transaction: must be kept in sync # As many reports will evaluate on a monthly base I prefer to store # date:year/month and date/day into separate columns create_trn = """ CREATE TABLE TRN ( ID VARCHAR(256) NOT NULL, NUM VARCHAR(256), DESCRIPTION VARCHAR(512), DATE_YM CHAR(7), DATE_D CHAR(2) ) """ insert_trn = """INSERT INTO TRN( ID, NUM, DESCRIPTION, DATE_YM, DATE_D) VALUES (?, ?, ?, ?, ?)""" def init_trn(): global crout crout = 'init_trn' trn0 = {}.fromkeys(['id', 'num', 'description', 'date_ym', 'date_d'], '') return trn0 # Definitions for splits create_split = """ CREATE TABLE SPLIT ( ID VARCHAR(256) NOT NULL, TRN_ID VARCHAR(256), VALUE DOUBLE, QUANTITY DOUBLE, ACCOUNT VARCHAR(256) ) """ insert_split = """INSERT INTO SPLIT( ID, TRN_ID, VALUE, QUANTITY, ACCOUNT) VALUES (?, ?, ?, ?, ?)""" def init_split(): global crout crout = 'init_split' split0 = {}.fromkeys(['id', 'trn_id', 'value', 'quantity', 'account'], '') return split0 # Definitions for acct_tree, will be completed before execution create_accttree0 = """CREATE TABLE ACCTTREE (ID VARCHAR(256) NOT NULL""" insert_accttree0 = """INSERT INTO ACCTTREE VALUES (?""" def createdelete(create_statement, table_name): global crout crout = 'createdelete' global last_input_createdelete ## last_input_createdelete = str(create_statement) + ' ' + str(table_name) try: Stmt.execute(create_statement) except: if table_name: Stmt.execute("DELETE FROM " + table_name) def eval_fraction(cont): global crout crout = 'eval_fraction' global last_input_eval_fraction ## last_input_eval_fraction = str(cont) l_split = cont.split('/') numerator = cont.split('/')[0] denominator = cont.split('/')[1] if denominator.isdigit() and float(denominator) != 0: floatnumber = float(numerator) / float(denominator) else: floatnumber = 0 return floatnumber def accounttree(): global crout crout = 'accounttree' accrowlist = [] accrowdict = {} accrowsresult = Stmt.executeQuery("SELECT ID, PARENT, NAME, TYPE FROM ACCOUNT") while accrowsresult.next(): acc = [] for i in range(accrowsresult.Columns.Count): acc.append(accrowsresult.getString(i + 1)) accrowlist.append(acc) for acc in accrowlist: accrowdict.update({acc[0]: acc[1:]}) hierarchy = [] maxlvl = 0 for acc in accrowdict: namelist = [] clist = accrowdict[acc] while clist[0]: namelist.append(clist[1]) clist = accrowdict[clist[0]] namelist.reverse() maxlvl = max(maxlvl, len(namelist)) namelist.insert(0, acc) hierarchy.append(namelist) try: hierarchy.sort(key=lambda l: l[1:]) except: pass filler = [] create_accttree = create_accttree0 insert_accttree = insert_accttree0 for i in range(maxlvl): create_accttree += ", " + "LEVEL" + str(i + 1) + " VARCHAR(256)" insert_accttree += ", ?" filler.append(' ') create_accttree += ')' insert_accttree += ')' createdelete(create_accttree, "ACCTTREE") Stmt_ins_accttree = Connection.prepareStatement(insert_accttree) for namelist in hierarchy: i = len(namelist) t_namelist = tuple(namelist + filler[i-1:]) ct = 0 for col in t_namelist: ct = ct + 1 Stmt_ins_accttree.setString(ct, col) Stmt_ins_accttree.executeUpdate() createdelete("CREATE INDEX ACCTTREE_ID ON ACCTTREE (ID)", None) return maxlvl def view_all_transactions(ct_lvl): global crout crout = 'view_all_transactions' global last_input_view_all_transactions ## last_input_view_all_transactions = str(ct_lvl) def vardefs(ct_lvl = ct_lvl): global crout crout = 'vardefs' v2 = """"ACCTTREE"."LEVEL?" AS "LEVEL?", """ v4 = """ "LEVEL?",""" vd2 = "" vd4 = "" for i in range(ct_lvl): sl = str(i + 1) vd2 = vd2 + v2.replace("?", sl) vd4 = vd4 + v4.replace("?", sl) vtup = (vd2, vd4) return vtup ## viewdef = ## "ACCTTREE"."LEVEL1" AS "LEVEL1", ## "ACCTTREE"."LEVEL2" AS "LEVEL2", ## "ACCTTREE"."LEVEL3" AS "LEVEL3", ## "ACCTTREE"."LEVEL4" AS "LEVEL4", ## "LEVEL1", "LEVEL2", "LEVEL3", "LEVEL4", ## viewdef1 = """CREATE VIEW ALL_TRANSACTIONS AS SELECT "ACCOUNT"."TYPE" AS "ACCOUNT-TYPE", """ viewdef3 = """ "ACCOUNT"."NAME" AS "ACCOUNT-NAME", "TRN"."DATE_YM" AS "DATE_YM", "TRN". "DATE_D" AS "DATE_D", "TRN"."NUM" AS "TRN-NUMBER", "TRN"."DESCRIPTION" AS "DESCRIPTION", CAST ( "SPLIT"."VALUE" AS "DECIMAL" ) AS "VALUE" FROM "SPLIT", "TRN", "ACCOUNT", "ACCTTREE" WHERE "TRN"."ID" = "SPLIT"."TRN_ID" AND "ACCOUNT"."ID" = "SPLIT"."ACCOUNT" AND "ACCTTREE"."ID" = "SPLIT"."ACCOUNT" AND "SPLIT"."VALUE" != '0' ORDER BY""" viewdef5 = """ "DATE_YM", "DATE_D", "TRN-NUMBER", "DESCRIPTION" """ vtup = vardefs() viewdef2 = vtup[0] viewdef4 = vtup[1] viewdef = viewdef1 + viewdef2 + viewdef3 + viewdef4 + viewdef5 Stmt.execute(viewdef) #**************************** SAX / XML *********************************** class GCContent(sax.handler.ContentHandler): def __init__(self): global crout crout = '__init__' global last_input___init__ ## last_input___init__ = str(self) self.account = init_account() self.trn = init_trn() self.split = init_split() self.tbl = '' self.name = '' self.status_date_posted = False self.date_posted = '' self.status_template_trns = False def startElement(self, name, attrs): global crout crout = 'startElement' global last_input_startElement last_input_startElement = str(name.encode(lcodec)) if ':' in name: self.tbl = name.split(':')[0] self.key = name.split(':')[1] def endElement(self, name): global crout crout = 'endElement' global last_input_endElement last_input_endElement = str(name.encode(lcodec)) def insert_statement(kind, value_dict): global crout global last_input_insert_statement crout = 'insert_statement' last_input_insert_statement = str(kind.encode(lcodec)) + ' ' + str(value_dict) global insert_ct insert_ct = insert_ct + 1 if insert_ct >= maxmemory: Stmt.execute("CHECKPOINT") insert_ct = insert_ct - maxmemory if kind == 'account': Stmt_ins_account.setString(1, value_dict['name']) Stmt_ins_account.setString(2, value_dict['id']) Stmt_ins_account.setString(3, value_dict['type']) Stmt_ins_account.setString(4, value_dict['description']) Stmt_ins_account.setString(5, value_dict['parent']) Stmt_ins_account.executeUpdate() elif kind == 'trn': Stmt_ins_trn.setString(1, value_dict['id']) Stmt_ins_trn.setString(2, value_dict['num']) Stmt_ins_trn.setString(3, value_dict['description']) Stmt_ins_trn.setString(4, value_dict['date_ym']) Stmt_ins_trn.setString(5, value_dict['date_d']) Stmt_ins_trn.executeUpdate() elif kind == 'split': Stmt_ins_split.setString(1, value_dict['id']) Stmt_ins_split.setString(2, value_dict['trn_id']) Stmt_ins_split.setDouble(3, value_dict['value']) Stmt_ins_split.setDouble(4, value_dict['quantity']) Stmt_ins_split.setString(5, value_dict['account']) Stmt_ins_split.executeUpdate() if name == 'gnc:account': for tup in self.account.iteritems(): self.account[tup[0]] = tup[1].rstrip() if self.status_template_trns == False: insert_statement('account', self.account) self.account = init_account() self.tbl = '' self.key = '' elif name == 'trn:date-posted': self.trn['date_ym'] = self.date_posted[0:7] self.trn['date_d'] = self.date_posted[8:10] self.status_date_posted = False self.date_posted = '' elif name == 'trn:split': self.split['trn_id'] = self.trn['id'] for tup in self.split.iteritems(): self.split[tup[0]] = tup[1].rstrip() self.split['value'] = eval_fraction(self.split['value']) self.split['quantity'] = eval_fraction(self.split['quantity']) if self.status_template_trns == False: insert_statement('split', self.split) self.split = init_split() self.tbl = '' self.key = '' elif name == 'gnc:transaction': for tup in self.trn.iteritems(): self.trn[tup[0]] = tup[1].rstrip() if self.status_template_trns == False: insert_statement('trn', self.trn) self.trn = init_trn() self.tbl = '' self.key = '' elif name == 'gnc:template-transactions': self.status_template_trns = False elif name == 'gnc:book': createdelete("CREATE INDEX ACCOUNT_ID ON ACCOUNT (ID)", None) createdelete("CREATE INDEX TRN_ID ON TRN (ID)", None) createdelete("CREATE INDEX SPLIT_ID ON SPLIT (ID)", None) createdelete("CREATE INDEX S_TRN_ID ON SPLIT (TRN_ID)", None) createdelete("CREATE INDEX S_ACCOUNT ON SPLIT (ACCOUNT)", None) def characters(self, content): global crout crout = 'characters' global last_input_characters ## last_input_characters = str(self) + ' ' + str(content.encode(lcodec)) if self.tbl == 'act': if self.key in self.account: self.account[self.key] += content elif self.tbl == 'trn': if self.key in self.trn: self.trn[self.key] += content elif self.key == 'date-posted': self.status_date_posted = True elif self.tbl == 'ts': if self.key == 'date' and self.status_date_posted == True: self.date_posted += content elif self.tbl == 'split': if self.key in self.split: self.split[self.key] += content elif self.tbl == 'gnc': if self.key == 'template-transactions': self.status_template_trns = True # ***************************** MSGBOX / XRAY ***************************** # Show a message box with the UNO based toolkit # This function was copied and adapted from OpenOffice.org API - Code Snippet Base # http://codesnippets.services.openoffice.org from com.sun.star.awt import Rectangle from com.sun.star.awt import WindowDescriptor from com.sun.star.awt.WindowClass import MODALTOP from com.sun.star.awt.VclWindowPeerAttribute import OK, OK_CANCEL, YES_NO, YES_NO_CANCEL, RETRY_CANCEL, DEF_OK, DEF_CANCEL, DEF_RETRY, DEF_YES, DEF_NO def MessageBox(MsgText, MsgTitle="GnuCash to Ooo", MsgType="messbox", MsgButtons=OK, ParentWin=None): global crout crout = 'MessageBox' global last_input_MessageBox ## last_input_MessageBox = str(MsgText) if not ParentWin: doc = XSCRIPTCONTEXT.getDocument() try: ParentWin = doc.CurrentController.Frame.ContainerWindow except AttributeError: ParentWin = doc.Frame.ContainerWindow MsgType = MsgType.lower() #available msg types MsgTypes = ("messbox", "infobox", "errorbox", "warningbox", "querybox") if not ( MsgType in MsgTypes ): MsgType = "messbox" #describe window properties. aDescriptor = WindowDescriptor() aDescriptor.Type = MODALTOP aDescriptor.WindowServiceName = MsgType aDescriptor.ParentIndex = -1 aDescriptor.Parent = ParentWin #aDescriptor.Bounds = Rectangle() aDescriptor.WindowAttributes = MsgButtons tk = ParentWin.getToolkit() msgbox = tk.createWindow(aDescriptor) msgbox.setMessageText(MsgText) if MsgTitle : msgbox.setCaptionText(MsgTitle) return msgbox.execute() ## callXray(DB) ##def callXray(obj): ## """Macro to call Basic XRay by Bernard Marcelly from Python.""" ## ### Only works if the according libraries are loaded at start of program ### See http://wiki.services.openoffice.org/wiki/Extensions_development_basic#X-Ray_tool ## ## sURL = "vnd.sun.star.script:XRayTool._Main.Xray?language=Basic&location=application" ## ## oMSPF = smgr.createInstanceWithContext( ## "com.sun.star.script.provider.MasterScriptProviderFactory", ctx) ## oMSP = oMSPF.createScriptProvider('') ## oScript = oMSP.getScript(sURL) ## oScript.invoke((obj,), (), ()) ## ## # ***************************** MAIN PROGRAM ****************************** def exec_fillGnuCashDB(): """Fill OpenOffice.org database with newest GnuCash data""" global crout crout = 'exec_fillGnuCashDB' filepaths = read_filepaths() if not filepaths: MessageBox('Reading filepaths not successful.\n' + 'Please run macro ' + '"' + set_macro + '"', MsgType="errorbox") return False gcfile = filepaths[0] dbname = filepaths[1] answer = MessageBox('Update database ' + dbname +'?', MsgType = "querybox", MsgButtons=YES_NO) if not answer == 2: # 2 = YES, 3 = NO return False global DB, Connection, Stmt # get the database DB=Context.getByName(dbname) dbhandler = smgr.createInstanceWithContext( "com.sun.star.sdb.InteractionHandler", ctx) # get connection to database Connection=DB.connectWithCompletion(dbhandler) # create Statement object Stmt=Connection.createStatement() # create base Tables createdelete(create_account, "ACCOUNT") createdelete(create_trn, "TRN") createdelete(create_split, "SPLIT") # drop indices Stmt.execute("DROP INDEX ACCOUNT_ID IF EXISTS") Stmt.execute("DROP INDEX TRN_ID IF EXISTS") Stmt.execute("DROP INDEX SPLIT_ID IF EXISTS") Stmt.execute("DROP INDEX S_TRN_ID IF EXISTS") Stmt.execute("DROP INDEX S_ACCOUNT_ID IF EXISTS") Stmt.execute("DROP INDEX ACCTTREE_ID IF EXISTS") # drop derived tables Stmt.execute("DROP VIEW ALL_TRANSACTIONS IF EXISTS") Stmt.execute("DROP TABLE ACCTTREE IF EXISTS") # read GnuCash Data try: f = gzip.open(gcfile) gcxml = f.read() except: f = open(gcfile) gcxml = f.read() global Stmt_ins_account, Stmt_ins_trn, Stmt_ins_split # create preparedStatement objects Stmt_ins_account = Connection.prepareStatement(insert_account) Stmt_ins_trn = Connection.prepareStatement(insert_trn) Stmt_ins_split = Connection.prepareStatement(insert_split) # parse data and insert into database handler = GCContent() parser = sax.make_parser() parser.setContentHandler(handler) parser.feed(gcxml) f.close() ct_lvl = accounttree() view_all_transactions(ct_lvl) # write checkpoint so all tables are stored in database # (and not only in logfile) Stmt.execute("CHECKPOINT") DB.DatabaseDocument.store() # close connection Connection.close() MessageBox('Database ' + dbname + ' has been successfully updated.', MsgType="infobox") def issue_error_messages(args): logfile = settings_filepath() settings = open(logfile, 'a') entrance_line = '\nErrorlogging ' + time.ctime() + '\n' settings.write(entrance_line) strMsg = "Error! %s %s " % (args.__class__.__name__, args) + '\n' settings.write(strMsg) current_routine = 'current routine = ' + crout + '\n' settings.write(current_routine) ## input_info = 'last input getDBFilename: ' + last_input_getDBFilename + '\n' ## settings.write(input_info) ## input_info = 'last input createDB: ' + last_input_createDB + '\n' ## settings.write(input_info) ## input_info = 'last input createdelete: ' + last_input_createdelete + '\n' ## settings.write(input_info) ## input_info = 'last input eval_fraction: ' + last_input_eval_fraction + '\n' ## settings.write(input_info) ## input_info = 'last input view_all_transactions: ' + last_input_view_all_transactions + '\n' ## settings.write(input_info) ## input_info = 'last input __init__: ' + last_input___init__ + '\n' ## settings.write(input_info) input_info = 'last input startElement: ' + last_input_startElement + '\n' settings.write(input_info) input_info = 'last input endElement: ' + last_input_endElement + '\n' settings.write(input_info) input_info = 'last input insert_statement: ' + last_input_insert_statement + '\n' settings.write(input_info) ## input_info = 'last input characters: ' + last_input_characters + '\n' ## settings.write(input_info) ## input_info = 'last input MessageBox: ' + last_input_MessageBox + '\n' ## settings.write(input_info) strMsg = strMsg + 'For further information look into file\n' + logfile MessageBox(strMsg, MsgType="errorbox") settings.close() return def fillGnuCashDB(): global crout crout = 'fillGnuCashDB' try: exec_fillGnuCashDB() except Exception, args: issue_error_messages(args) return def SetGnuCashFilePaths(): global crout crout = 'SetGnuCashFilePaths' try: exec_SetGnuCashFilePaths() except Exception, args: issue_error_messages(args) return g_exportedScripts = fillGnuCashDB, SetGnuCashFilePaths,