From 89c80113845d7b8287200327b54bcb24185e6555 2006-01-02 21:21:47 From: fperez Date: 2006-01-02 21:21:47 Subject: [PATCH] Fixes to: - embedding - traceback handling - tab completion Support for editing macros via %edit. Very conveninent. --- diff --git a/IPython/Logger.py b/IPython/Logger.py index b2defcd..989ec15 100644 --- a/IPython/Logger.py +++ b/IPython/Logger.py @@ -2,7 +2,7 @@ """ Logger class for IPython's logging facilities. -$Id: Logger.py 984 2005-12-31 08:40:31Z fperez $ +$Id: Logger.py 988 2006-01-02 21:21:47Z fperez $ """ #***************************************************************************** @@ -172,7 +172,12 @@ which already exists. But you must first start the logging process with # update the auto _i tables #print '***logging line',line # dbg #print '***cache_count', self.shell.outputcache.prompt_count # dbg - input_hist = self.shell.user_ns['_ih'] + try: + input_hist = self.shell.user_ns['_ih'] + except: + print 'userns:',self.shell.user_ns.keys() + return + if not continuation and line: self._iii = self._ii self._ii = self._i diff --git a/IPython/Magic.py b/IPython/Magic.py index 1d7ea6f..9b08492 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 986 2005-12-31 23:07:31Z fperez $""" +$Id: Magic.py 988 2006-01-02 21:21:47Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -742,12 +742,14 @@ Currently the magic system has the following functions:\n""" arguments are returned.""" user_ns = self.shell.user_ns + internal_ns = self.shell.internal_ns + user_config_ns = self.shell.user_config_ns out = [] typelist = parameter_s.split() - for i in self.shell.user_ns.keys(): + + for i in user_ns: if not (i.startswith('_') or i.startswith('_i')) \ - and not (self.shell.internal_ns.has_key(i) or - self.shell.user_config_ns.has_key(i)): + and not (i in internal_ns or i in user_config_ns): if typelist: if type(user_ns[i]).__name__ in typelist: out.append(i) @@ -1638,11 +1640,22 @@ Currently the magic system has the following functions:\n""" print 'The following commands were written to file `%s`:' % fname print cmds - def magic_ed(self,parameter_s = ''): + def _edit_macro(self,mname,macro): + """open an editor with the macro data in a file""" + filename = self.shell.mktempfile(macro.value) + self.shell.hooks.editor(filename) + + # and make a new macro object, to replace the old one + mfile = open(filename) + mvalue = mfile.read() + mfile.close() + self.shell.user_ns[mname] = Macro(mvalue) + + def magic_ed(self,parameter_s=''): """Alias to %edit.""" return self.magic_edit(parameter_s) - def magic_edit(self,parameter_s = '',last_call=['','']): + def magic_edit(self,parameter_s='',last_call=['','']): """Bring up an editor and execute the resulting code. Usage: @@ -1695,6 +1708,10 @@ Currently the magic system has the following functions:\n""" to load an editor exactly at the point where 'function' is defined, edit it and have the file be executed automatically. + If the object is a macro (see %macro for details), this opens up your + specified editor with a temporary file containing the macro's data. + Upon exit, the macro is reloaded with the contents of the file. + Note: opening at an exact line is only supported under Unix, and some editors (like kedit and gedit up to Gnome 2.8) do not understand the '+NUMBER' parameter necessary for this feature. Good editors like @@ -1826,6 +1843,7 @@ Currently the magic system has the following functions:\n""" data = eval(args,self.shell.user_ns) if not type(data) in StringTypes: raise DataIsObject + except (NameError,SyntaxError): # given argument is not a variable, try as a filename filename = make_filename(args) @@ -1833,9 +1851,16 @@ Currently the magic system has the following functions:\n""" warn("Argument given (%s) can't be found as a variable " "or as a filename." % args) return + data = '' use_temp = 0 except DataIsObject: + + # macros have a special edit function + if isinstance(data,Macro): + self._edit_macro(args,data) + return + # For objects, try to edit the file where they are defined try: filename = inspect.getabsfile(data) @@ -1861,13 +1886,7 @@ Currently the magic system has the following functions:\n""" data = '' if use_temp: - filename = tempfile.mktemp('.py') - self.shell.tempfiles.append(filename) - - if data and use_temp: - tmp_file = open(filename,'w') - tmp_file.write(data) - tmp_file.close() + filename = self.shell.mktempfile(data) # do actual editing here print 'Editing...', @@ -1887,9 +1906,6 @@ Currently the magic system has the following functions:\n""" self.shell.showtraceback() except: self.shell.showtraceback() - if use_temp: - contents = open(filename).read() - return contents def magic_xmode(self,parameter_s = ''): """Switch modes for the exception handlers. @@ -2568,10 +2584,10 @@ Defaulting color scheme to 'NoColor'""" Usage: - %store - Show list of all variables and their current values\\ - %store - Store the *current* value of the variable to disk\\ - %store -d - Remove the variable and its value from storage\\ - %store -r - Remove all variables from storage + %store - Show list of all variables and their current values\\ + %store - Store the *current* value of the variable to disk\\ + %store -d - Remove the variable and its value from storage\\ + %store -r - Remove all variables from storage It should be noted that if you change the value of a variable, you need to %store it again if you want to persist the new value. diff --git a/IPython/Release.py b/IPython/Release.py index 749aebc..5b0c0fe 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 987 2005-12-31 23:50:31Z fperez $""" +$Id: Release.py 988 2006-01-02 21:21:47Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2005 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.0.rc6' +version = '0.7.0.rc7' -revision = '$Revision: 987 $' +revision = '$Revision: 988 $' description = "An enhanced interactive Python shell." diff --git a/IPython/completer.py b/IPython/completer.py index 4ef1768..47987c6 100644 --- a/IPython/completer.py +++ b/IPython/completer.py @@ -192,14 +192,10 @@ class Completer: except: object = eval(expr, self.global_namespace) - # for modules which define __all__, complete only on those. - if type(object) == types.ModuleType and hasattr(object, '__all__'): - words = getattr(object, '__all__') - else: - words = dir(object) - if hasattr(object,'__class__'): - words.append('__class__') - words.extend(get_class_members(object.__class__)) + words = dir(object) + if hasattr(object,'__class__'): + words.append('__class__') + words.extend(get_class_members(object.__class__)) # filter out non-string attributes which may be stuffed by dir() calls # and poor coding in third-party modules diff --git a/IPython/hooks.py b/IPython/hooks.py index 1395fe9..a9d50d0 100644 --- a/IPython/hooks.py +++ b/IPython/hooks.py @@ -32,7 +32,7 @@ ip_set_hook('editor',myiphooks.calljed) The ip_set_hook function is put by IPython into the builtin namespace, so it is always available from all running code. -$Id: hooks.py 960 2005-12-28 06:51:01Z fperez $""" +$Id: hooks.py 988 2006-01-02 21:21:47Z fperez $""" #***************************************************************************** # Copyright (C) 2005 Fernando Perez. @@ -52,7 +52,7 @@ import os # but over time we'll move here all the public API for user-accessible things. __all__ = ['editor', 'fix_error_editor'] -def editor(self,filename, linenum): +def editor(self,filename, linenum=None): """Open the default editor at the given filename and linenumber. This is IPython's default editor hook, you can use it as an example to diff --git a/IPython/iplib.py b/IPython/iplib.py index 43e5993..3497dc4 100644 --- a/IPython/iplib.py +++ b/IPython/iplib.py @@ -6,7 +6,7 @@ Requires Python 2.1 or newer. This file contains all the classes and helper functions specific to IPython. -$Id: iplib.py 987 2005-12-31 23:50:31Z fperez $ +$Id: iplib.py 988 2006-01-02 21:21:47Z fperez $ """ #***************************************************************************** @@ -55,6 +55,7 @@ import re import shutil import string import sys +import tempfile import traceback import types @@ -100,80 +101,6 @@ def softspace(file, newvalue): return oldvalue #**************************************************************************** -# These special functions get installed in the builtin namespace, to provide -# programmatic (pure python) access to magics, aliases and system calls. This -# is important for logging, user scripting, and more. - -# We are basically exposing, via normal python functions, the three mechanisms -# in which ipython offers special call modes (magics for internal control, -# aliases for direct system access via pre-selected names, and !cmd for -# calling arbitrary system commands). - -def ipmagic(arg_s): - """Call a magic function by name. - - Input: a string containing the name of the magic function to call and any - additional arguments to be passed to the magic. - - ipmagic('name -opt foo bar') is equivalent to typing at the ipython - prompt: - - In[1]: %name -opt foo bar - - To call a magic without arguments, simply use ipmagic('name'). - - This provides a proper Python function to call IPython's magics in any - valid Python code you can type at the interpreter, including loops and - compound statements. It is added by IPython to the Python builtin - namespace upon initialization.""" - - args = arg_s.split(' ',1) - magic_name = args[0] - if magic_name.startswith(__IPYTHON__.ESC_MAGIC): - magic_name = magic_name[1:] - try: - magic_args = args[1] - except IndexError: - magic_args = '' - fn = getattr(__IPYTHON__,'magic_'+magic_name,None) - if fn is None: - error("Magic function `%s` not found." % magic_name) - else: - magic_args = __IPYTHON__.var_expand(magic_args) - return fn(magic_args) - -def ipalias(arg_s): - """Call an alias by name. - - Input: a string containing the name of the alias to call and any - additional arguments to be passed to the magic. - - ipalias('name -opt foo bar') is equivalent to typing at the ipython - prompt: - - In[1]: name -opt foo bar - - To call an alias without arguments, simply use ipalias('name'). - - This provides a proper Python function to call IPython's aliases in any - valid Python code you can type at the interpreter, including loops and - compound statements. It is added by IPython to the Python builtin - namespace upon initialization.""" - - args = arg_s.split(' ',1) - alias_name = args[0] - try: - alias_args = args[1] - except IndexError: - alias_args = '' - if alias_name in __IPYTHON__.alias_table: - __IPYTHON__.call_alias(alias_name,alias_args) - else: - error("Alias `%s` not found." % alias_name) - -def ipsystem(arg_s): - """Make a system call, using IPython.""" - __IPYTHON__.system(arg_s) #**************************************************************************** @@ -184,6 +111,8 @@ class SpaceInInput(exceptions.Exception): pass # Local use classes class Bunch: pass +class Undefined: pass + class InputList(list): """Class to store user input. @@ -255,27 +184,17 @@ class InteractiveShell(object,Magic): if ns is not None and type(ns) != types.DictType: raise TypeError,'namespace must be a dictionary' - # Put a reference to self in builtins so that any form of embedded or - # imported code can test for being inside IPython. - __builtin__.__IPYTHON__ = self - - # And load into builtins ipmagic/ipalias/ipsystem as well - __builtin__.ipmagic = ipmagic - __builtin__.ipalias = ipalias - __builtin__.ipsystem = ipsystem - - # Add to __builtin__ other parts of IPython's public API - __builtin__.ip_set_hook = self.set_hook + # Job manager (for jobs run as background threads) + self.jobs = BackgroundJobManager() - # Keep in the builtins a flag for when IPython is active. We set it - # with setdefault so that multiple nested IPythons don't clobber one - # another. Each will increase its value by one upon being activated, - # which also gives us a way to determine the nesting level. - __builtin__.__dict__.setdefault('__IPYTHON__active',0) + # track which builtins we add, so we can clean up later + self.builtins_added = {} + # This method will add the necessary builtins for operation, but + # tracking what it did via the builtins_added dict. + self.add_builtins() # Do the intuitively correct thing for quit/exit: we remove the - # builtins if they exist, and our own prefilter routine will handle - # these special cases + # builtins if they exist, and our own magics will deal with this try: del __builtin__.exit, __builtin__.quit except AttributeError: @@ -434,11 +353,6 @@ class InteractiveShell(object,Magic): # item which gets cleared once run. self.code_to_run = None - # Job manager (for jobs run as background threads) - self.jobs = BackgroundJobManager() - # Put the job manager into builtins so it's always there. - __builtin__.jobs = self.jobs - # escapes for automatic behavior on the command line self.ESC_SHELL = '!' self.ESC_HELP = '?' @@ -725,6 +639,45 @@ class InteractiveShell(object,Magic): self.user_ns[key] = obj + + def add_builtins(self): + """Store ipython references into the builtin namespace. + + Some parts of ipython operate via builtins injected here, which hold a + reference to IPython itself.""" + + builtins_new = dict(__IPYTHON__ = self, + ip_set_hook = self.set_hook, + jobs = self.jobs, + ipmagic = self.ipmagic, + ipalias = self.ipalias, + ipsystem = self.ipsystem, + ) + for biname,bival in builtins_new.items(): + try: + # store the orignal value so we can restore it + self.builtins_added[biname] = __builtin__.__dict__[biname] + except KeyError: + # or mark that it wasn't defined, and we'll just delete it at + # cleanup + self.builtins_added[biname] = Undefined + __builtin__.__dict__[biname] = bival + + # Keep in the builtins a flag for when IPython is active. We set it + # with setdefault so that multiple nested IPythons don't clobber one + # another. Each will increase its value by one upon being activated, + # which also gives us a way to determine the nesting level. + __builtin__.__dict__.setdefault('__IPYTHON__active',0) + + def clean_builtins(self): + """Remove any builtins which might have been added by add_builtins, or + restore overwritten ones to their previous values.""" + for biname,bival in self.builtins_added.items(): + if bival is Undefined: + del __builtin__.__dict__[biname] + else: + __builtin__.__dict__[biname] = bival + self.builtins_added.clear() def set_hook(self,name,hook): """set_hook(name,hook) -> sets an internal IPython hook. @@ -815,6 +768,82 @@ class InteractiveShell(object,Magic): call_pdb = property(_get_call_pdb,_set_call_pdb,None, 'Control auto-activation of pdb at exceptions') + + # These special functions get installed in the builtin namespace, to + # provide programmatic (pure python) access to magics, aliases and system + # calls. This is important for logging, user scripting, and more. + + # We are basically exposing, via normal python functions, the three + # mechanisms in which ipython offers special call modes (magics for + # internal control, aliases for direct system access via pre-selected + # names, and !cmd for calling arbitrary system commands). + + def ipmagic(self,arg_s): + """Call a magic function by name. + + Input: a string containing the name of the magic function to call and any + additional arguments to be passed to the magic. + + ipmagic('name -opt foo bar') is equivalent to typing at the ipython + prompt: + + In[1]: %name -opt foo bar + + To call a magic without arguments, simply use ipmagic('name'). + + This provides a proper Python function to call IPython's magics in any + valid Python code you can type at the interpreter, including loops and + compound statements. It is added by IPython to the Python builtin + namespace upon initialization.""" + + args = arg_s.split(' ',1) + magic_name = args[0] + if magic_name.startswith(self.ESC_MAGIC): + magic_name = magic_name[1:] + try: + magic_args = args[1] + except IndexError: + magic_args = '' + fn = getattr(self,'magic_'+magic_name,None) + if fn is None: + error("Magic function `%s` not found." % magic_name) + else: + magic_args = self.var_expand(magic_args) + return fn(magic_args) + + def ipalias(self,arg_s): + """Call an alias by name. + + Input: a string containing the name of the alias to call and any + additional arguments to be passed to the magic. + + ipalias('name -opt foo bar') is equivalent to typing at the ipython + prompt: + + In[1]: name -opt foo bar + + To call an alias without arguments, simply use ipalias('name'). + + This provides a proper Python function to call IPython's aliases in any + valid Python code you can type at the interpreter, including loops and + compound statements. It is added by IPython to the Python builtin + namespace upon initialization.""" + + args = arg_s.split(' ',1) + alias_name = args[0] + try: + alias_args = args[1] + except IndexError: + alias_args = '' + if alias_name in self.alias_table: + self.call_alias(alias_name,alias_args) + else: + error("Alias `%s` not found." % alias_name) + + def ipsystem(self,arg_s): + """Make a system call, using IPython.""" + self.system(arg_s) + def complete(self,text): """Return a sorted list of all possible completions on text. @@ -1287,9 +1316,18 @@ want to merge them back into the new files.""" % locals() global_ns = call_frame.f_globals # Update namespaces and fire up interpreter - self.user_ns = local_ns + + # The global one is easy, we can just throw it in self.user_global_ns = global_ns + # but the user/local one is tricky: ipython needs it to store internal + # data, but we also need the locals. We'll copy locals in the user + # one, but will track what got copied so we can delete them at exit. + # This is so that a later embedded call doesn't see locals from a + # previous call (which most likely existed in a separate scope). + local_varnames = local_ns.keys() + self.user_ns.update(local_ns) + # Patch for global embedding to make sure that things don't overwrite # user globals accidentally. Thanks to Richard # FIXME. Test this a bit more carefully (the if.. is new) @@ -1299,8 +1337,21 @@ want to merge them back into the new files.""" % locals() # make sure the tab-completer has the correct frame information, so it # actually completes using the frame's locals/globals self.set_completer_frame(call_frame) + + # before activating the interactive mode, we need to make sure that + # all names in the builtin namespace needed by ipython point to + # ourselves, and not to other instances. + self.add_builtins() self.interact(header) + + # now, purge out the user namespace from anything we might have added + # from the caller's local namespace + delvar = self.user_ns.pop + for var in local_varnames: + delvar(var,None) + # and clean builtins we may have overridden + self.clean_builtins() def interact(self, banner=None): """Closely emulate the interactive Python console. @@ -1327,7 +1378,9 @@ want to merge them back into the new files.""" % locals() __builtin__.__dict__['__IPYTHON__active'] += 1 # exit_now is set by a call to %Exit or %Quit + self.exit_now = False while not self.exit_now: + try: if more: prompt = self.outputcache.prompt2 @@ -1942,6 +1995,26 @@ want to merge them back into the new files.""" % locals() return line + def mktempfile(self,data=None): + """Make a new tempfile and return its filename. + + This makes a call to tempfile.mktemp, but it registers the created + filename internally so ipython cleans it up at exit time. + + Optional inputs: + + - data(None): if data is given, it gets written out to the temp file + immediately, and the file is closed again.""" + + filename = tempfile.mktemp('.py') + self.tempfiles.append(filename) + + if data: + tmp_file = open(filename,'w') + tmp_file.write(data) + tmp_file.close() + return filename + def write(self,data): """Write a string to the default output""" Term.cout.write(data) diff --git a/IPython/ultraTB.py b/IPython/ultraTB.py index 7820af1..c24829c 100644 --- a/IPython/ultraTB.py +++ b/IPython/ultraTB.py @@ -60,7 +60,7 @@ 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. -$Id: ultraTB.py 975 2005-12-29 23:50:22Z fperez $""" +$Id: ultraTB.py 988 2006-01-02 21:21:47Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Nathaniel Gray @@ -95,9 +95,14 @@ from IPython.Struct import Struct from IPython.excolors import ExceptionColors from IPython.genutils import Term,uniq_stable,error,info +# Globals +# amount of space to put line numbers before verbose tracebacks +INDENT_SIZE = 8 + #--------------------------------------------------------------------------- # Code begins +# Utility functions def inspect_error(): """Print a message about internal inspect errors. @@ -106,6 +111,76 @@ def inspect_error(): error('Internal Python error in the inspect module.\n' 'Below is the traceback from this internal error.\n') +def _fixed_getinnerframes(etb, context=1,tb_offset=0): + import linecache + LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5 + + records = 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:] + rname = rec_check[0][1] + if rname == '' or rname.endswith(''): + return rec_check + + 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)) + assert len(lines) == context + 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) +def _formatTracebackLines(lnum, index, lines, Colors, lvals=None): + numbers_width = INDENT_SIZE - 1 + res = [] + i = lnum - index + for line in lines: + 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.""" @@ -316,9 +391,7 @@ class VerboseTB(TBTools): # some locals Colors = self.Colors # just a shorthand + quicker name lookup ColorsNormal = Colors.Normal # used a lot - indent_size = 8 # we need some space to put line numbers before - indent = ' '*indent_size - numbers_width = indent_size - 1 # leave space between numbers & code + indent = ' '*INDENT_SIZE text_repr = pydoc.text.repr exc = '%s%s%s' % (Colors.excName, str(etype), ColorsNormal) em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal) @@ -353,7 +426,13 @@ class VerboseTB(TBTools): linecache.checkcache() # Drop topmost frames if requested try: - records = inspect.getinnerframes(etb, context)[self.tb_offset:] + # 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 @@ -519,32 +598,12 @@ class VerboseTB(TBTools): lvals = '' level = '%s %s\n' % (link,call) - excerpt = [] - if index is not None: - i = lnum - index - for line in lines: - 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 = '%s%s' % (marker,i) - line = tpl_line_em % (num,line) - else: - num = '%*s' % (numbers_width,i) - line = tpl_line % (num,line) - - excerpt.append(line) - if self.include_vars and i == lnum: - excerpt.append('%s\n' % lvals) - i += 1 - frames.append('%s%s' % (level,''.join(excerpt)) ) + + if index is None: + frames.append(level) + else: + frames.append('%s%s' % (level,''.join( + _formatTracebackLines(lnum,index,lines,self.Colors,lvals)))) # Get (safely) a string form of the exception info try: diff --git a/doc/ChangeLog b/doc/ChangeLog index 7ab8c8f..8f58bcd 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,26 @@ +2006-01-02 Fernando Perez + + * IPython/ultraTB.py (_fixed_getinnerframes): added Alex + Schmolck's patch to fix inspect.getinnerframes(). + + * IPython/iplib.py (InteractiveShell.__init__): significant fixes + for embedded instances, regarding handling of namespaces and items + added to the __builtin__ one. Multiple embedded instances and + recursive embeddings should work better now (though I'm not sure + I've got all the corner cases fixed, that code is a bit of a brain + twister). + + * IPython/Magic.py (magic_edit): added support to edit in-memory + macros (automatically creates the necessary temp files). %edit + also doesn't return the file contents anymore, it's just noise. + + * IPython/completer.py (Completer.attr_matches): revert change to + complete only on attributes listed in __all__. I realized it + cripples the tab-completion system as a tool for exploring the + internals of unknown libraries (it renders any non-__all__ + attribute off-limits). I got bit by this when trying to see + something inside the dis module. + 2005-12-31 Fernando Perez * IPython/iplib.py (InteractiveShell.__init__): add .meta diff --git a/doc/examples/example-embed.py b/doc/examples/example-embed.py index 88d67f5..038994d 100755 --- a/doc/examples/example-embed.py +++ b/doc/examples/example-embed.py @@ -27,7 +27,8 @@ else: print "The prompts for the nested copy have been modified" nested = 1 # what the embedded instance will see as sys.argv: - args = ['-pi1','In <\\#>:','-pi2',' .\\D.:','-po','Out<\\#>:','-nosep'] + args = ['-pi1','In <\\#>: ','-pi2',' .\\D.: ', + '-po','Out<\\#>: ','-nosep'] # First import the embeddable shell class from IPython.Shell import IPShellEmbed @@ -44,7 +45,8 @@ ipshell = IPShellEmbed(args, if nested: args[1] = 'In2<\\#>' else: - args = ['-pi1','In2<\\#>:','-pi2',' .\\D.:','-po','Out<\\#>:','-nosep'] + args = ['-pi1','In2<\\#>: ','-pi2',' .\\D.: ', + '-po','Out<\\#>: ','-nosep'] ipshell2 = IPShellEmbed(args,banner = 'Second IPython instance.') print '\nHello. This is printed from the main controller program.\n'