00001 __copyright__ = """\ 00002 (c). Copyright 1990-2008, Vyper Logix Corp., All Rights Reserved. 00003 00004 Published under Creative Commons License 00005 (http://creativecommons.org/licenses/by-nc/3.0/) 00006 restricted to non-commercial educational use only., 00007 00008 See also: http://www.VyperLogix.com and http://www.pypi.info for details. 00009 00010 THE AUTHOR VYPER LOGIX CORP DISCLAIMS ALL WARRANTIES WITH REGARD TO 00011 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 00012 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, 00013 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 00014 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 00015 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 00016 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! 00017 00018 USE AT YOUR OWN RISK. 00019 """ 00020 00021 import os 00022 import sys 00023 import uuid 00024 import bsddb 00025 import shelve 00026 import types 00027 import marshal 00028 import struct 00029 import re 00030 import pylzma 00031 00032 from struct import pack, unpack 00033 import zlib 00034 00035 from vyperlogix.hash.lists import HashedLists 00036 from vyperlogix.hash.lists import HashedLists2 00037 try: 00038 from pyax.datatype.apexdatetime import ApexDatetime 00039 except ImportError: 00040 from datetime import datetime as ApexDatetime 00041 import traceback 00042 from vyperlogix.enum.Enum import * 00043 from vyperlogix.classes import CooperativeClass 00044 from vyperlogix.misc import _utils 00045 from vyperlogix import misc 00046 from vyperlogix.misc import ObjectTypeName 00047 from vyperlogix.misc.ObjectTypeName import __typeName as ObjectTypeName__typeName 00048 from vyperlogix.hash import lists 00049 00050 from vyperlogix import cerealizer 00051 00052 try: 00053 from cPickle import Pickler, Unpickler 00054 except ImportError: 00055 from pickle import Pickler, Unpickler 00056 00057 try: 00058 from cStringIO import StringIO 00059 except ImportError: 00060 from StringIO import StringIO 00061 00062 dbx_name = lambda name,data_path:os.sep.join([data_path,'.'.join([os.path.basename(name.split('.')[0]),'dbx'])]) 00063 00064 ## 00065 # 00066 # Encrypt/decrypt variable length string using XTEA cypher as 00067 # key generator (OFB mode) 00068 # * key = 128 bit (16 char) 00069 # * iv = 64 bit (8 char) 00070 # * data = string (any length) 00071 # 00072 # >>> import os 00073 # >>> key = os.urandom(16) 00074 # >>> iv = os.urandom(8) 00075 # >>> data = os.urandom(10000) 00076 # >>> z = crypt(key,data,iv) 00077 # >>> crypt(key,z,iv) == data 00078 # True 00079 # 00080 # 00081 def crypt(key,data,iv='\00\00\00\00\00\00\00\00',n=32): 00082 def keygen(key,iv,n): 00083 while True: 00084 iv = xtea_encrypt(key,iv,n) 00085 for k in iv: 00086 yield ord(k) 00087 xor = [ chr(x^y) for (x,y) in zip(map(ord,data),keygen(key,iv,n)) ] 00088 return "".join(xor) 00089 00090 ## 00091 # 00092 # Encrypt 64 bit data block using XTEA block cypher 00093 # * key = 128 bit (16 char) 00094 # * block = 64 bit (8 char) 00095 # * n = rounds (default 32) 00096 # * endian = byte order (see 'struct' doc - default big/network) 00097 # 00098 # >>> z = xtea_encrypt('0123456789012345','ABCDEFGH') 00099 # >>> z.encode('hex') 00100 # 'b67c01662ff6964a' 00101 # 00102 # Only need to change byte order if sending/receiving from 00103 # alternative endian implementation 00104 # 00105 # >>> z = xtea_encrypt('0123456789012345','ABCDEFGH',endian="<") 00106 # >>> z.encode('hex') 00107 # 'ea0c3d7c1c22557f' 00108 # 00109 # 00110 def xtea_encrypt(key,block,n=32,endian="!"): 00111 v0,v1 = struct.unpack(endian+"2L",block) 00112 k = struct.unpack(endian+"4L",key) 00113 sum,delta,mask = 0L,0x9e3779b9L,0xffffffffL 00114 for round in range(n): 00115 v0 = (v0 + (((v1<<4 ^ v1>>5) + v1) ^ (sum + k[sum & 3]))) & mask 00116 sum = (sum + delta) & mask 00117 v1 = (v1 + (((v0<<4 ^ v0>>5) + v0) ^ (sum + k[sum>>11 & 3]))) & mask 00118 return struct.pack(endian+"2L",v0,v1) 00119 00120 ## 00121 # 00122 # Decrypt 64 bit data block using XTEA block cypher 00123 # * key = 128 bit (16 char) 00124 # * block = 64 bit (8 char) 00125 # * n = rounds (default 32) 00126 # * endian = byte order (see 'struct' doc - default big/network) 00127 # 00128 # >>> z = 'b67c01662ff6964a'.decode('hex') 00129 # >>> xtea_decrypt('0123456789012345',z) 00130 # 'ABCDEFGH' 00131 # 00132 # Only need to change byte order if sending/receiving from 00133 # alternative endian implementation 00134 # 00135 # >>> z = 'ea0c3d7c1c22557f'.decode('hex') 00136 # >>> xtea_decrypt('0123456789012345',z,endian="<") 00137 # 'ABCDEFGH' 00138 # 00139 # 00140 def xtea_decrypt(key,block,n=32,endian="!"): 00141 v0,v1 = struct.unpack(endian+"2L",block) 00142 k = struct.unpack(endian+"4L",key) 00143 delta,mask = 0x9e3779b9L,0xffffffffL 00144 sum = (delta * n) & mask 00145 for round in range(n): 00146 v1 = (v1 - (((v0<<4 ^ v0>>5) + v0) ^ (sum + k[sum>>11 & 3]))) & mask 00147 sum = (sum - delta) & mask 00148 v0 = (v0 - (((v1<<4 ^ v1>>5) + v1) ^ (sum + k[sum & 3]))) & mask 00149 return struct.pack(endian+"2L",v0,v1) 00150 00151 const_class_symbol = '__class__' 00152 00153 def unique(items): 00154 d = {} 00155 for item in items: 00156 d[item] = 1 00157 return d.keys() 00158 00159 def fileSize(fname): 00160 statinfo = os.stat(fname) 00161 return statinfo.st_size 00162 00163 def fullClassName(obj): 00164 return str(type(obj)).split("'")[1] 00165 00166 def terseClassName(sClassName): 00167 if (misc.isString(sClassName)): 00168 return sClassName.split('.')[-1] 00169 return '' 00170 00171 def obj2Dict(obj): 00172 d = {} 00173 d[const_class_symbol] = fullClassName(obj) 00174 spam = '_%s' % terseClassName(d[const_class_symbol]) 00175 try: 00176 for k,v in obj.__dict__.iteritems(): 00177 d[k.replace(spam,'')] = v 00178 except: 00179 o = [n for n in obj] 00180 o.insert(0,type(obj)) 00181 return obj2Dict(o) 00182 return d 00183 00184 def dict2Obj(value): 00185 obj = value 00186 if (isinstance(value,dict)): 00187 if (value.has_key(const_class_symbol)): 00188 cname = value[const_class_symbol] 00189 try: 00190 toks = cname.split('.') 00191 s = 'from %s import %s\nobj=%s()' % (toks[0],'.'.join(toks[1:-1]),'.'.join(toks[1:])) 00192 exec(s) 00193 except: 00194 obj = None 00195 if (obj): 00196 for k in [n for n in value.keys() if n != const_class_symbol]: 00197 if not n.startswith('__'): 00198 _k = '_%s' % toks[-1] 00199 else: 00200 _k = '%s' % (k) 00201 try: 00202 isQuoted = misc.isString(value[k]) 00203 _quote = '"' if isQuoted else '' 00204 s = 'obj.%s=%s%s%s' % (_k.replace('__',''),_quote,value[k],_quote) 00205 exec(s) 00206 except AttributeError: 00207 pass 00208 return obj 00209 00210 def isAnyAlphaNumeric(token): 00211 for t in token: 00212 if (t.isalnum()): 00213 return True 00214 return False 00215 00216 def isAllNonAlphaNumeric(token): 00217 for t in token: 00218 if (t.isalnum()): 00219 return False 00220 return True 00221 00222 # change a hexadecimal string to decimal number and reverse 00223 # check two different representations of the hexadecimal string 00224 # negative values and zero are accepted 00225 00226 ## 00227 # return the hexadecimal string representation of integer n 00228 def dec2hex(n): 00229 val = '0%X' % n 00230 return val[len(val)-2:] 00231 00232 ## 00233 # return the integer value of a hexadecimal string s 00234 def hex2dec(s): 00235 return int(s, 16) 00236 00237 hex_digits = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'] 00238 00239 def isHexDigits(s): 00240 if (len(s) > 1): 00241 for ch in s: 00242 if (not ch in hex_digits): 00243 return False 00244 return True 00245 return s in hex_digits 00246 00247 _base2hex = [(i,dec2hex(i)) for i in xrange(0,256)] 00248 00249 d_dec2hex = dict(_base2hex) 00250 00251 d_chr2hex = dict([(chr(t[0]),t[-1]) for t in _base2hex]) 00252 00253 d_hex2dec = lists.asDict(d_dec2hex,insideOut=True) 00254 00255 def __init_data__(): 00256 for k,v in d_hex2dec.iteritems(): 00257 d_hex2dec[k] = chr(v) 00258 __init_data__() 00259 00260 def strToHex(str): 00261 return ''.join([d_chr2hex[ch] for ch in str]) 00262 00263 def hexToStr(hex): 00264 return ''.join([d_hex2dec[hex[i:i+2]] for i in xrange(0,len(hex),2)]) 00265 00266 from types import ( 00267 IntType, TupleType, StringType, 00268 FloatType, LongType, ListType, 00269 DictType, NoneType, BooleanType, UnicodeType 00270 ) 00271 00272 class EncodeError(Exception): pass 00273 class DecodeError(Exception): pass 00274 00275 class CompressionOption(Enum): 00276 no_compression = 0 00277 compression = 1 00278 00279 HEADER = "SRW3" 00280 00281 protocol = { 00282 TupleType :"T", 00283 ListType :"L", 00284 DictType :"D", 00285 lists.HashedLists2 :"D", 00286 LongType :"B", 00287 IntType :"I", 00288 FloatType :"F", 00289 StringType :"S", 00290 ApexDatetime :"a", 00291 NoneType :"N", 00292 BooleanType :"b", 00293 UnicodeType :"U" 00294 } 00295 00296 encoder = {} 00297 ## 00298 # Registers an encoder function, for a type, in the global encoder dictionary. 00299 class register_encoder_for_type(object): 00300 def __init__(self, t): 00301 self.type = t 00302 def __call__(self, func): 00303 encoder[self.type] = func 00304 return func 00305 00306 #contains dictionary of decoding functions, where the dictionary key is the type prefix used. 00307 decoder = {} 00308 ## 00309 # Registers a decoder function, for a prefix, in the global decoder dictionary. 00310 class register_decoder_for_type(object): 00311 def __init__(self, t): 00312 self.prefix = protocol[t] 00313 def __call__(self, func): 00314 decoder[self.prefix] = func 00315 return func 00316 00317 ## <encoding functions> ## 00318 @register_encoder_for_type(DictType) 00319 @register_encoder_for_type(lists.HashedLists2) 00320 def enc_dict_type(obj): 00321 data = "".join([encoder[type(i)](i) for i in obj.items()]) 00322 return "%s%s%s" % (protocol[type(obj)], pack("!L", len(data)), data) 00323 00324 @register_encoder_for_type(TupleType) 00325 @register_encoder_for_type(ListType) 00326 def enc_list_type(obj): 00327 data = "".join([encoder[type(i)](i) for i in obj]) 00328 return "%s%s%s" % (protocol[type(obj)], pack("!L", len(data)), data) 00329 00330 @register_encoder_for_type(IntType) 00331 def enc_int_type(obj): 00332 return "%s%s" % (protocol[IntType], pack("!i", obj)) 00333 00334 @register_encoder_for_type(FloatType) 00335 def enc_float_type(obj): 00336 return "%s%s" % (protocol[FloatType], pack("!d", obj)) 00337 00338 @register_encoder_for_type(LongType) 00339 def enc_long_type(obj): 00340 obj = hex(obj)[2:-1] 00341 return "%s%s%s" % (protocol[LongType], pack("!L", len(obj)), obj) 00342 00343 @register_encoder_for_type(UnicodeType) 00344 def enc_unicode_type(obj): 00345 obj = obj.encode('utf-8') 00346 return "%s%s%s" % (protocol[UnicodeType], pack("!L", len(obj)), obj) 00347 00348 @register_encoder_for_type(StringType) 00349 def enc_string_type(obj): 00350 return "%s%s%s" % (protocol[StringType], pack("!L", len(obj)), obj) 00351 00352 @register_encoder_for_type(ApexDatetime) 00353 def enc_apex_datetime_type(obj): 00354 obj = str(obj) 00355 return "%s%s%s" % (protocol[ApexDatetime], pack("!L", len(obj)), obj) 00356 00357 @register_encoder_for_type(NoneType) 00358 def enc_none_type(obj): 00359 return protocol[NoneType] 00360 00361 @register_encoder_for_type(BooleanType) 00362 def enc_bool_type(obj): 00363 return protocol[BooleanType] + str(int(obj)) 00364 00365 ## 00366 # Encode simple Python types into a binary string. 00367 def dumps(obj, compress=CompressionOption.no_compression, phase=1): 00368 option = "N" if compress.value == CompressionOption.no_compression.value else "Z" 00369 try: 00370 data = encoder[type(obj)](obj) 00371 if compress.value == CompressionOption.compression.value: data = zlib.compress(data) 00372 return "%s%s%s" % (HEADER, option, data) 00373 except KeyError, e: 00374 if (phase == 1): 00375 try: 00376 data = obj2Dict(obj) 00377 return dumps(data,compress,phase+1) 00378 except: 00379 raise EncodeError, "Type not supported. (%s) during phase #%2d" % (e,phase) 00380 else: 00381 raise EncodeError, "Type not supported. (%s) during phase #%2d" % (e,phase) 00382 ## </encoding functions> ## 00383 00384 ## <decoding functions> ## 00385 def build_sequence(data, cast=list): 00386 size = unpack('!L', data.read(4))[0] 00387 items = [] 00388 data_tell = data.tell 00389 data_read = data.read 00390 items_append = items.append 00391 start_position = data.tell() 00392 while (data_tell() - start_position) < size: 00393 T = data_read(1) 00394 value = decoder[T](data) 00395 items_append(value) 00396 return cast(items) 00397 00398 @register_decoder_for_type(TupleType) 00399 def dec_tuple_type(data): 00400 return build_sequence(data, cast=tuple) 00401 00402 @register_decoder_for_type(ListType) 00403 def dec_list_type(data): 00404 return build_sequence(data, cast=list) 00405 00406 @register_decoder_for_type(DictType) 00407 def dec_dict_type(data): 00408 return build_sequence(data, cast=dict) 00409 00410 @register_decoder_for_type(lists.HashedLists2) 00411 def dec_HashedLists2_type(data): 00412 return build_sequence(data, cast=lists.HashedLists2) 00413 00414 @register_decoder_for_type(LongType) 00415 def dec_long_type(data): 00416 size = unpack('!L', data.read(4))[0] 00417 value = long(data.read(size),16) 00418 return value 00419 00420 @register_decoder_for_type(StringType) 00421 def dec_string_type(data): 00422 size = unpack('!L', data.read(4))[0] 00423 value = str(data.read(size)) 00424 return value 00425 00426 @register_decoder_for_type(ApexDatetime) 00427 def dec_apex_datetime_type(data): 00428 value = dec_string_type(data) 00429 return ApexDatetime.fromSfIso(value.split('+')[0]) 00430 00431 @register_decoder_for_type(FloatType) 00432 def dec_float_type(data): 00433 value = unpack('!d', data.read(8))[0] 00434 return value 00435 00436 @register_decoder_for_type(IntType) 00437 def dec_int_type(data): 00438 value = unpack('!i', data.read(4))[0] 00439 return value 00440 00441 @register_decoder_for_type(NoneType) 00442 def dec_none_type(data): 00443 return None 00444 00445 @register_decoder_for_type(BooleanType) 00446 def dec_bool_type(data): 00447 value = int(data.read(1)) 00448 return bool(value) 00449 00450 @register_decoder_for_type(UnicodeType) 00451 def dec_unicode_type(data): 00452 size = unpack('!L', data.read(4))[0] 00453 value = data.read(size).decode('utf-8') 00454 return value 00455 00456 ## 00457 # 00458 # Decode a binary string into the original Python types. 00459 # 00460 def loads(data,beSilent=False): 00461 buffer = StringIO(data) 00462 header = buffer.read(len(HEADER)) 00463 if (not beSilent): 00464 assert header == HEADER 00465 option = buffer.read(1) 00466 decompress = False 00467 if option == "Z": 00468 buffer = StringIO(zlib.decompress(buffer.read())) 00469 try: 00470 value = decoder[buffer.read(1)](buffer) 00471 except KeyError, e: 00472 raise DecodeError, "Type prefix not supported. (%s)" % e 00473 00474 value = dict2Obj(value) 00475 return value 00476 ## </decoding functions> ## 00477 00478 class PickleMethods(Enum): 00479 none = 0 00480 useBsdDbShelf = 2**0 00481 useStrings = 2**1 00482 useMarshal = 2**2 00483 useSafeSerializer = 2**3 # (+++) this is very slow ! Make this run faster ! 00484 useSimpleJSon = 2**4 00485 useCerealizer = 2**5 00486 useLegacyFileMode = 2**10 # this performs no filename munging - takes the filename given and opens it... 00487 use_lzma = 2**14 00488 use_zlib = 2**15 00489 00490 class NormalizedKeyOptions(Enum): 00491 via_list = 0 00492 via_dict = 1 00493 use_hash1 = 2**14 00494 use_hash2 = 2**15 00495 00496 _class_tag = lambda name:''.join([ch for ch in name if (ch.isupper()) or (ch.isdigit())]) 00497 class_tag = lambda cls:_class_tag(ObjectTypeName__typeName(cls)) 00498 00499 unlistify = lambda item:item if (not misc.isList(item)) else item[0] 00500 00501 ## 00502 # PickledHash is a persistent hash with unique keys, see PickledHash2 for the persistent hash that handles duplicated keys with lists for values. 00503 # 00504 # dbx = PickledHash(fileName, method=PickleMethods.useStrings) 00505 # 00506 # PickleMethods.useBsdDbShelf = 54x 00507 # PickleMethods.useStrings = 26x 00508 # PickleMethods.useSafeSerializer = 4x 00509 # PickleMethods.useMarshal = 1x 00510 # 00511 class PickledHash(CooperativeClass.Cooperative): 00512 def __init__(self, fileName, method=PickleMethods.useStrings): 00513 from vyperlogix.crypto.Encryptors import Encryptors 00514 self.__method = method 00515 self.__isPickleMethodUseStrings = ((method.value & PickleMethods.useStrings.value) != 0) 00516 self.__isPickleMethodUseLZMA = ((method.value & PickleMethods.use_lzma.value) != 0) 00517 self.__isPickleMethodUseBsdDbShelf = ((method.value & PickleMethods.useBsdDbShelf.value) != 0) 00518 self.__isPickleMethodUseMarshal = ((method.value & PickleMethods.useMarshal.value) != 0) 00519 self.__isPickleMethodUseSafeSerializer = ((method.value & PickleMethods.useSafeSerializer.value) != 0) 00520 self.__isPickleMethodUseCerealizer = ((method.value & PickleMethods.useCerealizer.value) != 0) 00521 self.__isPickleMethodUseSimpleJSon = ((method.value & PickleMethods.useSimpleJSon.value) != 0) 00522 self.__isPickleMethodUseZLIB = (not self.isPickleMethodUseLZMA) and ((method.value & PickleMethods.use_zlib.value) != 0) 00523 self.__isPickleMethodUseLegacyFileMode = ((method.value & PickleMethods.useLegacyFileMode.value) != 0) 00524 00525 self.__fileName = fileName 00526 if (not self.isPickleMethodUseLegacyFileMode) and (not isFilenameMungedAlready(fileName)): 00527 self.__fileName = self.tag_filename(fileName) 00528 self.__isOpened = False 00529 00530 self.open() 00531 00532 def tag_classname(self): 00533 return class_tag(self) 00534 00535 def tag_filename(self, fname): 00536 return '%s%s%s_%s.%s' % (os.path.dirname(fname),os.sep,os.path.basename(fname).split('.')[0],self.tag_classname(),os.path.basename(fname).split('.')[-1]) 00537 00538 def __repr__(self): 00539 return '(%s) on "%s" storing %d keys using the "%s" method; issue the appropriate method to turn this object into the string you want this to be however there may be a lot of date once this is done.' % (str(self.__class__),self.fileName,len(self.keys()),str(self.method)) 00540 00541 def method(): 00542 doc = "method" 00543 def fget(self): 00544 return self.__method 00545 return locals() 00546 method = property(**method()) 00547 00548 def isOpened(): 00549 doc = "isOpened" 00550 def fget(self): 00551 return self.__isOpened 00552 return locals() 00553 isOpened = property(**isOpened()) 00554 00555 def fileName(): 00556 doc = "fileName" 00557 def fget(self): 00558 return self.__fileName 00559 return locals() 00560 fileName = property(**fileName()) 00561 00562 def db(): 00563 doc = "db" 00564 def fget(self): 00565 return self.__db 00566 return locals() 00567 db = property(**db()) 00568 00569 def unPickleItem(self,glob): 00570 return Unpickler(StringIO(glob)).load() 00571 00572 def pickleItem(self,glob): 00573 io = StringIO() 00574 Pickler(io, -1).dump(glob) 00575 return io.getvalue() 00576 00577 def unlistify(self,item): 00578 return unlistify(item) 00579 00580 def __getitem__(self, key): 00581 from vyperlogix.crypto.Encryptors import Encryptors 00582 try: 00583 val = self.__db[key] 00584 if (not self.isPickleMethodUseSafeSerializer): 00585 if (self.isPickleMethodUseZLIB): 00586 val = zlib.decompress(val) 00587 elif (self.isPickleMethodUseLZMA): 00588 val = pylzma.decompress(val) 00589 if (self.isPickleMethodUseStrings): 00590 val = val.split(',') 00591 if (len(val) > 1): 00592 val = [tuple(x.split('|')) if x.find('|') > -1 else x for x in val] 00593 elif (self.isPickleMethodUseBsdDbShelf): 00594 val = self.unPickleItem(val) 00595 elif (self.isPickleMethodUseMarshal): 00596 val = marshal.loads(hexToStr(val)) 00597 elif (self.isPickleMethodUseSafeSerializer): 00598 try: 00599 val = loads(val,beSilent=True) 00600 except: 00601 pass 00602 if (isinstance(val,dict)): 00603 d_val = HashedLists2() 00604 d_val.fromDict(val) 00605 val = d_val 00606 elif (self.isPickleMethodUseCerealizer): 00607 val = cerealizer.loads(val) 00608 except Exception, details: 00609 val = 'UNKNOWN value for key (%s) of type "%s" due to ERROR "%s".' % (key,str(key.__class__),str(details)) 00610 return val 00611 00612 def __setitem__(self, key, value): 00613 from vyperlogix.crypto.Encryptors import Encryptors 00614 from vyperlogix.misc import GenPasswd 00615 00616 key = key if (misc.isString(key)) else str(key) 00617 if (self.has_key(key)) and (value == None): 00618 self.__delitem__(key) 00619 else: 00620 if (misc.isList(value)): 00621 value = [v if (not lists.can_asDict(v)) else v.asDict() for v in value] 00622 else: 00623 value = value if (not lists.can_asDict(value)) else value.asDict() 00624 if (self.isPickleMethodUseStrings): 00625 if (not misc.isString(value)): 00626 if not misc.isList(value): 00627 value = list(value) if (not isinstance(value,dict)) else [(k,v) for k,v in value.iteritems()] 00628 val = ['|'.join([str(x) for x in v]) if isinstance(v,tuple) else str(v) for v in value] 00629 if (len(val) > 0): 00630 value = ','.join(val) if (len(val) > 1) else val[0] 00631 else: 00632 value = '' 00633 elif (self.isPickleMethodUseMarshal): 00634 value = strToHex(marshal.dumps(value,2)) 00635 elif (self.isPickleMethodUseBsdDbShelf): 00636 value = self.pickleItem(value) 00637 elif (self.isPickleMethodUseSafeSerializer): 00638 value = dumps(value,CompressionOption.compression) 00639 elif (self.isPickleMethodUseCerealizer): 00640 #cls = eval(ObjectTypeName.typeClassName(value)) 00641 #if (not cerealizer.isRegistered(cls)): 00642 #cerealizer.register(cls) 00643 value = cerealizer.dumps(value) 00644 if (not self.isPickleMethodUseSafeSerializer): 00645 if (self.isPickleMethodUseZLIB): 00646 value = zlib.compress(value,zlib.Z_BEST_COMPRESSION) 00647 elif (self.isPickleMethodUseLZMA): 00648 value = pylzma.compress(value, eos=1) 00649 self.__db[key] = value 00650 00651 def __delitem__(self, key): 00652 del self.__db[key] 00653 00654 def __str__(self): 00655 return self.__repr__() 00656 00657 def __len__(self): 00658 return len(self.keys()) 00659 00660 def has_key(self, key): 00661 return self.__db.has_key(key) 00662 00663 def keys(self): 00664 try: 00665 return self.__db.keys() 00666 except: 00667 pass 00668 return [] 00669 00670 def values(self): 00671 try: 00672 return self.__db.values() 00673 except: 00674 pass 00675 return [] 00676 00677 ## 00678 # 00679 # Get a list of keys sorted in a fashion that allows for easier manipulation - 00680 # padded or normalized to allow sorting to work. 00681 # 00682 # options = see also NormalizedKeyOptions enumeration 00683 # 00684 def normalizedSortedKeys(self,options=NormalizedKeyOptions.via_list): 00685 from vyperlogix.hash import lists 00686 00687 try: 00688 _asDict = options.value & NormalizedKeyOptions.via_dict.value 00689 except: 00690 _asDict = False 00691 00692 try: 00693 _useHash1 = options.value & NormalizedKeyOptions.use_hash1.value 00694 except: 00695 _asDict = False 00696 _useHash1 = False 00697 00698 try: 00699 _useHash2 = options.value & NormalizedKeyOptions.use_hash2.value 00700 except: 00701 _useHash2 = False 00702 00703 _useHash2 = ( (not _useHash1) and (not _useHash2) ) or _useHash2 00704 _useHash1 = False if (_useHash1 and _useHash2) else _useHash1 00705 00706 d_keys = lists.HashedLists() if _useHash1 else lists.HashedLists2() if _useHash2 else {} 00707 00708 def normalizeKey(k,m): 00709 toks = k.split(',') 00710 n = toks[0] 00711 del toks[0] 00712 getLen = lambda m,n:m-len(n) 00713 formatter = lambda p,m,n,f:p % (' '*getLen(m,n),f(n)) 00714 _value = '' 00715 _isString = (misc.isString(n)) 00716 _pattern = '%s%s' if _isString else '%s%d' 00717 _func = str if _isString else int 00718 _value = formatter(_pattern,m,n,_func) 00719 toks.insert(0,_value) 00720 s = ','.join(toks) 00721 if (_asDict): 00722 d_keys[s] = k 00723 return s 00724 00725 l_keys = [len(k.split(',')[0]) for k in self.keys()] 00726 l_keys.sort() 00727 _max_len = l_keys[-1] if len(l_keys) > 0 else 0 00728 _keys = [normalizeKey(k,_max_len) for k in self.keys()] 00729 _keys.sort() 00730 _keys.reverse() 00731 return _keys if (not _asDict) else d_keys 00732 00733 def sync(self): 00734 if (self.isOpened): 00735 self.__db.sync() 00736 00737 def flush(self): 00738 self.sync() 00739 00740 def iteritems(self): 00741 return ((k,self.__getitem__(k)) for k in self.keys()) 00742 00743 def close(self): 00744 if (self.isOpened): 00745 self.__db.close() 00746 self.__isOpened = False 00747 00748 def queryANDitems(self,*args): 00749 recs = set() 00750 for arg in args: 00751 items = [] 00752 if (self.has_key(arg)): 00753 items = self[arg] 00754 if (not misc.isList(items)): 00755 items = [items] 00756 items = set(items) 00757 if len(recs) == 0: 00758 recs = items 00759 else: 00760 recs &= items 00761 return list(recs) 00762 00763 def queryMostlyANDitems(self,*args): 00764 recs = set() 00765 for arg in args: 00766 items = [] 00767 if (self.has_key(arg)): 00768 items = self[arg] 00769 if (not misc.isList(items)): 00770 items = [items] 00771 items = set(items) 00772 if len(recs) == 0: 00773 recs = items 00774 elif len(recs & items) > 0: 00775 recs &= items 00776 return list(recs) 00777 00778 def isPickleMethodUseStrings(): 00779 doc = "isPickleMethodUseStrings boolean" 00780 def fget(self): 00781 return self.__isPickleMethodUseStrings 00782 return locals() 00783 isPickleMethodUseStrings = property(**isPickleMethodUseStrings()) 00784 00785 def isPickleMethodUseBsdDbShelf(): 00786 doc = "isPickleMethodUseBsdDbShelf boolean" 00787 def fget(self): 00788 return self.__isPickleMethodUseBsdDbShelf 00789 return locals() 00790 isPickleMethodUseBsdDbShelf = property(**isPickleMethodUseBsdDbShelf()) 00791 00792 def isPickleMethodUseLZMA(): 00793 doc = "isPickleMethodUseLZMA boolean" 00794 def fget(self): 00795 return self.__isPickleMethodUseLZMA 00796 return locals() 00797 isPickleMethodUseLZMA = property(**isPickleMethodUseLZMA()) 00798 00799 def isPickleMethodUseMarshal(): 00800 doc = "isPickleMethodUseMarshal boolean" 00801 def fget(self): 00802 return self.__isPickleMethodUseMarshal 00803 return locals() 00804 isPickleMethodUseMarshal = property(**isPickleMethodUseMarshal()) 00805 00806 def isPickleMethodUseSafeSerializer(): 00807 doc = "isPickleMethodUseSafeSerializer boolean" 00808 def fget(self): 00809 return self.__isPickleMethodUseSafeSerializer 00810 return locals() 00811 isPickleMethodUseSafeSerializer = property(**isPickleMethodUseSafeSerializer()) 00812 00813 def isPickleMethodUseCerealizer(): 00814 doc = "isPickleMethodUseCerealizer boolean" 00815 def fget(self): 00816 return self.__isPickleMethodUseCerealizer 00817 return locals() 00818 isPickleMethodUseCerealizer = property(**isPickleMethodUseCerealizer()) 00819 00820 def isPickleMethodUseSimpleJSon(): 00821 doc = "isPickleMethodUseSimpleJSon boolean" 00822 def fget(self): 00823 return self.__isPickleMethodUseSimpleJSon 00824 return locals() 00825 isPickleMethodUseSimpleJSon = property(**isPickleMethodUseSimpleJSon()) 00826 00827 def isPickleMethodUseZLIB(): 00828 doc = "isPickleMethodUseZLIB boolean" 00829 def fget(self): 00830 return self.__isPickleMethodUseZLIB 00831 return locals() 00832 isPickleMethodUseZLIB = property(**isPickleMethodUseZLIB()) 00833 00834 def isPickleMethodUseLegacyFileMode(): 00835 doc = "isPickleMethodUseLegacyFileMode boolean" 00836 def fget(self): 00837 return self.__isPickleMethodUseLegacyFileMode 00838 return locals() 00839 isPickleMethodUseLegacyFileMode = property(**isPickleMethodUseLegacyFileMode()) 00840 00841 def open(self): 00842 file_flag = lambda fname:'c' if (not os.path.exists(fname)) else 'rw' 00843 if (not self.isOpened): 00844 if ( (self.isPickleMethodUseStrings) or (self.isPickleMethodUseMarshal) or (self.isPickleMethodUseSafeSerializer) ): 00845 self.__db = bsddb.btopen(self.fileName,file_flag(self.fileName)) 00846 self.__isOpened = True 00847 elif (self.isPickleMethodUseBsdDbShelf): 00848 self.__db = shelve.BsdDbShelf(bsddb.btopen(self.fileName,file_flag(self.fileName)),0,True) 00849 self.__isOpened = True 00850 00851 def reset(self): 00852 self.close() 00853 os.remove(self.fileName) 00854 self.__isOpened = False 00855 self.open() 00856 00857 def dump(self,callback=None): 00858 if (self.isOpened): 00859 import pprint 00860 tName = os.sep.join([os.path.dirname(self.fileName),'.'.join([os.path.basename(self.fileName).split('.')[0],'txt'])]) 00861 fHand = open(tName,'w') 00862 pp = pprint.PrettyPrinter(indent=4,width=80) 00863 print >>fHand, '(%s) :: (%s) :: dbx=(%s)' % (__name__,self.fileName,str(self)) 00864 for k,v in self.iteritems(): 00865 if (callback): 00866 try: 00867 print >>fHand, '%s :: %s' % (k,callback(v)) 00868 except: 00869 print >>fHand, '%s :: %s' % (k,pp.pformat(v)) 00870 print >>fHand 00871 print >>fHand, '='*60 00872 print >>fHand 00873 fHand.flush() 00874 fHand.close() 00875 00876 ## 00877 # PickledHash2 allows keys to be duplicated with values being placed in lists when keys are duplicated. 00878 # 00879 # dbx = PickledHash2(fileName, method=PickleMethods.useStrings) 00880 # 00881 # PickleMethods.useBsdDbShelf = 54x 00882 # PickleMethods.useStrings = 26x 00883 # PickleMethods.useSafeSerializer = 4x 00884 # PickleMethods.useMarshal = 1x 00885 # 00886 class PickledHash2(PickledHash): 00887 def __init__(self, fileName, method=PickleMethods.useBsdDbShelf): 00888 _isProperType = lambda obj:(ObjectTypeName.typeClassName(obj).find('Enum.EnumInstance') > -1) 00889 isProperType = _isProperType(method) 00890 _isProperValue = lambda obj:((obj.value & PickleMethods.useBsdDbShelf.value) != 0) 00891 isProperValue = False 00892 if (isProperType): 00893 isProperValue = _isProperValue(method) 00894 if (not isProperType) or (not isProperValue): 00895 if (not isProperType): 00896 method = PickleMethods.useBsdDbShelf 00897 isProperValue = _isProperValue(method) 00898 if (not isProperValue): 00899 method |= PickleMethods.useBsdDbShelf 00900 return super(PickledHash2, self).__init__(fileName,method) 00901 00902 def __getitem__(self, key): 00903 return [] if (not super(PickledHash2, self).has_key(key)) else super(PickledHash2, self).__getitem__(key) 00904 00905 def __setitem__(self, key, value): 00906 key = key if (misc.isString(key)) else str(key) 00907 if (self.has_key(key)): 00908 bucket = super(PickledHash2, self).__getitem__(key) 00909 if (misc.isList(bucket)): 00910 bucket.append(value) 00911 super(PickledHash2, self).__setitem__(key,bucket) 00912 else: 00913 super(PickledHash2, self).__setitem__(key,[value]) 00914 else: 00915 super(PickledHash2, self).__setitem__(key,value) 00916 00917 ## 00918 # PickledFastHash2 allows keys to be duplicated with values being placed in lists when keys are duplicated. 00919 # 00920 # dbx = PickledFastHash2(fileName) ... uses PickleMethods.useBsdDbShelf because this method runs faster than all the other methods. 00921 # 00922 # Works the same as lists.HashedLists() 00923 # 00924 # PickleMethods.useBsdDbShelf = 54x 00925 # PickleMethods.useStrings = 26x 00926 # PickleMethods.useSafeSerializer = 4x 00927 # PickleMethods.useMarshal = 1x 00928 # 00929 class PickledFastHash2(PickledHash2): 00930 def __init__(self, fileName, method=PickleMethods.useBsdDbShelf): 00931 return super(PickledFastHash2, self).__init__(fileName,method) 00932 00933 ## 00934 # PickledFastCompressedHash2 allows keys to be duplicated with values being placed in lists when keys are duplicated. 00935 # 00936 # dbx = PickledFastCompressedHash2(fileName) ... uses PickleMethods.useBsdDbShelf because this method runs faster than all the other methods. 00937 # 00938 # Works the same as lists.HashedLists() 00939 # 00940 # PickleMethods.useBsdDbShelf = 54x 00941 # PickleMethods.useStrings = 26x 00942 # PickleMethods.useSafeSerializer = 4x 00943 # PickleMethods.useMarshal = 1x 00944 # 00945 class PickledFastCompressedHash2(PickledFastHash2): 00946 def __init__(self, fileName): 00947 e = PickleMethods.useBsdDbShelf | PickleMethods.use_zlib 00948 super(PickledFastCompressedHash2, self).__init__(fileName,e) 00949 00950 ## 00951 # PickledLzmaHash2 allows keys to be duplicated with values being placed in lists when keys are duplicated. 00952 # 00953 # dbx = PickledLzmaHash2(fileName) ... uses PickleMethods.useBsdDbShelf because this method runs faster than all the other methods. 00954 # 00955 # Works the same as lists.HashedLists() 00956 # 00957 # PickleMethods.useBsdDbShelf = 54x 00958 # PickleMethods.useStrings = 26x 00959 # PickleMethods.useSafeSerializer = 4x 00960 # PickleMethods.useMarshal = 1x 00961 # 00962 class PickledLzmaHash2(PickledFastHash2): 00963 def __init__(self, fileName): 00964 e = PickleMethods.useBsdDbShelf | PickleMethods.use_lzma 00965 super(PickledLzmaHash2, self).__init__(fileName,e) 00966 00967 __classes = [PickledHash, PickledHash2, PickledFastHash2, PickledFastCompressedHash2, PickledFastHash2, PickledLzmaHash2] 00968 __classes_tags = ['_'+_class_tag(n.split('.')[len(n.split('.'))-1:][0]) for n in [ObjectTypeName._typeName(cls) for cls in __classes]] 00969 00970 def isFilenameMungedAlready(fname): 00971 return (any([fname.find(f) > -1 for f in __classes_tags])) 00972 00973 def getMungedFilenameFor(filename): 00974 _root = os.path.dirname(filename) 00975 fname = os.path.splitext(os.path.basename(filename))[0] 00976 ext = os.path.splitext(filename)[-1] 00977 _files = [os.sep.join([_root,f]) for f in os.listdir(_root) if (f.startswith(fname)) and (f.endswith(ext))] 00978 return filename if (len(_files) == 0) else _files[0] 00979 00980 ## 00981 # Uses the filename to determine which class should be used to open the database file. Fails with a list if filename has more than one variation present in the same folder. 00982 def openPickledHashBasedOnFilename(filename, method=PickleMethods.none): 00983 def deMungeFileName(fname): 00984 if (isFilenameMungedAlready(fname)): 00985 toks = fname.split('_') 00986 if (len(toks) > 2): 00987 while (len(toks) > 2): 00988 toks[0] = '_'.join(toks[0:2]) 00989 del toks[1] 00990 _toks = toks[-1].split('.') 00991 _fname = '.'.join([toks[:len(toks)-1][0],_toks[-1]]) 00992 _tag = '_'+_toks[0] 00993 return (fname,_fname,_tag) 00994 return (None, None) 00995 00996 dname = os.path.dirname(filename) 00997 if (len(dname) == 0): 00998 dname = os.path.abspath('.') 00999 _obj = None 01000 _tag = '' 01001 fname = os.path.basename(filename) 01002 fname, _fname, _tag = deMungeFileName(fname) 01003 toks = fname.split('.') 01004 if (len(toks) > 1): 01005 toks[-1] = '.'+toks[-1] 01006 files = [deMungeFileName(f) for f in os.listdir(dname)] 01007 files = [f[1] for f in files if (f[0] == fname) and (f[-1] == _tag)] 01008 if (len(files) == 1): 01009 if (len(_tag) == 0): 01010 return openPickledHashBasedOnFilename(os.sep.join([dname,files[0]]),method=method) 01011 i = misc.findInListSafely(__classes_tags,_tag) 01012 if (i > -1): 01013 info_string = '' 01014 toks = ObjectTypeName._typeName(__classes[i]).split('.') 01015 className = toks[len(toks)-1:][0] 01016 try: 01017 s = '%s(filename,method=method)' % (className) 01018 _obj = eval(s) 01019 except TypeError: 01020 try: 01021 s = '%s(filename)' % (className) 01022 _obj = eval(s) 01023 except Exception, details: 01024 info_string = str(details) 01025 else: 01026 raise ValueError('(%s) :: Cannot figure-out the class name based on "%s", recommend working this out on you own because you seemed to have written some bad code or maybe "%s".' % (misc.funcName(),_tag,info_string)) 01027 else: 01028 raise ValueError('(%s) :: Too %s files (%d) named like "%s" %s for %s, recommend using the class name "%s" and open it yourself.' % (misc.funcName(),'many' if (len(files) > 1) else 'few',len(files),str(files),str(toks),filename,_tag)) 01029 return _obj 01030 01031 def put_data(_fname,key,value,fOut=None,isUnique=True): 01032 dbx = PickledFastCompressedHash2(_fname) 01033 try: 01034 value = value if (not misc.isList(value)) else value[0] 01035 if (isUnique) and (dbx.has_key(key)): 01036 del dbx[key] 01037 dbx[key] = value 01038 except Exception, details: 01039 from vyperlogix.misc import _utils 01040 fOut = sys.stderr if (fOut is None) else fOut 01041 print >>fOut, _utils.formattedException(details) 01042 finally: 01043 dbx.close() 01044 01045 def get_data(_fname,key,fOut=None,isUnique=True): 01046 dbx = PickledFastCompressedHash2(_fname) 01047 value = None 01048 try: 01049 value = dbx[key] 01050 if (isUnique): 01051 value = value if (not misc.isList(value)) else None if (len(value) == 0) else value[0] 01052 except Exception, details: 01053 from vyperlogix.misc import _utils 01054 fOut = sys.stderr if (fOut is None) else fOut 01055 print >>fOut, _utils.formattedException(details) 01056 finally: 01057 dbx.close() 01058 return value 01059 01060 if (__name__ == '__main__'): 01061 import sys 01062 print >>sys.stdout, __copyright__ 01063 print >>sys.stderr, __copyright__ 01064 01065 #dbx = openPickledHashBasedOnFilename('Z:\\@myMagma\\python-local-new-trunk\\test\\win32\\logs\\2008-07-31_07_55_58\\dbx\\CaseWatcher2Cases.dbx') 01066 #lists.prettyPrint(dbx,title='%s'%(dbx.fileName)) 01067 #dbx.close() 01068 #pass 01069 01070
© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."
Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.
122,241 lines of code and growing...