##// END OF EJS Templates
Backport PR #10207: Fix deactivation of embedded instance....
Thomas Kluyver -
Show More
@@ -12,6 +12,7 b' import sys'
12 12 import warnings
13 13
14 14 from IPython.core import ultratb, compilerop
15 from IPython.core import magic_arguments
15 16 from IPython.core.magic import Magics, magics_class, line_magic
16 17 from IPython.core.interactiveshell import DummyMod, InteractiveShell
17 18 from IPython.terminal.interactiveshell import TerminalInteractiveShell
@@ -27,22 +28,68 b' class KillEmbeded(Exception):pass'
27 28 class EmbeddedMagics(Magics):
28 29
29 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 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 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
35 permanently disable a shell that is being called inside a loop: once
36 you've figured out what you needed from it, you may then kill it and
37 the program will then continue to run without the interactive shell
38 interfering again.
42 that an embedded IPython will never activate again for the given call
43 location. This is useful to permanently disable a shell that is being
44 called inside a loop: once you've figured out what you needed from it,
45 you may then kill it and the program will then continue to run without
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')
42 if kill:
43 self.shell.embedded_active = False
44 print ("This embedded IPython will not reactivate anymore "
45 "once you exit.")
65 args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s)
66 print(args)
67 if args.instance:
68 # let no ask
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 95 @line_magic
@@ -79,29 +126,37 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
79 126
80 127 @property
81 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 136 @embedded_active.setter
85 137 def embedded_active(self, value):
86 if value :
87 if self._call_location_id in InteractiveShellEmbed._inactive_locations:
88 InteractiveShellEmbed._inactive_locations.remove(self._call_location_id)
138 if value:
139 InteractiveShellEmbed._inactive_locations.discard(
140 self._call_location_id)
141 InteractiveShellEmbed._inactive_locations.discard(
142 self._init_location_id)
89 143 else:
90 InteractiveShellEmbed._inactive_locations.add(self._call_location_id)
144 InteractiveShellEmbed._inactive_locations.add(
145 self._call_location_id)
91 146
92 147 def __init__(self, **kw):
93
94
95 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 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 160 # don't use the ipython crash handler so that user exceptions aren't
106 161 # trapped
107 162 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
@@ -109,6 +164,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
109 164 call_pdb=self.pdb)
110 165
111 166 def init_sys_modules(self):
167 """
168 Explicitly overwrite :any:`IPython.core.interactiveshell` to do nothing.
169 """
112 170 pass
113 171
114 172 def init_magics(self):
@@ -116,7 +174,7 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
116 174 self.register_magics(EmbeddedMagics)
117 175
118 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 178 """Activate the interactive interpreter.
121 179
122 180 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
@@ -133,7 +191,16 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
133 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 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 204 if not self.embedded_active:
138 205 return
139 206
@@ -312,8 +379,10 b' def embed(**kwargs):'
312 379 cls = type(saved_shell_instance)
313 380 cls.clear_instance()
314 381 frame = sys._getframe(1)
315 shell = InteractiveShellEmbed.instance(_call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno), **kwargs)
316 shell(header=header, stack_depth=2, compile_flags=compile_flags)
382 shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % (
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 386 InteractiveShellEmbed.clear_instance()
318 387 #restore previous instance
319 388 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