Skip to content

Instantly share code, notes, and snippets.

@spin6lock
Created August 10, 2012 07:01
Show Gist options
  • Save spin6lock/3312053 to your computer and use it in GitHub Desktop.
Save spin6lock/3312053 to your computer and use it in GitHub Desktop.
python update
# -*- coding: utf-8 -*-
def update(module_name):
import types, gc, re
def test_and_process_list(obj, old, new):
if not isinstance(obj, list): return
# find the references in list
refs = [ index for index, item in enumerate(obj) if item is old ]
# update the list
for index in refs: obj[index] = new
def test_and_process_dict(obj, old, new):
if not isinstance(obj, dict): return
# if the reference is in the key
refs = [ key for key,_ in obj.iteritems() if key is old ]
for key in refs:
obj[new] = obj[key]
del obj[key]
# if the reference is in the value
refs = [ key for key,value in obj.iteritems() if value is old ]
for key in refs: obj[key] = new
def test_and_process_method(obj, old, new):
return
# fix-me: method reference have some bug to fix
# 2010-03-15 15:27:51 by BlueQ
if not isinstance(obj, (types.MethodType, types.UnboundMethodType)): return
obj.im_self.__class__ = new
func = obj
new_func = getattr(obj.im_self, obj.im_func, obj.func_name)
objs = gc.get_referrers(func)
[ map( lambda fun:fun(obj, func, new_func),
[test_and_process_list,
test_and_process_dict]
) for obj in objs]
def test_and_process_object(obj, old, new):
if not isclass(old): return
if not isinstance(obj, old): return
obj.__class__ = new
def process_default(obj, old, new):
# do nothing
pass
def update_one_reference((obj, old, new)):
# process update by the type of object
map( lambda fun: fun(obj, old, new),
[test_and_process_dict,
test_and_process_list,
test_and_process_method,
test_and_process_object,
process_default])
def update_references((old_value, new_value)):
objs = gc.get_referrers(old_value)
map( update_one_reference, [(obj, old_value, new_value) for obj in objs] )
def isclass(cls):
return isinstance(cls, types.TypeType)
# Test the variable, if it need update return True else return False
def need_update_variable((key, old_value)):
# rules:
# 1. internal variables (start with '__' and end with '__') use the OLD value
# 2. classes use the NEW value
# 3. functions use the NEW value
# 4. variables with the name is all upper charaters use the NEW value
# 5. other variables use OLD value
if re.match(r'__.*__', key): # rule 1
setattr(module, key, old_value)
return False
if isclass(old_value): # rule 2
print ">>> [U] class: %s"%key
return True
if callable(old_value): # rule 3
print ">>> [U] function: %s"%key
return True
if key.isupper(): # rule 4
print ">>> [U] const: %s"%key
return True
# these variables use the cached value, replace it back
setattr(module, key, old_value) # rule 5
return False
def update_module(module, update_items):
print ">>> [I] the following variables are updated"
# find all the variables that need update
vars = filter( need_update_variable, update_items.iteritems() )
# update all the reference of each variable
map( update_references, [(old_value, getattr(module, key)) for key, old_value in vars] )
gc.disable()
try:
print ""
print ">>> =============================="
print ">>> [I] updating module %s...."%module_name
# collect garbage before gc.get_referrers
gc.collect()
module = __import__(module_name)
update_items = dict(module.__dict__)
reload(module)
update_module(module, update_items)
print ">>> [I] update %s success" % module_name
print ">>> =============================="
print ""
finally:
gc.enable()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment