diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 8b98936..6e48d30 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -25,14 +25,14 @@ def test_rehashx(): _ip.magic('rehashx') # Practically ALL ipython development systems will have more than 10 aliases - assert len(_ip.IP.alias_table) > 10 + yield (nt.assert_true, len(_ip.IP.alias_table) > 10) for key, val in _ip.IP.alias_table.items(): # we must strip dots from alias names - assert '.' not in key + nt.assert_true('.' not in key) # rehashx must fill up syscmdlist scoms = _ip.db['syscmdlist'] - assert len(scoms) > 10 + yield (nt.assert_true, len(scoms) > 10) def doctest_hist_f(): @@ -42,7 +42,8 @@ def doctest_hist_f(): In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-') - In [11]: %history -n -f $tfile 3 + In [11]: %hist -n -f $tfile 3 + """ @@ -51,9 +52,12 @@ def doctest_hist_r(): XXX - This test is not recording the output correctly. Not sure why... + In [20]: 'hist' in _ip.IP.lsmagic() + Out[20]: True + In [6]: x=1 - In [7]: hist -n -r 2 + In [7]: %hist -n -r 2 x=1 # random hist -n -r 2 # random """ @@ -94,12 +98,13 @@ def test_shist(): @dec.skipif_not_numpy def test_numpy_clear_array_undec(): + from IPython.extensions import clearcmd + _ip.ex('import numpy as np') _ip.ex('a = np.empty(2)') - - yield nt.assert_true,'a' in _ip.user_ns + yield (nt.assert_true, 'a' in _ip.user_ns) _ip.magic('clear array') - yield nt.assert_false,'a' in _ip.user_ns + yield (nt.assert_false, 'a' in _ip.user_ns) @dec.skip() diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 48150b7..4a22aa8 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -91,7 +91,7 @@ from inspect import getsourcefile, getfile, getmodule,\ # IPython's own modules # Modified pdb which doesn't damage IPython's readline handling from IPython.utils import PyColorize -from IPython.core import debugger +from IPython.core import debugger, ipapi from IPython.utils.ipstruct import Struct from IPython.core.excolors import exception_colors from IPython.utils.genutils import Term,uniq_stable,error,info @@ -268,10 +268,12 @@ def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None): # This lets us get fully syntax-highlighted tracebacks. if scheme is None: - try: - scheme = __IPYTHON__.rc.colors - except: + ipinst = ipapi.get() + if ipinst is not None: + scheme = ipinst.IP.rc.colors + else: scheme = DEFAULT_SCHEME + _line_format = _parser.format2 for line in lines: @@ -490,7 +492,9 @@ class ListTB(TBTools): # vds:>> if have_filedata: - __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0) + ipinst = ipapi.get() + if ipinst is not None: + ipinst.IP.hooks.synchronize_with_editor(filename, lineno, 0) # vds:<< return list @@ -810,7 +814,9 @@ class VerboseTB(TBTools): filepath, lnum = records[-1][1:3] #print "file:", str(file), "linenb", str(lnum) # dbg filepath = os.path.abspath(filepath) - __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0) + ipinst = ipapi.get() + if ipinst is not None: + ipinst.IP.hooks.synchronize_with_editor(filepath, lnum, 0) # vds: << # return all our info assembled as a single string diff --git a/IPython/frontend/tests/test_prefilterfrontend.py b/IPython/frontend/tests/test_prefilterfrontend.py index de11c91..4e1b05d 100644 --- a/IPython/frontend/tests/test_prefilterfrontend.py +++ b/IPython/frontend/tests/test_prefilterfrontend.py @@ -15,6 +15,7 @@ __docformat__ = "restructuredtext en" from copy import copy, deepcopy from cStringIO import StringIO import string +import sys from nose.tools import assert_equal @@ -23,22 +24,6 @@ from IPython.core.ipapi import get as get_ipython0 from IPython.testing.plugin.ipdoctest import default_argv -def safe_deepcopy(d): - """ Deep copy every key of the given dict, when possible. Elsewhere - do a copy. - """ - copied_d = dict() - for key, value in d.iteritems(): - try: - copied_d[key] = deepcopy(value) - except: - try: - copied_d[key] = copy(value) - except: - copied_d[key] = value - return copied_d - - class TestPrefilterFrontEnd(PrefilterFrontEnd): input_prompt_template = string.Template('') @@ -72,17 +57,34 @@ def isolate_ipython0(func): with arguments. """ def my_func(): - iplib = get_ipython0() - if iplib is None: + ip0 = get_ipython0() + if ip0 is None: return func() - ipython0 = iplib.IP - global_ns = safe_deepcopy(ipython0.user_global_ns) - user_ns = safe_deepcopy(ipython0.user_ns) + # We have a real ipython running... + user_ns = ip0.IP.user_ns + user_global_ns = ip0.IP.user_global_ns + + # Previously the isolation was attempted with a deep copy of the user + # dicts, but we found cases where this didn't work correctly. I'm not + # quite sure why, but basically it did damage the user namespace, such + # that later tests stopped working correctly. Instead we use a simpler + # approach, just computing the list of added keys to the namespace and + # eliminating those afterwards. Existing keys that may have been + # modified remain modified. So far this has proven to be robust. + + # Compute set of old local/global keys + old_locals = set(user_ns.keys()) + old_globals = set(user_global_ns.keys()) try: out = func() finally: - ipython0.user_ns = user_ns - ipython0.user_global_ns = global_ns + # Find new keys, and if any, remove them + new_locals = set(user_ns.keys()) - old_locals + new_globals = set(user_global_ns.keys()) - old_globals + for k in new_locals: + del user_ns[k] + for k in new_globals: + del user_global_ns[k] # Undo the hack at creation of PrefilterFrontEnd from IPython.core import iplib iplib.InteractiveShell.isthreaded = False @@ -97,7 +99,7 @@ def test_execution(): """ Test execution of a command. """ f = TestPrefilterFrontEnd() - f.input_buffer = 'print 1' + f.input_buffer = 'print(1)' f._on_enter() out_value = f.out.getvalue() assert_equal(out_value, '1\n') @@ -228,7 +230,14 @@ def test_completion_indexing(): f._on_enter() f.input_buffer = 'a[0].' f.complete_current_input() - assert_equal(f.input_buffer, 'a[0].__') + + if sys.version_info[:2] >= (2,6): + # In Python 2.6, ints picked up a few non __ methods, so now there are + # no completions. + assert_equal(f.input_buffer, 'a[0].') + else: + # Right answer for 2.4/2.5 + assert_equal(f.input_buffer, 'a[0].__') @isolate_ipython0 @@ -238,8 +247,13 @@ def test_completion_equal(): f = TestPrefilterFrontEnd() f.input_buffer = 'a=1.' f.complete_current_input() - assert_equal(f.input_buffer, 'a=1.__') - + if sys.version_info[:2] >= (2,6): + # In Python 2.6, ints picked up a few non __ methods, so now there are + # no completions. + assert_equal(f.input_buffer, 'a=1.') + else: + # Right answer for 2.4/2.5 + assert_equal(f.input_buffer, 'a=1.__') if __name__ == '__main__': diff --git a/IPython/kernel/contexts.py b/IPython/kernel/contexts.py index 183da3a..45eeb2b 100644 --- a/IPython/kernel/contexts.py +++ b/IPython/kernel/contexts.py @@ -26,7 +26,7 @@ import sys from twisted.internet.error import ConnectionRefusedError -from IPython.ultraTB import _fixed_getinnerframes, findsource +from IPython.core.ultratb import _fixed_getinnerframes, findsource from IPython.core import ipapi from IPython.kernel import error diff --git a/IPython/kernel/core/interpreter.py b/IPython/kernel/core/interpreter.py index 05cec24..ad76cc2 100644 --- a/IPython/kernel/core/interpreter.py +++ b/IPython/kernel/core/interpreter.py @@ -29,7 +29,7 @@ import sys import traceback # Local imports. -from IPython.kernel.core import ultraTB +from IPython.core import ultratb from IPython.kernel.core.display_trap import DisplayTrap from IPython.kernel.core.macro import Macro from IPython.kernel.core.prompts import CachedOutput @@ -167,9 +167,9 @@ class Interpreter(object): formatters=self.traceback_formatters) # This is used temporarily for reformating exceptions in certain - # cases. It will go away once the ultraTB stuff is ported + # cases. It will go away once the ultratb stuff is ported # to ipython1 - self.tbHandler = ultraTB.FormattedTB(color_scheme='NoColor', + self.tbHandler = ultratb.FormattedTB(color_scheme='NoColor', mode='Context', tb_offset=2) diff --git a/IPython/kernel/core/ultraTB.py b/IPython/kernel/core/ultraTB.py deleted file mode 100644 index 268e2aa..0000000 --- a/IPython/kernel/core/ultraTB.py +++ /dev/null @@ -1,1067 +0,0 @@ -# -*- coding: utf-8 -*- -""" -ultraTB.py -- Spice up your tracebacks! - -* ColorTB -I've always found it a bit hard to visually parse tracebacks in Python. The -ColorTB class is a solution to that problem. It colors the different parts of a -traceback in a manner similar to what you would expect from a syntax-highlighting -text editor. - -Installation instructions for ColorTB: - import sys,ultraTB - sys.excepthook = ultraTB.ColorTB() - -* VerboseTB -I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds -of useful info when a traceback occurs. Ping originally had it spit out HTML -and intended it for CGI programmers, but why should they have all the fun? I -altered it to spit out colored text to the terminal. It's a bit overwhelming, -but kind of neat, and maybe useful for long-running programs that you believe -are bug-free. If a crash *does* occur in that type of program you want details. -Give it a shot--you'll love it or you'll hate it. - -Note: - - The Verbose mode prints the variables currently visible where the exception - happened (shortening their strings if too long). This can potentially be - very slow, if you happen to have a huge data structure whose string - representation is complex to compute. Your computer may appear to freeze for - a while with cpu usage at 100%. If this occurs, you can cancel the traceback - with Ctrl-C (maybe hitting it more than once). - - If you encounter this kind of situation often, you may want to use the - Verbose_novars mode instead of the regular Verbose, which avoids formatting - variables (but otherwise includes the information and context given by - Verbose). - - -Installation instructions for ColorTB: - import sys,ultraTB - sys.excepthook = ultraTB.VerboseTB() - -Note: Much of the code in this module was lifted verbatim from the standard -library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'. - -* Color schemes -The colors are defined in the class TBTools through the use of the -ColorSchemeTable class. Currently the following exist: - - - NoColor: allows all of this module to be used in any terminal (the color - escapes are just dummy blank strings). - - - Linux: is meant to look good in a terminal like the Linux console (black - or very dark background). - - - LightBG: similar to Linux but swaps dark/light colors to be more readable - in light background terminals. - -You can implement other color schemes easily, the syntax is fairly -self-explanatory. Please send back new schemes you develop to the author for -possible inclusion in future releases. -""" - -#***************************************************************************** -# Copyright (C) 2001 Nathaniel Gray -# Copyright (C) 2001-2004 Fernando Perez -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#***************************************************************************** - -# Required modules -import inspect -import keyword -import linecache -import os -import pydoc -import re -import string -import sys -import time -import tokenize -import traceback -import types - -# For purposes of monkeypatching inspect to fix a bug in it. -from inspect import getsourcefile, getfile, getmodule,\ - ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode - - -# IPython's own modules -# Modified pdb which doesn't damage IPython's readline handling -from IPython.utils import PyColorize -from IPython.core import debugger -from IPython.utils.ipstruct import Struct -from IPython.core.excolors import exception_colors -from IPython.utils.genutils import Term,uniq_stable,error,info - -# Globals -# amount of space to put line numbers before verbose tracebacks -INDENT_SIZE = 8 - -# Default color scheme. This is used, for example, by the traceback -# formatter. When running in an actual IPython instance, the user's rc.colors -# value is used, but havinga module global makes this functionality available -# to users of ultraTB who are NOT running inside ipython. -DEFAULT_SCHEME = 'NoColor' - -#--------------------------------------------------------------------------- -# Code begins - -# Utility functions -def inspect_error(): - """Print a message about internal inspect errors. - - These are unfortunately quite common.""" - - error('Internal Python error in the inspect module.\n' - 'Below is the traceback from this internal error.\n') - - -def findsource(object): - """Return the entire source file and starting line number for an object. - - The argument may be a module, class, method, function, traceback, frame, - or code object. The source code is returned as a list of all the lines - in the file and the line number indexes a line in that list. An IOError - is raised if the source code cannot be retrieved. - - FIXED version with which we monkeypatch the stdlib to work around a bug.""" - - file = getsourcefile(object) or getfile(object) - # If the object is a frame, then trying to get the globals dict from its - # module won't work. Instead, the frame object itself has the globals - # dictionary. - globals_dict = None - if inspect.isframe(object): - # XXX: can this ever be false? - globals_dict = object.f_globals - else: - module = getmodule(object, file) - if module: - globals_dict = module.__dict__ - lines = linecache.getlines(file, globals_dict) - if not lines: - raise IOError('could not get source code') - - if ismodule(object): - return lines, 0 - - if isclass(object): - name = object.__name__ - pat = re.compile(r'^(\s*)class\s*' + name + r'\b') - # make some effort to find the best matching class definition: - # use the one with the least indentation, which is the one - # that's most probably not inside a function definition. - candidates = [] - for i in range(len(lines)): - match = pat.match(lines[i]) - if match: - # if it's at toplevel, it's already the best one - if lines[i][0] == 'c': - return lines, i - # else add whitespace to candidate list - candidates.append((match.group(1), i)) - if candidates: - # this will sort by whitespace, and by line number, - # less whitespace first - candidates.sort() - return lines, candidates[0][1] - else: - raise IOError('could not find class definition') - - if ismethod(object): - object = object.im_func - if isfunction(object): - object = object.func_code - if istraceback(object): - object = object.tb_frame - if isframe(object): - object = object.f_code - if iscode(object): - if not hasattr(object, 'co_firstlineno'): - raise IOError('could not find function definition') - pat = re.compile(r'^(\s*def\s)|(.*(? 0: - if pmatch(lines[lnum]): break - lnum -= 1 - - return lines, lnum - raise IOError('could not find code object') - -# Monkeypatch inspect to apply our bugfix. This code only works with py25 -if sys.version_info[:2] >= (2,5): - inspect.findsource = findsource - -def fix_frame_records_filenames(records): - """Try to fix the filenames in each record from inspect.getinnerframes(). - - Particularly, modules loaded from within zip files have useless filenames - attached to their code object, and inspect.getinnerframes() just uses it. - """ - fixed_records = [] - for frame, filename, line_no, func_name, lines, index in records: - # Look inside the frame's globals dictionary for __file__, which should - # be better. - better_fn = frame.f_globals.get('__file__', None) - if isinstance(better_fn, str): - # Check the type just in case someone did something weird with - # __file__. It might also be None if the error occurred during - # import. - filename = better_fn - fixed_records.append((frame, filename, line_no, func_name, lines, index)) - return fixed_records - - -def _fixed_getinnerframes(etb, context=1,tb_offset=0): - import linecache - LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5 - - records = fix_frame_records_filenames(inspect.getinnerframes(etb, context)) - - # If the error is at the console, don't build any context, since it would - # otherwise produce 5 blank lines printed out (there is no file at the - # console) - rec_check = records[tb_offset:] - try: - rname = rec_check[0][1] - if rname == '' or rname.endswith(''): - return rec_check - except IndexError: - pass - - aux = traceback.extract_tb(etb) - assert len(records) == len(aux) - for i, (file, lnum, _, _) in zip(range(len(records)), aux): - maybeStart = lnum-1 - context//2 - start = max(maybeStart, 0) - end = start + context - lines = linecache.getlines(file)[start:end] - # pad with empty lines if necessary - if maybeStart < 0: - lines = (['\n'] * -maybeStart) + lines - if len(lines) < context: - lines += ['\n'] * (context - len(lines)) - buf = list(records[i]) - buf[LNUM_POS] = lnum - buf[INDEX_POS] = lnum - 1 - start - buf[LINES_POS] = lines - records[i] = tuple(buf) - return records[tb_offset:] - -# Helper function -- largely belongs to VerboseTB, but we need the same -# functionality to produce a pseudo verbose TB for SyntaxErrors, so that they -# can be recognized properly by ipython.el's py-traceback-line-re -# (SyntaxErrors have to be treated specially because they have no traceback) - -_parser = PyColorize.Parser() - -def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None): - numbers_width = INDENT_SIZE - 1 - res = [] - i = lnum - index - - # This lets us get fully syntax-highlighted tracebacks. - if scheme is None: - try: - # Again, reference to a global __IPYTHON__ that doesn't exist. - # XXX - scheme = __IPYTHON__.rc.colors - except: - scheme = DEFAULT_SCHEME - _line_format = _parser.format2 - - for line in lines: - new_line, err = _line_format(line,'str',scheme) - if not err: line = new_line - - if i == lnum: - # This is the line with the error - pad = numbers_width - len(str(i)) - if pad >= 3: - marker = '-'*(pad-3) + '-> ' - elif pad == 2: - marker = '> ' - elif pad == 1: - marker = '>' - else: - marker = '' - num = marker + str(i) - line = '%s%s%s %s%s' %(Colors.linenoEm, num, - Colors.line, line, Colors.Normal) - else: - num = '%*s' % (numbers_width,i) - line = '%s%s%s %s' %(Colors.lineno, num, - Colors.Normal, line) - - res.append(line) - if lvals and i == lnum: - res.append(lvals + '\n') - i = i + 1 - return res - - -#--------------------------------------------------------------------------- -# Module classes -class TBTools: - """Basic tools used by all traceback printer classes.""" - - def __init__(self,color_scheme = 'NoColor',call_pdb=False): - # Whether to call the interactive pdb debugger after printing - # tracebacks or not - self.call_pdb = call_pdb - - # Create color table - self.color_scheme_table = exception_colors() - - self.set_colors(color_scheme) - self.old_scheme = color_scheme # save initial value for toggles - - if call_pdb: - self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name) - else: - self.pdb = None - - def set_colors(self,*args,**kw): - """Shorthand access to the color table scheme selector method.""" - - # Set own color table - self.color_scheme_table.set_active_scheme(*args,**kw) - # for convenience, set Colors to the active scheme - self.Colors = self.color_scheme_table.active_colors - # Also set colors of debugger - if hasattr(self,'pdb') and self.pdb is not None: - self.pdb.set_colors(*args,**kw) - - def color_toggle(self): - """Toggle between the currently active color scheme and NoColor.""" - - if self.color_scheme_table.active_scheme_name == 'NoColor': - self.color_scheme_table.set_active_scheme(self.old_scheme) - self.Colors = self.color_scheme_table.active_colors - else: - self.old_scheme = self.color_scheme_table.active_scheme_name - self.color_scheme_table.set_active_scheme('NoColor') - self.Colors = self.color_scheme_table.active_colors - -#--------------------------------------------------------------------------- -class ListTB(TBTools): - """Print traceback information from a traceback list, with optional color. - - Calling: requires 3 arguments: - (etype, evalue, elist) - as would be obtained by: - etype, evalue, tb = sys.exc_info() - if tb: - elist = traceback.extract_tb(tb) - else: - elist = None - - It can thus be used by programs which need to process the traceback before - printing (such as console replacements based on the code module from the - standard library). - - Because they are meant to be called without a full traceback (only a - list), instances of this class can't call the interactive pdb debugger.""" - - def __init__(self,color_scheme = 'NoColor'): - TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0) - - def __call__(self, etype, value, elist): - Term.cout.flush() - print >> Term.cerr, self.text(etype,value,elist) - Term.cerr.flush() - - def text(self,etype, value, elist,context=5): - """Return a color formatted string with the traceback info.""" - - Colors = self.Colors - out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)] - if elist: - out_string.append('Traceback %s(most recent call last)%s:' % \ - (Colors.normalEm, Colors.Normal) + '\n') - out_string.extend(self._format_list(elist)) - lines = self._format_exception_only(etype, value) - for line in lines[:-1]: - out_string.append(" "+line) - out_string.append(lines[-1]) - return ''.join(out_string) - - def _format_list(self, extracted_list): - """Format a list of traceback entry tuples for printing. - - Given a list of tuples as returned by extract_tb() or - extract_stack(), return a list of strings ready for printing. - Each string in the resulting list corresponds to the item with the - same index in the argument list. Each string ends in a newline; - the strings may contain internal newlines as well, for those items - whose source text line is not None. - - Lifted almost verbatim from traceback.py - """ - - Colors = self.Colors - list = [] - for filename, lineno, name, line in extracted_list[:-1]: - item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \ - (Colors.filename, filename, Colors.Normal, - Colors.lineno, lineno, Colors.Normal, - Colors.name, name, Colors.Normal) - if line: - item = item + ' %s\n' % line.strip() - list.append(item) - # Emphasize the last entry - filename, lineno, name, line = extracted_list[-1] - item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \ - (Colors.normalEm, - Colors.filenameEm, filename, Colors.normalEm, - Colors.linenoEm, lineno, Colors.normalEm, - Colors.nameEm, name, Colors.normalEm, - Colors.Normal) - if line: - item = item + '%s %s%s\n' % (Colors.line, line.strip(), - Colors.Normal) - list.append(item) - return list - - def _format_exception_only(self, etype, value): - """Format the exception part of a traceback. - - The arguments are the exception type and value such as given by - sys.exc_info()[:2]. The return value is a list of strings, each ending - in a newline. Normally, the list contains a single string; however, - for SyntaxError exceptions, it contains several lines that (when - printed) display detailed information about where the syntax error - occurred. The message indicating which exception occurred is the - always last string in the list. - - Also lifted nearly verbatim from traceback.py - """ - - have_filedata = False - Colors = self.Colors - list = [] - try: - stype = Colors.excName + etype.__name__ + Colors.Normal - except AttributeError: - stype = etype # String exceptions don't get special coloring - if value is None: - list.append( str(stype) + '\n') - else: - if etype is SyntaxError: - try: - msg, (filename, lineno, offset, line) = value - except: - have_filedata = False - else: - have_filedata = True - #print 'filename is',filename # dbg - if not filename: filename = "" - list.append('%s File %s"%s"%s, line %s%d%s\n' % \ - (Colors.normalEm, - Colors.filenameEm, filename, Colors.normalEm, - Colors.linenoEm, lineno, Colors.Normal )) - if line is not None: - i = 0 - while i < len(line) and line[i].isspace(): - i = i+1 - list.append('%s %s%s\n' % (Colors.line, - line.strip(), - Colors.Normal)) - if offset is not None: - s = ' ' - for c in line[i:offset-1]: - if c.isspace(): - s = s + c - else: - s = s + ' ' - list.append('%s%s^%s\n' % (Colors.caret, s, - Colors.Normal) ) - value = msg - s = self._some_str(value) - if s: - list.append('%s%s:%s %s\n' % (str(stype), Colors.excName, - Colors.Normal, s)) - else: - list.append('%s\n' % str(stype)) - - # This is being commented out for now as the __IPYTHON__ variable - # referenced here is not resolved and causes massive test failures - # and errors. B. Granger, 04/2009. XXX - # See https://bugs.launchpad.net/bugs/362137 - # # vds:>> - # if have_filedata: - # __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0) - # # vds:<< - - return list - - def _some_str(self, value): - # Lifted from traceback.py - try: - return str(value) - except: - return '' % type(value).__name__ - -#---------------------------------------------------------------------------- -class VerboseTB(TBTools): - """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead - of HTML. Requires inspect and pydoc. Crazy, man. - - Modified version which optionally strips the topmost entries from the - traceback, to be used with alternate interpreters (because their own code - would appear in the traceback).""" - - def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0, - call_pdb = 0, include_vars=1): - """Specify traceback offset, headers and color scheme. - - Define how many frames to drop from the tracebacks. Calling it with - tb_offset=1 allows use of this handler in interpreters which will have - their own code at the top of the traceback (VerboseTB will first - remove that frame before printing the traceback info).""" - TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb) - self.tb_offset = tb_offset - self.long_header = long_header - self.include_vars = include_vars - - def text(self, etype, evalue, etb, context=5): - """Return a nice text document describing the traceback.""" - - # some locals - try: - etype = etype.__name__ - except AttributeError: - pass - Colors = self.Colors # just a shorthand + quicker name lookup - ColorsNormal = Colors.Normal # used a lot - col_scheme = self.color_scheme_table.active_scheme_name - indent = ' '*INDENT_SIZE - em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal) - undefined = '%sundefined%s' % (Colors.em, ColorsNormal) - exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal) - - # some internal-use functions - def text_repr(value): - """Hopefully pretty robust repr equivalent.""" - # this is pretty horrible but should always return *something* - try: - return pydoc.text.repr(value) - except KeyboardInterrupt: - raise - except: - try: - return repr(value) - except KeyboardInterrupt: - raise - except: - try: - # all still in an except block so we catch - # getattr raising - name = getattr(value, '__name__', None) - if name: - # ick, recursion - return text_repr(name) - klass = getattr(value, '__class__', None) - if klass: - return '%s instance' % text_repr(klass) - except KeyboardInterrupt: - raise - except: - return 'UNRECOVERABLE REPR FAILURE' - def eqrepr(value, repr=text_repr): return '=%s' % repr(value) - def nullrepr(value, repr=text_repr): return '' - - # meat of the code begins - try: - etype = etype.__name__ - except AttributeError: - pass - - if self.long_header: - # Header with the exception type, python version, and date - pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable - date = time.ctime(time.time()) - - head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal, - exc, ' '*(75-len(str(etype))-len(pyver)), - pyver, string.rjust(date, 75) ) - head += "\nA problem occured executing Python code. Here is the sequence of function"\ - "\ncalls leading up to the error, with the most recent (innermost) call last." - else: - # Simplified header - head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc, - string.rjust('Traceback (most recent call last)', - 75 - len(str(etype)) ) ) - frames = [] - # Flush cache before calling inspect. This helps alleviate some of the - # problems with python 2.3's inspect.py. - linecache.checkcache() - # Drop topmost frames if requested - try: - # Try the default getinnerframes and Alex's: Alex's fixes some - # problems, but it generates empty tracebacks for console errors - # (5 blanks lines) where none should be returned. - #records = inspect.getinnerframes(etb, context)[self.tb_offset:] - #print 'python records:', records # dbg - records = _fixed_getinnerframes(etb, context,self.tb_offset) - #print 'alex records:', records # dbg - except: - - # FIXME: I've been getting many crash reports from python 2.3 - # users, traceable to inspect.py. If I can find a small test-case - # to reproduce this, I should either write a better workaround or - # file a bug report against inspect (if that's the real problem). - # So far, I haven't been able to find an isolated example to - # reproduce the problem. - inspect_error() - traceback.print_exc(file=Term.cerr) - info('\nUnfortunately, your original traceback can not be constructed.\n') - return '' - - # build some color string templates outside these nested loops - tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal) - tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm, - ColorsNormal) - tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \ - (Colors.vName, Colors.valEm, ColorsNormal) - tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal) - tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal, - Colors.vName, ColorsNormal) - tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal) - tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal) - tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line, - ColorsNormal) - - # now, loop over all records printing context and info - abspath = os.path.abspath - for frame, file, lnum, func, lines, index in records: - #print '*** record:',file,lnum,func,lines,index # dbg - try: - file = file and abspath(file) or '?' - except OSError: - # if file is '' or something not in the filesystem, - # the abspath call will throw an OSError. Just ignore it and - # keep the original file string. - pass - link = tpl_link % file - try: - args, varargs, varkw, locals = inspect.getargvalues(frame) - except: - # This can happen due to a bug in python2.3. We should be - # able to remove this try/except when 2.4 becomes a - # requirement. Bug details at http://python.org/sf/1005466 - inspect_error() - traceback.print_exc(file=Term.cerr) - info("\nIPython's exception reporting continues...\n") - - if func == '?': - call = '' - else: - # Decide whether to include variable details or not - var_repr = self.include_vars and eqrepr or nullrepr - try: - call = tpl_call % (func,inspect.formatargvalues(args, - varargs, varkw, - locals,formatvalue=var_repr)) - except KeyError: - # Very odd crash from inspect.formatargvalues(). The - # scenario under which it appeared was a call to - # view(array,scale) in NumTut.view.view(), where scale had - # been defined as a scalar (it should be a tuple). Somehow - # inspect messes up resolving the argument list of view() - # and barfs out. At some point I should dig into this one - # and file a bug report about it. - inspect_error() - traceback.print_exc(file=Term.cerr) - info("\nIPython's exception reporting continues...\n") - call = tpl_call_fail % func - - # Initialize a list of names on the current line, which the - # tokenizer below will populate. - names = [] - - def tokeneater(token_type, token, start, end, line): - """Stateful tokeneater which builds dotted names. - - The list of names it appends to (from the enclosing scope) can - contain repeated composite names. This is unavoidable, since - there is no way to disambguate partial dotted structures until - the full list is known. The caller is responsible for pruning - the final list of duplicates before using it.""" - - # build composite names - if token == '.': - try: - names[-1] += '.' - # store state so the next token is added for x.y.z names - tokeneater.name_cont = True - return - except IndexError: - pass - if token_type == tokenize.NAME and token not in keyword.kwlist: - if tokeneater.name_cont: - # Dotted names - names[-1] += token - tokeneater.name_cont = False - else: - # Regular new names. We append everything, the caller - # will be responsible for pruning the list later. It's - # very tricky to try to prune as we go, b/c composite - # names can fool us. The pruning at the end is easy - # to do (or the caller can print a list with repeated - # names if so desired. - names.append(token) - elif token_type == tokenize.NEWLINE: - raise IndexError - # we need to store a bit of state in the tokenizer to build - # dotted names - tokeneater.name_cont = False - - def linereader(file=file, lnum=[lnum], getline=linecache.getline): - line = getline(file, lnum[0]) - lnum[0] += 1 - return line - - # Build the list of names on this line of code where the exception - # occurred. - try: - # This builds the names list in-place by capturing it from the - # enclosing scope. - tokenize.tokenize(linereader, tokeneater) - except IndexError: - # signals exit of tokenizer - pass - except tokenize.TokenError,msg: - _m = ("An unexpected error occurred while tokenizing input\n" - "The following traceback may be corrupted or invalid\n" - "The error message is: %s\n" % msg) - error(_m) - - # prune names list of duplicates, but keep the right order - unique_names = uniq_stable(names) - - # Start loop over vars - lvals = [] - if self.include_vars: - for name_full in unique_names: - name_base = name_full.split('.',1)[0] - if name_base in frame.f_code.co_varnames: - if locals.has_key(name_base): - try: - value = repr(eval(name_full,locals)) - except: - value = undefined - else: - value = undefined - name = tpl_local_var % name_full - else: - if frame.f_globals.has_key(name_base): - try: - value = repr(eval(name_full,frame.f_globals)) - except: - value = undefined - else: - value = undefined - name = tpl_global_var % name_full - lvals.append(tpl_name_val % (name,value)) - if lvals: - lvals = '%s%s' % (indent,em_normal.join(lvals)) - else: - lvals = '' - - level = '%s %s\n' % (link,call) - - if index is None: - frames.append(level) - else: - frames.append('%s%s' % (level,''.join( - _formatTracebackLines(lnum,index,lines,Colors,lvals, - col_scheme)))) - - # Get (safely) a string form of the exception info - try: - etype_str,evalue_str = map(str,(etype,evalue)) - except: - # User exception is improperly defined. - etype,evalue = str,sys.exc_info()[:2] - etype_str,evalue_str = map(str,(etype,evalue)) - # ... and format it - exception = ['%s%s%s: %s' % (Colors.excName, etype_str, - ColorsNormal, evalue_str)] - if type(evalue) is types.InstanceType: - try: - names = [w for w in dir(evalue) if isinstance(w, basestring)] - except: - # Every now and then, an object with funny inernals blows up - # when dir() is called on it. We do the best we can to report - # the problem and continue - _m = '%sException reporting error (object with broken dir())%s:' - exception.append(_m % (Colors.excName,ColorsNormal)) - etype_str,evalue_str = map(str,sys.exc_info()[:2]) - exception.append('%s%s%s: %s' % (Colors.excName,etype_str, - ColorsNormal, evalue_str)) - names = [] - for name in names: - value = text_repr(getattr(evalue, name)) - exception.append('\n%s%s = %s' % (indent, name, value)) - - # This is being commented out for now as the __IPYTHON__ variable - # referenced here is not resolved and causes massive test failures - # and errors. B. Granger, 04/2009. XXX - # See https://bugs.launchpad.net/bugs/362137 - # # vds: >> - # if records: - # filepath, lnum = records[-1][1:3] - # #print "file:", str(file), "linenb", str(lnum) # dbg - # filepath = os.path.abspath(filepath) - # __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0) - # # vds: << - - # return all our info assembled as a single string - return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) ) - - def debugger(self,force=False): - """Call up the pdb debugger if desired, always clean up the tb - reference. - - Keywords: - - - force(False): by default, this routine checks the instance call_pdb - flag and does not actually invoke the debugger if the flag is false. - The 'force' option forces the debugger to activate even if the flag - is false. - - If the call_pdb flag is set, the pdb interactive debugger is - invoked. In all cases, the self.tb reference to the current traceback - is deleted to prevent lingering references which hamper memory - management. - - Note that each call to pdb() does an 'import readline', so if your app - requires a special setup for the readline completers, you'll have to - fix that by hand after invoking the exception handler.""" - - if force or self.call_pdb: - if self.pdb is None: - self.pdb = debugger.Pdb( - self.color_scheme_table.active_scheme_name) - # the system displayhook may have changed, restore the original - # for pdb - dhook = sys.displayhook - sys.displayhook = sys.__displayhook__ - self.pdb.reset() - # Find the right frame so we don't pop up inside ipython itself - if hasattr(self,'tb'): - etb = self.tb - else: - etb = self.tb = sys.last_traceback - while self.tb.tb_next is not None: - self.tb = self.tb.tb_next - try: - if etb and etb.tb_next: - etb = etb.tb_next - self.pdb.botframe = etb.tb_frame - self.pdb.interaction(self.tb.tb_frame, self.tb) - finally: - sys.displayhook = dhook - - if hasattr(self,'tb'): - del self.tb - - def handler(self, info=None): - (etype, evalue, etb) = info or sys.exc_info() - self.tb = etb - Term.cout.flush() - print >> Term.cerr, self.text(etype, evalue, etb) - Term.cerr.flush() - - # Changed so an instance can just be called as VerboseTB_inst() and print - # out the right info on its own. - def __call__(self, etype=None, evalue=None, etb=None): - """This hook can replace sys.excepthook (for Python 2.1 or higher).""" - if etb is None: - self.handler() - else: - self.handler((etype, evalue, etb)) - try: - self.debugger() - except KeyboardInterrupt: - print "\nKeyboardInterrupt" - -#---------------------------------------------------------------------------- -class FormattedTB(VerboseTB,ListTB): - """Subclass ListTB but allow calling with a traceback. - - It can thus be used as a sys.excepthook for Python > 2.1. - - Also adds 'Context' and 'Verbose' modes, not available in ListTB. - - Allows a tb_offset to be specified. This is useful for situations where - one needs to remove a number of topmost frames from the traceback (such as - occurs with python programs that themselves execute other python code, - like Python shells). """ - - def __init__(self, mode = 'Plain', color_scheme='Linux', - tb_offset = 0,long_header=0,call_pdb=0,include_vars=0): - - # NEVER change the order of this list. Put new modes at the end: - self.valid_modes = ['Plain','Context','Verbose'] - self.verbose_modes = self.valid_modes[1:3] - - VerboseTB.__init__(self,color_scheme,tb_offset,long_header, - call_pdb=call_pdb,include_vars=include_vars) - self.set_mode(mode) - - def _extract_tb(self,tb): - if tb: - return traceback.extract_tb(tb) - else: - return None - - def text(self, etype, value, tb,context=5,mode=None): - """Return formatted traceback. - - If the optional mode parameter is given, it overrides the current - mode.""" - - if mode is None: - mode = self.mode - if mode in self.verbose_modes: - # verbose modes need a full traceback - return VerboseTB.text(self,etype, value, tb,context=5) - else: - # We must check the source cache because otherwise we can print - # out-of-date source code. - linecache.checkcache() - # Now we can extract and format the exception - elist = self._extract_tb(tb) - if len(elist) > self.tb_offset: - del elist[:self.tb_offset] - return ListTB.text(self,etype,value,elist) - - def set_mode(self,mode=None): - """Switch to the desired mode. - - If mode is not specified, cycles through the available modes.""" - - if not mode: - new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \ - len(self.valid_modes) - self.mode = self.valid_modes[new_idx] - elif mode not in self.valid_modes: - raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\ - 'Valid modes: '+str(self.valid_modes) - else: - self.mode = mode - # include variable details only in 'Verbose' mode - self.include_vars = (self.mode == self.valid_modes[2]) - - # some convenient shorcuts - def plain(self): - self.set_mode(self.valid_modes[0]) - - def context(self): - self.set_mode(self.valid_modes[1]) - - def verbose(self): - self.set_mode(self.valid_modes[2]) - -#---------------------------------------------------------------------------- -class AutoFormattedTB(FormattedTB): - """A traceback printer which can be called on the fly. - - It will find out about exceptions by itself. - - A brief example: - - AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux') - try: - ... - except: - AutoTB() # or AutoTB(out=logfile) where logfile is an open file object - """ - def __call__(self,etype=None,evalue=None,etb=None, - out=None,tb_offset=None): - """Print out a formatted exception traceback. - - Optional arguments: - - out: an open file-like object to direct output to. - - - tb_offset: the number of frames to skip over in the stack, on a - per-call basis (this overrides temporarily the instance's tb_offset - given at initialization time. """ - - if out is None: - out = Term.cerr - Term.cout.flush() - if tb_offset is not None: - tb_offset, self.tb_offset = self.tb_offset, tb_offset - print >> out, self.text(etype, evalue, etb) - self.tb_offset = tb_offset - else: - print >> out, self.text(etype, evalue, etb) - out.flush() - try: - self.debugger() - except KeyboardInterrupt: - print "\nKeyboardInterrupt" - - def text(self,etype=None,value=None,tb=None,context=5,mode=None): - if etype is None: - etype,value,tb = sys.exc_info() - self.tb = tb - return FormattedTB.text(self,etype,value,tb,context=5,mode=mode) - -#--------------------------------------------------------------------------- -# A simple class to preserve Nathan's original functionality. -class ColorTB(FormattedTB): - """Shorthand to initialize a FormattedTB in Linux colors mode.""" - def __init__(self,color_scheme='Linux',call_pdb=0): - FormattedTB.__init__(self,color_scheme=color_scheme, - call_pdb=call_pdb) - -#---------------------------------------------------------------------------- -# module testing (minimal) -if __name__ == "__main__": - def spam(c, (d, e)): - x = c + d - y = c * d - foo(x, y) - - def foo(a, b, bar=1): - eggs(a, b + bar) - - def eggs(f, g, z=globals()): - h = f + g - i = f - g - return h / i - - print '' - print '*** Before ***' - try: - print spam(1, (2, 3)) - except: - traceback.print_exc() - print '' - - handler = ColorTB() - print '*** ColorTB ***' - try: - print spam(1, (2, 3)) - except: - apply(handler, sys.exc_info() ) - print '' - - handler = VerboseTB() - print '*** VerboseTB ***' - try: - print spam(1, (2, 3)) - except: - apply(handler, sys.exc_info() ) - print '' - diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 44b732e..1232474 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -50,6 +50,7 @@ def test_for(mod): have_curses = test_for('_curses') have_wx = test_for('wx') +have_wx_aui = test_for('wx.aui') have_zi = test_for('zope.interface') have_twisted = test_for('twisted') have_foolscap = test_for('foolscap') @@ -67,8 +68,9 @@ def make_exclude(): pjoin('IPython', 'frontend', 'process', 'winprocess.py'), pjoin('IPython_doctest_plugin'), pjoin('IPython', 'extensions', 'ipy_'), - pjoin('IPython', 'extensions', 'clearcmd'), + pjoin('IPython', 'extensions', 'PhysicalQInput'), pjoin('IPython', 'extensions', 'PhysicalQInteractive'), + pjoin('IPython', 'extensions', 'InterpreterPasteInput'), pjoin('IPython', 'extensions', 'scitedirector'), pjoin('IPython', 'extensions', 'numeric_formats'), pjoin('IPython', 'testing', 'attic'), @@ -81,6 +83,9 @@ def make_exclude(): EXCLUDE.append(pjoin('IPython', 'gui')) EXCLUDE.append(pjoin('IPython', 'frontend', 'wx')) + if not have_wx_aui: + EXCLUDE.append(pjoin('IPython', 'gui', 'wx', 'wxIPython')) + if not have_objc: EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa')) @@ -111,6 +116,7 @@ def make_exclude(): return EXCLUDE + #----------------------------------------------------------------------------- # Functions and classes #----------------------------------------------------------------------------- @@ -237,7 +243,7 @@ def run_iptestall(): t_start = time.time() for name,runner in runners.iteritems(): print '*'*77 - print 'IPython test set:', name + print 'IPython test group:',name res = runner.run() if res: failed[name] = res @@ -248,14 +254,14 @@ def run_iptestall(): # summarize results print print '*'*77 - print 'Ran %s test sets in %.3fs' % (nrunners, t_tests) + print 'Ran %s test groups in %.3fs' % (nrunners, t_tests) print if not failed: print 'OK' else: # If anything went wrong, point out what command to rerun manually to # see the actual errors and individual summary - print 'ERROR - %s out of %s test sets failed.' % (nfail, nrunners) + print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners) for name in failed: failed_runner = runners[name] print '-'*40 @@ -276,4 +282,4 @@ def main(): if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index 3428af4..3534ec8 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -208,6 +208,15 @@ def start_ipython(): _ip.IP.magic_run_ori = _ip.IP.magic_run _ip.IP.magic_run = im + # XXX - For some very bizarre reason, the loading of %history by default is + # failing. This needs to be fixed later, but for now at least this ensures + # that tests that use %hist run to completion. + from IPython.core import history + history.init_ipython(_ip) + if not hasattr(_ip.IP,'magic_history'): + raise RuntimeError("Can't load magics, aborting") + + # The start call MUST be made here. I'm not sure yet why it doesn't work if # it is made later, at plugin initialization time, but in all my tests, that's # the case. diff --git a/IPython/utils/genutils.py b/IPython/utils/genutils.py index 1fe1622..b320848 100644 --- a/IPython/utils/genutils.py +++ b/IPython/utils/genutils.py @@ -881,7 +881,7 @@ def doctest_reload(): This routine: - - reloads doctest + - imports doctest but does NOT reload it (see below). - resets its global 'master' attribute to None, so that multiple uses of the module interactively don't produce cumulative reports. @@ -890,20 +890,20 @@ def doctest_reload(): modified displayhook. Doctest expects the default displayhook behavior deep down, so our modification breaks it completely. For this reason, a hard monkeypatch seems like a reasonable solution rather than asking - users to manually use a different doctest runner when under IPython.""" + users to manually use a different doctest runner when under IPython. - import doctest - reload(doctest) - doctest.master=None + Note + ---- - try: - doctest.DocTestRunner - except AttributeError: - # This is only for python 2.3 compatibility, remove once we move to - # 2.4 only. - pass - else: - doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run) + This function *used to* reload doctest, but this has been disabled because + reloading doctest unconditionally can cause massive breakage of other + doctest-dependent modules already in memory, such as those for IPython's + own testing system. The name wasn't changed to avoid breaking people's + code, but the reload call isn't actually made anymore.""" + + import doctest + doctest.master = None + doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run) #---------------------------------------------------------------------------- class HomeDirError(Error): diff --git a/docs/examples/kernel/task2.py b/docs/examples/kernel/task2.py old mode 100644 new mode 100755 index 661ad22..bfbe3e0 --- a/docs/examples/kernel/task2.py +++ b/docs/examples/kernel/task2.py @@ -3,6 +3,8 @@ from IPython.kernel import client import time +import sys +flush = sys.stdout.flush tc = client.TaskClient() mec = client.MultiEngineClient() @@ -16,6 +18,7 @@ for i in range(6): time.sleep(1.0) print "Queue status (vebose=False)" print tc.queue_status() + flush() for i in range(24): tc.run(client.StringTask('time.sleep(1)')) @@ -24,12 +27,14 @@ for i in range(6): time.sleep(1.0) print "Queue status (vebose=True)" print tc.queue_status(True) + flush() for i in range(12): tc.run(client.StringTask('time.sleep(2)')) print "Queue status (vebose=True)" print tc.queue_status(True) +flush() qs = tc.queue_status(True) sched = qs['scheduled'] @@ -41,4 +46,5 @@ for i in range(6): time.sleep(1.0) print "Queue status (vebose=True)" print tc.queue_status(True) + flush() diff --git a/docs/source/interactive/reference.txt b/docs/source/interactive/reference.txt index 2478756..4cf25f4 100644 --- a/docs/source/interactive/reference.txt +++ b/docs/source/interactive/reference.txt @@ -1329,8 +1329,9 @@ For stand-alone use of the feature in your programs which do not use IPython at all, put the following lines toward the top of your 'main' routine:: - import sys,IPython.ultraTB - sys.excepthook = IPython.ultraTB.FormattedTB(mode='Verbose', + import sys + from IPython.core import ultratb + sys.excepthook = ultratb.FormattedTB(mode='Verbose', color_scheme='Linux', call_pdb=1) The mode keyword can be either 'Verbose' or 'Plain', giving either very