Show More
@@ -219,132 +219,140 b' def superreload(module, reload=reload, old_objects={}):' | |||||
219 |
|
219 | |||
220 | return module |
|
220 | return module | |
221 |
|
221 | |||
222 | reloader = ModuleReloader() |
|
|||
223 |
|
||||
224 | #------------------------------------------------------------------------------ |
|
222 | #------------------------------------------------------------------------------ | |
225 | # IPython connectivity |
|
223 | # IPython connectivity | |
226 | #------------------------------------------------------------------------------ |
|
224 | #------------------------------------------------------------------------------ | |
227 | from IPython.core import ipapi |
|
|||
228 | from IPython.core.error import TryNext |
|
|||
229 |
|
||||
230 | ip = ipapi.get() |
|
|||
231 |
|
||||
232 | autoreload_enabled = False |
|
|||
233 |
|
||||
234 | def runcode_hook(self): |
|
|||
235 | if not autoreload_enabled: |
|
|||
236 | raise TryNext |
|
|||
237 | try: |
|
|||
238 | reloader.check() |
|
|||
239 | except: |
|
|||
240 | pass |
|
|||
241 |
|
||||
242 | def enable_autoreload(): |
|
|||
243 | global autoreload_enabled |
|
|||
244 | autoreload_enabled = True |
|
|||
245 |
|
||||
246 | def disable_autoreload(): |
|
|||
247 | global autoreload_enabled |
|
|||
248 | autoreload_enabled = False |
|
|||
249 |
|
||||
250 | def autoreload_f(self, parameter_s=''): |
|
|||
251 | r""" %autoreload => Reload modules automatically |
|
|||
252 |
|
||||
253 | %autoreload |
|
|||
254 | Reload all modules (except those excluded by %aimport) automatically now. |
|
|||
255 |
|
||||
256 | %autoreload 0 |
|
|||
257 | Disable automatic reloading. |
|
|||
258 |
|
||||
259 | %autoreload 1 |
|
|||
260 | Reload all modules imported with %aimport every time before executing |
|
|||
261 | the Python code typed. |
|
|||
262 |
|
||||
263 | %autoreload 2 |
|
|||
264 | Reload all modules (except those excluded by %aimport) every time |
|
|||
265 | before executing the Python code typed. |
|
|||
266 |
|
||||
267 | Reloading Python modules in a reliable way is in general |
|
|||
268 | difficult, and unexpected things may occur. %autoreload tries to |
|
|||
269 | work around common pitfalls by replacing function code objects and |
|
|||
270 | parts of classes previously in the module with new versions. This |
|
|||
271 | makes the following things to work: |
|
|||
272 |
|
225 | |||
273 | - Functions and classes imported via 'from xxx import foo' are upgraded |
|
226 | from IPython.core.plugin import Plugin | |
274 | to new versions when 'xxx' is reloaded. |
|
227 | from IPython.core.hooks import TryNext | |
275 |
|
228 | |||
276 | - Methods and properties of classes are upgraded on reload, so that |
|
229 | class Autoreload(Plugin): | |
277 | calling 'c.foo()' on an object 'c' created before the reload causes |
|
230 | def __init__(self, shell=None, config=None): | |
278 | the new code for 'foo' to be executed. |
|
231 | super(Autoreload, self).__init__(shell=shell, config=config) | |
279 |
|
232 | |||
280 | Some of the known remaining caveats are: |
|
233 | self.shell.define_magic('autoreload', self.magic_autoreload) | |
|
234 | self.shell.define_magic('aimport', self.magic_aimport) | |||
|
235 | self.shell.set_hook('pre_run_code_hook', self.pre_run_code_hook) | |||
281 |
|
236 | |||
282 | - Replacing code objects does not always succeed: changing a @property |
|
237 | self._enabled = False | |
283 | in a class to an ordinary method or a method to a member variable |
|
238 | self._reloader = ModuleReloader() | |
284 | can cause problems (but in old objects only). |
|
239 | self._reloader.check_all = False | |
285 |
|
240 | |||
286 | - Functions that are removed (eg. via monkey-patching) from a module |
|
241 | def pre_run_code_hook(self, ipself): | |
287 | before it is reloaded are not upgraded. |
|
242 | if not self._enabled: | |
288 |
|
243 | raise TryNext | ||
289 | - C extension modules cannot be reloaded, and so cannot be |
|
244 | try: | |
290 | autoreloaded. |
|
245 | self._reloader.check() | |
291 |
|
246 | except: | ||
292 | """ |
|
247 | pass | |
293 | if parameter_s == '': |
|
|||
294 | reloader.check(True) |
|
|||
295 | elif parameter_s == '0': |
|
|||
296 | disable_autoreload() |
|
|||
297 | elif parameter_s == '1': |
|
|||
298 | reloader.check_all = False |
|
|||
299 | enable_autoreload() |
|
|||
300 | elif parameter_s == '2': |
|
|||
301 | reloader.check_all = True |
|
|||
302 | enable_autoreload() |
|
|||
303 |
|
||||
304 | def aimport_f(self, parameter_s=''): |
|
|||
305 | """%aimport => Import modules for automatic reloading. |
|
|||
306 |
|
248 | |||
307 | %aimport |
|
249 | def magic_autoreload(self, ipself, parameter_s=''): | |
308 | List modules to automatically import and not to import. |
|
250 | r"""%autoreload => Reload modules automatically | |
|
251 | ||||
|
252 | %autoreload | |||
|
253 | Reload all modules (except those excluded by %aimport) automatically | |||
|
254 | now. | |||
|
255 | ||||
|
256 | %autoreload 0 | |||
|
257 | Disable automatic reloading. | |||
|
258 | ||||
|
259 | %autoreload 1 | |||
|
260 | Reload all modules imported with %aimport every time before executing | |||
|
261 | the Python code typed. | |||
|
262 | ||||
|
263 | %autoreload 2 | |||
|
264 | Reload all modules (except those excluded by %aimport) every time | |||
|
265 | before executing the Python code typed. | |||
|
266 | ||||
|
267 | Reloading Python modules in a reliable way is in general | |||
|
268 | difficult, and unexpected things may occur. %autoreload tries to | |||
|
269 | work around common pitfalls by replacing function code objects and | |||
|
270 | parts of classes previously in the module with new versions. This | |||
|
271 | makes the following things to work: | |||
|
272 | ||||
|
273 | - Functions and classes imported via 'from xxx import foo' are upgraded | |||
|
274 | to new versions when 'xxx' is reloaded. | |||
|
275 | ||||
|
276 | - Methods and properties of classes are upgraded on reload, so that | |||
|
277 | calling 'c.foo()' on an object 'c' created before the reload causes | |||
|
278 | the new code for 'foo' to be executed. | |||
|
279 | ||||
|
280 | Some of the known remaining caveats are: | |||
|
281 | ||||
|
282 | - Replacing code objects does not always succeed: changing a @property | |||
|
283 | in a class to an ordinary method or a method to a member variable | |||
|
284 | can cause problems (but in old objects only). | |||
|
285 | ||||
|
286 | - Functions that are removed (eg. via monkey-patching) from a module | |||
|
287 | before it is reloaded are not upgraded. | |||
|
288 | ||||
|
289 | - C extension modules cannot be reloaded, and so cannot be | |||
|
290 | autoreloaded. | |||
|
291 | ||||
|
292 | """ | |||
|
293 | if parameter_s == '': | |||
|
294 | self._reloader.check(True) | |||
|
295 | elif parameter_s == '0': | |||
|
296 | self._enabled = False | |||
|
297 | elif parameter_s == '1': | |||
|
298 | self._reloader.check_all = False | |||
|
299 | self._enabled = True | |||
|
300 | elif parameter_s == '2': | |||
|
301 | self._reloader.check_all = True | |||
|
302 | self._enabled = True | |||
|
303 | ||||
|
304 | def magic_aimport(self, ipself, parameter_s=''): | |||
|
305 | """%aimport => Import modules for automatic reloading. | |||
|
306 | ||||
|
307 | %aimport | |||
|
308 | List modules to automatically import and not to import. | |||
|
309 | ||||
|
310 | %aimport foo | |||
|
311 | Import module 'foo' and mark it to be autoreloaded for %autoreload 1 | |||
|
312 | ||||
|
313 | %aimport -foo | |||
|
314 | Mark module 'foo' to not be autoreloaded for %autoreload 1 | |||
|
315 | ||||
|
316 | """ | |||
|
317 | ||||
|
318 | modname = parameter_s | |||
|
319 | if not modname: | |||
|
320 | to_reload = self._reloader.modules.keys() | |||
|
321 | to_reload.sort() | |||
|
322 | to_skip = self._reloader.skip_modules.keys() | |||
|
323 | to_skip.sort() | |||
|
324 | if self._reloader.check_all: | |||
|
325 | print "Modules to reload:\nall-expect-skipped" | |||
|
326 | else: | |||
|
327 | print "Modules to reload:\n%s" % ' '.join(to_reload) | |||
|
328 | print "\nModules to skip:\n%s" % ' '.join(to_skip) | |||
|
329 | elif modname.startswith('-'): | |||
|
330 | modname = modname[1:] | |||
|
331 | try: | |||
|
332 | del self._reloader.modules[modname] | |||
|
333 | except KeyError: | |||
|
334 | pass | |||
|
335 | self._reloader.skip_modules[modname] = True | |||
|
336 | else: | |||
|
337 | try: | |||
|
338 | del self._reloader.skip_modules[modname] | |||
|
339 | except KeyError: | |||
|
340 | pass | |||
|
341 | self._reloader.modules[modname] = True | |||
309 |
|
342 | |||
310 | %aimport foo |
|
343 | # Inject module to user namespace; handle also submodules properly | |
311 | Import module 'foo' and mark it to be autoreloaded for %autoreload 1 |
|
344 | __import__(modname) | |
|
345 | basename = modname.split('.')[0] | |||
|
346 | mod = sys.modules[basename] | |||
|
347 | ipself.push({basename: mod}) | |||
312 |
|
348 | |||
313 | %aimport -foo |
|
|||
314 | Mark module 'foo' to not be autoreloaded for %autoreload 1 |
|
|||
315 |
|
349 | |||
316 | """ |
|
350 | _loaded = False | |
317 |
|
351 | |||
318 | modname = parameter_s |
|
352 | def load_ipython_extension(ip): | |
319 | if not modname: |
|
353 | """Load the extension in IPython.""" | |
320 | to_reload = reloader.modules.keys() |
|
354 | global _loaded | |
321 | to_reload.sort() |
|
355 | if not _loaded: | |
322 | to_skip = reloader.skip_modules.keys() |
|
356 | plugin = Autoreload(shell=ip, config=ip.config) | |
323 | to_skip.sort() |
|
357 | ip.plugin_manager.register_plugin('autoreload', plugin) | |
324 | if reloader.check_all: |
|
358 | _loaded = True | |
325 | print "Modules to reload:\nall-expect-skipped" |
|
|||
326 | else: |
|
|||
327 | print "Modules to reload:\n%s" % ' '.join(to_reload) |
|
|||
328 | print "\nModules to skip:\n%s" % ' '.join(to_skip) |
|
|||
329 | elif modname.startswith('-'): |
|
|||
330 | modname = modname[1:] |
|
|||
331 | try: del reloader.modules[modname] |
|
|||
332 | except KeyError: pass |
|
|||
333 | reloader.skip_modules[modname] = True |
|
|||
334 | else: |
|
|||
335 | try: del reloader.skip_modules[modname] |
|
|||
336 | except KeyError: pass |
|
|||
337 | reloader.modules[modname] = True |
|
|||
338 |
|
||||
339 | # Inject module to user namespace; handle also submodules properly |
|
|||
340 | __import__(modname) |
|
|||
341 | basename = modname.split('.')[0] |
|
|||
342 | mod = sys.modules[basename] |
|
|||
343 | ip.push({basename: mod}) |
|
|||
344 |
|
||||
345 | def init(): |
|
|||
346 | ip.define_magic('autoreload', autoreload_f) |
|
|||
347 | ip.define_magic('aimport', aimport_f) |
|
|||
348 | ip.set_hook('pre_runcode_hook', runcode_hook) |
|
|||
349 |
|
||||
350 | init() |
|
General Comments 0
You need to be logged in to leave comments.
Login now