0001 #!/bin/env python 0002 #------------------------------------------------------------------------ 0003 # Copyright (c) 1997-2001 by Total Control Software 0004 # All Rights Reserved 0005 #------------------------------------------------------------------------ 0006 # 0007 # Module Name: dbShelve.py 0008 # 0009 # Description: A reimplementation of the standard shelve.py that 0010 # forces the use of cPickle, and DB. 0011 # 0012 # Creation Date: 11/3/97 3:39:04PM 0013 # 0014 # License: This is free software. You may use this software for any 0015 # purpose including modification/redistribution, so long as 0016 # this header remains intact and that you do not claim any 0017 # rights of ownership or authorship of this software. This 0018 # software has been tested, but no warranty is expressed or 0019 # implied. 0020 # 0021 # 13-Dec-2000: Updated to be used with the new bsddb3 package. 0022 # Added DBShelfCursor class. 0023 # 0024 #------------------------------------------------------------------------ 0025 0026 """Manage shelves of pickled objects using bsddb database files for the 0027 storage. 0028 """ 0029 0030 #------------------------------------------------------------------------ 0031 0032 import cPickle 0033 try: 0034 from UserDict import DictMixin 0035 except ImportError: 0036 # DictMixin is new in Python 2.3 0037 class DictMixin: pass 0038 import db 0039 0040 #------------------------------------------------------------------------ 0041 0042 0043 def open(filename, flags=db.DB_CREATE, mode=0660, filetype=db.DB_HASH, 0044 dbenv=None, dbname=None): 0045 """ 0046 A simple factory function for compatibility with the standard 0047 shleve.py module. It can be used like this, where key is a string 0048 and data is a pickleable object: 0049 0050 from bsddb import dbshelve 0051 db = dbshelve.open(filename) 0052 0053 db[key] = data 0054 0055 db.close() 0056 """ 0057 if type(flags) == type(''): 0058 sflag = flags 0059 if sflag == 'r': 0060 flags = db.DB_RDONLY 0061 elif sflag == 'rw': 0062 flags = 0 0063 elif sflag == 'w': 0064 flags = db.DB_CREATE 0065 elif sflag == 'c': 0066 flags = db.DB_CREATE 0067 elif sflag == 'n': 0068 flags = db.DB_TRUNCATE | db.DB_CREATE 0069 else: 0070 raise db.DBError, "flags should be one of 'r', 'w', 'c' or 'n' or use the bsddb.db.DB_* flags" 0071 0072 d = DBShelf(dbenv) 0073 d.open(filename, dbname, filetype, flags, mode) 0074 return d 0075 0076 #--------------------------------------------------------------------------- 0077 0078 class DBShelf(DictMixin): 0079 """A shelf to hold pickled objects, built upon a bsddb DB object. It 0080 automatically pickles/unpickles data objects going to/from the DB. 0081 """ 0082 def __init__(self, dbenv=None): 0083 self.db = db.DB(dbenv) 0084 self.binary = 1 0085 0086 0087 def __del__(self): 0088 self.close() 0089 0090 0091 def __getattr__(self, name): 0092 """Many methods we can just pass through to the DB object. 0093 (See below) 0094 """ 0095 return getattr(self.db, name) 0096 0097 0098 #----------------------------------- 0099 # Dictionary access methods 0100 0101 def __len__(self): 0102 return len(self.db) 0103 0104 0105 def __getitem__(self, key): 0106 data = self.db[key] 0107 return cPickle.loads(data) 0108 0109 0110 def __setitem__(self, key, value): 0111 data = cPickle.dumps(value, self.binary) 0112 self.db[key] = data 0113 0114 0115 def __delitem__(self, key): 0116 del self.db[key] 0117 0118 0119 def keys(self, txn=None): 0120 if txn != None: 0121 return self.db.keys(txn) 0122 else: 0123 return self.db.keys() 0124 0125 0126 def items(self, txn=None): 0127 if txn != None: 0128 items = self.db.items(txn) 0129 else: 0130 items = self.db.items() 0131 newitems = [] 0132 0133 for k, v in items: 0134 newitems.append( (k, cPickle.loads(v)) ) 0135 return newitems 0136 0137 def values(self, txn=None): 0138 if txn != None: 0139 values = self.db.values(txn) 0140 else: 0141 values = self.db.values() 0142 0143 return map(cPickle.loads, values) 0144 0145 #----------------------------------- 0146 # Other methods 0147 0148 def __append(self, value, txn=None): 0149 data = cPickle.dumps(value, self.binary) 0150 return self.db.append(data, txn) 0151 0152 def append(self, value, txn=None): 0153 if self.get_type() != db.DB_RECNO: 0154 self.append = self.__append 0155 return self.append(value, txn=txn) 0156 raise db.DBError, "append() only supported when dbshelve opened with filetype=dbshelve.db.DB_RECNO" 0157 0158 0159 def associate(self, secondaryDB, callback, flags=0): 0160 def _shelf_callback(priKey, priData, realCallback=callback): 0161 data = cPickle.loads(priData) 0162 return realCallback(priKey, data) 0163 return self.db.associate(secondaryDB, _shelf_callback, flags) 0164 0165 0166 #def get(self, key, default=None, txn=None, flags=0): 0167 def get(self, *args, **kw): 0168 # We do it with *args and **kw so if the default value wasn't 0169 # given nothing is passed to the extension module. That way 0170 # an exception can be raised if set_get_returns_none is turned 0171 # off. 0172 data = apply(self.db.get, args, kw) 0173 try: 0174 return cPickle.loads(data) 0175 except (TypeError, cPickle.UnpicklingError): 0176 return data # we may be getting the default value, or None, 0177 # so it doesn't need unpickled. 0178 0179 def get_both(self, key, value, txn=None, flags=0): 0180 data = cPickle.dumps(value, self.binary) 0181 data = self.db.get(key, data, txn, flags) 0182 return cPickle.loads(data) 0183 0184 0185 def cursor(self, txn=None, flags=0): 0186 c = DBShelfCursor(self.db.cursor(txn, flags)) 0187 c.binary = self.binary 0188 return c 0189 0190 0191 def put(self, key, value, txn=None, flags=0): 0192 data = cPickle.dumps(value, self.binary) 0193 return self.db.put(key, data, txn, flags) 0194 0195 0196 def join(self, cursorList, flags=0): 0197 raise NotImplementedError 0198 0199 0200 #---------------------------------------------- 0201 # Methods allowed to pass-through to self.db 0202 # 0203 # close, delete, fd, get_byteswapped, get_type, has_key, 0204 # key_range, open, remove, rename, stat, sync, 0205 # upgrade, verify, and all set_* methods. 0206 0207 0208 #--------------------------------------------------------------------------- 0209 0210 class DBShelfCursor: 0211 """ 0212 """ 0213 def __init__(self, cursor): 0214 self.dbc = cursor 0215 0216 def __del__(self): 0217 self.close() 0218 0219 0220 def __getattr__(self, name): 0221 """Some methods we can just pass through to the cursor object. (See below)""" 0222 return getattr(self.dbc, name) 0223 0224 0225 #---------------------------------------------- 0226 0227 def dup(self, flags=0): 0228 return DBShelfCursor(self.dbc.dup(flags)) 0229 0230 0231 def put(self, key, value, flags=0): 0232 data = cPickle.dumps(value, self.binary) 0233 return self.dbc.put(key, data, flags) 0234 0235 0236 def get(self, *args): 0237 count = len(args) # a method overloading hack 0238 method = getattr(self, 'get_%d' % count) 0239 apply(method, args) 0240 0241 def get_1(self, flags): 0242 rec = self.dbc.get(flags) 0243 return self._extract(rec) 0244 0245 def get_2(self, key, flags): 0246 rec = self.dbc.get(key, flags) 0247 return self._extract(rec) 0248 0249 def get_3(self, key, value, flags): 0250 data = cPickle.dumps(value, self.binary) 0251 rec = self.dbc.get(key, flags) 0252 return self._extract(rec) 0253 0254 0255 def current(self, flags=0): return self.get_1(flags|db.DB_CURRENT) 0256 def first(self, flags=0): return self.get_1(flags|db.DB_FIRST) 0257 def last(self, flags=0): return self.get_1(flags|db.DB_LAST) 0258 def next(self, flags=0): return self.get_1(flags|db.DB_NEXT) 0259 def prev(self, flags=0): return self.get_1(flags|db.DB_PREV) 0260 def consume(self, flags=0): return self.get_1(flags|db.DB_CONSUME) 0261 def next_dup(self, flags=0): return self.get_1(flags|db.DB_NEXT_DUP) 0262 def next_nodup(self, flags=0): return self.get_1(flags|db.DB_NEXT_NODUP) 0263 def prev_nodup(self, flags=0): return self.get_1(flags|db.DB_PREV_NODUP) 0264 0265 0266 def get_both(self, key, value, flags=0): 0267 data = cPickle.dumps(value, self.binary) 0268 rec = self.dbc.get_both(key, flags) 0269 return self._extract(rec) 0270 0271 0272 def set(self, key, flags=0): 0273 rec = self.dbc.set(key, flags) 0274 return self._extract(rec) 0275 0276 def set_range(self, key, flags=0): 0277 rec = self.dbc.set_range(key, flags) 0278 return self._extract(rec) 0279 0280 def set_recno(self, recno, flags=0): 0281 rec = self.dbc.set_recno(recno, flags) 0282 return self._extract(rec) 0283 0284 set_both = get_both 0285 0286 def _extract(self, rec): 0287 if rec is None: 0288 return None 0289 else: 0290 key, data = rec 0291 return key, cPickle.loads(data) 0292 0293 #---------------------------------------------- 0294 # Methods allowed to pass-through to self.dbc 0295 # 0296 # close, count, delete, get_recno, join_item 0297 0298 0299 #--------------------------------------------------------------------------- 0300
Generated by PyXR 0.9.4