##// END OF EJS Templates
Fix deactivation of embedded instance....
Matthias Bussonnier -
Show More
@@ -10,6 +10,7 b' import sys'
10 import warnings
10 import warnings
11
11
12 from IPython.core import ultratb, compilerop
12 from IPython.core import ultratb, compilerop
13 from IPython.core import magic_arguments
13 from IPython.core.magic import Magics, magics_class, line_magic
14 from IPython.core.magic import Magics, magics_class, line_magic
14 from IPython.core.interactiveshell import DummyMod, InteractiveShell
15 from IPython.core.interactiveshell import DummyMod, InteractiveShell
15 from IPython.terminal.interactiveshell import TerminalInteractiveShell
16 from IPython.terminal.interactiveshell import TerminalInteractiveShell
@@ -25,22 +26,68 b' class KillEmbeded(Exception):pass'
25 class EmbeddedMagics(Magics):
26 class EmbeddedMagics(Magics):
26
27
27 @line_magic
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 def kill_embedded(self, parameter_s=''):
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 This function (after asking for confirmation) sets an internal flag so
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
40 that an embedded IPython will never activate again for the given call
33 permanently disable a shell that is being called inside a loop: once
41 location. This is useful to permanently disable a shell that is being
34 you've figured out what you needed from it, you may then kill it and
42 called inside a loop: once you've figured out what you needed from it,
35 the program will then continue to run without the interactive shell
43 you may then kill it and the program will then continue to run without
36 interfering again.
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')
63 args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s)
40 if kill:
64 print(args)
41 self.shell.embedded_active = False
65 if args.instance:
42 print ("This embedded IPython will not reactivate anymore "
66 # let no ask
43 "once you exit.")
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 @line_magic
93 @line_magic
@@ -77,29 +124,37 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
77
124
78 @property
125 @property
79 def embedded_active(self):
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 @embedded_active.setter
134 @embedded_active.setter
83 def embedded_active(self, value):
135 def embedded_active(self, value):
84 if value :
136 if value:
85 if self._call_location_id in InteractiveShellEmbed._inactive_locations:
137 InteractiveShellEmbed._inactive_locations.discard(
86 InteractiveShellEmbed._inactive_locations.remove(self._call_location_id)
138 self._call_location_id)
139 InteractiveShellEmbed._inactive_locations.discard(
140 self._init_location_id)
87 else:
141 else:
88 InteractiveShellEmbed._inactive_locations.add(self._call_location_id)
142 InteractiveShellEmbed._inactive_locations.add(
143 self._call_location_id)
89
144
90 def __init__(self, **kw):
145 def __init__(self, **kw):
91
92
93 if kw.get('user_global_ns', None) is not None:
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 super(InteractiveShellEmbed,self).__init__(**kw)
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 # don't use the ipython crash handler so that user exceptions aren't
158 # don't use the ipython crash handler so that user exceptions aren't
104 # trapped
159 # trapped
105 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
160 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
@@ -107,6 +162,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
107 call_pdb=self.pdb)
162 call_pdb=self.pdb)
108
163
109 def init_sys_modules(self):
164 def init_sys_modules(self):
165 """
166 Explicitly overwrite :any:`IPython.core.interactiveshell` to do nothing.
167 """
110 pass
168 pass
111
169
112 def init_magics(self):
170 def init_magics(self):
@@ -114,7 +172,7 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
114 self.register_magics(EmbeddedMagics)
172 self.register_magics(EmbeddedMagics)
115
173
116 def __call__(self, header='', local_ns=None, module=None, dummy=None,
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 """Activate the interactive interpreter.
176 """Activate the interactive interpreter.
119
177
120 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
178 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
@@ -131,7 +189,16 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
131 can still have a specific call work by making it as IPShell(dummy=False).
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 # If the user has turned it off, go away
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 if not self.embedded_active:
202 if not self.embedded_active:
136 return
203 return
137
204
@@ -310,8 +377,10 b' def embed(**kwargs):'
310 cls = type(saved_shell_instance)
377 cls = type(saved_shell_instance)
311 cls.clear_instance()
378 cls.clear_instance()
312 frame = sys._getframe(1)
379 frame = sys._getframe(1)
313 shell = InteractiveShellEmbed.instance(_call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno), **kwargs)
380 shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % (
314 shell(header=header, stack_depth=2, compile_flags=compile_flags)
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 InteractiveShellEmbed.clear_instance()
384 InteractiveShellEmbed.clear_instance()
316 #restore previous instance
385 #restore previous instance
317 if saved_shell_instance is not None:
386 if saved_shell_instance is not None:
@@ -31,6 +31,23 b' Remarkable changes and fixes:'
31 ``limit_to_all`` option of the completer. :ghpull:`10198`
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 IPython 5.1
52 IPython 5.1
36 ===========
53 ===========
General Comments 0
You need to be logged in to leave comments. Login now