::-- limodou [2005-04-08 16:31:56]
Obj2Ini
类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, obj=None, 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 if not obj:
67 obj = EmptyClass()
68 currentobj = obj
69 parentobj = obj
70 for line in f:
71 line = line.strip()
72 if not line: continue
73 if line[0] in ('#', ';'): continue
74 if line.startswith('[') and line.endswith(']'): #sub object
75 #set original class
76 classname, classinfo = line[1:-1].split('=')
77 module, _class = __getmoduleandclass(classinfo)
78 __import__(module)
79 mod = sys.modules[module]
80 _klass = getattr(mod, _class)
81 if classname:
82 sub = EmptyClass()
83 parentname = __getparentobjname(classname)
84 setattr(parentobj, classname, sub)
85 else:
86 sub = currentobj
87 parentname = ''
88 sub.__class__ = _klass
89 if parentname:
90 parentobj = objects[parentname]
91 else:
92 parentobj = currentobj
93 objects[classname] = sub
94 currentobj = sub
95 else:
96 if line.find('='):
97 delimeter = '='
98 else:
99 delimeter = ':'
100 key, value = line.split(delimeter, 1)
101 key = key.strip()
102 exec __filter(line, encoding) in namespace
103 setattr(currentobj, key, namespace[key])
104 return obj
105 else:
106 line = f.readline()
107 namespace = {}
108 exec __filter('var='+line, encoding) in namespace
109 return namespace['var']
110
111 def __dumpsubobj(obj, objname, parentname, filename, encoding=None):
112 if hasattr(filename, "write"):
113 f = filename
114 else:
115 f = file(filename, "w")
116
117 if parentname:
118 f.write("\n[%s.%s=%s.%s]\n" % (parentname, objname, obj.__class__.__module__, obj.__class__.__name__))
119 else:
120 f.write("\n[%s=%s.%s]\n" % (objname, obj.__class__.__module__, obj.__class__.__name__))
121 objects = {}
122 for key, value in vars(obj).items():
123 if isinstance(value, types.InstanceType):
124 objects[key] = value
125 else:
126 __write_var(f, key, value, encoding)
127 for key, value in objects.items():
128 __dumpsubobj(value, key, objname, f, encoding)
129
130 def __write_var(f, key, var, encoding):
131 f.write("%s=%s\n" % (key, __uni_prt(var, encoding)))
132
133 def __getdefaultencoding(encoding):
134 if not encoding:
135 encoding = locale.getdefaultlocale()[1]
136 if not encoding:
137 encoding = sys.getfilesystemencoding()
138 return encoding
139
140 def __uni_prt(a, encoding=None):
141 escapechars = [("\\", "\\\\"), ("'", r"\'"), ('\"', r'\"'), ('\b', r'\b'),
142 ('\t', r"\t"), ('\r', r"\r"), ('\n', r"\n")]
143 s = []
144 encoding = __getdefaultencoding(encoding)
145 if isinstance(a, (list, tuple)):
146 if isinstance(a, list):
147 s.append('[')
148 else:
149 s.append('(')
150 for i, k in enumerate(a):
151 s.append(__uni_prt(k, encoding))
152 if i<len(a)-1:
153 s.append(', ')
154 if isinstance(a, list):
155 s.append(']')
156 else:
157 s.append(')')
158 elif isinstance(a, dict):
159 s.append('{')
160 for i, k in enumerate(a.items()):
161 key, value = k
162 s.append('%s: %s' % (__uni_prt(key, encoding), __uni_prt(value, encoding)))
163 if i<len(a.items())-1:
164 s.append(', ')
165 s.append('}')
166 elif isinstance(a, str):
167 t = a
168 for i in escapechars:
169 t = t.replace(i[0], i[1])
170 s.append("'%s'" % t)
171 elif isinstance(a, unicode):
172 t = a
173 for i in escapechars:
174 t = t.replace(i[0], i[1])
175 s.append("u'%s'" % t.encode(encoding))
176 else:
177 s.append(str(a))
178 return ''.join(s)
179
180 def __filter(s, encoding):
181 import StringIO
182 import tokenize
183 import token
184
185 f = StringIO.StringIO(s)
186 g = tokenize.generate_tokens(f.readline)
187 slist = []
188 namespace = {}
189 for tokentype, t, start, end, line in g:
190 if tokentype == token.STRING:
191 if t[0] == 'u':
192 exec "v=" + t[1:] in namespace
193 slist.append(repr(unicode(namespace["v"], encoding)))
194 else:
195 slist.append(t)
196 else:
197 slist.append(t)
198 return ''.join(slist)
199
200 if __name__ == '__main__':
201 class A:
202 a = 1
203 def __init__(self):
204 self.b = 1
205 self.c = unicode("中\\'国", 'utf-8')
206 self.d = (self.c, self.b)
207 self.e = [self.b, self.c, self.d]
208 self.f = {self.b:self.c, self.d:self.e}
209
210 a = A()
211 #f = sys.stdout
212 f = "test1.ini"
213 b = A()
214 b.s = "aa\ba\"a\ns'ss\tsdd\r"
215 c = A()
216 a.obj = b
217 a.obj.obj = c
218 dump(a, f)
219
220 s = load(f)
221 print vars(s)
222 print s.__class__.__name__
223
224 # f = sys.stdout
225 # dump(s, f)
226
227 a = ['a', 'b',(1,2), '中文', {'a':[1,2,3]}]
228 dump(a, 'test2.ini')
229 b = load('test2.ini')
230 print b