::-- limodou [DateTime(2005-04-08T16:31:56Z)] TableOfContents

Obj2Ini

类Ini形式的对象序列化模块

说明

参见:[http://www.donews.net/limodou/archive/2005/04/09/328275.aspx 类ini形式的对象序列化模块]

代码

   1 #coding=utf-8
   2 # dump python object to ini format file
   3 # Author: limodou ([email protected])
   4 # Copyleft GPL
   5 # $Id: obj2ini.py,v 1.2 2005/04/21 15:42:39 limodou Exp $
   6 #
   7 # 2005/07/31 
   8 #            1. 增加变量的支持。
   9 #            2. 修改输出的ini格式为第一行为#obj表示是对象,#var表示是变量。
  10 #            同时为了兼容性,当第一行不是#var或#obj时默认为#obj。
  11 #            3. 修改load方法的调用参数
  12 
  13 import types
  14 import sys
  15 import locale
  16 import types
  17 
  18 def dump(obj, filename, encoding=None):
  19     encoding = __getdefaultencoding(encoding)
  20 
  21     if hasattr(filename, "write"):
  22         f = filename
  23     else:
  24         f = file(filename, "w")
  25     
  26     if isinstance(obj, types.InstanceType):
  27         objects = {}
  28         f.write("#obj\n")
  29         f.write("[=%s.%s]\n" % (obj.__class__.__module__, obj.__class__.__name__))
  30         for key, value in vars(obj).items():
  31             if isinstance(value, types.InstanceType):
  32                 objects[key] = value
  33             else:
  34                 __write_var(f, key, value, encoding) 
  35         for key, value in objects.items():
  36             __dumpsubobj(value, key, '', f, encoding)
  37     else:
  38         f.write("#var\n")
  39         f.write(__uni_prt(obj, encoding))
  40     
  41 class EmptyClass:
  42     pass
  43 
  44 def __getparentobjname(name):
  45     a = name.split('.')
  46     return '.'.join(a[:-1])
  47 
  48 def __getmoduleandclass(name):
  49     a = name.split('.')
  50     return '.'.join(a[:-1]), a[-1]
  51 
  52 def load(filename, encoding=None):
  53     encoding = __getdefaultencoding(encoding)
  54 
  55     if hasattr(filename, "read"):
  56         f = filename
  57     else:
  58         f = file(filename, "r")
  59 
  60     firstline = f.readline()
  61     if firstline.startswith('#obj') or not firstline.startswith('#var'):
  62         if not firstline.startswith('#obj'):
  63             f.seek(0)
  64         objects = {}
  65         namespace = {}
  66         obj = EmptyClass()
  67         currentobj = obj
  68         parentobj = obj
  69         for line in f:
  70             line = line.strip()
  71             if not line: continue
  72             if line[0] in ('#', ';'): continue
  73             if line.startswith('[') and line.endswith(']'): #sub object
  74                 #set original class 
  75                 classname, classinfo = line[1:-1].split('=')
  76                 module, _class = __getmoduleandclass(classinfo)
  77                 __import__(module)
  78                 mod = sys.modules[module]
  79                 _klass = getattr(mod, _class)
  80                 if classname:
  81                     sub = EmptyClass()
  82                     parentname = __getparentobjname(classname)
  83                     setattr(parentobj, classname, sub)
  84                 else:
  85                     sub = currentobj
  86                     parentname = ''
  87                 sub.__class__ = _klass
  88                 if parentname:
  89                     parentobj = objects[parentname]
  90                 else:
  91                     parentobj = currentobj
  92                 objects[classname] = sub
  93                 currentobj = sub
  94             else:
  95                 if line.find('='):
  96                     delimeter = '='
  97                 else:
  98                     delimeter = ':'
  99                 key, value = line.split(delimeter, 1)
 100                 key = key.strip()
 101                 exec __filter(line, encoding) in namespace
 102                 setattr(currentobj, key, namespace[key])
 103         return obj
 104     else:
 105         line = f.readline()
 106         namespace = {}
 107         exec __filter('var='+line, encoding) in namespace
 108         return namespace['var']
 109 
 110 def __dumpsubobj(obj, objname, parentname, filename, encoding=None):
 111     if hasattr(filename, "write"):
 112         f = filename
 113     else:
 114         f = file(filename, "w")
 115     
 116     if parentname:
 117         f.write("\n[%s.%s=%s.%s]\n" % (parentname, objname, obj.__class__.__module__, obj.__class__.__name__))
 118     else:
 119         f.write("\n[%s=%s.%s]\n" % (objname, obj.__class__.__module__, obj.__class__.__name__))
 120     objects = {}
 121     for key, value in vars(obj).items():
 122         if isinstance(value, types.InstanceType):
 123             objects[key] = value
 124         else:
 125             __write_var(f, key, value, encoding) 
 126     for key, value in objects.items():
 127         __dumpsubobj(value, key, objname, f, encoding)    
 128         
 129 def __write_var(f, key, var, encoding):
 130     f.write("%s=%s\n" % (key, __uni_prt(var, encoding)))
 131     
 132 def __getdefaultencoding(encoding):
 133     if not encoding:
 134         encoding = locale.getdefaultlocale()[1]
 135     if not encoding:
 136         encoding = sys.getfilesystemencoding()
 137     return encoding
 138         
 139 def __uni_prt(a, encoding=None):
 140     escapechars = [("\\", "\\\\"), ("'", r"\'"), ('\"', r'\"'), ('\b', r'\b'), 
 141         ('\t', r"\t"), ('\r', r"\r"), ('\n', r"\n")]
 142     s = []
 143     encoding = __getdefaultencoding(encoding)
 144     if isinstance(a, (list, tuple)):
 145         if isinstance(a, list):
 146             s.append('[')
 147         else:
 148             s.append('(')
 149         for i, k in enumerate(a):
 150             s.append(__uni_prt(k, encoding))
 151             if i<len(a)-1:
 152                 s.append(', ')
 153         if isinstance(a, list):
 154             s.append(']')
 155         else:
 156             s.append(')')
 157     elif isinstance(a, dict):
 158         s.append('{')
 159         for i, k in enumerate(a.items()):
 160             key, value = k
 161             s.append('%s: %s' % (__uni_prt(key, encoding), __uni_prt(value, encoding)))
 162             if i<len(a.items())-1:
 163                 s.append(', ')
 164         s.append('}')
 165     elif isinstance(a, str):
 166         t = a
 167         for i in escapechars:
 168             t = t.replace(i[0], i[1])
 169         s.append("'%s'" % t)
 170     elif isinstance(a, unicode):
 171         t = a
 172         for i in escapechars:
 173             t = t.replace(i[0], i[1])
 174         s.append("u'%s'" % t.encode(encoding))
 175     else:
 176         s.append(str(a))
 177     return ''.join(s)
 178 
 179 def __filter(s, encoding):
 180     import StringIO
 181     import tokenize
 182     import token
 183     
 184     f = StringIO.StringIO(s)
 185     g = tokenize.generate_tokens(f.readline)
 186     slist = []
 187     namespace = {}
 188     for tokentype, t, start, end, line in g:
 189         if tokentype == token.STRING:
 190             if t[0] == 'u':
 191                 exec "v=" + t[1:] in namespace
 192                 slist.append(repr(unicode(namespace["v"], encoding)))
 193             else:
 194                 slist.append(t)
 195         else:
 196             slist.append(t)
 197     return ''.join(slist)
 198                 
 199 if __name__ == '__main__':
 200     class A:
 201         a = 1
 202         def __init__(self):
 203             self.b = 1
 204             self.c = unicode("\\'", 'utf-8')
 205             self.d = (self.c, self.b)
 206             self.e = [self.b, self.c, self.d]
 207             self.f = {self.b:self.c, self.d:self.e}
 208     
 209     a = A()
 210     #f = sys.stdout
 211     f = "test1.ini"
 212     b = A()
 213     b.s = "aa\ba\"a\ns'ss\tsdd\r"
 214     c = A()
 215     a.obj = b
 216     a.obj.obj = c
 217     dump(a, f)
 218     
 219     s = load(f)
 220     print vars(s)
 221     print s.__class__.__name__
 222     
 223 #    f = sys.stdout
 224 #    dump(s, f)
 225 
 226     a = ['a', 'b',(1,2), '中文', {'a':[1,2,3]}]
 227     dump(a, 'test2.ini')
 228     b = load('test2.ini')
 229     print b