::-- 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