Thank you so much! When I finally get a moment to take a break, I'll look in more detail into using your suggestion.
--b On Apr 26, 2007, at 12:47 AM, Pauli Virtanen wrote: > belinda thom kirjoitti: >> On Apr 25, 2007, at 12:46 PM, Bill Baxter wrote: >> >> Agree w/most of what you've said, but will add one other thing that >> drives me nuts in python that hasn't been a problem in Matplotlib: >> >> In Python, if interacting w/the interpreter as your primary IDE, and >> if you've got multiple files that depend on one another that you're >> modifying, then you need to restart the interpreter frequently b/c >> otherwise things in the interpreter can be stale; IOW, changes to >> several interdependent files aren't easy to import so that everything >> in your interpreted environment reflects the latest code. Yeah, >> there's reload tricks, but doing them in the right order and the >> right number of times can be a pain when dependencies are cyclic. >> >> I realize in general that this issue of stale code is just difficult, >> that its not inherently a Python problem per se, for automatic >> percolation of code changes backwards in time is difficult in >> general, but I've never had the problem bite me when I was developing >> in Matlab. I just save whatever file, and it appears that whatever's >> latest on disk is what's executed. (Friends who know more about PL >> than I tell me I've been lucky.) > > I've been using the attached autoreload code (by Thomas Heller, > different versions are probably floating around the net) rather > successfully for a more Matlabish feel to IPython. It reloads modules > every time their files have been changed. > > Of course, this doesn't solve all staleness problems you describe, but > only eliminates manual work involved in solving the most common ones. > Reloading modules does have pitfalls [1], but at least in my use these > haven't really mattered much in practice. > > I think having autoreload functionality bundled with IPython (maybe > turned off per default) would be quite useful: although in some rare > cases autoreloading doesn't work in the ideal way, it's very > convenient > not to have to type reload(foo) after every change, especially when > tweaking for example plotting scripts. > > Pauli > > [1] For example, instances of classes created are not updated on > reload, > but continue using the old code. Also, from foo import * imports > are not > updated, so you'll have to manually touch files that do this if 'foo' > has been changed. > """ > > autoreload.py - automatically reload changed source > code into a running program > > You might want to add the following to your ~/.ipython/ipythonrc > > import_mod sys > execute sys.path.append('path/where/this/file/resides') > import_mod autoreload > execute autoreload.run() > > or adding the following > > import sys > sys.path.append('path/where/this/file/resides') > import autoreload > autoreload.run() > > to some startup file. > > > Created: Thomas Heller, 2000-04-17 > Modified: Pauli Virtanen, 2006 > """ > > # $Id: autoreload.py 3117 2006-09-27 20:28:46Z pauli $ > # > # $Log: autoreload.py,v $ > # Revision 1.9 2001/11/15 18:41:18 thomas > # Cleaned up and made working again before posting to c.l.p. > # Added code to update bound (or unbound) methods as suggested > # by Just van Rossum. Thanks! > # > # ... > # > # 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.9 $".split()[1] > > # ToDo: > # > # Cannot reload __main__ - explain why this cannot work, > # and explain a workaround. > # > # 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, inspect, traceback > > def _get_compiled_ext(): > for ext, mode, typ in imp.get_suffixes(): > if typ == imp.PY_COMPILED: > return ext > > # the official way to get the extension of compiled files (.pyc > or .pyo) > 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 > print "# starting autoreload" > 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): > skipped = {} > 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: > pymtime = os.stat(file[:-1])[8] > if pymtime <= os.stat(file)[8]: > continue > if skipped.get(file[:-1], None) == pymtime: > continue > except OSError: > continue > > try: > superreload(m) > if file[:-1] in skipped: > del skipped[file[:-1]] > except: > skipped[file[:-1]] = pymtime > import traceback > traceback.print_exc(0) > > def update_function(old, new, attrnames): > for name in attrnames: > setattr(old, name, getattr(new, name)) > > 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.setdefault(key, []).append(object) > # print the refcount of old objects: > ## if type(object) in (types.FunctionType, types.ClassType): > ## print name, map(sys.getrefcount, _old_objects[key]) > > ## print "# reloading module %r" % module > > module = reload(module) > # XXX We have a problem here if importing the module fails! > > # iterate over all objects and update them > count = 0 > # XXX Can we 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 type(new_obj) == types.ClassType: > old_obj.__dict__.update(new_obj.__dict__) > count += 1 > elif type(new_obj) == types.FunctionType: > update_function(old_obj, > new_obj, > "func_code func_defaults func_doc".split()) > count += 1 > elif type(new_obj) == types.MethodType: > update_function(old_obj.im_func, > new_obj.im_func, > "func_code func_defaults func_doc".split()) > count += 1 > ## stop = time.clock() > ## print "# updated %d objects from %s" % (count, module) > ## print "# This took %.3f seconds" % (stop - start) > > return module > > _watcher = ModuleWatcher() > > run = _watcher.run > stop = _watcher.stop > > __all__ = ['run', 'stop', 'superreload'] > _______________________________________________ > Numpy-discussion mailing list > Numpy-discussion@scipy.org > http://projects.scipy.org/mailman/listinfo/numpy-discussion _______________________________________________ Numpy-discussion mailing list Numpy-discussion@scipy.org http://projects.scipy.org/mailman/listinfo/numpy-discussion