##// END OF EJS Templates
Fix deactivation of embedded instance....
Matthias Bussonnier -
Show More
@@ -10,6 +10,7 b' import sys'
10 10 import warnings
11 11
12 12 from IPython.core import ultratb, compilerop
13 from IPython.core import magic_arguments
13 14 from IPython.core.magic import Magics, magics_class, line_magic
14 15 from IPython.core.interactiveshell import DummyMod, InteractiveShell
15 16 from IPython.terminal.interactiveshell import TerminalInteractiveShell
@@ -25,22 +26,68 b' class KillEmbeded(Exception):pass'
25 26 class EmbeddedMagics(Magics):
26 27
27 28 @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')
28 36 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
30 38
31 39 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
37 61 """
38 62
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()
44 91
45 92
46 93 @line_magic
@@ -77,29 +124,37 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
77 124
78 125 @property
79 126 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)
81 133
82 134 @embedded_active.setter
83 135 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)
87 141 else:
88 InteractiveShellEmbed._inactive_locations.add(self._call_location_id)
142 InteractiveShellEmbed._inactive_locations.add(
143 self._call_location_id)
89 144
90 145 def __init__(self, **kw):
91
92
93 146 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.")
95 149
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
97 155
98 156 super(InteractiveShellEmbed,self).__init__(**kw)
99 157
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)
103 158 # don't use the ipython crash handler so that user exceptions aren't
104 159 # trapped
105 160 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
@@ -107,6 +162,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
107 162 call_pdb=self.pdb)
108 163
109 164 def init_sys_modules(self):
165 """
166 Explicitly overwrite :any:`IPython.core.interactiveshell` to do nothing.
167 """
110 168 pass
111 169
112 170 def init_magics(self):
@@ -114,7 +172,7 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
114 172 self.register_magics(EmbeddedMagics)
115 173
116 174 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):
118 176 """Activate the interactive interpreter.
119 177
120 178 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
@@ -131,7 +189,16 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
131 189 can still have a specific call work by making it as IPShell(dummy=False).
132 190 """
133 191
192 # we are called, set the underlying interactiveshell not to exit.
193 self.keep_running = True
194
134 195 # 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
135 202 if not self.embedded_active:
136 203 return
137 204
@@ -310,8 +377,10 b' def embed(**kwargs):'
310 377 cls = type(saved_shell_instance)
311 378 cls.clear_instance()
312 379 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))
315 384 InteractiveShellEmbed.clear_instance()
316 385 #restore previous instance
317 386 if saved_shell_instance is not None:
@@ -31,6 +31,23 b' Remarkable changes and fixes:'
31 31 ``limit_to_all`` option of the completer. :ghpull:`10198`
32 32
33 33
34 Changes of behavior to :any:`InteractiveShellEmbed`.
35
36 :any:`InteractiveShellEmbed` interactive behavior have changed a bit in between
37 5.1 and 5.2. By default ``%kill_embedded`` magic will prevent further invocation
38 of the current ``call location`` instead of preventing further invocation of
39 the current instance creation location. For most use case this will not change
40 much for you, though previous behavior was confusing and less consistent with
41 previous IPython versions.
42
43 You can now deactivate instances by using ``%kill_embedded --instance`` flag,
44 (or ``-i`` in short). The ``%kill_embedded`` magic also gained a
45 ``--yes``/``-y`` option which skip confirmation step, and ``-x``/``--exit``
46 which also exit the current embedded call without asking for confirmation.
47
48 See :ghpull:`10207`.
49
50
34 51
35 52 IPython 5.1
36 53 ===========
General Comments 0
You need to be logged in to leave comments. Login now