Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

AutoReload: autoreload.py

Line 
1 #
2 # autoreload.py - automatically reload changed source
3 # code into a running program
4 #
5 # You may want to place the following two lines
6 # into your sitecustomize.py:
7 #
8 # import autoreload
9 # autoreload.run()
10 #
11 # or you can use the superreload() function
12 # instead of the standard reload() function.
13 #
14
15 # Created: Thomas Heller, 2000-04-17
16 #
17 # $Id: autoreload.py,v 1.9 2001/11/15 18:41:18 thomas Exp $
18 #
19 # $Log: autoreload.py,v $
20 # Revision 1.9  2001/11/15 18:41:18  thomas
21 # Cleaned up and made working again before posting to c.l.p.
22 # Added code to update bound (or unbound) methods as suggested
23 # by Just van Rossum. Thanks!
24 #
25 # ...
26 #
27 # Revision 1.1  2001/10/04 16:54:04  thomas
28 # Discovered this old module on my machine, it didn't work too well,
29 # but seems worth to continue with it...
30 # Checked in as a first step.
31
32 version = "$Revision: 1.9 $".split()[1]
33
34 # ToDo:
35 #
36 #  Cannot reload __main__ - explain why this cannot work,
37 #  and explain a workaround.
38 #
39 #  Optimize - the number of watches objects (in old_objects)
40 #  grows without limits. Think if this is really necessary...
41
42
43 import time, os, threading, sys, types, imp
44
45 def _get_compiled_ext():
46     for ext, mode, typ in imp.get_suffixes():
47         if typ == imp.PY_COMPILED:
48             return ext
49
50 # the official way to get the extension of compiled files (.pyc or .pyo)
51 PY_COMPILED_EXT = _get_compiled_ext()
52
53 class ModuleWatcher:
54     running = 0
55     def __init__(self):
56         # If we don't do this, there may be tracebacks
57         # when shutting down python.
58         import atexit
59         atexit.register(self.stop)
60
61     def run(self):
62         if self.running:
63             print "# autoreload already running"
64             return
65         print "# starting autoreload"
66         self.running = 1
67         self.thread = threading.Thread(target=self._check_modules)
68         self.thread.setDaemon(1)
69         self.thread.start()
70
71     def stop(self):
72         if not self.running:
73             print "# autoreload not running"
74             return
75         self.running = 0
76         self.thread.join()
77         print "# autoreload stopped"
78
79     def _check_modules(self):
80         while self.running:
81             time.sleep(0.01)
82             for m in sys.modules.values():
83                 if not hasattr(m, '__file__'):
84                     continue
85                 if m.__name__ == '__main__':
86
87                     # we cannot reload(__main__) First I thought we
88                     # could use mod = imp.load_module() and then
89                     # reload(mod) to simulate reload(main), but this
90                     # would execute the code in __main__ a second
91                     # time.
92
93                     continue
94                 file = m.__file__
95                 path, ext = os.path.splitext(file)
96
97                 if ext.lower() == '.py':
98                     ext = PY_COMPILED_EXT
99                     file = path + PY_COMPILED_EXT
100                 if ext != PY_COMPILED_EXT:
101                     continue
102
103                 try:
104                     if os.stat(file[:-1])[8] <= os.stat(file)[8]:
105                         continue
106                 except OSError:
107                     continue
108
109                 try:
110                     superreload(m)
111                 except:
112                     import traceback
113                     traceback.print_exc(0)
114
115 def update_function(old, new, attrnames):
116     for name in attrnames:
117         setattr(old, name, getattr(new, name))
118
119 def superreload(module,
120                 reload=reload,
121                 _old_objects = {}):
122     """superreload (module) ->  module
123
124     Enhanced version of the builtin reload function.
125     superreload replaces the class dictionary of every top-level
126     class in the module with the new one automatically,
127     as well as every function's code object.
128     """
129 ##    start = time.clock()
130     # retrieve the attributes from the module before the reload,
131     # and remember them in _old_objects.
132     for name, object in module.__dict__.items():
133         key = (module.__name__, name)
134         _old_objects.setdefault(key, []).append(object)
135         # print the refcount of old objects:
136 ##        if type(object) in (types.FunctionType, types.ClassType):
137 ##            print name, map(sys.getrefcount, _old_objects[key])
138
139 ##    print "# reloading module %r" % module
140
141     module = reload(module)
142     # XXX We have a problem here if importing the module fails!
143
144     # iterate over all objects and update them
145     count = 0
146     # XXX Can we optimize here?
147     # It may be that no references to the objects are present
148     # except those from our _old_objects dictionary.
149     # We should remove those. I have to learn about weak-refs!
150     for name, new_obj in module.__dict__.items():
151         key = (module.__name__, name)
152         if _old_objects.has_key(key):
153             for old_obj in _old_objects[key]:
154                 if type(new_obj) == types.ClassType:
155                     old_obj.__dict__.update(new_obj.__dict__)
156                     count += 1
157                 elif type(new_obj) == types.FunctionType:
158                     update_function(old_obj,
159                            new_obj,
160                            "func_code func_defaults func_doc".split())
161                     count += 1
162                 elif type(new_obj) == types.MethodType:
163                     update_function(old_obj.im_func,
164                            new_obj.im_func,
165                            "func_code func_defaults func_doc".split())
166                     count += 1
167 ##    stop = time.clock()
168 ##    print "# updated %d objects from %s" % (count, module)
169 ##    print "# This took %.3f seconds" % (stop - start)
170
171     return module
172
173 _watcher = ModuleWatcher()
174
175 run = _watcher.run
176 stop = _watcher.stop
177
178 __all__ = ['run', 'stop', 'superreload']

Hosted by WebFaction

Log in as guest/cpguest to create tickets