1010import warnings
1111
1212from IPython .core import ultratb , compilerop
13+ from IPython .core import magic_arguments
1314from IPython .core .magic import Magics , magics_class , line_magic
1415from IPython .core .interactiveshell import DummyMod , InteractiveShell
1516from IPython .terminal .interactiveshell import TerminalInteractiveShell
@@ -25,22 +26,68 @@ class KillEmbeded(Exception):pass
2526class EmbeddedMagics (Magics ):
2627
2728 @line_magic
29+ @magic_arguments .magic_arguments ()
30+ @magic_arguments .argument ('-i' , '--instance' , action = 'store_true' ,
31+ help = 'Kill instance instead of call location' )
32+ @magic_arguments .argument ('-x' , '--exit' , action = 'store_true' ,
33+ help = 'Also exit the current session' )
34+ @magic_arguments .argument ('-y' , '--yes' , action = 'store_true' ,
35+ help = 'Do not ask confirmation' )
2836 def kill_embedded (self , parameter_s = '' ):
29- """%kill_embedded : deactivate for good the current embedded IPython.
37+ """%kill_embedded : deactivate for good the current embedded IPython
3038
3139 This function (after asking for confirmation) sets an internal flag so
32- that an embedded IPython will never activate again. This is useful to
33- permanently disable a shell that is being called inside a loop: once
34- you've figured out what you needed from it, you may then kill it and
35- the program will then continue to run without the interactive shell
36- interfering again.
40+ that an embedded IPython will never activate again for the given call
41+ location. This is useful to permanently disable a shell that is being
42+ called inside a loop: once you've figured out what you needed from it,
43+ you may then kill it and the program will then continue to run without
44+ the interactive shell interfering again.
45+
46+
47+ Kill Instance Option
48+ --------------------
49+
50+ If for some reasons you need to kill the location where the instance is
51+ created and not called, for example if you create a single instance in
52+ one place and debug in many locations, you can use the ``--instance``
53+ option to kill this specific instance. Like for the ``call location``
54+ killing an "instance" should work even if it is recreated within a
55+ loop.
56+
57+ .. note::
58+
59+ This was the default behavior before IPython 5.2
60+
3761 """
3862
39- kill = ask_yes_no ("Are you sure you want to kill this embedded instance? [y/N] " ,'n' )
40- if kill :
41- self .shell .embedded_active = False
42- print ("This embedded IPython will not reactivate anymore "
43- "once you exit." )
63+ args = magic_arguments .parse_argstring (self .kill_embedded , parameter_s )
64+ print (args )
65+ if args .instance :
66+ # let no ask
67+ if not args .yes :
68+ kill = ask_yes_no (
69+ "Are you sure you want to kill this embedded instance? [y/N] " , 'n' )
70+ else :
71+ kill = True
72+ if kill :
73+ self .shell ._disable_init_location ()
74+ print ("This embedded IPython instance will not reactivate anymore "
75+ "once you exit." )
76+ else :
77+ if not args .yes :
78+ kill = ask_yes_no (
79+ "Are you sure you want to kill this embedded call_location? [y/N] " , 'n' )
80+ else :
81+ kill = True
82+ if kill :
83+ self .shell .embedded_active = False
84+ print ("This embedded IPython call location will not reactivate anymore "
85+ "once you exit." )
86+
87+ if args .exit :
88+ # Ask-exit does not really ask, it just set internals flags to exit
89+ # on next loop.
90+ self .shell .ask_exit ()
4491
4592
4693 @line_magic
@@ -77,44 +124,55 @@ class InteractiveShellEmbed(TerminalInteractiveShell):
77124
78125 @property
79126 def embedded_active (self ):
80- return self ._call_location_id not in InteractiveShellEmbed ._inactive_locations
127+ return (self ._call_location_id not in InteractiveShellEmbed ._inactive_locations )\
128+ and (self ._init_location_id not in InteractiveShellEmbed ._inactive_locations )
129+
130+ def _disable_init_location (self ):
131+ """Disable the current Instance creation location"""
132+ InteractiveShellEmbed ._inactive_locations .add (self ._init_location_id )
81133
82134 @embedded_active .setter
83135 def embedded_active (self , value ):
84- if value :
85- if self ._call_location_id in InteractiveShellEmbed ._inactive_locations :
86- InteractiveShellEmbed ._inactive_locations .remove (self ._call_location_id )
136+ if value :
137+ InteractiveShellEmbed ._inactive_locations .discard (
138+ self ._call_location_id )
139+ InteractiveShellEmbed ._inactive_locations .discard (
140+ self ._init_location_id )
87141 else :
88- InteractiveShellEmbed ._inactive_locations .add (self ._call_location_id )
142+ InteractiveShellEmbed ._inactive_locations .add (
143+ self ._call_location_id )
89144
90145 def __init__ (self , ** kw ):
91-
92-
93146 if kw .get ('user_global_ns' , None ) is not None :
94- raise DeprecationWarning ("Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0." )
147+ raise DeprecationWarning (
148+ "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0." )
95149
96- self ._call_location_id = kw .pop ('_call_location_id' , None )
150+ clid = kw .pop ('_init_location_id' , None )
151+ if not clid :
152+ frame = sys ._getframe (1 )
153+ clid = '%s:%s' % (frame .f_code .co_filename , frame .f_lineno )
154+ self ._init_location_id = clid
97155
98156 super (InteractiveShellEmbed ,self ).__init__ (** kw )
99157
100- if not self ._call_location_id :
101- frame = sys ._getframe (1 )
102- self ._call_location_id = '%s:%s' % (frame .f_code .co_filename , frame .f_lineno )
103158 # don't use the ipython crash handler so that user exceptions aren't
104159 # trapped
105160 sys .excepthook = ultratb .FormattedTB (color_scheme = self .colors ,
106161 mode = self .xmode ,
107162 call_pdb = self .pdb )
108163
109164 def init_sys_modules (self ):
165+ """
166+ Explicitly overwrite :any:`IPython.core.interactiveshell` to do nothing.
167+ """
110168 pass
111169
112170 def init_magics (self ):
113171 super (InteractiveShellEmbed , self ).init_magics ()
114172 self .register_magics (EmbeddedMagics )
115173
116174 def __call__ (self , header = '' , local_ns = None , module = None , dummy = None ,
117- stack_depth = 1 , global_ns = None , compile_flags = None ):
175+ stack_depth = 1 , global_ns = None , compile_flags = None , ** kw ):
118176 """Activate the interactive interpreter.
119177
120178 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
@@ -131,7 +189,16 @@ def __call__(self, header='', local_ns=None, module=None, dummy=None,
131189 can still have a specific call work by making it as IPShell(dummy=False).
132190 """
133191
192+ # we are called, set the underlying interactiveshell not to exit.
193+ self .keep_running = True
194+
134195 # If the user has turned it off, go away
196+ clid = kw .pop ('_call_location_id' , None )
197+ if not clid :
198+ frame = sys ._getframe (1 )
199+ clid = '%s:%s' % (frame .f_code .co_filename , frame .f_lineno )
200+ self ._call_location_id = clid
201+
135202 if not self .embedded_active :
136203 return
137204
@@ -310,8 +377,10 @@ def embed(**kwargs):
310377 cls = type (saved_shell_instance )
311378 cls .clear_instance ()
312379 frame = sys ._getframe (1 )
313- shell = InteractiveShellEmbed .instance (_call_location_id = '%s:%s' % (frame .f_code .co_filename , frame .f_lineno ), ** kwargs )
314- shell (header = header , stack_depth = 2 , compile_flags = compile_flags )
380+ shell = InteractiveShellEmbed .instance (_init_location_id = '%s:%s' % (
381+ frame .f_code .co_filename , frame .f_lineno ), ** kwargs )
382+ shell (header = header , stack_depth = 2 , compile_flags = compile_flags ,
383+ _call_location_id = '%s:%s' % (frame .f_code .co_filename , frame .f_lineno ))
315384 InteractiveShellEmbed .clear_instance ()
316385 #restore previous instance
317386 if saved_shell_instance is not None :
0 commit comments