From 6aff330d18014dc8360cadb0bc4563a077a93685 2009-07-30 21:37:17 From: Fernando Perez Date: 2009-07-30 21:37:17 Subject: [PATCH] [merge] Merging with upstream trunk. --- diff --git a/IPython/Extensions/ipy_autoreload.py b/IPython/Extensions/ipy_autoreload.py index e64161d..230f575 100644 --- a/IPython/Extensions/ipy_autoreload.py +++ b/IPython/Extensions/ipy_autoreload.py @@ -1,7 +1,7 @@ """ IPython extension: autoreload modules before executing the next line -Try:: +Try:: %autoreload? @@ -32,7 +32,7 @@ PY_COMPILED_EXT = _get_compiled_ext() class ModuleReloader(object): failed = {} """Modules that failed to reload: {module: mtime-on-failed-reload, ...}""" - + modules = {} """Modules specially marked as autoreloadable.""" @@ -44,39 +44,39 @@ class ModuleReloader(object): old_objects = {} """(module-name, name) -> weakref, for replacing old code objects""" - + def check(self, check_all=False): """Check whether some modules need to be reloaded.""" - + if check_all or self.check_all: modules = sys.modules.keys() else: modules = self.modules.keys() - + for modname in modules: m = sys.modules.get(modname, None) if modname in self.skip_modules: continue - + if not hasattr(m, '__file__'): continue - + if m.__name__ == '__main__': # we cannot reload(__main__) continue - + filename = m.__file__ dirname = os.path.dirname(filename) path, ext = os.path.splitext(filename) - + if ext.lower() == '.py': ext = PY_COMPILED_EXT filename = os.path.join(dirname, path + PY_COMPILED_EXT) - + if ext != PY_COMPILED_EXT: continue - + try: pymtime = os.stat(filename[:-1]).st_mtime if pymtime <= os.stat(filename).st_mtime: @@ -85,7 +85,7 @@ class ModuleReloader(object): continue except OSError: continue - + try: superreload(m, reload, self.old_objects) if filename[:-1] in self.failed: @@ -118,12 +118,12 @@ def update_class(old, new): new_obj = getattr(new, key) except AttributeError: # obsolete attribute: remove it - try: + try: delattr(old, key) except (AttributeError, TypeError): pass continue - + if update_generic(old_obj, new_obj): continue try: @@ -146,9 +146,9 @@ UPDATE_RULES = [ (lambda a, b: isinstance2(a, b, types.TypeType), update_class), (lambda a, b: isinstance2(a, b, types.FunctionType), - update_function), + update_function), (lambda a, b: isinstance2(a, b, property), - update_property), + update_property), (lambda a, b: isinstance2(a, b, types.MethodType), lambda a, b: update_function(a.im_func, b.im_func)), ] @@ -168,15 +168,15 @@ class StrongRef(object): def superreload(module, reload=reload, old_objects={}): """Enhanced version of the builtin reload function. - + superreload remembers objects previously in the module, and - upgrades the class dictionary of every old class in the module - upgrades the code object of every old function and method - clears the module's namespace before reloading - + """ - + # collect old objects in the module for name, obj in module.__dict__.items(): if not hasattr(obj, '__module__') or obj.__module__ != module.__name__: @@ -199,7 +199,7 @@ def superreload(module, reload=reload, old_objects={}): except (TypeError, AttributeError, KeyError): pass module = reload(module) - + # iterate over all objects and update functions & classes for name, new_obj in module.__dict__.items(): key = (module.__name__, name) @@ -248,40 +248,46 @@ def disable_autoreload(): def autoreload_f(self, parameter_s=''): r""" %autoreload => Reload modules automatically - + %autoreload Reload all modules (except those excluded by %aimport) automatically now. - + + %autoreload 0 + Disable automatic reloading. + %autoreload 1 Reload all modules imported with %aimport every time before executing the Python code typed. - + %autoreload 2 Reload all modules (except those excluded by %aimport) every time before executing the Python code typed. - - Reloading Python modules in a reliable way is in general difficult, - and unexpected things may occur. %autoreload tries to work - around common pitfalls by replacing code objects of functions - previously in the module with new versions. This makes the following - things to work: + + Reloading Python modules in a reliable way is in general + difficult, and unexpected things may occur. %autoreload tries to + work around common pitfalls by replacing function code objects and + parts of classes previously in the module with new versions. This + makes the following things to work: - Functions and classes imported via 'from xxx import foo' are upgraded to new versions when 'xxx' is reloaded. + - Methods and properties of classes are upgraded on reload, so that calling 'c.foo()' on an object 'c' created before the reload causes the new code for 'foo' to be executed. - + Some of the known remaining caveats are: - + - Replacing code objects does not always succeed: changing a @property in a class to an ordinary method or a method to a member variable can cause problems (but in old objects only). + - Functions that are removed (eg. via monkey-patching) from a module before it is reloaded are not upgraded. + - C extension modules cannot be reloaded, and so cannot be autoreloaded. - + """ if parameter_s == '': reloader.check(True) @@ -307,7 +313,7 @@ def aimport_f(self, parameter_s=''): Mark module 'foo' to not be autoreloaded for %autoreload 1 """ - + modname = parameter_s if not modname: to_reload = reloader.modules.keys() @@ -329,12 +335,15 @@ def aimport_f(self, parameter_s=''): except KeyError: pass reloader.modules[modname] = True - mod = __import__(modname) - ip.to_user_ns({modname: mod}) + # Inject module to user namespace; handle also submodules properly + __import__(modname) + basename = modname.split('.')[0] + mod = sys.modules[basename] + ip.to_user_ns({basename: mod}) def init(): ip.expose_magic('autoreload', autoreload_f) ip.expose_magic('aimport', aimport_f) ip.set_hook('pre_runcode_hook', runcode_hook) - + init() diff --git a/IPython/frontend/wx/console_widget.py b/IPython/frontend/wx/console_widget.py index 8fcb17a..8c7967f 100644 --- a/IPython/frontend/wx/console_widget.py +++ b/IPython/frontend/wx/console_widget.py @@ -447,29 +447,30 @@ class ConsoleWidget(editwindow.EditWindow): # different callbacks share local variables? # Intercept some specific keys. - if event.KeyCode == ord('L') and event.ControlDown() : + key_code = event.GetKeyCode() + if key_code == ord('L') and event.ControlDown() : self.scroll_to_bottom() - elif event.KeyCode == ord('K') and event.ControlDown() : + elif key_code == ord('K') and event.ControlDown() : self.input_buffer = '' - elif event.KeyCode == ord('A') and event.ControlDown() : + elif key_code == ord('A') and event.ControlDown() : self.GotoPos(self.GetLength()) self.SetSelectionStart(self.current_prompt_pos) self.SetSelectionEnd(self.GetCurrentPos()) catched = True - elif event.KeyCode == ord('E') and event.ControlDown() : + elif key_code == ord('E') and event.ControlDown() : self.GotoPos(self.GetLength()) catched = True - elif event.KeyCode == wx.WXK_PAGEUP: + elif key_code == wx.WXK_PAGEUP: self.ScrollPages(-1) - elif event.KeyCode == wx.WXK_PAGEDOWN: + elif key_code == wx.WXK_PAGEDOWN: self.ScrollPages(1) - elif event.KeyCode == wx.WXK_HOME: + elif key_code == wx.WXK_HOME: self.GotoPos(self.GetLength()) - elif event.KeyCode == wx.WXK_END: + elif key_code == wx.WXK_END: self.GotoPos(self.GetLength()) - elif event.KeyCode == wx.WXK_UP and event.ShiftDown(): + elif key_code == wx.WXK_UP and event.ShiftDown(): self.ScrollLines(-1) - elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown(): + elif key_code == wx.WXK_DOWN and event.ShiftDown(): self.ScrollLines(1) else: catched = False @@ -477,13 +478,12 @@ class ConsoleWidget(editwindow.EditWindow): if self.AutoCompActive(): event.Skip() else: - if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \ - event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN, - wx.MOD_SHIFT): + if key_code in (13, wx.WXK_NUMPAD_ENTER): + # XXX: not catching modifiers, to be wx2.6-compatible catched = True if not self.enter_catched: self.CallTipCancel() - if event.Modifiers == wx.MOD_SHIFT: + if event.ShiftDown(): # Try to force execution self.GotoPos(self.GetLength()) self.write('\n' + self.continuation_prompt(), @@ -493,19 +493,18 @@ class ConsoleWidget(editwindow.EditWindow): self._on_enter() self.enter_catched = True - elif event.KeyCode == wx.WXK_HOME: - if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN): + elif key_code == wx.WXK_HOME: + if not event.ShiftDown(): self.GotoPos(self.current_prompt_pos) catched = True - - elif event.Modifiers == wx.MOD_SHIFT: + else: # FIXME: This behavior is not ideal: if the selection # is already started, it will jump. self.SetSelectionStart(self.current_prompt_pos) self.SetSelectionEnd(self.GetCurrentPos()) catched = True - elif event.KeyCode == wx.WXK_UP: + elif key_code == wx.WXK_UP: if self.GetCurrentLine() > self.current_prompt_line: if self.GetCurrentLine() == self.current_prompt_line + 1 \ and self.GetColumn(self.GetCurrentPos()) < \ @@ -515,18 +514,18 @@ class ConsoleWidget(editwindow.EditWindow): event.Skip() catched = True - elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK): + elif key_code in (wx.WXK_LEFT, wx.WXK_BACK): if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1): event.Skip() catched = True - elif event.KeyCode == wx.WXK_RIGHT: + elif key_code == wx.WXK_RIGHT: if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1): event.Skip() catched = True - elif event.KeyCode == wx.WXK_DELETE: + elif key_code == wx.WXK_DELETE: if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1): event.Skip() catched = True @@ -535,7 +534,7 @@ class ConsoleWidget(editwindow.EditWindow): # Put the cursor back in the edit region if not self._keep_cursor_in_buffer(): if not (self.GetCurrentPos() == self.GetLength() - and event.KeyCode == wx.WXK_DELETE): + and key_code == wx.WXK_DELETE): event.Skip() catched = True diff --git a/IPython/frontend/wx/wx_frontend.py b/IPython/frontend/wx/wx_frontend.py index 854c47e..e22c91e 100644 --- a/IPython/frontend/wx/wx_frontend.py +++ b/IPython/frontend/wx/wx_frontend.py @@ -389,7 +389,8 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): """ # FIXME: This method needs to be broken down in smaller ones. current_line_num = self.GetCurrentLine() - if event.KeyCode in (ord('c'), ord('C')) and event.ControlDown(): + key_code = event.GetKeyCode() + if key_code in (ord('c'), ord('C')) and event.ControlDown(): # Capture Control-C if self._input_state == 'subprocess': if self.debug: @@ -403,40 +404,39 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # XXX: We need to make really sure we # get back to a prompt. elif self._input_state == 'subprocess' and ( - ( event.KeyCode<256 and - not event.ControlDown() ) + ( key_code <256 and not event.ControlDown() ) or - ( event.KeyCode in (ord('d'), ord('D')) and + ( key_code in (ord('d'), ord('D')) and event.ControlDown())): # We are running a process, we redirect keys. ConsoleWidget._on_key_down(self, event, skip=skip) - char = chr(event.KeyCode) + char = chr(key_code) # Deal with some inconsistency in wx keycodes: if char == '\r': char = '\n' elif not event.ShiftDown(): char = char.lower() - if event.ControlDown() and event.KeyCode in (ord('d'), ord('D')): + if event.ControlDown() and key_code in (ord('d'), ord('D')): char = '\04' self._running_process.process.stdin.write(char) self._running_process.process.stdin.flush() - elif event.KeyCode in (ord('('), 57, 53): + elif key_code in (ord('('), 57, 53): # Calltips event.Skip() self.do_calltip() - elif self.AutoCompActive() and not event.KeyCode == ord('\t'): + elif self.AutoCompActive() and not key_code == ord('\t'): event.Skip() - if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE): + if key_code in (wx.WXK_BACK, wx.WXK_DELETE): wx.CallAfter(self._popup_completion, create=True) - elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, + elif not key_code in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_ESCAPE): wx.CallAfter(self._popup_completion) else: # Up history - if event.KeyCode == wx.WXK_UP and ( - ( current_line_num == self.current_prompt_line and - event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) ) - or event.ControlDown() ): + if key_code == wx.WXK_UP and ( + event.ControlDown() or + current_line_num == self.current_prompt_line + ): new_buffer = self.get_history_previous( self.input_buffer) if new_buffer is not None: @@ -445,23 +445,24 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # Go to first line, for seemless history up. self.GotoPos(self.current_prompt_pos) # Down history - elif event.KeyCode == wx.WXK_DOWN and ( - ( current_line_num == self.LineCount -1 and - event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) ) - or event.ControlDown() ): + elif key_code == wx.WXK_DOWN and ( + event.ControlDown() or + current_line_num == self.LineCount -1 + ): new_buffer = self.get_history_next() if new_buffer is not None: self.input_buffer = new_buffer # Tab-completion - elif event.KeyCode == ord('\t'): + elif key_code == ord('\t'): current_line, current_line_num = self.CurLine - if not re.match(r'^\s*$', current_line): + if not re.match(r'^%s\s*$' % self.continuation_prompt(), + current_line): self.complete_current_input() if self.AutoCompActive(): wx.CallAfter(self._popup_completion, create=True) else: event.Skip() - elif event.KeyCode == wx.WXK_BACK: + elif key_code == wx.WXK_BACK: # If characters where erased, check if we have to # remove a line. # XXX: What about DEL? @@ -496,7 +497,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): def _on_key_up(self, event, skip=True): """ Called when any key is released. """ - if event.KeyCode in (59, ord('.')): + if event.GetKeyCode() in (59, ord('.')): # Intercepting '.' event.Skip() wx.CallAfter(self._popup_completion, create=True) diff --git a/IPython/kernel/scripts/ipcluster.py b/IPython/kernel/scripts/ipcluster.py old mode 100755 new mode 100644