Mercurial > cpython-lru_cache-weakref
annotate Lib/persist.py @ 4566:6403c94de50d legacy-trunk
Added safeguard against failure in __del__.
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Wed, 27 Nov 1996 19:39:58 +0000 |
| parents | 517d29ebc840 |
| children |
| rev | line source |
|---|---|
| 195 | 1 # persist.py |
| 2 # | |
| 3 # Implement limited persistence. | |
| 4 # | |
| 5 # Simple interface: | |
| 6 # persist.save() save __main__ module on file (overwrite) | |
| 7 # persist.load() load __main__ module from file (merge) | |
| 8 # | |
| 9 # These use the filename persist.defaultfile, initialized to 'wsrestore.py'. | |
| 10 # | |
| 11 # A raw interface also exists: | |
| 12 # persist.writedict(dict, fp) save dictionary to open file | |
| 13 # persist.readdict(dict, fp) read (merge) dictionary from open file | |
| 14 # | |
| 15 # Internally, the function dump() and a whole bunch of support of functions | |
| 16 # traverse a graph of objects and print them in a restorable form | |
| 17 # (which happens to be a Python module). | |
| 18 # | |
| 19 # XXX Limitations: | |
| 20 # - Volatile objects are dumped as strings: | |
| 21 # - open files, windows etc. | |
| 22 # - Other 'obscure' objects are dumped as strings: | |
| 23 # - classes, instances and methods | |
| 24 # - compiled regular expressions | |
| 25 # - anything else reasonably obscure (e.g., capabilities) | |
| 26 # - type objects for obscure objects | |
| 27 # - It's slow when there are many of lists or dictionaries | |
| 28 # (This could be fixed if there were a quick way to compute a hash | |
| 29 # function of any object, even if recursive) | |
| 30 | |
| 31 defaultfile = 'wsrestore.py' | |
| 32 | |
| 33 def save(): | |
| 34 import __main__ | |
| 776 | 35 import os |
| 195 | 36 # XXX On SYSV, if len(defaultfile) >= 14, this is wrong! |
| 37 backup = defaultfile + '~' | |
| 38 try: | |
| 776 | 39 os.unlink(backup) |
| 40 except os.error: | |
| 195 | 41 pass |
| 42 try: | |
| 776 | 43 os.rename(defaultfile, backup) |
| 44 except os.error: | |
| 195 | 45 pass |
| 46 fp = open(defaultfile, 'w') | |
| 47 writedict(__main__.__dict__, fp) | |
| 48 fp.close() | |
| 49 | |
| 50 def load(): | |
| 51 import __main__ | |
| 52 fp = open(defaultfile, 'r') | |
| 53 readdict(__main__.__dict__, fp) | |
| 54 | |
| 55 def writedict(dict, fp): | |
| 56 import sys | |
| 57 savestdout = sys.stdout | |
| 58 try: | |
| 59 sys.stdout = fp | |
| 60 dump(dict) # Writes to sys.stdout | |
| 61 finally: | |
| 62 sys.stdout = savestdout | |
| 63 | |
| 64 def readdict(dict, fp): | |
|
217
1958723bfe02
Remove reference to util.
Guido van Rossum <guido@python.org>
parents:
195
diff
changeset
|
65 contents = fp.read() |
| 195 | 66 globals = {} |
| 67 exec(contents, globals) | |
| 68 top = globals['top'] | |
| 69 for key in top.keys(): | |
| 70 if dict.has_key(key): | |
| 71 print 'warning:', key, 'not overwritten' | |
| 72 else: | |
| 73 dict[key] = top[key] | |
| 74 | |
| 75 | |
| 76 # Function dump(x) prints (on sys.stdout!) a sequence of Python statements | |
| 77 # that, when executed in an empty environment, will reconstruct the | |
| 78 # contents of an arbitrary dictionary. | |
| 79 | |
| 80 import sys | |
| 81 | |
| 82 # Name used for objects dict on output. | |
| 83 # | |
| 84 FUNNYNAME = FN = 'A' | |
| 85 | |
| 86 # Top-level function. Call with the object you want to dump. | |
| 87 # | |
| 88 def dump(x): | |
| 89 types = {} | |
| 90 stack = [] # Used by test for recursive objects | |
| 91 print FN, '= {}' | |
| 92 topuid = dumpobject(x, types, stack) | |
| 93 print 'top =', FN, '[', `topuid`, ']' | |
| 94 | |
| 95 # Generic function to dump any object. | |
| 96 # | |
| 97 dumpswitch = {} | |
| 98 # | |
| 99 def dumpobject(x, types, stack): | |
| 100 typerepr = `type(x)` | |
| 101 if not types.has_key(typerepr): | |
| 102 types[typerepr] = {} | |
| 103 typedict = types[typerepr] | |
| 104 if dumpswitch.has_key(typerepr): | |
| 105 return dumpswitch[typerepr](x, typedict, types, stack) | |
| 106 else: | |
| 107 return dumpbadvalue(x, typedict, types, stack) | |
| 108 | |
| 109 # Generic function to dump unknown values. | |
| 110 # This assumes that the Python interpreter prints such values as | |
| 111 # <foo object at xxxxxxxx>. | |
| 112 # The object will be read back as a string: '<foo object at xxxxxxxx>'. | |
| 113 # In some cases it may be possible to fix the dump manually; | |
| 114 # to ease the editing, these cases are labeled with an XXX comment. | |
| 115 # | |
| 116 def dumpbadvalue(x, typedict, types, stack): | |
| 117 xrepr = `x` | |
| 118 if typedict.has_key(xrepr): | |
| 119 return typedict[xrepr] | |
| 120 uid = genuid() | |
| 121 typedict[xrepr] = uid | |
| 122 print FN, '[', `uid`, '] =', `xrepr`, '# XXX' | |
| 123 return uid | |
| 124 | |
| 125 # Generic function to dump pure, simple values, except strings | |
| 126 # | |
| 127 def dumpvalue(x, typedict, types, stack): | |
| 128 xrepr = `x` | |
| 129 if typedict.has_key(xrepr): | |
| 130 return typedict[xrepr] | |
| 131 uid = genuid() | |
| 132 typedict[xrepr] = uid | |
| 133 print FN, '[', `uid`, '] =', `x` | |
| 134 return uid | |
| 135 | |
| 136 # Functions to dump string objects | |
| 137 # | |
| 138 def dumpstring(x, typedict, types, stack): | |
| 139 # XXX This can break if strings have embedded '\0' bytes | |
| 140 # XXX because of a bug in the dictionary module | |
| 141 if typedict.has_key(x): | |
| 142 return typedict[x] | |
| 143 uid = genuid() | |
| 144 typedict[x] = uid | |
| 145 print FN, '[', `uid`, '] =', `x` | |
| 146 return uid | |
| 147 | |
| 148 # Function to dump type objects | |
| 149 # | |
| 150 typeswitch = {} | |
| 529 | 151 class some_class: |
| 195 | 152 def method(self): pass |
| 153 some_instance = some_class() | |
| 154 # | |
| 155 def dumptype(x, typedict, types, stack): | |
| 156 xrepr = `x` | |
| 157 if typedict.has_key(xrepr): | |
| 158 return typedict[xrepr] | |
| 159 uid = genuid() | |
| 160 typedict[xrepr] = uid | |
| 161 if typeswitch.has_key(xrepr): | |
| 162 print FN, '[', `uid`, '] =', typeswitch[xrepr] | |
| 559 | 163 elif x == type(sys): |
| 195 | 164 print 'import sys' |
| 165 print FN, '[', `uid`, '] = type(sys)' | |
| 559 | 166 elif x == type(sys.stderr): |
| 195 | 167 print 'import sys' |
| 168 print FN, '[', `uid`, '] = type(sys.stderr)' | |
| 559 | 169 elif x == type(dumptype): |
| 195 | 170 print 'def some_function(): pass' |
| 171 print FN, '[', `uid`, '] = type(some_function)' | |
| 559 | 172 elif x == type(some_class): |
|
1291
517d29ebc840
* ftplib.py: added abort() command (sends oob data).
Guido van Rossum <guido@python.org>
parents:
776
diff
changeset
|
173 print 'class some_class: pass' |
| 195 | 174 print FN, '[', `uid`, '] = type(some_class)' |
| 559 | 175 elif x == type(some_instance): |
|
1291
517d29ebc840
* ftplib.py: added abort() command (sends oob data).
Guido van Rossum <guido@python.org>
parents:
776
diff
changeset
|
176 print 'class another_class: pass' |
| 195 | 177 print 'some_instance = another_class()' |
| 178 print FN, '[', `uid`, '] = type(some_instance)' | |
| 559 | 179 elif x == type(some_instance.method): |
|
1291
517d29ebc840
* ftplib.py: added abort() command (sends oob data).
Guido van Rossum <guido@python.org>
parents:
776
diff
changeset
|
180 print 'class yet_another_class:' |
| 195 | 181 print ' def method(): pass' |
| 182 print 'another_instance = yet_another_class()' | |
| 183 print FN, '[', `uid`, '] = type(another_instance.method)' | |
| 184 else: | |
| 185 # Unknown type | |
| 186 print FN, '[', `uid`, '] =', `xrepr`, '# XXX' | |
| 187 return uid | |
| 188 | |
| 189 # Initialize the typeswitch | |
| 190 # | |
| 191 for x in None, 0, 0.0, '', (), [], {}: | |
| 192 typeswitch[`type(x)`] = 'type(' + `x` + ')' | |
| 193 for s in 'type(0)', 'abs', '[].append': | |
| 194 typeswitch[`type(eval(s))`] = 'type(' + s + ')' | |
| 195 | |
| 196 # Dump a tuple object | |
| 197 # | |
| 198 def dumptuple(x, typedict, types, stack): | |
| 199 item_uids = [] | |
| 200 xrepr = '' | |
| 201 for item in x: | |
| 202 item_uid = dumpobject(item, types, stack) | |
| 203 item_uids.append(item_uid) | |
| 204 xrepr = xrepr + ' ' + item_uid | |
| 205 del stack[-1:] | |
| 206 if typedict.has_key(xrepr): | |
| 207 return typedict[xrepr] | |
| 208 uid = genuid() | |
| 209 typedict[xrepr] = uid | |
| 210 print FN, '[', `uid`, '] = (', | |
| 211 for item_uid in item_uids: | |
| 212 print FN, '[', `item_uid`, '],', | |
| 213 print ')' | |
| 214 return uid | |
| 215 | |
| 216 # Dump a list object | |
| 217 # | |
| 218 def dumplist(x, typedict, types, stack): | |
| 219 # Check for recursion | |
| 220 for x1, uid1 in stack: | |
| 221 if x is x1: return uid1 | |
| 222 # Check for occurrence elsewhere in the typedict | |
| 223 for uid1 in typedict.keys(): | |
| 224 if x is typedict[uid1]: return uid1 | |
| 225 # This uses typedict differently! | |
| 226 uid = genuid() | |
| 227 typedict[uid] = x | |
| 228 print FN, '[', `uid`, '] = []' | |
| 229 stack.append(x, uid) | |
| 230 item_uids = [] | |
| 231 for item in x: | |
| 232 item_uid = dumpobject(item, types, stack) | |
| 233 item_uids.append(item_uid) | |
| 234 del stack[-1:] | |
| 235 for item_uid in item_uids: | |
| 236 print FN, '[', `uid`, '].append(', FN, '[', `item_uid`, '])' | |
| 237 return uid | |
| 238 | |
| 239 # Dump a dictionary object | |
| 240 # | |
| 241 def dumpdict(x, typedict, types, stack): | |
| 242 # Check for recursion | |
| 243 for x1, uid1 in stack: | |
| 244 if x is x1: return uid1 | |
| 245 # Check for occurrence elsewhere in the typedict | |
| 246 for uid1 in typedict.keys(): | |
| 247 if x is typedict[uid1]: return uid1 | |
| 248 # This uses typedict differently! | |
| 249 uid = genuid() | |
| 250 typedict[uid] = x | |
| 251 print FN, '[', `uid`, '] = {}' | |
| 252 stack.append(x, uid) | |
| 253 item_uids = [] | |
| 254 for key in x.keys(): | |
| 255 val_uid = dumpobject(x[key], types, stack) | |
| 256 item_uids.append(key, val_uid) | |
| 257 del stack[-1:] | |
| 258 for key, val_uid in item_uids: | |
| 259 print FN, '[', `uid`, '][', `key`, '] =', | |
| 260 print FN, '[', `val_uid`, ']' | |
| 261 return uid | |
| 262 | |
| 263 # Dump a module object | |
| 264 # | |
| 265 def dumpmodule(x, typedict, types, stack): | |
| 266 xrepr = `x` | |
| 267 if typedict.has_key(xrepr): | |
| 268 return typedict[xrepr] | |
| 269 from string import split | |
| 270 # `x` has the form <module 'foo'> | |
| 271 name = xrepr[9:-2] | |
| 272 uid = genuid() | |
| 273 typedict[xrepr] = uid | |
| 274 print 'import', name | |
| 275 print FN, '[', `uid`, '] =', name | |
| 276 return uid | |
| 277 | |
| 278 | |
| 279 # Initialize dumpswitch, a table of functions to dump various objects, | |
| 280 # indexed by `type(x)`. | |
| 281 # | |
| 282 for x in None, 0, 0.0: | |
| 283 dumpswitch[`type(x)`] = dumpvalue | |
| 284 for x, f in ('', dumpstring), (type(0), dumptype), ((), dumptuple), \ | |
| 285 ([], dumplist), ({}, dumpdict), (sys, dumpmodule): | |
| 286 dumpswitch[`type(x)`] = f | |
| 287 | |
| 288 | |
| 289 # Generate the next unique id; a string consisting of digits. | |
| 290 # The seed is stored as seed[0]. | |
| 291 # | |
| 292 seed = [0] | |
| 293 # | |
| 294 def genuid(): | |
| 295 x = seed[0] | |
| 296 seed[0] = seed[0] + 1 | |
| 297 return `x` |
