diff --git a/IPython/Extensions/InterpreterPasteInput.py b/IPython/Extensions/InterpreterPasteInput.py index c984d36..bcedda2 100644 --- a/IPython/Extensions/InterpreterPasteInput.py +++ b/IPython/Extensions/InterpreterPasteInput.py @@ -83,6 +83,8 @@ __license__ = Release.license import re +from IPython.iplib import InteractiveShell + PROMPT_RE = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )') def prefilter_paste(self,line,continuation): @@ -106,13 +108,15 @@ def prefilter_paste(self,line,continuation): return '' else: return self._prefilter(line,continuation) - -# Rebind this to be the new IPython prefilter: -from IPython.iplib import InteractiveShell -InteractiveShell.prefilter = prefilter_paste -# Clean up the namespace. -del InteractiveShell,prefilter_paste +def activate_prefilter(): + """Rebind the input-pasting filter to be the new IPython prefilter""" + InteractiveShell.prefilter = prefilter_paste + +def deactivate_prefilter(): + """Reset the filter.""" + InteractiveShell.prefilter = InteractiveShell._prefilter # Just a heads up at the console +activate_prefilter() print '*** Pasting of code with ">>>" or "..." has been enabled.' diff --git a/IPython/Extensions/ipy_profile_doctest.py b/IPython/Extensions/ipy_profile_doctest.py index f4f7d1d..f8eb372 100644 --- a/IPython/Extensions/ipy_profile_doctest.py +++ b/IPython/Extensions/ipy_profile_doctest.py @@ -42,4 +42,7 @@ def main(): # Use plain exceptions, to also resemble normal pyhton. o.xmode = 'plain' + # Store the activity flag in the metadata bag from the running shell + ip.IP.meta.doctest_mode = True + main() diff --git a/IPython/Extensions/ipy_profile_scipy.py b/IPython/Extensions/ipy_profile_scipy.py index 08155e4..7c929c2 100644 --- a/IPython/Extensions/ipy_profile_scipy.py +++ b/IPython/Extensions/ipy_profile_scipy.py @@ -12,14 +12,14 @@ def main(): ip = IPython.ipapi.get() try: - ip.ex("import scipy") ip.ex("import numpy") + ip.ex("import scipy") - ip.ex("from scipy import *") ip.ex("from numpy import *") + ip.ex("from scipy import *") print "SciPy profile successfully loaded." except ImportError: print "Unable to start scipy profile, are scipy and numpy installed?" -main() \ No newline at end of file +main() diff --git a/IPython/Magic.py b/IPython/Magic.py index 3a1a1aa..32c7df1 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 2595 2007-08-08 09:41:33Z vivainio $""" +$Id: Magic.py 2601 2007-08-10 07:01:29Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -2912,4 +2912,90 @@ Defaulting color scheme to 'NoColor'""" suffix = (sys.platform == 'win32' and '.ini' or '') (userdir / ('ipythonrc' + suffix)).write_text('# Empty, see ipy_user_conf.py\n') + + def magic_doctest_mode(self,parameter_s=''): + """Toggle doctest mode on and off. + + This mode allows you to toggle the prompt behavior between normal + IPython prompts and ones that are as similar to the default IPython + interpreter as possible. + + It also supports the pasting of code snippets that have leading '>>>' + and '...' prompts in them. This means that you can paste doctests from + files or docstrings (even if they have leading whitespace), and the + code will execute correctly. You can then use '%history -tn' to see + the translated history without line numbers; this will give you the + input after removal of all the leading prompts and whitespace, which + can be pasted back into an editor. + + With these features, you can switch into this mode easily whenever you + need to do testing and changes to doctests, without having to leave + your existing IPython session. + """ + + # XXX - Fix this to have cleaner activate/deactivate calls. + from IPython.Extensions import InterpreterPasteInput as ipaste + from IPython.ipstruct import Struct + + # Shorthands + shell = self.shell + oc = shell.outputcache + rc = shell.rc + meta = shell.meta + # dstore is a data store kept in the instance metadata bag to track any + # changes we make, so we can undo them later. + dstore = meta.setdefault('doctest_mode',Struct()) + save_dstore = dstore.setdefault + + # save a few values we'll need to recover later + mode = save_dstore('mode',False) + save_dstore('rc_pprint',rc.pprint) + save_dstore('xmode',shell.InteractiveTB.mode) + save_dstore('rc_separate_in',rc.separate_in) + save_dstore('rc_separate_out',rc.separate_out) + save_dstore('rc_separate_out2',rc.separate_out2) + save_dstore('rc_prompts_pad_left',rc.prompts_pad_left) + + if mode == False: + # turn on + ipaste.activate_prefilter() + + oc.prompt1.p_template = '>>> ' + oc.prompt2.p_template = '... ' + oc.prompt_out.p_template = '' + + oc.prompt1.sep = '' + oc.prompt_out.output_sep = '' + oc.prompt_out.output_sep2 = '\n' + + oc.prompt1.pad_left = oc.prompt2.pad_left = \ + oc.prompt_out.pad_left = False + + shell.magic_xmode('Plain') + + rc.pprint = False + + else: + # turn off + ipaste.deactivate_prefilter() + + oc.prompt1.p_template = rc.prompt_in1 + oc.prompt2.p_template = rc.prompt_in2 + oc.prompt_out.p_template = rc.prompt_out + + oc.prompt1.sep = dstore.rc_separate_in + oc.prompt_out.output_sep = dstore.rc_separate_out + oc.prompt_out.output_sep2 = dstore.rc_separate_out2 + + oc.prompt1.pad_left = oc.prompt2.pad_left = \ + oc.prompt_out.pad_left = dstore.rc_prompts_pad_left + shell.magic_xmode(dstore.xmode) + + rc.pprint = dstore.rc_pprint + + # Store new mode and inform + dstore.mode = bool(1-int(mode)) + print 'Doctest mode is:', + print ['OFF','ON'][dstore.mode] + # end Magic diff --git a/IPython/Prompts.py b/IPython/Prompts.py index a70ad5b..37e9c58 100644 --- a/IPython/Prompts.py +++ b/IPython/Prompts.py @@ -2,7 +2,7 @@ """ Classes for handling input/output prompts. -$Id: Prompts.py 2397 2007-05-26 10:06:26Z vivainio $""" +$Id: Prompts.py 2601 2007-08-10 07:01:29Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez @@ -215,8 +215,19 @@ def str_safe(arg): out = '' % msg return out -class BasePrompt: +class BasePrompt(object): """Interactive prompt similar to Mathematica's.""" + + def _get_p_template(self): + return self._p_template + + def _set_p_template(self,val): + self._p_template = val + self.set_p_str() + + p_template = property(_get_p_template,_set_p_template, + doc='Template for prompt string creation') + def __init__(self,cache,sep,prompt,pad_left=False): # Hack: we access information about the primary prompt through the @@ -232,7 +243,9 @@ class BasePrompt: # Flag to left-pad prompt strings to match the length of the primary # prompt self.pad_left = pad_left - # Set template to create each actual prompt (where numbers change) + + # Set template to create each actual prompt (where numbers change). + # Use a property self.p_template = prompt self.set_p_str() diff --git a/IPython/ipapi.py b/IPython/ipapi.py index e93f7c2..85ac9d2 100644 --- a/IPython/ipapi.py +++ b/IPython/ipapi.py @@ -251,7 +251,8 @@ class IPApi: Inputs: - - vars: string with variable names separated by whitespace + - vars: string with variable names separated by whitespace, or a + dict with name/value pairs. - interactive: if True (default), the var will be listed with %whos et. al. @@ -285,33 +286,53 @@ class IPApi: # if this routine crashes on the next line after: ip.to_user_ns('x y') ... + + # To expose *ALL* the local variables from the function, use: + ip.to_user_ns(locals()) + + ... # return - If you need to rename variables, just use ip.user_ns with dict - and update: - - # exposes variables 'foo' as 'x' and 'bar' as 'y' in IPython - # user namespace - ip.user_ns.update(dict(x=foo,y=bar)) + + If you need to rename variables, the dict input makes it easy. For + example, this call exposes variables 'foo' as 'x' and 'bar' as 'y' + in IPython user namespace: + + ip.to_user_ns(dict(x=foo,y=bar)) """ # print 'vars given:',vars # dbg - # Get the caller's frame to evaluate the given names in - cf = sys._getframe(1) - user_ns = self.user_ns + # We need a dict of name/value pairs to do namespace updates. + if isinstance(vars,dict): + # If a dict was given, no need to change anything. + vdict = vars + elif isinstance(vars,basestring): + # If a string with names was given, get the caller's frame to + # evaluate the given names in + cf = sys._getframe(1) + vdict = {} + for name in vars.split(): + try: + vdict[name] = eval(name,cf.f_globals,cf.f_locals) + except: + print ('could not get var. %s from %s' % + (name,cf.f_code.co_name)) + else: + raise ValueError('vars must be a string or a dict') + + # Propagate variables to user namespace + self.user_ns.update(vdict) + + # And configure interactive visibility config_ns = self.IP.user_config_ns - for name in vars.split(): - try: - val = eval(name,cf.f_globals,cf.f_locals) - user_ns[name] = val - if not interactive: - config_ns[name] = val - else: - config_ns.pop(name,None) - except: - print ('could not get var. %s from %s' % - (name,cf.f_code.co_name)) + if interactive: + for name,val in vdict.iteritems(): + config_ns.pop(name,None) + else: + for name,val in vdict.iteritems(): + config_ns[name] = val + def expand_alias(self,line): """ Expand an alias in the command line diff --git a/doc/ChangeLog b/doc/ChangeLog index 7550120..d6ac415 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,14 @@ +2007-8-9 Fernando Perez + + * IPython/ipapi.py (to_user_ns): update to accept a dict as well as + a string with names. + +2007-08-09 Fernando Perez + + * IPython/Magic.py (magic_doctest_mode): added new %doctest_mode + magic to toggle on/off the doctest pasting support without having + to leave a session to switch to a separate profile. + 2007-08-08 Fernando Perez * IPython/Extensions/ipy_profile_doctest.py (main): fix prompt to