IsPython really O-O?
Thomas Heller
thomas.heller at ion-tof.com
Tue Nov 13 15:51:53 EST 2001
> "AD" == Andrew Dalke <dalke at dalkescientific.com> writes:
AD> but I've never really needed it. Better I think would be if
AD> Python's IDE's offered a reload() which was closer to
AD> Smalltalks's, where a modified class definition propagates
AD> even to existing instances of that class. So someone could
AD> edit a module and manipulate things interactively without
AD> having to reload and rerun everything.
Here's a script I'm sometimes working on which does this.
It's not bulletproof, but it kindof works.
It runs a thread in the background (once started), which checks
the timestamp of all modules loaded from the filesystem.
It it's out of date, is is reloaded automatically.
Classes and functions in the reloaded module are
updated automatically to the new version.
Hopefully sometime I will complete it and post it to the Python Cookbook.
Thomas
---- autoreload.py ----
#
# autoreload.py - automatically reload changed source
# code into a running program
#
# You may want to place the following two lines
# into your sitecustomize.py:
#
# import autoreload
# autoreload.run()
#
# Created: Thomas Heller, 2000-04-17
#
# $Id: autoreload.py,v 1.8 2001/11/13 20:44:51 thomas Exp $
#
# $Log: autoreload.py,v $
# Revision 1.8 2001/11/13 20:44:51 thomas
# Clean up a little...
#
# Revision 1.7 2001/10/05 16:38:35 thomas
# Assure a clean shutdown of the thread with atexit
#
# Revision 1.6 2001/10/04 19:21:46 thomas
# Only some comments added and a typo fixed.
#
# Revision 1.3 2001/10/04 18:37:54 thomas
# Stores now old objects with (modulename, objectname) as keys.
#
# Revision 1.1 2001/10/04 16:54:04 thomas
# Discovered this old module on my machine, it didn't work too well,
# but seems worth to continue with it...
# Checked in as a first step.
version = "$Revision: 1.8 $".split()[1]
# ToDo:
#
# Cannot reload __main__ - explain why this cannot work
#
# Optimize - the number of watches objects (in old_objects)
# grows without limits. Think if this is really necessary...
import time, os, threading, sys, types, imp
def _get_compiled_ext():
for ext, mode, typ in imp.get_suffixes():
if typ == imp.PY_COMPILED:
return ext
PY_COMPILED_EXT = _get_compiled_ext()
class ModuleWatcher:
running = 0
def __init__(self):
# If we don't do this, there may be tracebacks
# when shutting down python.
import atexit
atexit.register(self.stop)
def run(self):
if self.running:
print "# autoreload already running"
return
self.running = 1
self.thread = threading.Thread(target=self._check_modules)
self.thread.setDaemon(1)
self.thread.start()
def stop(self):
if not self.running:
print "# autoreload not running"
return
self.running = 0
self.thread.join()
## print "# autoreload stopped"
def _check_modules(self):
## print "# autoreload running"
while self.running:
time.sleep(0.01)
for m in sys.modules.values():
if not hasattr(m, '__file__'):
continue
if m.__name__ == '__main__':
# we cannot reload(__main__) First I thought we
# could use mod = imp.load_module() and then
# reload(mod) to simulate reload(main), but this
# would execute the code in __main__ a second
# time.
continue
file = m.__file__
dirname = os.path.dirname(file)
path, ext = os.path.splitext(file)
if ext.lower() == '.py':
ext = PY_COMPILED_EXT
file = os.path.join(dirname, path + PY_COMPILED_EXT)
if ext != PY_COMPILED_EXT:
continue
try:
if os.stat(file[:-1])[8] <= os.stat(file)[8]:
continue
except OSError:
continue
try:
superreload(m)
except:
import traceback
traceback.print_exc(0)
def superreload(module,
reload=reload,
_old_objects={}):
"""superreload (module) -> module
Enhanced version of the builtin reload function.
superreload replaces the class dictionary of every top-level
class in the module with the new one automatically,
as well as every function's code object.
"""
start = time.clock()
# retrieve the attributes from the module before the reload,
# and remember them in _old_objects.
for name, object in module.__dict__.items():
key = (module.__name__, name)
_old_objects[key] = _old_objects.get(key, []) + [object]
module = reload(module)
# iterate over all objects and update them
count = 0
# XXX We should optimize here:
# It may be that no references to the objects are present
# except those from our _old_objects dictionary.
# We should remove those. I have to learn about weak-refs!
for name, new_obj in module.__dict__.items():
key = (module.__name__, name)
if _old_objects.has_key(key):
for old_obj in _old_objects[key]:
## if sys.getrefcount(old_obj) == 3:
## _old_objects[key].remove(old_obj)
## continue
if type(new_obj) == types.ClassType:
old_obj.__dict__ = new_obj.__dict__.copy()
count += 1
print sys.getrefcount(old_obj), name
elif type(new_obj) == types.FunctionType:
old_obj.func_code = new_obj.func_code
count += 1
print sys.getrefcount(old_obj), name
stop = time.clock()
print "# updated %d objects from %s" % (count, module)
print "# This took %.3f seconds" % (stop - start)
print
return module
_watcher = ModuleWatcher()
run = _watcher.run
stop = _watcher.stop
---- EOF ----
More information about the Python-list
mailing list