##// END OF EJS Templates
[merge] Merging with upstream trunk.
Fernando Perez -
r2097:6aff330d merge
parent child Browse files
Show More
@@ -1,7 +1,7 b''
1 1 """
2 2 IPython extension: autoreload modules before executing the next line
3 3
4 Try::
4 Try::
5 5
6 6 %autoreload?
7 7
@@ -32,7 +32,7 b' PY_COMPILED_EXT = _get_compiled_ext()'
32 32 class ModuleReloader(object):
33 33 failed = {}
34 34 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
35
35
36 36 modules = {}
37 37 """Modules specially marked as autoreloadable."""
38 38
@@ -44,39 +44,39 b' class ModuleReloader(object):'
44 44
45 45 old_objects = {}
46 46 """(module-name, name) -> weakref, for replacing old code objects"""
47
47
48 48 def check(self, check_all=False):
49 49 """Check whether some modules need to be reloaded."""
50
50
51 51 if check_all or self.check_all:
52 52 modules = sys.modules.keys()
53 53 else:
54 54 modules = self.modules.keys()
55
55
56 56 for modname in modules:
57 57 m = sys.modules.get(modname, None)
58 58
59 59 if modname in self.skip_modules:
60 60 continue
61
61
62 62 if not hasattr(m, '__file__'):
63 63 continue
64
64
65 65 if m.__name__ == '__main__':
66 66 # we cannot reload(__main__)
67 67 continue
68
68
69 69 filename = m.__file__
70 70 dirname = os.path.dirname(filename)
71 71 path, ext = os.path.splitext(filename)
72
72
73 73 if ext.lower() == '.py':
74 74 ext = PY_COMPILED_EXT
75 75 filename = os.path.join(dirname, path + PY_COMPILED_EXT)
76
76
77 77 if ext != PY_COMPILED_EXT:
78 78 continue
79
79
80 80 try:
81 81 pymtime = os.stat(filename[:-1]).st_mtime
82 82 if pymtime <= os.stat(filename).st_mtime:
@@ -85,7 +85,7 b' class ModuleReloader(object):'
85 85 continue
86 86 except OSError:
87 87 continue
88
88
89 89 try:
90 90 superreload(m, reload, self.old_objects)
91 91 if filename[:-1] in self.failed:
@@ -118,12 +118,12 b' def update_class(old, new):'
118 118 new_obj = getattr(new, key)
119 119 except AttributeError:
120 120 # obsolete attribute: remove it
121 try:
121 try:
122 122 delattr(old, key)
123 123 except (AttributeError, TypeError):
124 124 pass
125 125 continue
126
126
127 127 if update_generic(old_obj, new_obj): continue
128 128
129 129 try:
@@ -146,9 +146,9 b' UPDATE_RULES = ['
146 146 (lambda a, b: isinstance2(a, b, types.TypeType),
147 147 update_class),
148 148 (lambda a, b: isinstance2(a, b, types.FunctionType),
149 update_function),
149 update_function),
150 150 (lambda a, b: isinstance2(a, b, property),
151 update_property),
151 update_property),
152 152 (lambda a, b: isinstance2(a, b, types.MethodType),
153 153 lambda a, b: update_function(a.im_func, b.im_func)),
154 154 ]
@@ -168,15 +168,15 b' class StrongRef(object):'
168 168
169 169 def superreload(module, reload=reload, old_objects={}):
170 170 """Enhanced version of the builtin reload function.
171
171
172 172 superreload remembers objects previously in the module, and
173 173
174 174 - upgrades the class dictionary of every old class in the module
175 175 - upgrades the code object of every old function and method
176 176 - clears the module's namespace before reloading
177
177
178 178 """
179
179
180 180 # collect old objects in the module
181 181 for name, obj in module.__dict__.items():
182 182 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
@@ -199,7 +199,7 b' def superreload(module, reload=reload, old_objects={}):'
199 199 except (TypeError, AttributeError, KeyError):
200 200 pass
201 201 module = reload(module)
202
202
203 203 # iterate over all objects and update functions & classes
204 204 for name, new_obj in module.__dict__.items():
205 205 key = (module.__name__, name)
@@ -248,40 +248,46 b' def disable_autoreload():'
248 248
249 249 def autoreload_f(self, parameter_s=''):
250 250 r""" %autoreload => Reload modules automatically
251
251
252 252 %autoreload
253 253 Reload all modules (except those excluded by %aimport) automatically now.
254
254
255 %autoreload 0
256 Disable automatic reloading.
257
255 258 %autoreload 1
256 259 Reload all modules imported with %aimport every time before executing
257 260 the Python code typed.
258
261
259 262 %autoreload 2
260 263 Reload all modules (except those excluded by %aimport) every time
261 264 before executing the Python code typed.
262
263 Reloading Python modules in a reliable way is in general difficult,
264 and unexpected things may occur. %autoreload tries to work
265 around common pitfalls by replacing code objects of functions
266 previously in the module with new versions. This makes the following
267 things to work:
265
266 Reloading Python modules in a reliable way is in general
267 difficult, and unexpected things may occur. %autoreload tries to
268 work around common pitfalls by replacing function code objects and
269 parts of classes previously in the module with new versions. This
270 makes the following things to work:
268 271
269 272 - Functions and classes imported via 'from xxx import foo' are upgraded
270 273 to new versions when 'xxx' is reloaded.
274
271 275 - Methods and properties of classes are upgraded on reload, so that
272 276 calling 'c.foo()' on an object 'c' created before the reload causes
273 277 the new code for 'foo' to be executed.
274
278
275 279 Some of the known remaining caveats are:
276
280
277 281 - Replacing code objects does not always succeed: changing a @property
278 282 in a class to an ordinary method or a method to a member variable
279 283 can cause problems (but in old objects only).
284
280 285 - Functions that are removed (eg. via monkey-patching) from a module
281 286 before it is reloaded are not upgraded.
287
282 288 - C extension modules cannot be reloaded, and so cannot be
283 289 autoreloaded.
284
290
285 291 """
286 292 if parameter_s == '':
287 293 reloader.check(True)
@@ -307,7 +313,7 b" def aimport_f(self, parameter_s=''):"
307 313 Mark module 'foo' to not be autoreloaded for %autoreload 1
308 314
309 315 """
310
316
311 317 modname = parameter_s
312 318 if not modname:
313 319 to_reload = reloader.modules.keys()
@@ -329,12 +335,15 b" def aimport_f(self, parameter_s=''):"
329 335 except KeyError: pass
330 336 reloader.modules[modname] = True
331 337
332 mod = __import__(modname)
333 ip.to_user_ns({modname: mod})
338 # Inject module to user namespace; handle also submodules properly
339 __import__(modname)
340 basename = modname.split('.')[0]
341 mod = sys.modules[basename]
342 ip.to_user_ns({basename: mod})
334 343
335 344 def init():
336 345 ip.expose_magic('autoreload', autoreload_f)
337 346 ip.expose_magic('aimport', aimport_f)
338 347 ip.set_hook('pre_runcode_hook', runcode_hook)
339
348
340 349 init()
@@ -447,29 +447,30 b' class ConsoleWidget(editwindow.EditWindow):'
447 447 # different callbacks share local variables?
448 448
449 449 # Intercept some specific keys.
450 if event.KeyCode == ord('L') and event.ControlDown() :
450 key_code = event.GetKeyCode()
451 if key_code == ord('L') and event.ControlDown() :
451 452 self.scroll_to_bottom()
452 elif event.KeyCode == ord('K') and event.ControlDown() :
453 elif key_code == ord('K') and event.ControlDown() :
453 454 self.input_buffer = ''
454 elif event.KeyCode == ord('A') and event.ControlDown() :
455 elif key_code == ord('A') and event.ControlDown() :
455 456 self.GotoPos(self.GetLength())
456 457 self.SetSelectionStart(self.current_prompt_pos)
457 458 self.SetSelectionEnd(self.GetCurrentPos())
458 459 catched = True
459 elif event.KeyCode == ord('E') and event.ControlDown() :
460 elif key_code == ord('E') and event.ControlDown() :
460 461 self.GotoPos(self.GetLength())
461 462 catched = True
462 elif event.KeyCode == wx.WXK_PAGEUP:
463 elif key_code == wx.WXK_PAGEUP:
463 464 self.ScrollPages(-1)
464 elif event.KeyCode == wx.WXK_PAGEDOWN:
465 elif key_code == wx.WXK_PAGEDOWN:
465 466 self.ScrollPages(1)
466 elif event.KeyCode == wx.WXK_HOME:
467 elif key_code == wx.WXK_HOME:
467 468 self.GotoPos(self.GetLength())
468 elif event.KeyCode == wx.WXK_END:
469 elif key_code == wx.WXK_END:
469 470 self.GotoPos(self.GetLength())
470 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
471 elif key_code == wx.WXK_UP and event.ShiftDown():
471 472 self.ScrollLines(-1)
472 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
473 elif key_code == wx.WXK_DOWN and event.ShiftDown():
473 474 self.ScrollLines(1)
474 475 else:
475 476 catched = False
@@ -477,13 +478,12 b' class ConsoleWidget(editwindow.EditWindow):'
477 478 if self.AutoCompActive():
478 479 event.Skip()
479 480 else:
480 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
481 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN,
482 wx.MOD_SHIFT):
481 if key_code in (13, wx.WXK_NUMPAD_ENTER):
482 # XXX: not catching modifiers, to be wx2.6-compatible
483 483 catched = True
484 484 if not self.enter_catched:
485 485 self.CallTipCancel()
486 if event.Modifiers == wx.MOD_SHIFT:
486 if event.ShiftDown():
487 487 # Try to force execution
488 488 self.GotoPos(self.GetLength())
489 489 self.write('\n' + self.continuation_prompt(),
@@ -493,19 +493,18 b' class ConsoleWidget(editwindow.EditWindow):'
493 493 self._on_enter()
494 494 self.enter_catched = True
495 495
496 elif event.KeyCode == wx.WXK_HOME:
497 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
496 elif key_code == wx.WXK_HOME:
497 if not event.ShiftDown():
498 498 self.GotoPos(self.current_prompt_pos)
499 499 catched = True
500
501 elif event.Modifiers == wx.MOD_SHIFT:
500 else:
502 501 # FIXME: This behavior is not ideal: if the selection
503 502 # is already started, it will jump.
504 503 self.SetSelectionStart(self.current_prompt_pos)
505 504 self.SetSelectionEnd(self.GetCurrentPos())
506 505 catched = True
507 506
508 elif event.KeyCode == wx.WXK_UP:
507 elif key_code == wx.WXK_UP:
509 508 if self.GetCurrentLine() > self.current_prompt_line:
510 509 if self.GetCurrentLine() == self.current_prompt_line + 1 \
511 510 and self.GetColumn(self.GetCurrentPos()) < \
@@ -515,18 +514,18 b' class ConsoleWidget(editwindow.EditWindow):'
515 514 event.Skip()
516 515 catched = True
517 516
518 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
517 elif key_code in (wx.WXK_LEFT, wx.WXK_BACK):
519 518 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
520 519 event.Skip()
521 520 catched = True
522 521
523 elif event.KeyCode == wx.WXK_RIGHT:
522 elif key_code == wx.WXK_RIGHT:
524 523 if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1):
525 524 event.Skip()
526 525 catched = True
527 526
528 527
529 elif event.KeyCode == wx.WXK_DELETE:
528 elif key_code == wx.WXK_DELETE:
530 529 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
531 530 event.Skip()
532 531 catched = True
@@ -535,7 +534,7 b' class ConsoleWidget(editwindow.EditWindow):'
535 534 # Put the cursor back in the edit region
536 535 if not self._keep_cursor_in_buffer():
537 536 if not (self.GetCurrentPos() == self.GetLength()
538 and event.KeyCode == wx.WXK_DELETE):
537 and key_code == wx.WXK_DELETE):
539 538 event.Skip()
540 539 catched = True
541 540
@@ -389,7 +389,8 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
389 389 """
390 390 # FIXME: This method needs to be broken down in smaller ones.
391 391 current_line_num = self.GetCurrentLine()
392 if event.KeyCode in (ord('c'), ord('C')) and event.ControlDown():
392 key_code = event.GetKeyCode()
393 if key_code in (ord('c'), ord('C')) and event.ControlDown():
393 394 # Capture Control-C
394 395 if self._input_state == 'subprocess':
395 396 if self.debug:
@@ -403,40 +404,39 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
403 404 # XXX: We need to make really sure we
404 405 # get back to a prompt.
405 406 elif self._input_state == 'subprocess' and (
406 ( event.KeyCode<256 and
407 not event.ControlDown() )
407 ( key_code <256 and not event.ControlDown() )
408 408 or
409 ( event.KeyCode in (ord('d'), ord('D')) and
409 ( key_code in (ord('d'), ord('D')) and
410 410 event.ControlDown())):
411 411 # We are running a process, we redirect keys.
412 412 ConsoleWidget._on_key_down(self, event, skip=skip)
413 char = chr(event.KeyCode)
413 char = chr(key_code)
414 414 # Deal with some inconsistency in wx keycodes:
415 415 if char == '\r':
416 416 char = '\n'
417 417 elif not event.ShiftDown():
418 418 char = char.lower()
419 if event.ControlDown() and event.KeyCode in (ord('d'), ord('D')):
419 if event.ControlDown() and key_code in (ord('d'), ord('D')):
420 420 char = '\04'
421 421 self._running_process.process.stdin.write(char)
422 422 self._running_process.process.stdin.flush()
423 elif event.KeyCode in (ord('('), 57, 53):
423 elif key_code in (ord('('), 57, 53):
424 424 # Calltips
425 425 event.Skip()
426 426 self.do_calltip()
427 elif self.AutoCompActive() and not event.KeyCode == ord('\t'):
427 elif self.AutoCompActive() and not key_code == ord('\t'):
428 428 event.Skip()
429 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
429 if key_code in (wx.WXK_BACK, wx.WXK_DELETE):
430 430 wx.CallAfter(self._popup_completion, create=True)
431 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
431 elif not key_code in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
432 432 wx.WXK_RIGHT, wx.WXK_ESCAPE):
433 433 wx.CallAfter(self._popup_completion)
434 434 else:
435 435 # Up history
436 if event.KeyCode == wx.WXK_UP and (
437 ( current_line_num == self.current_prompt_line and
438 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
439 or event.ControlDown() ):
436 if key_code == wx.WXK_UP and (
437 event.ControlDown() or
438 current_line_num == self.current_prompt_line
439 ):
440 440 new_buffer = self.get_history_previous(
441 441 self.input_buffer)
442 442 if new_buffer is not None:
@@ -445,23 +445,24 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
445 445 # Go to first line, for seemless history up.
446 446 self.GotoPos(self.current_prompt_pos)
447 447 # Down history
448 elif event.KeyCode == wx.WXK_DOWN and (
449 ( current_line_num == self.LineCount -1 and
450 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
451 or event.ControlDown() ):
448 elif key_code == wx.WXK_DOWN and (
449 event.ControlDown() or
450 current_line_num == self.LineCount -1
451 ):
452 452 new_buffer = self.get_history_next()
453 453 if new_buffer is not None:
454 454 self.input_buffer = new_buffer
455 455 # Tab-completion
456 elif event.KeyCode == ord('\t'):
456 elif key_code == ord('\t'):
457 457 current_line, current_line_num = self.CurLine
458 if not re.match(r'^\s*$', current_line):
458 if not re.match(r'^%s\s*$' % self.continuation_prompt(),
459 current_line):
459 460 self.complete_current_input()
460 461 if self.AutoCompActive():
461 462 wx.CallAfter(self._popup_completion, create=True)
462 463 else:
463 464 event.Skip()
464 elif event.KeyCode == wx.WXK_BACK:
465 elif key_code == wx.WXK_BACK:
465 466 # If characters where erased, check if we have to
466 467 # remove a line.
467 468 # XXX: What about DEL?
@@ -496,7 +497,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
496 497 def _on_key_up(self, event, skip=True):
497 498 """ Called when any key is released.
498 499 """
499 if event.KeyCode in (59, ord('.')):
500 if event.GetKeyCode() in (59, ord('.')):
500 501 # Intercepting '.'
501 502 event.Skip()
502 503 wx.CallAfter(self._popup_completion, create=True)
1 NO CONTENT: modified file chmod 100755 => 100644
General Comments 0
You need to be logged in to leave comments. Login now