##// END OF EJS Templates
Backport PR #10207: Fix deactivation of embedded instance....
Thomas Kluyver -
Show More
@@ -12,6 +12,7 b' import sys'
12 import warnings
12 import warnings
13
13
14 from IPython.core import ultratb, compilerop
14 from IPython.core import ultratb, compilerop
15 from IPython.core import magic_arguments
15 from IPython.core.magic import Magics, magics_class, line_magic
16 from IPython.core.magic import Magics, magics_class, line_magic
16 from IPython.core.interactiveshell import DummyMod, InteractiveShell
17 from IPython.core.interactiveshell import DummyMod, InteractiveShell
17 from IPython.terminal.interactiveshell import TerminalInteractiveShell
18 from IPython.terminal.interactiveshell import TerminalInteractiveShell
@@ -27,22 +28,68 b' class KillEmbeded(Exception):pass'
27 class EmbeddedMagics(Magics):
28 class EmbeddedMagics(Magics):
28
29
29 @line_magic
30 @line_magic
31 @magic_arguments.magic_arguments()
32 @magic_arguments.argument('-i', '--instance', action='store_true',
33 help='Kill instance instead of call location')
34 @magic_arguments.argument('-x', '--exit', action='store_true',
35 help='Also exit the current session')
36 @magic_arguments.argument('-y', '--yes', action='store_true',
37 help='Do not ask confirmation')
30 def kill_embedded(self, parameter_s=''):
38 def kill_embedded(self, parameter_s=''):
31 """%kill_embedded : deactivate for good the current embedded IPython.
39 """%kill_embedded : deactivate for good the current embedded IPython
32
40
33 This function (after asking for confirmation) sets an internal flag so
41 This function (after asking for confirmation) sets an internal flag so
34 that an embedded IPython will never activate again. This is useful to
42 that an embedded IPython will never activate again for the given call
35 permanently disable a shell that is being called inside a loop: once
43 location. This is useful to permanently disable a shell that is being
36 you've figured out what you needed from it, you may then kill it and
44 called inside a loop: once you've figured out what you needed from it,
37 the program will then continue to run without the interactive shell
45 you may then kill it and the program will then continue to run without
38 interfering again.
46 the interactive shell interfering again.
47
48
49 Kill Instance Option
50 --------------------
51
52 If for some reasons you need to kill the location where the instance is
53 created and not called, for example if you create a single instance in
54 one place and debug in many locations, you can use the ``--instance``
55 option to kill this specific instance. Like for the ``call location``
56 killing an "instance" should work even if it is recreated within a
57 loop.
58
59 .. note::
60
61 This was the default behavior before IPython 5.2
62
39 """
63 """
40
64
41 kill = ask_yes_no("Are you sure you want to kill this embedded instance? [y/N] ",'n')
65 args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s)
42 if kill:
66 print(args)
43 self.shell.embedded_active = False
67 if args.instance:
44 print ("This embedded IPython will not reactivate anymore "
68 # let no ask
45 "once you exit.")
69 if not args.yes:
70 kill = ask_yes_no(
71 "Are you sure you want to kill this embedded instance? [y/N] ", 'n')
72 else:
73 kill = True
74 if kill:
75 self.shell._disable_init_location()
76 print("This embedded IPython instance will not reactivate anymore "
77 "once you exit.")
78 else:
79 if not args.yes:
80 kill = ask_yes_no(
81 "Are you sure you want to kill this embedded call_location? [y/N] ", 'n')
82 else:
83 kill = True
84 if kill:
85 self.shell.embedded_active = False
86 print("This embedded IPython call location will not reactivate anymore "
87 "once you exit.")
88
89 if args.exit:
90 # Ask-exit does not really ask, it just set internals flags to exit
91 # on next loop.
92 self.shell.ask_exit()
46
93
47
94
48 @line_magic
95 @line_magic
@@ -79,29 +126,37 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
79
126
80 @property
127 @property
81 def embedded_active(self):
128 def embedded_active(self):
82 return self._call_location_id not in InteractiveShellEmbed._inactive_locations
129 return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\
130 and (self._init_location_id not in InteractiveShellEmbed._inactive_locations)
131
132 def _disable_init_location(self):
133 """Disable the current Instance creation location"""
134 InteractiveShellEmbed._inactive_locations.add(self._init_location_id)
83
135
84 @embedded_active.setter
136 @embedded_active.setter
85 def embedded_active(self, value):
137 def embedded_active(self, value):
86 if value :
138 if value:
87 if self._call_location_id in InteractiveShellEmbed._inactive_locations:
139 InteractiveShellEmbed._inactive_locations.discard(
88 InteractiveShellEmbed._inactive_locations.remove(self._call_location_id)
140 self._call_location_id)
141 InteractiveShellEmbed._inactive_locations.discard(
142 self._init_location_id)
89 else:
143 else:
90 InteractiveShellEmbed._inactive_locations.add(self._call_location_id)
144 InteractiveShellEmbed._inactive_locations.add(
145 self._call_location_id)
91
146
92 def __init__(self, **kw):
147 def __init__(self, **kw):
93
94
95 if kw.get('user_global_ns', None) is not None:
148 if kw.get('user_global_ns', None) is not None:
96 raise DeprecationWarning("Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.")
149 raise DeprecationWarning(
150 "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.")
97
151
98 self._call_location_id = kw.pop('_call_location_id', None)
152 clid = kw.pop('_init_location_id', None)
153 if not clid:
154 frame = sys._getframe(1)
155 clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
156 self._init_location_id = clid
99
157
100 super(InteractiveShellEmbed,self).__init__(**kw)
158 super(InteractiveShellEmbed,self).__init__(**kw)
101
159
102 if not self._call_location_id:
103 frame = sys._getframe(1)
104 self._call_location_id = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
105 # don't use the ipython crash handler so that user exceptions aren't
160 # don't use the ipython crash handler so that user exceptions aren't
106 # trapped
161 # trapped
107 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
162 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
@@ -109,6 +164,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
109 call_pdb=self.pdb)
164 call_pdb=self.pdb)
110
165
111 def init_sys_modules(self):
166 def init_sys_modules(self):
167 """
168 Explicitly overwrite :any:`IPython.core.interactiveshell` to do nothing.
169 """
112 pass
170 pass
113
171
114 def init_magics(self):
172 def init_magics(self):
@@ -116,7 +174,7 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
116 self.register_magics(EmbeddedMagics)
174 self.register_magics(EmbeddedMagics)
117
175
118 def __call__(self, header='', local_ns=None, module=None, dummy=None,
176 def __call__(self, header='', local_ns=None, module=None, dummy=None,
119 stack_depth=1, global_ns=None, compile_flags=None):
177 stack_depth=1, global_ns=None, compile_flags=None, **kw):
120 """Activate the interactive interpreter.
178 """Activate the interactive interpreter.
121
179
122 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
180 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
@@ -133,7 +191,16 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
133 can still have a specific call work by making it as IPShell(dummy=False).
191 can still have a specific call work by making it as IPShell(dummy=False).
134 """
192 """
135
193
194 # we are called, set the underlying interactiveshell not to exit.
195 self.keep_running = True
196
136 # If the user has turned it off, go away
197 # If the user has turned it off, go away
198 clid = kw.pop('_call_location_id', None)
199 if not clid:
200 frame = sys._getframe(1)
201 clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
202 self._call_location_id = clid
203
137 if not self.embedded_active:
204 if not self.embedded_active:
138 return
205 return
139
206
@@ -312,8 +379,10 b' def embed(**kwargs):'
312 cls = type(saved_shell_instance)
379 cls = type(saved_shell_instance)
313 cls.clear_instance()
380 cls.clear_instance()
314 frame = sys._getframe(1)
381 frame = sys._getframe(1)
315 shell = InteractiveShellEmbed.instance(_call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno), **kwargs)
382 shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % (
316 shell(header=header, stack_depth=2, compile_flags=compile_flags)
383 frame.f_code.co_filename, frame.f_lineno), **kwargs)
384 shell(header=header, stack_depth=2, compile_flags=compile_flags,
385 _call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno))
317 InteractiveShellEmbed.clear_instance()
386 InteractiveShellEmbed.clear_instance()
318 #restore previous instance
387 #restore previous instance
319 if saved_shell_instance is not None:
388 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