mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	* Several modules: change "class C(): ..." to "class C: ...". * flp.py: support for frozen forms. * Added string.find() which is like index but returns -1 if not found
		
			
				
	
	
		
			297 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
# persist.py
 | 
						|
#
 | 
						|
# Implement limited persistence.
 | 
						|
#
 | 
						|
# Simple interface:
 | 
						|
#	persist.save()		save __main__ module on file (overwrite)
 | 
						|
#	persist.load()		load __main__ module from file (merge)
 | 
						|
#
 | 
						|
# These use the filename persist.defaultfile, initialized to 'wsrestore.py'.
 | 
						|
#
 | 
						|
# A raw interface also exists:
 | 
						|
#	persist.writedict(dict, fp)	save dictionary to open file
 | 
						|
#	persist.readdict(dict, fp)	read (merge) dictionary from open file
 | 
						|
#
 | 
						|
# Internally, the function dump() and a whole bunch of support of functions
 | 
						|
# traverse a graph of objects and print them in a restorable form
 | 
						|
# (which happens to be a Python module).
 | 
						|
#
 | 
						|
# XXX Limitations:
 | 
						|
# - Volatile objects are dumped as strings:
 | 
						|
#   - open files, windows etc.
 | 
						|
# - Other 'obscure' objects are dumped as strings:
 | 
						|
#   - classes, instances and methods
 | 
						|
#   - compiled regular expressions
 | 
						|
#   - anything else reasonably obscure (e.g., capabilities)
 | 
						|
#   - type objects for obscure objects
 | 
						|
# - It's slow when there are many of lists or dictionaries
 | 
						|
#   (This could be fixed if there were a quick way to compute a hash
 | 
						|
#   function of any object, even if recursive)
 | 
						|
 | 
						|
defaultfile = 'wsrestore.py'
 | 
						|
 | 
						|
def save():
 | 
						|
	import __main__
 | 
						|
	import os
 | 
						|
	# XXX On SYSV, if len(defaultfile) >= 14, this is wrong!
 | 
						|
	backup = defaultfile + '~'
 | 
						|
	try:
 | 
						|
		os.unlink(backup)
 | 
						|
	except os.error:
 | 
						|
		pass
 | 
						|
	try:
 | 
						|
		os.rename(defaultfile, backup)
 | 
						|
	except os.error:
 | 
						|
		pass
 | 
						|
	fp = open(defaultfile, 'w')
 | 
						|
	writedict(__main__.__dict__, fp)
 | 
						|
	fp.close()
 | 
						|
 | 
						|
def load():
 | 
						|
	import __main__
 | 
						|
	fp = open(defaultfile, 'r')
 | 
						|
	readdict(__main__.__dict__, fp)
 | 
						|
 | 
						|
def writedict(dict, fp):
 | 
						|
	import sys
 | 
						|
	savestdout = sys.stdout
 | 
						|
	try:
 | 
						|
		sys.stdout = fp
 | 
						|
		dump(dict)	# Writes to sys.stdout
 | 
						|
	finally:
 | 
						|
		sys.stdout = savestdout
 | 
						|
 | 
						|
def readdict(dict, fp):
 | 
						|
	contents = fp.read()
 | 
						|
	globals = {}
 | 
						|
	exec(contents, globals)
 | 
						|
	top = globals['top']
 | 
						|
	for key in top.keys():
 | 
						|
		if dict.has_key(key):
 | 
						|
			print 'warning:', key, 'not overwritten'
 | 
						|
		else:
 | 
						|
			dict[key] = top[key]
 | 
						|
 | 
						|
 | 
						|
# Function dump(x) prints (on sys.stdout!) a sequence of Python statements
 | 
						|
# that, when executed in an empty environment, will reconstruct the
 | 
						|
# contents of an arbitrary dictionary.
 | 
						|
 | 
						|
import sys
 | 
						|
 | 
						|
# Name used for objects dict on output.
 | 
						|
#
 | 
						|
FUNNYNAME = FN = 'A'
 | 
						|
 | 
						|
# Top-level function.  Call with the object you want to dump.
 | 
						|
#
 | 
						|
def dump(x):
 | 
						|
	types = {}
 | 
						|
	stack = []			# Used by test for recursive objects
 | 
						|
	print FN, '= {}'
 | 
						|
	topuid = dumpobject(x, types, stack)
 | 
						|
	print 'top =', FN, '[', `topuid`, ']'
 | 
						|
 | 
						|
# Generic function to dump any object.
 | 
						|
#
 | 
						|
dumpswitch = {}
 | 
						|
#
 | 
						|
def dumpobject(x, types, stack):
 | 
						|
	typerepr = `type(x)`
 | 
						|
	if not types.has_key(typerepr):
 | 
						|
		types[typerepr] = {}
 | 
						|
	typedict = types[typerepr]
 | 
						|
	if dumpswitch.has_key(typerepr):
 | 
						|
		return dumpswitch[typerepr](x, typedict, types, stack)
 | 
						|
	else:
 | 
						|
		return dumpbadvalue(x, typedict, types, stack)
 | 
						|
 | 
						|
# Generic function to dump unknown values.
 | 
						|
# This assumes that the Python interpreter prints such values as
 | 
						|
# <foo object at xxxxxxxx>.
 | 
						|
# The object will be read back as a string: '<foo object at xxxxxxxx>'.
 | 
						|
# In some cases it may be possible to fix the dump manually;
 | 
						|
# to ease the editing, these cases are labeled with an XXX comment.
 | 
						|
#
 | 
						|
def dumpbadvalue(x, typedict, types, stack):
 | 
						|
	xrepr = `x`
 | 
						|
	if typedict.has_key(xrepr):
 | 
						|
		return typedict[xrepr]
 | 
						|
	uid = genuid()
 | 
						|
	typedict[xrepr] = uid
 | 
						|
	print FN, '[', `uid`, '] =', `xrepr`, '# XXX'
 | 
						|
	return uid
 | 
						|
 | 
						|
# Generic function to dump pure, simple values, except strings
 | 
						|
#
 | 
						|
def dumpvalue(x, typedict, types, stack):
 | 
						|
	xrepr = `x`
 | 
						|
	if typedict.has_key(xrepr):
 | 
						|
		return typedict[xrepr]
 | 
						|
	uid = genuid()
 | 
						|
	typedict[xrepr] = uid
 | 
						|
	print FN, '[', `uid`, '] =', `x`
 | 
						|
	return uid
 | 
						|
 | 
						|
# Functions to dump string objects
 | 
						|
#
 | 
						|
def dumpstring(x, typedict, types, stack):
 | 
						|
	# XXX This can break if strings have embedded '\0' bytes
 | 
						|
	# XXX because of a bug in the dictionary module
 | 
						|
	if typedict.has_key(x):
 | 
						|
		return typedict[x]
 | 
						|
	uid = genuid()
 | 
						|
	typedict[x] = uid
 | 
						|
	print FN, '[', `uid`, '] =', `x`
 | 
						|
	return uid
 | 
						|
 | 
						|
# Function to dump type objects
 | 
						|
#
 | 
						|
typeswitch = {}
 | 
						|
class some_class:
 | 
						|
	def method(self): pass
 | 
						|
some_instance = some_class()
 | 
						|
#
 | 
						|
def dumptype(x, typedict, types, stack):
 | 
						|
	xrepr = `x`
 | 
						|
	if typedict.has_key(xrepr):
 | 
						|
		return typedict[xrepr]
 | 
						|
	uid = genuid()
 | 
						|
	typedict[xrepr] = uid
 | 
						|
	if typeswitch.has_key(xrepr):
 | 
						|
		print FN, '[', `uid`, '] =', typeswitch[xrepr]
 | 
						|
	elif x == type(sys):
 | 
						|
		print 'import sys'
 | 
						|
		print FN, '[', `uid`, '] = type(sys)'
 | 
						|
	elif x == type(sys.stderr):
 | 
						|
		print 'import sys'
 | 
						|
		print FN, '[', `uid`, '] = type(sys.stderr)'
 | 
						|
	elif x == type(dumptype):
 | 
						|
		print 'def some_function(): pass'
 | 
						|
		print FN, '[', `uid`, '] = type(some_function)'
 | 
						|
	elif x == type(some_class):
 | 
						|
		print 'class some_class: pass'
 | 
						|
		print FN, '[', `uid`, '] = type(some_class)'
 | 
						|
	elif x == type(some_instance):
 | 
						|
		print 'class another_class: pass'
 | 
						|
		print 'some_instance = another_class()'
 | 
						|
		print FN, '[', `uid`, '] = type(some_instance)'
 | 
						|
	elif x == type(some_instance.method):
 | 
						|
		print 'class yet_another_class:'
 | 
						|
		print '    def method(): pass'
 | 
						|
		print 'another_instance = yet_another_class()'
 | 
						|
		print FN, '[', `uid`, '] = type(another_instance.method)'
 | 
						|
	else:
 | 
						|
		# Unknown type
 | 
						|
		print FN, '[', `uid`, '] =', `xrepr`, '# XXX'
 | 
						|
	return uid
 | 
						|
 | 
						|
# Initialize the typeswitch
 | 
						|
#
 | 
						|
for x in None, 0, 0.0, '', (), [], {}:
 | 
						|
	typeswitch[`type(x)`] = 'type(' + `x` + ')'
 | 
						|
for s in 'type(0)', 'abs', '[].append':
 | 
						|
	typeswitch[`type(eval(s))`] = 'type(' + s + ')'
 | 
						|
 | 
						|
# Dump a tuple object
 | 
						|
#
 | 
						|
def dumptuple(x, typedict, types, stack):
 | 
						|
	item_uids = []
 | 
						|
	xrepr = ''
 | 
						|
	for item in x:
 | 
						|
		item_uid = dumpobject(item, types, stack)
 | 
						|
		item_uids.append(item_uid)
 | 
						|
		xrepr = xrepr + ' ' + item_uid
 | 
						|
	del stack[-1:]
 | 
						|
	if typedict.has_key(xrepr):
 | 
						|
		return typedict[xrepr]
 | 
						|
	uid = genuid()
 | 
						|
	typedict[xrepr] = uid
 | 
						|
	print FN, '[', `uid`, '] = (',
 | 
						|
	for item_uid in item_uids:
 | 
						|
		print FN, '[', `item_uid`, '],',
 | 
						|
	print ')'
 | 
						|
	return uid
 | 
						|
 | 
						|
# Dump a list object
 | 
						|
#
 | 
						|
def dumplist(x, typedict, types, stack):
 | 
						|
	# Check for recursion
 | 
						|
	for x1, uid1 in stack:
 | 
						|
		if x is x1: return uid1
 | 
						|
	# Check for occurrence elsewhere in the typedict
 | 
						|
	for uid1 in typedict.keys():
 | 
						|
		if x is typedict[uid1]: return uid1
 | 
						|
	# This uses typedict differently!
 | 
						|
	uid = genuid()
 | 
						|
	typedict[uid] = x
 | 
						|
	print FN, '[', `uid`, '] = []'
 | 
						|
	stack.append(x, uid)
 | 
						|
	item_uids = []
 | 
						|
	for item in x:
 | 
						|
		item_uid = dumpobject(item, types, stack)
 | 
						|
		item_uids.append(item_uid)
 | 
						|
	del stack[-1:]
 | 
						|
	for item_uid in item_uids:
 | 
						|
		print FN, '[', `uid`, '].append(', FN, '[', `item_uid`, '])'
 | 
						|
	return uid
 | 
						|
 | 
						|
# Dump a dictionary object
 | 
						|
#
 | 
						|
def dumpdict(x, typedict, types, stack):
 | 
						|
	# Check for recursion
 | 
						|
	for x1, uid1 in stack:
 | 
						|
		if x is x1: return uid1
 | 
						|
	# Check for occurrence elsewhere in the typedict
 | 
						|
	for uid1 in typedict.keys():
 | 
						|
		if x is typedict[uid1]: return uid1
 | 
						|
	# This uses typedict differently!
 | 
						|
	uid = genuid()
 | 
						|
	typedict[uid] = x
 | 
						|
	print FN, '[', `uid`, '] = {}'
 | 
						|
	stack.append(x, uid)
 | 
						|
	item_uids = []
 | 
						|
	for key in x.keys():
 | 
						|
		val_uid = dumpobject(x[key], types, stack)
 | 
						|
		item_uids.append(key, val_uid)
 | 
						|
	del stack[-1:]
 | 
						|
	for key, val_uid in item_uids:
 | 
						|
		print FN, '[', `uid`, '][', `key`, '] =',
 | 
						|
		print FN, '[', `val_uid`, ']'
 | 
						|
	return uid
 | 
						|
 | 
						|
# Dump a module object
 | 
						|
#
 | 
						|
def dumpmodule(x, typedict, types, stack):
 | 
						|
	xrepr = `x`
 | 
						|
	if typedict.has_key(xrepr):
 | 
						|
		return typedict[xrepr]
 | 
						|
	from string import split
 | 
						|
	# `x` has the form <module 'foo'>
 | 
						|
	name = xrepr[9:-2]
 | 
						|
	uid = genuid()
 | 
						|
	typedict[xrepr] = uid
 | 
						|
	print 'import', name
 | 
						|
	print FN, '[', `uid`, '] =', name
 | 
						|
	return uid
 | 
						|
 | 
						|
 | 
						|
# Initialize dumpswitch, a table of functions to dump various objects,
 | 
						|
# indexed by `type(x)`.
 | 
						|
#
 | 
						|
for x in None, 0, 0.0:
 | 
						|
	dumpswitch[`type(x)`] = dumpvalue
 | 
						|
for x, f in ('', dumpstring), (type(0), dumptype), ((), dumptuple), \
 | 
						|
		([], dumplist), ({}, dumpdict), (sys, dumpmodule):
 | 
						|
	dumpswitch[`type(x)`] = f
 | 
						|
 | 
						|
 | 
						|
# Generate the next unique id; a string consisting of digits.
 | 
						|
# The seed is stored as seed[0].
 | 
						|
#
 | 
						|
seed = [0]
 | 
						|
#
 | 
						|
def genuid():
 | 
						|
	x = seed[0]
 | 
						|
	seed[0] = seed[0] + 1
 | 
						|
	return `x`
 |