diff roundup/backends/back_metakit.py @ 2711:6b18005c3bb4

addclass(): variable 'cn' (class name) was not initialized. __open(): self.config is not a module anymore. use config['HOME'] instead of config.__file__ to find tracker home directory; check new-style schema file first. trim trailing spaces; add vim modeline
author Alexander Smishlajev <a1s@users.sourceforge.net>
date Wed, 29 Sep 2004 10:19:40 +0000
parents d68a444fcce3
children 330261e53766
line wrap: on
line diff
--- a/roundup/backends/back_metakit.py	Wed Sep 29 09:34:26 2004 +0000
+++ b/roundup/backends/back_metakit.py	Wed Sep 29 10:19:40 2004 +0000
@@ -1,4 +1,4 @@
-# $Id: back_metakit.py,v 1.84 2004-07-28 05:00:31 richard Exp $
+# $Id: back_metakit.py,v 1.85 2004-09-29 10:19:40 a1s Exp $
 '''Metakit backend for Roundup, originally by Gordon McMillan.
 
 Known Current Bugs:
@@ -32,7 +32,7 @@
 - Metakit relies in reference counting to close the database, there is
   no explicit close call.  This can cause issues if a metakit
   database is referenced multiple times, one might not actually be
-  closing the db.                                    
+  closing the db.
 - probably a bunch of stuff that I'm not aware of yet because I haven't
   fully read through the source. One of these days....
 '''
@@ -137,7 +137,7 @@
             raise KeyError, 'There is no class called "%s"'%classname
     def getclasses(self):
         return self.classes.keys()
-    # --- end of ping's spec 
+    # --- end of ping's spec
 
     # --- exposed methods
     def commit(self):
@@ -185,17 +185,18 @@
     def addclass(self, cl):
         ''' Add a Class to the hyperdatabase.
         '''
-        self.classes[cl.classname] = cl
-        if self.tables.find(name=cl.classname) < 0:
-            self.tables.append(name=cl.classname)
+        cn = cl.classname
+        self.classes[cn] = cl
+        if self.tables.find(name=cn) < 0:
+            self.tables.append(name=cn)
 
         # add default Edit and View permissions
         self.security.addPermission(name="Create", klass=cn,
             description="User is allowed to create "+cn)
-        self.security.addPermission(name="Edit", klass=cl.classname,
-            description="User is allowed to edit "+cl.classname)
-        self.security.addPermission(name="View", klass=cl.classname,
-            description="User is allowed to access "+cl.classname)
+        self.security.addPermission(name="Edit", klass=cn,
+            description="User is allowed to edit "+cn)
+        self.security.addPermission(name="View", klass=cn,
+            description="User is allowed to access "+cn)
 
     def addjournal(self, tablenm, nodeid, action, params, creator=None,
                    creation=None):
@@ -271,7 +272,7 @@
         nodeid = int(nodeid)
         tblid = self.tables.find(name=tablenm)
         if tblid == -1:
-            return 
+            return
         i = 0
         hist = self.hist
         while i < len(hist):
@@ -280,7 +281,7 @@
             else:
                 i = i + 1
         self.dirty = 1
-        
+
     def close(self):
         ''' Close off the connection.
         '''
@@ -323,17 +324,17 @@
         self.fastopen = 0
         if os.path.exists(db):
             dbtm = os.path.getmtime(db)
-            pkgnm = self.config.__name__.split('.')[0]
-            schemamod = sys.modules.get(pkgnm+'.dbinit', None)
-            if schemamod:
-                if os.path.exists(schemamod.__file__):
-                    schematm = os.path.getmtime(schemamod.__file__)
-                    if schematm < dbtm:
-                        # found schema mod - it's older than the db
-                        self.fastopen = 1
-                else:
-                     # can't find schemamod - must be frozen
+            schemafile = os.path.join(self.config['HOME'], 'schema.py')
+            if not os.path.isfile(schemafile):
+                # try old-style schema
+                schemafile = os.path.join(self.config['HOME'], 'dbinit.py')
+            if os.path.isfile(schemafile):
+                if os.path.getmtime(schemafile) < dbtm:
+                    # found schema mod - it's older than the db
                     self.fastopen = 1
+            else:
+                 # can't find schemamod - must be frozen
+                self.fastopen = 1
 
         # open the db
         db = metakit.storage(db, 1)
@@ -363,7 +364,7 @@
         '''
         files_dir = os.path.join(self.config.DATABASE, 'files')
         return files_in_dir(files_dir)
-        
+
 _STRINGTYPE = type('')
 _LISTTYPE = type([])
 _CREATE, _SET, _RETIRE, _LINK, _UNLINK, _RESTORE = range(6)
@@ -392,7 +393,7 @@
 
 class Class(hyperdb.Class):
     ''' The handle to a particular class of nodes in a hyperdatabase.
-        
+
         All methods except __repr__ and getnode must be implemented by a
         concrete backend Class of which this is one.
     '''
@@ -438,7 +439,7 @@
 
     def setid(self, maxid):
         self.maxid = maxid + 1
-        
+
     def enableJournalling(self):
         '''Turn journalling on for this class
         '''
@@ -448,7 +449,7 @@
         '''Turn journalling off for this class
         '''
         self.do_journal = 0
-        
+
     #
     # Detector/reactor interface
     #
@@ -477,7 +478,7 @@
         '''
         for react in self.reactors[action]:
             react(self.db, self, nodeid, oldvalues)
-            
+
     # --- the hyperdb.Class methods
     def create(self, **propvalues):
         ''' Create a new node of this class and return its id.
@@ -486,13 +487,13 @@
 
         The values of arguments must be acceptable for the types of their
         corresponding properties or a TypeError is raised.
-        
+
         If this class has a key property, it must be present and its value
         must not collide with other key strings or a ValueError is raised.
-        
+
         Any other properties on this class that are missing from the
         'propvalues' dictionary are set to None.
-        
+
         If an id in a link or multilink property does not refer to a valid
         node, an IndexError is raised.
         '''
@@ -517,7 +518,7 @@
            self.maxid -= 1
            raise
        return str(newid)
-    
+
     def get(self, nodeid, propname, default=_marker, cache=1):
         '''Get the value of a property on an existing node of this class.
 
@@ -557,10 +558,10 @@
         if converter:
             raw = converter(raw)
         return raw
-        
+
     def set(self, nodeid, **propvalues):
         '''Modify a property on an existing node of this class.
-        
+
         'nodeid' must be the id of an existing node of this class or an
         IndexError is raised.
 
@@ -621,7 +622,7 @@
             if  value == oldvalue:
                 del propvalues[key]
                 continue
-            
+
             # check to make sure we're not duplicating an existing key
             if key == self.key:
                 iv = self.getindexview(READWRITE)
@@ -644,7 +645,7 @@
                         key)
                 # Roundup sets to "unselected" by passing None
                 if value is None:
-                    value = 0   
+                    value = 0
                 # if it isn't a number, it's a key
                 try:
                     int(value)
@@ -661,7 +662,7 @@
 
                 setattr(row, key, int(value))
                 changes[key] = oldvalue
-                
+
                 if self.do_journal and prop.do_journal:
                     # register the unlink with the old linked node
                     if oldvalue:
@@ -785,7 +786,7 @@
                     setattr(row, key, value.serialise())
                 changes[key] = str(oldvalue)
                 propvalues[key] = str(value)
- 
+
             elif isinstance(prop, hyperdb.Number):
                 if value is None:
                     v = 0
@@ -838,13 +839,13 @@
                 self.db.addjournal(self.classname, nodeid, _SET, changes)
 
         return propvalues, oldnode
-    
+
     def retire(self, nodeid):
         '''Retire a node.
-        
+
         The properties on the node remain available from the get() method,
         and the node's id is never reused.
-        
+
         Retired nodes are not returned by the find(), list(), or lookup()
         methods, and other nodes may reuse the values of their key properties.
         '''
@@ -886,7 +887,7 @@
         # check if key property was overrided
         key = self.getkey()
         keyvalue = self.get(nodeid, key)
-        
+
         try:
             id = self.lookup(keyvalue)
         except KeyError:
@@ -940,7 +941,7 @@
 
         'date' is a Timestamp object specifying the time of the change and
         'tag' is the journaltag specified when the database was opened.
-        '''        
+        '''
         if not self.do_journal:
             raise ValueError, 'Journalling is disabled for this class'
         return self.db.getjournal(self.classname, nodeid)
@@ -959,7 +960,7 @@
                 # drop the old key table
                 tablename = "_%s.%s"%(self.classname, self.key)
                 self.db._db.getas(tablename)
-                
+
             #raise ValueError, "%s already indexed on %s"%(self.classname,
             #    self.key)
 
@@ -976,11 +977,11 @@
         # exists then everything is okay.  If this table
         # doesn't exist, then generate a new table on the
         # key value.
-        
+
         # first setkey for this run or key has been changed
         self.key = propname
         tablename = "_%s.%s"%(self.classname, self.key)
-        
+
         iv = self.db._db.view(tablename)
         if self.db.fastopen and iv.structure():
             return
@@ -1007,7 +1008,7 @@
         '''
         if not self.key:
             raise TypeError, 'No key property set for class %s'%self.classname
-        
+
         if type(keyvalue) is not _STRINGTYPE:
             raise TypeError, '%r is not a string'%keyvalue
 
@@ -1046,7 +1047,7 @@
 
     def destroy(self, id):
         '''Destroy a node.
-        
+
         WARNING: this method should never be used except in extremely rare
                  situations where there could never be links to the node being
                  deleted
@@ -1077,12 +1078,12 @@
             view.delete(ndx)
             self.db.destroyjournal(self.classname, id)
             self.db.dirty = 1
-        
+
     def find(self, **propspec):
         '''Get the ids of nodes in this class which link to the given nodes.
 
         'propspec'
-             consists of keyword args propname={nodeid:1,}   
+             consists of keyword args propname={nodeid:1,}
         'propname'
              must be the name of a property in this class, or a
              KeyError is raised.  That property must be a Link or
@@ -1145,7 +1146,7 @@
         for row in view:
             rslt.append(str(row.id))
         return rslt
-            
+
 
     def list(self):
         ''' Return a list of the ids of the active nodes in this class.
@@ -1158,7 +1159,7 @@
     def getnodeids(self):
         ''' Retrieve all the ids of the nodes for a particular Class.
 
-            Set retired=None to get all nodes. Otherwise it'll get all the 
+            Set retired=None to get all nodes. Otherwise it'll get all the
             retired or non-retired nodes, depending on the flag.
         '''
         l = []
@@ -1204,7 +1205,7 @@
         The filter must match all properties specificed - but if the
         property value to match is a list, any one of the values in the
         list may match for that property to match.
-        '''        
+        '''
         if __debug__:
             start_t = time.time()
 
@@ -1293,7 +1294,7 @@
                         wherehigh[propname] = None
                 except ValueError:
                     # If range creation fails - ignore that search parameter
-                    pass                        
+                    pass
             elif isinstance(prop, hyperdb.Interval):
                 try:
                     # Try to filter on range of intervals
@@ -1312,7 +1313,7 @@
                         wherehigh[propname] = None
                 except ValueError:
                     # If range creation fails - ignore that search parameter
-                    pass                        
+                    pass
             elif isinstance(prop, hyperdb.Number):
                 where[propname] = int(value)
             else:
@@ -1337,7 +1338,7 @@
                 return 0
             iv = v.filter(ff)
             v = v.remapwith(iv)
-        
+
         if orcriteria:
             def ff(row, crit=orcriteria):
                 for propname, allowed in crit.items():
@@ -1345,10 +1346,10 @@
                     if val not in allowed:
                         return 0
                 return 1
-            
+
             iv = v.filter(ff)
             v = v.remapwith(iv)
-        
+
         if regexes:
             def ff(row, r=regexes):
                 for propname, regex in r.items():
@@ -1356,10 +1357,10 @@
                     if not regex.search(val):
                         return 0
                 return 1
-            
+
             iv = v.filter(ff)
             v = v.remapwith(iv)
-        
+
         if sort or group:
             sortspec = []
             rev = []
@@ -1393,7 +1394,7 @@
                     rev.append(prop)
                 sortspec.append(prop)
             v = v.sortrev(sortspec, rev)[:] #XXX Metakit bug
-            
+
         rslt = []
         for row in v:
             id = str(row.id)
@@ -1407,12 +1408,12 @@
             self.db.stats['filtering'] += (time.time() - start_t)
 
         return rslt
-    
+
     def hasnode(self, nodeid):
         '''Determine if the given nodeid actually exists
         '''
         return int(nodeid) < self.maxid
-    
+
     def labelprop(self, default_to_id=0):
         '''Return the property name for a label for the given node.
 
@@ -1443,7 +1444,7 @@
         properties in a caseless search.
 
         If the property is not a String property, a TypeError is raised.
-        
+
         The return is a list of the id of all nodes that match.
         '''
         for propname in requirements.keys():
@@ -1452,7 +1453,7 @@
                 raise TypeError, "'%s' not a String property"%propname
             requirements[propname] = requirements[propname].lower()
         requirements['_isdel'] = 0
-        
+
         l = []
         for row in self.getview().select(requirements):
             l.append(str(row.id))
@@ -1487,7 +1488,7 @@
         self.comactions = []
         self.rbactions = []
         self.idcache = {}
-    def _rollback(self):  
+    def _rollback(self):
         ''' called pre rollback of the DB.
             interested subclasses may override '''
         self.comactions = []
@@ -1525,11 +1526,11 @@
 
         # if we have structure in the database, and the structure hasn't
         # changed
-        # note on view.ordered ->        
+        # note on view.ordered ->
         # return a metakit view ordered on the id column
         # id is always the first column.  This speeds up
         # look-ups on the id column.
-        
+
         if mkprops and self.db.fastopen:
             return view.ordered(1)
 
@@ -1612,7 +1613,7 @@
         l.append(repr(self.is_retired(nodeid)))
 
         return l
-        
+
     def import_list(self, propnames, proplist):
         ''' Import a node - all information including "id" is present and
             should not be sanity checked. Triggers are not triggered. The
@@ -1718,7 +1719,7 @@
 
     def import_journals(self, entries):
         '''Import a class's journal.
-        
+
         Uses setjournal() to set the journal for each item.'''
         properties = self.getprops()
         d = {}
@@ -1797,7 +1798,7 @@
         if not bool: res = None
         else: res = bool - 1
         return res
-    
+
     def getNumber(number):
         if number == 0: res = None
         elif number < 0: res = number
@@ -1813,10 +1814,10 @@
     hyperdb.Boolean   : getBoolean,
     hyperdb.Number    : getNumber,
     hyperdb.String    : lambda s: s and str(s) or None,
-}                
+}
 
 class FileName(hyperdb.String):
-    isfilename = 1            
+    isfilename = 1
 
 _typmap = {
     FileName : 'S',
@@ -1972,7 +1973,7 @@
             mime_type = self.default_mime_type
         self.db.indexer.add_text((self.classname, nodeid, 'content'),
             str(self.get(nodeid, 'content')), mime_type)
- 
+
 class IssueClass(Class, roundupdb.IssueClass):
     ''' The newly-created class automatically includes the "messages",
         "files", "nosy", and "superseder" properties.  If the 'properties'
@@ -1993,7 +1994,7 @@
         if not properties.has_key('superseder'):
             properties['superseder'] = hyperdb.Multilink(classname)
         Class.__init__(self, db, classname, **properties)
-        
+
 CURVERSION = 2
 
 class Indexer(Indexer):
@@ -2024,7 +2025,7 @@
         '''close the indexing database'''
         del self.db
         self.db = None
-  
+
     def force_reindex(self):
         '''Force a reindexing of the database.  This essentially
         empties the tables ids and index and sets a flag so
@@ -2077,7 +2078,7 @@
             if not self.disallows.has_key(word):
                 words[word] = 1
         words = words.keys()
-        
+
         index = self.db.view('index').ordered(1)
         for word in words:
             ndx = index.find(word=word)
@@ -2091,7 +2092,7 @@
         '''look up all the words in the wordlist.
         If none are found return an empty dictionary
         * more rules here
-        '''        
+        '''
         hits = None
         index = self.db.view('index').ordered(1)
         for word in wordlist:
@@ -2132,3 +2133,4 @@
             self.db = metakit.storage(self.path, 1)
         self.changed = 0
 
+# vim: set et sts=4 sw=4 :

Roundup Issue Tracker: http://roundup-tracker.org/