From daeb7020ba902be8d9bba43740e835ff8f0904c3 2007-04-06 02:58:37 From: fperez Date: 2007-04-06 02:58:37 Subject: [PATCH] - Various small fixes and cleanups. - Proper determination of main thread id, thanks to Stefan. --- diff --git a/IPython/Magic.py b/IPython/Magic.py index b40aff2..55869da 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 2200 2007-04-03 05:24:30Z fperez $""" +$Id: Magic.py 2221 2007-04-06 02:58:37Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -932,7 +932,10 @@ Currently the magic system has the following functions:\n""" varlist = self.magic_who_ls(parameter_s) if not varlist: - print 'Interactive namespace is empty.' + if parameter_s: + print 'No variables match your requested type.' + else: + print 'Interactive namespace is empty.' return # if we have variables, move on... @@ -962,7 +965,10 @@ Currently the magic system has the following functions:\n""" varnames = self.magic_who_ls(parameter_s) if not varnames: - print 'Interactive namespace is empty.' + if parameter_s: + print 'No variables match your requested type.' + else: + print 'Interactive namespace is empty.' return # if we have variables, move on... diff --git a/IPython/Release.py b/IPython/Release.py index 697f5b3..de72a11 100644 --- a/IPython/Release.py +++ b/IPython/Release.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Release data for the IPython project. -$Id: Release.py 2217 2007-04-05 06:06:26Z fperez $""" +$Id: Release.py 2221 2007-04-06 02:58:37Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez @@ -25,7 +25,7 @@ name = 'ipython' revision = '2191' #version = '0.7.4.svn.r' + revision.rstrip('M') -version = '0.7.4.rc1' +version = '0.8.0' description = "An enhanced interactive Python shell." diff --git a/IPython/Shell.py b/IPython/Shell.py index 007c57f..1c288dc 100644 --- a/IPython/Shell.py +++ b/IPython/Shell.py @@ -4,7 +4,7 @@ All the matplotlib support code was co-developed with John Hunter, matplotlib's author. -$Id: Shell.py 2216 2007-04-05 06:00:13Z fperez $""" +$Id: Shell.py 2221 2007-04-06 02:58:37Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez @@ -25,6 +25,7 @@ import Queue import inspect import os import sys +import thread import threading import time @@ -36,7 +37,6 @@ try: except ImportError: HAS_CTYPES = False - # IPython imports import IPython from IPython import ultraTB @@ -54,7 +54,7 @@ KBINT = False USE_TK = False # ID for the main thread, used for cross-thread exceptions -MAIN_THREAD_ID = None +MAIN_THREAD_ID = thread.get_ident() # Tag when runcode() is active, for exception handling CODE_RUN = None @@ -203,7 +203,7 @@ class IPShellEmbed: # Set global subsystems (display,completions) to our values sys.displayhook = self.sys_displayhook_embed if self.IP.has_readline: - self.IP.readline.set_completer(self.IP.Completer.complete) + self.IP.set_completer() if self.banner and header: format = '%s\n%s\n' @@ -312,18 +312,6 @@ else: KBINT = True -def _set_main_thread_id(): - """Ugly hack to find the main thread's ID. - """ - global MAIN_THREAD_ID - for tid, tobj in threading._active.items(): - # There must be a better way to do this than looking at the str() for - # each thread object... - if 'MainThread' in str(tobj): - #print 'main tid:',tid # dbg - MAIN_THREAD_ID = tid - break - class MTInteractiveShell(InteractiveShell): """Simple multi-threaded shell.""" @@ -351,6 +339,9 @@ class MTInteractiveShell(InteractiveShell): # A queue to hold the code to be executed. A scalar variable is NOT # enough, because uses like macros cause reentrancy. self.code_queue = Queue.Queue() + + # Track once we properly install our special sigint handler + self._sigint_handler_not_ready = True # Stuff to do at closing time self._kill = False @@ -406,7 +397,6 @@ class MTInteractiveShell(InteractiveShell): Multithreaded wrapper around IPython's runcode().""" - global CODE_RUN # Exceptions need to be raised differently depending on which thread is @@ -423,14 +413,18 @@ class MTInteractiveShell(InteractiveShell): tokill() print >>Term.cout, 'Done.' - # Install sigint handler. It feels stupid to do this on every single - # pass - try: - signal(SIGINT,sigint_handler) - except SystemError: - # This happens under Windows, which seems to have all sorts - # of problems with signal handling. Oh well... - pass + # Install sigint handler. It feels stupid to test this on every single + # pass. At least we keep track of having done it before... We use a + # negative variable so we don't have to call 'not' every time + if self._sigint_handler_not_ready: + # Try only once... + self._sigint_handler_not_ready = False + try: + signal(SIGINT,sigint_handler) + except SystemError: + # This happens under Windows, which seems to have all sorts + # of problems with signal handling. Oh well... + pass # Flush queue of pending code by calling the run methood of the parent # class with all items which may be in the queue. @@ -681,10 +675,6 @@ class IPThread(threading.Thread): self.IP.mainloop(self._banner) self.IP.kill() - def start(self): - threading.Thread.start(self) - _set_main_thread_id() - class IPShellGTK(IPThread): """Run a gtk mainloop() in a separate thread. @@ -855,7 +845,6 @@ class IPShellWX(IPThread): self.agent.StartWork() return True - _set_main_thread_id() self.app = App(redirect=False) self.wx_mainloop(self.app) self.join() @@ -1001,8 +990,8 @@ class IPShellQt4(IPThread): return result -# A set of matplotlib public IPython shell classes, for single-threaded -# (Tk* and FLTK* backends) and multithreaded (GTK* and WX* backends) use. +# A set of matplotlib public IPython shell classes, for single-threaded (Tk* +# and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use. def _load_pylab(user_ns): """Allow users to disable pulling all of pylab into the top-level namespace. diff --git a/IPython/iplib.py b/IPython/iplib.py index 44bb05e..a00897f 100644 --- a/IPython/iplib.py +++ b/IPython/iplib.py @@ -6,7 +6,7 @@ Requires Python 2.3 or newer. This file contains all the classes and helper functions specific to IPython. -$Id: iplib.py 2207 2007-04-05 02:07:24Z fperez $ +$Id: iplib.py 2221 2007-04-06 02:58:37Z fperez $ """ #***************************************************************************** @@ -882,6 +882,10 @@ class InteractiveShell(object,Magic): self.Completer.__class__) self.Completer.matchers.insert(pos,newcomp) + def set_completer(self): + """reset readline's completer to be our own.""" + self.readline.set_completer(self.Completer.complete) + def _get_call_pdb(self): return self._call_pdb @@ -1311,7 +1315,7 @@ want to merge them back into the new files.""" % locals() self.readline = readline # save this in sys so embedded copies can restore it properly sys.ipcompleter = self.Completer.complete - readline.set_completer(self.Completer.complete) + self.set_completer() # Configure readline according to user's prefs for rlcommand in self.rc.readline_parse_and_bind: @@ -1488,7 +1492,7 @@ want to merge them back into the new files.""" % locals() self.InteractiveTB(etype,value,tb,tb_offset=tb_offset) if self.InteractiveTB.call_pdb and self.has_readline: # pdb mucks up readline, fix it back - self.readline.set_completer(self.Completer.complete) + self.set_completer() def mainloop(self,banner=None): """Creates the local namespace and starts the mainloop. @@ -1979,14 +1983,17 @@ want to merge them back into the new files.""" % locals() continuation in a sequence of inputs. """ + # Code run by the user may have modified the readline completer state. + # We must ensure that our completer is back in place. + self.set_completer() + try: line = raw_input_original(prompt).decode(sys.stdin.encoding) - #line = raw_input_original(prompt) except ValueError: - warn("\n********\nYou or a %run:ed script called sys.stdin.close() or sys.stdout.close()!\nExiting IPython!") + warn("\n********\nYou or a %run:ed script called sys.stdin.close()" + " or sys.stdout.close()!\nExiting IPython!") self.exit_now = True return "" - # Try to be reasonably smart about not re-indenting pasted input more # than necessary. We do this by trimming out the auto-indent initial @@ -2174,14 +2181,9 @@ want to merge them back into the new files.""" % locals() # It also allows users to assign to either alias or magic names true # python variables (the magic/alias systems always take second seat to # true python code). - # - # We also go to direct execution if there's a binary operator in there, - # so users get the regular exception. Note that '-' is NOT included, - # since it is also a unary operator ('+' can also be used as unary, but - # in practice it rarely is). - if theRest and theRest[0] in '!=()<>+*/%^&|': + if theRest and theRest[0] in '!=()': return self.handle_normal(line,continue_prompt) - + if oinfo is None: # let's try to ensure that _oinfo is ONLY called when autocall is # on. Since it has inevitable potential side effects, at least diff --git a/doc/ChangeLog b/doc/ChangeLog index 344028e..d504bc8 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,25 @@ +2007-04-05 Fernando Perez + + * IPython/Shell.py (MAIN_THREAD_ID): get rid of my stupid hack to + find the main thread id and use the proper API call. Thanks to + Stefan for the fix. + + * test/test_prefilter.py (esc_handler_tests): udpate one of Dan's + unit tests to reflect fixed ticket #52, and add more tests sent by + him. + + * IPython/iplib.py (raw_input): restore the readline completer + state on every input, in case third-party code messed it up. + (_prefilter): revert recent addition of early-escape checks which + prevent many valid alias calls from working. + + * IPython/Shell.py (MTInteractiveShell.runcode): add a tracking + flag for sigint handler so we don't run a full signal() call on + each runcode access. + + * IPython/Magic.py (magic_whos): small improvement to diagnostic + message. + 2007-04-04 Fernando Perez * IPython/Shell.py (sigint_handler): I *THINK* I finally got diff --git a/test/test_prefilter.py b/test/test_prefilter.py index c7fb734..cc4675e 100644 --- a/test/test_prefilter.py +++ b/test/test_prefilter.py @@ -145,8 +145,15 @@ esc_handler_tests = [ ( '?thing', handle_help, ), ( 'thing?', handle_help ), # '?' can trail... ( 'thing!', handle_normal), # but only '?' can trail - ( '!thing?', handle_help), # trailing '?' wins if more than one ( ' ?thing', handle_help), # ignore leading whitespace + # Trailing qmark combos. Odd special cases abound + ( '!thing?', handle_shell_escape), # trailing '?' loses to shell esc + ( '!thing ?', handle_shell_escape), + ( '!!thing?', handle_shell_escape), + ( '%cmd?', handle_help), + ( '/cmd?', handle_help), + ( ';cmd?', handle_help), + ( ',cmd?', handle_help), ( '!ls', handle_shell_escape ), ( '%magic', handle_magic), # Possibly, add test for /,; once those are unhooked from %autocall