diff --git a/IPython/OInspect.py b/IPython/OInspect.py index aff32da..c5859d9 100644 --- a/IPython/OInspect.py +++ b/IPython/OInspect.py @@ -6,7 +6,7 @@ Uses syntax highlighting for presenting the various information elements. Similar in spirit to the inspect module, but all calls take a name argument to reference the name under which an object is being read. -$Id: OInspect.py 1016 2006-01-14 00:54:23Z vivainio $ +$Id: OInspect.py 1058 2006-01-22 14:30:01Z vivainio $ """ #***************************************************************************** @@ -234,8 +234,15 @@ class Inspector: self.noinfo('file',oname) else: # run contents of file through pager starting at line - # where the object is defined - page(self.format(open(inspect.getabsfile(obj)).read()),lineno) + # where the object is defined + ofile = inspect.getabsfile(obj) + + if (ofile.endswith('.so') or ofile.endswith('.dll')): + print 'File %r is binary, not printing.' % ofile + else: + # Print only text files, not extension binaries. + page(self.format(open(ofile).read()),lineno) + #page(self.format(open(inspect.getabsfile(obj)).read()),lineno) def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0): """Show detailed information about an object. @@ -319,12 +326,18 @@ class Inspector: except: pass # Filename where object was defined + binary_file = False try: - file = inspect.getabsfile(obj) - if file.endswith(''): - file = 'Dynamically generated function. No source code available.' - out.writeln(header('File:\t\t')+file) - except: pass + fname = inspect.getabsfile(obj) + if fname.endswith(''): + fname = 'Dynamically generated function. No source code available.' + if fname.endswith('.so') or fname.endswith('.dll'): + binary_file = True + out.writeln(header('File:\t\t')+fname) + except: + # if anything goes wrong, we don't want to show source, so it's as + # if the file was binary + binary_file = True # reconstruct the function definition and print it: defln = self.__getdef(obj,oname) @@ -341,8 +354,9 @@ class Inspector: # Flush the source cache because inspect can return out-of-date source linecache.checkcache() try: - source = self.format(inspect.getsource(obj)) - out.write(header('Source:\n')+source.rstrip()) + if not binary_file: + source = self.format(inspect.getsource(obj)) + out.write(header('Source:\n')+source.rstrip()) except: if ds: out.writeln(header('Docstring:\n') + indent(ds)) diff --git a/IPython/Release.py b/IPython/Release.py index 1d27f54..76c1213 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 1014 2006-01-13 19:16:41Z vivainio $""" +$Id: Release.py 1058 2006-01-22 14:30:01Z vivainio $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez @@ -22,9 +22,9 @@ name = 'ipython' # because bdist_rpm does not accept dashes (an RPM) convention, and # bdist_deb does not accept underscores (a Debian convention). -version = '0.7.1.svn' +version = '0.7.2.svn' -revision = '$Revision: 1014 $' +revision = '$Revision: 1058 $' description = "An enhanced interactive Python shell." diff --git a/IPython/Shell.py b/IPython/Shell.py index e447627..1f3a779 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 1005 2006-01-12 08:39:26Z fperez $""" +$Id: Shell.py 1058 2006-01-22 14:30:01Z vivainio $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez @@ -18,13 +18,14 @@ __author__ = '%s <%s>' % Release.authors['Fernando'] __license__ = Release.license # Code begins -import __main__ import __builtin__ +import __main__ +import Queue import os -import sys import signal -import time +import sys import threading +import time import IPython from IPython import ultraTB @@ -272,9 +273,15 @@ class MTInteractiveShell(InteractiveShell): InteractiveShell.__init__(self,name,usage,rc,user_ns, user_global_ns,banner2) - # Locking control variable - self.thread_ready = threading.Condition() + # Locking control variable. We need to use a norma lock, not an RLock + # here. I'm not exactly sure why, it seems to me like it should be + # the opposite, but we deadlock with an RLock. Puzzled... + self.thread_ready = threading.Condition(threading.Lock()) + # 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() + # Stuff to do at closing time self._kill = False on_kill = kw.get('on_kill') @@ -311,11 +318,16 @@ class MTInteractiveShell(InteractiveShell): return True # Case 3 - # Store code in self, so the execution thread can handle it - self.thread_ready.acquire() - self.code_to_run = code - self.thread_ready.wait() # Wait until processed in timeout interval - self.thread_ready.release() + # Store code in queue, so the execution thread can handle it. + + # Note that with macros and other applications, we MAY re-enter this + # section, so we have to acquire the lock with non-blocking semantics, + # else we deadlock. + got_lock = self.thread_ready.acquire(False) + self.code_queue.put(code) + if got_lock: + self.thread_ready.wait() # Wait until processed in timeout interval + self.thread_ready.release() return False @@ -325,7 +337,7 @@ class MTInteractiveShell(InteractiveShell): Multithreaded wrapper around IPython's runcode().""" # lock thread-protected stuff - self.thread_ready.acquire() + self.thread_ready.acquire(False) # Install sigint handler try: @@ -342,10 +354,15 @@ class MTInteractiveShell(InteractiveShell): tokill() print >>Term.cout, 'Done.' - # Run pending code by calling parent class - if self.code_to_run is not None: + # Flush queue of pending code by calling the run methood of the parent + # class with all items which may be in the queue. + while 1: + try: + code_to_run = self.code_queue.get_nowait() + except Queue.Empty: + break self.thread_ready.notify() - InteractiveShell.runcode(self,self.code_to_run) + InteractiveShell.runcode(self,code_to_run) # We're done with thread-protected variables self.thread_ready.release() @@ -354,7 +371,7 @@ class MTInteractiveShell(InteractiveShell): def kill (self): """Kill the thread, returning when it has been shut down.""" - self.thread_ready.acquire() + self.thread_ready.acquire(False) self._kill = True self.thread_ready.release() @@ -366,7 +383,7 @@ class MatplotlibShellBase: inheritance hierarchy, so that it overrides the relevant methods.""" def _matplotlib_config(self,name): - """Return various items needed to setup the user's shell with matplotlib""" + """Return items needed to setup the user's shell with matplotlib""" # Initialize matplotlib to interactive mode always import matplotlib @@ -408,7 +425,6 @@ class MatplotlibShellBase: # overwrite the original matplotlib.use with our wrapper matplotlib.use = use - # This must be imported last in the matplotlib series, after # backend/interactivity choices have been made try: diff --git a/IPython/genutils.py b/IPython/genutils.py index 0bf0954..1bb2659 100644 --- a/IPython/genutils.py +++ b/IPython/genutils.py @@ -5,7 +5,7 @@ General purpose utilities. This is a grab-bag of stuff I find useful in most programs I write. Some of these things are also convenient when working at the command line. -$Id: genutils.py 1032 2006-01-20 09:03:57Z fperez $""" +$Id: genutils.py 1058 2006-01-22 14:30:01Z vivainio $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez. @@ -213,14 +213,18 @@ def debugp(expr,pre_msg=''): """Print the value of an expression from the caller's frame. Takes an expression, evaluates it in the caller's frame and prints both - the given expression and the resulting value. The input must be of a form - suitable for eval().""" + the given expression and the resulting value (as well as a debug mark + indicating the name of the calling function. The input must be of a form + suitable for eval(). + + An optional message can be passed, which will be prepended to the printed + expr->value pair.""" cf = sys._getframe(1) - print '[DBG] %s %s -> %r' % (pre_msg,expr, - eval(expr,cf.f_globals,cf.f_locals)) + print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr, + eval(expr,cf.f_globals,cf.f_locals)) -# deactivate it from here: +# deactivate it by uncommenting the following line, which makes it a no-op def debugp(expr,pre_msg=''): pass #---------------------------------------------------------------------------- diff --git a/IPython/iplib.py b/IPython/iplib.py index 31881b1..532bfdb 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 1038 2006-01-20 23:43:35Z vivainio $ +$Id: iplib.py 1058 2006-01-22 14:30:01Z vivainio $ """ #***************************************************************************** @@ -274,7 +274,7 @@ class InteractiveShell(object,Magic): # intentional (or sensible), I don't know. In any case, the idea is # that if you need to access the built-in namespace directly, you # should start with "import __builtin__" (note, no 's') which will - # definitely give you a module. Yeah, it's somewhat confusing:-(. + # definitely give you a module. Yeah, it's somewhat confusing:-(. if user_ns is None: # Set __name__ to __main__ to better match the behavior of the @@ -1460,6 +1460,10 @@ want to merge them back into the new files.""" % locals() self.readline_startup_hook(None) self.write("\n") self.exit() + except: + # exceptions here are VERY RARE, but they can be triggered + # asynchronously by signal handlers, for example. + self.showtraceback() else: more = self.push(line) @@ -1550,7 +1554,8 @@ want to merge them back into the new files.""" % locals() def autoindent_update(self,line): """Keep track of the indent level.""" - debugp('line','autoindent_update:') + #import traceback; traceback.print_stack() # dbg + debugp('line') debugp('self.indent_current_nsp') if self.autoindent: if line: @@ -1761,7 +1766,9 @@ want to merge them back into the new files.""" % locals() debugp('self.indent_current_nsp') debugp('line') - return self.prefilter(line,continue_prompt) + lineout = self.prefilter(line,continue_prompt) + debugp('lineout') + return lineout def split_user_input(self,line): """Split user input into pre-char, function part and rest.""" @@ -1938,8 +1945,9 @@ want to merge them back into the new files.""" % locals() # of a size different to the indent level, will exit the input loop. if (continue_prompt and self.autoindent and line.isspace() and - (line != self.indent_current_str() or + (0 < abs(len(line) - self.indent_current_nsp) <= 2 or (self.buffer[-1]).isspace() )): + #print 'reset line' # dbg line = '' self.log(line,continue_prompt) diff --git a/README_Windows.txt b/README_Windows.txt index 71319de..abeb6ab 100644 --- a/README_Windows.txt +++ b/README_Windows.txt @@ -9,7 +9,7 @@ Requirements IPython runs under (as far as the Windows family is concerned): -- Windows XP (I think WinNT/2000 are ok): works well. It needs: +- Windows XP, 2000 (and probably WinNT): works well. It needs: * PyWin32, the win32 Python extensions from http://starship.python.net/crew/mhammond. @@ -33,10 +33,18 @@ Installation Double-click the supplied .exe installer file. If all goes well, that's all you need to do. You should now have an IPython entry in your Start Menu. + +Installation from source distribution +------------------------------------- + In case the automatic installer does not work for some reason, you can download the ipython-XXX.tar.gz file, which contains the full IPython source -distribution (the popular WinZip can read .tar.gz files). After uncompressing -the archive, you can install it at a command terminal just like any other -Python module, by using python setup.py install'. After this completes, you -can run the supplied win32_manual_post_install.py script which will add -the relevant shortcuts to your startup menu. +distribution (the popular WinZip can read .tar.gz files). + +After uncompressing the archive, you can install it at a command terminal just +like any other Python module, by using python setup.py install'. After this +completes, you can run the supplied win32_manual_post_install.py script which +will add the relevant shortcuts to your startup menu. + +Optionally, you may skip installation altogether and just launch "ipython.py" +from the root folder of the extracted source distribution. diff --git a/doc/ChangeLog b/doc/ChangeLog index 5643b5b..1c36819 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,38 @@ +2006-01-22 Ville Vainio + + * Merge from branches/0.7.1 into trunk, revs 1052-1057 + +2006-01-22 Fernando Perez + + * IPython/OInspect.py (Inspector.pinfo): fix bug where foo?? or + %pfile foo would print the file for foo even if it was a binary. + Now, extensions '.so' and '.dll' are skipped. + + * IPython/Shell.py (MTInteractiveShell.__init__): Fix threading + bug, where macros would fail in all threaded modes. I'm not 100% + sure, so I'm going to put out an rc instead of making a release + today, and wait for feedback for at least a few days. + + * IPython/iplib.py (handle_normal): fix (finally? somehow I doubt + it...) the handling of pasting external code with autoindent on. + To get out of a multiline input, the rule will appear for most + users unchanged: two blank lines or change the indent level + proposed by IPython. But there is a twist now: you can + add/subtract only *one or two spaces*. If you add/subtract three + or more (unless you completely delete the line), IPython will + accept that line, and you'll need to enter a second one of pure + whitespace. I know it sounds complicated, but I can't find a + different solution that covers all the cases, with the right + heuristics. Hopefully in actual use, nobody will really notice + all these strange rules and things will 'just work'. + +2006-01-21 Fernando Perez + + * IPython/iplib.py (interact): catch exceptions which can be + triggered asynchronously by signal handlers. Thanks to an + automatic crash report, submitted by Colin Kingsley + . + 2006-01-20 Ville Vainio * Ipython/Extensions/ext_rehashdir.py: Created a usable example