##// END OF EJS Templates
autoreload docstring
vivainio2 -
Show More
@@ -1,239 +1,244 b''
1 1 """
2 2 IPython extension: autoreload modules before executing the next line
3 3
4 Try::
5
6 %autoreload?
7
8 for documentation.
4 9 """
5 10
6 11 # Pauli Virtanen <pav@iki.fi>, 2008.
7 12 # Thomas Heller, 2000.
8 13 #
9 14 # This IPython module is written by Pauli Virtanen, based on the autoreload
10 15 # code by Thomas Heller.
11 16
12 17 #------------------------------------------------------------------------------
13 18 # Autoreload functionality
14 19 #------------------------------------------------------------------------------
15 20
16 21 import time, os, threading, sys, types, imp, inspect, traceback, atexit
17 22
18 23 def _get_compiled_ext():
19 24 """Official way to get the extension of compiled files (.pyc or .pyo)"""
20 25 for ext, mode, typ in imp.get_suffixes():
21 26 if typ == imp.PY_COMPILED:
22 27 return ext
23 28
24 29 PY_COMPILED_EXT = _get_compiled_ext()
25 30
26 31 class ModuleReloader(object):
27 32 skipped = {}
28 33 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
29 34
30 35 modules = {}
31 36 """Modules specially marked as autoreloadable."""
32 37
33 38 skip_modules = {}
34 39 """Modules specially marked as not autoreloadable."""
35 40
36 41 check_all = True
37 42 """Autoreload all modules, not just those listed in 'modules'"""
38 43
39 44 def check(self, check_all=False):
40 45 """Check whether some modules need to be reloaded."""
41 46
42 47 if check_all or self.check_all:
43 48 modules = sys.modules.keys()
44 49 else:
45 50 modules = self.modules.keys()
46 51
47 52 for modname in modules:
48 53 m = sys.modules.get(modname, None)
49 54
50 55 if modname in self.skip_modules:
51 56 continue
52 57
53 58 if not hasattr(m, '__file__'):
54 59 continue
55 60
56 61 if m.__name__ == '__main__':
57 62 # we cannot reload(__main__)
58 63 continue
59 64
60 65 filename = m.__file__
61 66 dirname = os.path.dirname(filename)
62 67 path, ext = os.path.splitext(filename)
63 68
64 69 if ext.lower() == '.py':
65 70 ext = PY_COMPILED_EXT
66 71 filename = os.path.join(dirname, path + PY_COMPILED_EXT)
67 72
68 73 if ext != PY_COMPILED_EXT:
69 74 continue
70 75
71 76 try:
72 77 pymtime = os.stat(filename[:-1]).st_mtime
73 78 if pymtime <= os.stat(filename).st_mtime:
74 79 continue
75 80 if self.skipped.get(filename[:-1], None) == pymtime:
76 81 continue
77 82 except OSError:
78 83 continue
79 84
80 85 try:
81 86 superreload(m)
82 87 if filename[:-1] in self.skipped:
83 88 del self.skipped[filename[:-1]]
84 89 except:
85 90 self.skipped[filename[:-1]] = pymtime
86 91
87 92 def update_function(old, new, attrnames):
88 93 for name in attrnames:
89 94 setattr(old, name, getattr(new, name))
90 95
91 96 def superreload(module, reload=reload):
92 97 """Enhanced version of the builtin reload function.
93 98
94 99 superreload replaces the class dictionary of every top-level
95 100 class in the module with the new one automatically,
96 101 as well as every function's code object.
97 102
98 103 """
99 104
100 105 module = reload(module)
101 106
102 107 # iterate over all objects and update them
103 108 count = 0
104 109 for name, new_obj in module.__dict__.items():
105 110 key = (module.__name__, name)
106 111 if _old_objects.has_key(key):
107 112 for old_obj in _old_objects[key]:
108 113 if type(new_obj) == types.ClassType:
109 114 old_obj.__dict__.update(new_obj.__dict__)
110 115 count += 1
111 116 elif type(new_obj) == types.FunctionType:
112 117 update_function(old_obj,
113 118 new_obj,
114 119 "func_code func_defaults func_doc".split())
115 120 count += 1
116 121 elif type(new_obj) == types.MethodType:
117 122 update_function(old_obj.im_func,
118 123 new_obj.im_func,
119 124 "func_code func_defaults func_doc".split())
120 125 count += 1
121 126
122 127 return module
123 128
124 129 reloader = ModuleReloader()
125 130
126 131 #------------------------------------------------------------------------------
127 132 # IPython monkey-patching
128 133 #------------------------------------------------------------------------------
129 134
130 135 import IPython.iplib
131 136
132 137 autoreload_enabled = False
133 138
134 139 def runcode_hook(self):
135 140 if not autoreload_enabled:
136 141 raise IPython.ipapi.TryNext
137 142 try:
138 143 reloader.check()
139 144 except:
140 145 pass
141 146
142 147
143 148 def enable_autoreload():
144 149 global autoreload_enabled
145 150 autoreload_enabled = True
146 151
147 152
148 153 def disable_autoreload():
149 154 global autoreload_enabled
150 155 autoreload_enabled = False
151 156
152 157 #------------------------------------------------------------------------------
153 158 # IPython connectivity
154 159 #------------------------------------------------------------------------------
155 160
156 161 import IPython.ipapi
157 162 ip = IPython.ipapi.get()
158 163
159 164 def autoreload_f(self, parameter_s=''):
160 165 r""" %autoreload => Reload modules automatically
161 166
162 167 %autoreload
163 168 Reload all modules (except thoses excluded by %aimport) automatically now.
164 169
165 170 %autoreload 1
166 171 Reload all modules imported with %aimport every time before executing
167 172 the Python code typed.
168 173
169 174 %autoreload 2
170 175 Reload all modules (except thoses excluded by %aimport) every time
171 176 before executing the Python code typed.
172 177
173 178 Reloading Python modules in a reliable way is in general
174 179 difficult, and unexpected things may occur. Some of the common
175 180 caveats relevant for 'autoreload' are:
176 181
177 182 - Modules are not reloaded in any specific order, and no dependency
178 183 analysis is done. For example, modules with 'from xxx import foo'
179 184 retain old versions of 'foo' when 'xxx' is autoreloaded.
180 185 - Functions or objects imported from the autoreloaded module to
181 186 the interactive namespace are not updated.
182 187 - C extension modules cannot be reloaded, and so cannot be
183 188 autoreloaded.
184 189 """
185 190 if parameter_s == '':
186 191 reloader.check(True)
187 192 elif parameter_s == '0':
188 193 disable_autoreload()
189 194 elif parameter_s == '1':
190 195 reloader.check_all = False
191 196 enable_autoreload()
192 197 elif parameter_s == '2':
193 198 reloader.check_all = True
194 199 enable_autoreload()
195 200
196 201 def aimport_f(self, parameter_s=''):
197 202 """%aimport => Import modules for automatic reloading.
198 203
199 204 %aimport
200 205 List modules to automatically import and not to import.
201 206
202 207 %aimport foo
203 208 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
204 209
205 210 %aimport -foo
206 211 Mark module 'foo' to not be autoreloaded for %autoreload 1
207 212
208 213 """
209 214
210 215 modname = parameter_s
211 216 if not modname:
212 217 to_reload = reloader.modules.keys()
213 218 to_reload.sort()
214 219 to_skip = reloader.skip_modules.keys()
215 220 to_skip.sort()
216 221 if reloader.check_all:
217 222 print "Modules to reload:\nall-expect-skipped"
218 223 else:
219 224 print "Modules to reload:\n%s" % ' '.join(to_reload)
220 225 print "\nModules to skip:\n%s" % ' '.join(to_skip)
221 226 elif modname.startswith('-'):
222 227 modname = modname[1:]
223 228 try: del reloader.modules[modname]
224 229 except KeyError: pass
225 230 reloader.skip_modules[modname] = True
226 231 else:
227 232 try: del reloader.skip_modules[modname]
228 233 except KeyError: pass
229 234 reloader.modules[modname] = True
230 235
231 236 mod = __import__(modname)
232 237 ip.to_user_ns({modname: mod})
233 238
234 239 def init():
235 240 ip.expose_magic('autoreload', autoreload_f)
236 241 ip.expose_magic('aimport', aimport_f)
237 242 ip.set_hook('pre_runcode_hook', runcode_hook)
238 243
239 244 init() No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now