diff --git a/IPython/Shell.py b/IPython/Shell.py index 60af047..8e9a870 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 2222 2007-04-06 17:11:27Z fperez $""" +$Id: Shell.py 2577 2007-08-02 23:50:02Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez @@ -39,8 +39,8 @@ except ImportError: # IPython imports import IPython -from IPython import ultraTB -from IPython.genutils import Term,warn,error,flag_calls +from IPython import ultraTB, ipapi +from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no from IPython.iplib import InteractiveShell from IPython.ipmaker import make_IPython from IPython.Magic import Magic @@ -79,6 +79,22 @@ class IPShell: sys.exit() #----------------------------------------------------------------------------- +def kill_embedded(self,parameter_s=''): + """%kill_embedded : deactivate for good the current embedded IPython. + + This function (after asking for confirmation) sets an internal flag so that + an embedded IPython will never activate again. This is useful to + permanently disable a shell that is being called inside a loop: once you've + figured out what you needed from it, you may then kill it and the program + will then continue to run without the interactive shell interfering again. + """ + + kill = ask_yes_no("Are you sure you want to kill this embedded instance " + "(y/n)? [y/N] ",'n') + if kill: + self.shell.embedded_active = False + print "This embedded IPython will not reactivate anymore once you exit." + class IPShellEmbed: """Allow embedding an IPython shell into a running program. @@ -153,6 +169,9 @@ class IPShellEmbed: embedded=True, user_ns=user_ns) + ip = ipapi.IPApi(self.IP) + ip.expose_magic("kill_embedded",kill_embedded) + # copy our own displayhook also self.sys_displayhook_embed = sys.displayhook # and leave the system's display hook clean @@ -196,6 +215,14 @@ class IPShellEmbed: The optional keyword parameter dummy controls whether the call actually does anything. """ + # If the user has turned it off, go away + if not self.IP.embedded_active: + return + + # Normal exits from interactive mode set this flag, so the shell can't + # re-enter (it checks this variable at the start of interactive mode). + self.IP.exit_now = False + # Allow the dummy parameter to override the global __dummy_mode if dummy or (dummy != 0 and self.__dummy_mode): return diff --git a/IPython/genutils.py b/IPython/genutils.py index e7d8b02..50842d8 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 2568 2007-07-29 21:38:44Z fperez $""" +$Id: genutils.py 2577 2007-08-02 23:50:02Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez. @@ -1055,7 +1055,7 @@ def raw_input_ext(prompt='', ps2='... '): #---------------------------------------------------------------------------- def ask_yes_no(prompt,default=None): - """Asks a question and returns an integer 1/0 (y/n) answer. + """Asks a question and returns a boolean (y/n) answer. If default is given (one of 'y','n'), it is used if the user input is empty. Otherwise the question is repeated until an answer is given. diff --git a/IPython/iplib.py b/IPython/iplib.py index 18ef9ff..6824ab3 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 2571 2007-08-01 14:48:03Z vivainio $ +$Id: iplib.py 2577 2007-08-02 23:50:02Z fperez $ """ #***************************************************************************** @@ -228,6 +228,10 @@ class InteractiveShell(object,Magic): # We need to know whether the instance is meant for embedding, since # global/local namespaces need to be handled differently in that case self.embedded = embedded + if embedded: + # Control variable so users can, from within the embedded instance, + # permanently deactivate it. + self.embedded_active = True # command compiler self.compile = codeop.CommandCompiler() @@ -1566,7 +1570,7 @@ want to merge them back into the new files.""" % locals() # 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 diff --git a/doc/ChangeLog b/doc/ChangeLog index dfa7297..ae45862 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,17 @@ +2007-08-02 Fernando Perez + + * IPython/Shell.py (IPShellEmbed.__call__): fix bug introduced in + r1357, which had killed multiple invocations of an embedded + ipython (this means that example-embed has been broken for over 1 + year!!!). Rather than possibly breaking the batch stuff for which + the code in iplib.py/interact was introduced, I worked around the + problem in the embedding class in Shell.py. We really need a + bloody test suite for this code, I'm sick of finding stuff that + used to work breaking left and right every time I use an old + feature I hadn't touched in a few months. + (kill_embedded): Add a new magic that only shows up in embedded + mode, to allow users to permanently deactivate an embedded instance. + 2007-08-01 Ville Vainio * iplib.py, ipy_profile_sh.py (runlines): Fix the bug where raw diff --git a/doc/examples/example-embed.py b/doc/examples/example-embed.py index 038994d..137fbb1 100755 --- a/doc/examples/example-embed.py +++ b/doc/examples/example-embed.py @@ -54,7 +54,9 @@ print '\nHello. This is printed from the main controller program.\n' # You can then call ipshell() anywhere you need it (with an optional # message): ipshell('***Called from top level. ' - 'Hit Ctrl-D to exit interpreter and continue program.') + 'Hit Ctrl-D to exit interpreter and continue program.\n' + 'Note that if you use %kill_embedded, you can fully deactivate\n' + 'This embedded instance so it will never turn on again') print '\nBack in caller program, moving along...\n'