get_transaction().commit() does not commit: Zope: OOBTree definition & creation
Thank you very much for your comments. Yes, I shortened the code, because otherwise the mails get too long. This is a basic accounting db, using Zope, which I intend to make publicly available once it is stable, so disclosing the code is no problem at all, just a question of length and this mailing list is already very active. I researched further, and it seems that it is the question of where you define the OOBTree. I naively thought you simply define the entire DB as an OOBTree, but I realized that you only define sub-branches as OOBTrees and only upon creation. I made some changes and now it runs. However, I am puzzled by your comment that an OOBTree does not allow these transactions. How do you open a db with an OOBTree ??? When I open the file AccDB.fs with a text editor I can see, that my code must have been executed, because I can see the strings for the nodes ! The new code (again shortened, because the original is still work in progress and contains a lot of scrap, if you want the full code, because there is something fundamentally strange, let me know I can mail it directly.): (PS: I know that my style is extremely unpythonic, but don't be too strict, I am only on python since a couple of months) The main loop: def test(): db = AccountingDB() print 'Database file:',db.mountedDB # create a ledger r = db.ledger_create('001','2003') if r[0] == False: if r[1][0] == 2: print "The database file does not exist, Will be created new now!" db.mount_db(True) db.unmount_db() print "DB Created, now creating ledger anew !" r = db.ledger_create('001','2003') if r[0] == False : print 'failed miserably ! aborting ...' ; return print "Created new DB & ledger, congrats !" else: print r print "Can not find DB file. Aborting ..." return # open the ledger print db.ledger_open('001','2003') print db.ledger_close() Produces this output in the shell, provided the db file does not exist:
AccDB.test() Database file: C:\Documents and Settings\Kirchhoff\My Documents\Python\AccDB\AccDB.fs The database file does not exist, Will be created new now! DB Created, now creating ledger anew ! Created new DB & ledger, congrats ! (True, 'Opened:C:\\Documents and Settings\\Kirchhoff\\My Documents\\Python\\AccDB\\AccDB.fs') (True, 'Closed')
The functions, ledger_create: Creates a new DB and a basic ledger in dictionary form and closes the ledger. ledger_open: Opens an existing ledger. ledger_close: Closes an existing ledger. I am 100% sure that the code is executed, because all functions perform basic entry checks and do abort if they can not find a valid ledger structure in place. On top, the function basic_validation() performs an extensive validation of the infrastructure, so that the code would abort with an error message, if the ledgers were not correctly created: def __init__(self): # Defines variables to be used throughout the instance, while the # session is in place. # self.mountedDB = 'C:\Documents and Settings\Kirchhoff\My Documents\Python\AccDB\AccDB.fs' self.cust_acc = '' self.fin_yr = '' self.open = '' self.maxper = 13 self.periods = ','.join(map(str,range(1,self.maxper+1))) self.open_per = '' self.closed_pers = [] self.user = '' def mount_db(self, flag=False): """ Mounts the accounting database.""" # Check that my DB exists. This is the default. However, when the very first ledger is created, # Zope must create a DB and for this, the check must be skipped. if flag == False: r = hkToolBox.Test_File(self.mountedDB,'w') if r == False: r = hkToolBox.Test_File(self.mountedDB, 'e') if r == False : return(False,[2,'File does not exist']) else : return(False,[1,'File can not be opened for writing']) # Mount DB: # Note: If you have an error in this section, upon re-run it is likely # that the db is still locked and that FileStorage wil fail, because no connection.close() was executed. # Solution: End python and restart python. self.st = FileStorage.FileStorage(self.mountedDB) self.db = DB(self.st) self.connection = self.db.open() self.dbroot = self.connection.root() #self.dbroot = OOBTree() I found that when you define # entire root as OOBTree on every start # data is not stored. return (True,'db mounted:'+ self.mountedDB) def unmount_db(self): """ Unmounts the database. This is required to free the locking that ZODB tracks in its lock table.""" get_transaction().commit() # commit any changes that may be pending. self.connection.close() self.db.close() self.st.close() def ledger_create(self,CstNo,FY): """Creates a new ledger for a customer and a new financial year.""" #Input Validation: CstNo & FY must be strings. # Input validation: if type(CstNo) <> str : return(False,[1000,'CstNo no string']) if type(FY) <> str : return(False,[1001,'FY must be string']) r = self.mount_db() if r[0] == False : return(False,r[1]) # Ensure that this account and financial year does not exist: if self.dbroot.has_key(CstNo) == True : if self.dbroot[CstNo].has_key(FY) == True : self.unmount_db() ; return(False, FY+' exist for '+CstNo) else : # if CstNo sub-branch does not exist self.dbroot[CstNo] = OOBTree() # Only define the OOBTree once, upon creation. self._p_changed = 1 get_transaction().commit() # Since neither this FY or neither this FY nor CstNo do exist, create base ledger: # Note: This ledger must pass the basic_validation() ! zero=chr(0)+chr(0)+chr(0)+chr(0) # Set up basic infrastructure self.dbroot[CstNo] = { FY :{} } self.dbroot[CstNo] [FY] = { 'ini' : {} , 'accper' : {} } self.dbroot[CstNo] [FY] ['ini'] ['lastE'] = zero self.dbroot[CstNo] [FY] ['ini'] ['lastS'] = zero self.dbroot[CstNo] [FY] ['ini'] ['locked'] = '' self.dbroot[CstNo] [FY] ['ini'] ['closed'] = [] self.dbroot[CstNo] [FY] ['ini'] ['open'] = '1' self.dbroot[CstNo] [FY] ['ini'] ['templ'] = '' self.dbroot[CstNo] [FY] ['1'] = {} self.dbroot[CstNo] [FY] ['1'] ['E'] = {} self.dbroot[CstNo] [FY] ['1'] ['S'] = {} self.dbroot[CstNo] [FY] ['1'] ['accno'] = {} self.dbroot[CstNo] [FY] ['1'] ['acba' ] = {} self._p_changed = 1 get_transaction().commit() # I recommend always to leave validation here, because it ensures that both routines # are always in concordance & will help in future debugging. r = self.basic_validation(CstNo,FY) self.unmount_db() if r[0] == False : return (False, r[1]) return (True,[0,'ledger created ok']) def ledger_open(self,CstNo, FY, User='guest'): """iniializes the class with basic settings.""" # Initializes the database environment. # These variables will be used throughout the instance to access records. # If this ledger does not yet exist, a new one is created. # Returns: # Tuple:(False/True , 'error message if False') #Input Validation if type(CstNo) <> str : return(False,[1000,'CstNo must be string']) if type(FY) <> str : return(False,[1001,'FY must be string']) r = self.mount_db() if r[0] == False : return(False,r[1]) # if you need to validate the user (pathword &c.), do it here. # Verify that DB is not locked. If not, lock it now. if self.dbroot.has_key(CstNo) == False : self.unmount_db() ; return(False, [3,'Customer account does not exist']) if self.dbroot[CstNo].has_key(FY) == False : self.unmount_db() ; return(False, [4,'Financial Year does not exist']) # Test that this branch (Fin Year of Customer) is not in use & reserve: if self.dbroot[CstNo] [FY] ['ini'] ['locked'] <> '' : return(False,[5,self.dbroot[CstNo] [FY] ['ini'] ['locked']]) self.dbroot[CstNo] [FY] ['ini'] ['locked'] = User get_transaction().commit() # Debug: Validate the database: m=self.basic_validation(CstNo,FY) if m[0] == False : self.unmount_db() ; return(False, m[1]) # Set the environment variables for the instance self.cust_acc = CstNo self.fin_yr = FY self.user = User self.open_per = self.dbroot[self.cust_acc] [self.fin_yr] ['ini'] ['open'] self.closed_pers = self.dbroot[self.cust_acc] [self.fin_yr] ['ini'] ['closed'] # ... happy booking ! return(True,'Opened:' + self.mountedDB) def ledger_close(self): """Closes currently opened ledger & unmounts DB.""" # check that environment variables are proper and that branch is actually locked. if self.dbroot.has_key(self.cust_acc) == False : self.unmount_db() ; return(False, [3,'Custumer account does not exist']) if self.dbroot[self.cust_acc].has_key(self.fin_yr) == False : self.unmount_db() ; return(False, [4,'Financial Year does not exist']) # unlock branch u0 = self.dbroot[self.cust_acc] [self.fin_yr] ['ini'] ['locked'] self.dbroot[self.cust_acc] [self.fin_yr] ['ini'] ['locked'] = '' self._p_changed = 1 get_transaction().commit() # unmount DB self.unmount_db() # reset all variables. u1 = self.user self.__init__() # just for checking consistency: if u0 <> u1 : return(False,[6,'User who closed was not same as opened']) return(True, 'Closed') Dieter Maurer <dieter@handshake.de> 2003/11/15 04:50 宛先: Harm_Kirchhoff@mail.digital.co.jp cc: zope@zope.org 件名: Re: [Zope] get_transaction().commit() does not commit Harm_Kirchhoff@mail.digital.co.jp wrote at 2003-11-14 19:28 +0900:
I guess it is another newbie question, but I can not save data to the DB:
I open the DB like this:
self.st = FileStorage.FileStorage(self.mountedDB) self.db = DB(self.st) self.connection = self.db.open() self.dbroot = self.connection.root() self.dbroot = OOBTree() return (True,'db mounted:'+ self.mountedDB)
Next I make a number of changes to self.dbroot:
self.dbroot[CstNo] [FY] ['1'] ['E'] = {}
Are you sure, this code is executed? An "OOBTree" would not allow these operations.
... When I open again and try verify whether the keys exist, using self.dbroot.has_key(CstNo) # for example they do not exist. Looking at the DB with a text editor to see what is in there, reveals that there is nothing. The entire program runs through without any error.
There must be more about which you do not tell us. Somewhere inside this darkness is something that confuses you. -- Dieter
Harm_Kirchhoff@mail.digital.co.jp wrote at 2003-11-17 10:07 +0900:
... I naively thought you simply define the entire DB as an OOBTree,
You can do this, indeed.
but I realized that you only define sub-branches as OOBTrees and only upon creation.
This is possible but not necessary.
I made some changes and now it runs.
Fine.
However, I am puzzled by your comment that an OOBTree does not allow these transactions. How do you open a db with an OOBTree ???
When you report problems to the list, your problem report should be concise and the example code should produce the described problem. This was not the case with your example code. It would never have shown the problem you described (as instead, it had raised an "KeyError"). The correct way would have been to make a minimal example reproducing the problem and then post this example.
... if you want the full code, because there is something fundamentally strange, let me know I can mail it directly.):
I am never interested in full code -- just in (minimal!) code that reproduces the wrong (!) behaviour (and not some other problem). And only, in order to help you... Once, you have solved your problem, I am no longer interested in it *UNLESS* I indicated that I am very surprised about what you reported. -- Dieter
participants (2)
-
Dieter Maurer -
Harm_Kirchhoff@mail.digital.co.jp