##// END OF EJS Templates
Reexpose a KillEmbeded alias for backward compat
Matthias Bussonnier -
Show More
@@ -1,392 +1,396 b''
1 1 # encoding: utf-8
2 2 """
3 3 An embedded IPython shell.
4 4 """
5 5 # Copyright (c) IPython Development Team.
6 6 # Distributed under the terms of the Modified BSD License.
7 7
8 8
9 9 import sys
10 10 import warnings
11 11
12 12 from IPython.core import ultratb, compilerop
13 13 from IPython.core import magic_arguments
14 14 from IPython.core.magic import Magics, magics_class, line_magic
15 15 from IPython.core.interactiveshell import DummyMod, InteractiveShell
16 16 from IPython.terminal.interactiveshell import TerminalInteractiveShell
17 17 from IPython.terminal.ipapp import load_default_config
18 18
19 19 from traitlets import Bool, CBool, Unicode
20 20 from IPython.utils.io import ask_yes_no
21 21
22 22 class KillEmbedded(Exception):pass
23 23
24 # kept for backward compatibility as IPython 6 was released with
25 # the typo. See https://github.com/ipython/ipython/pull/10706
26 KillEmbeded = KillEmbedded
27
24 28 # This is an additional magic that is exposed in embedded shells.
25 29 @magics_class
26 30 class EmbeddedMagics(Magics):
27 31
28 32 @line_magic
29 33 @magic_arguments.magic_arguments()
30 34 @magic_arguments.argument('-i', '--instance', action='store_true',
31 35 help='Kill instance instead of call location')
32 36 @magic_arguments.argument('-x', '--exit', action='store_true',
33 37 help='Also exit the current session')
34 38 @magic_arguments.argument('-y', '--yes', action='store_true',
35 39 help='Do not ask confirmation')
36 40 def kill_embedded(self, parameter_s=''):
37 41 """%kill_embedded : deactivate for good the current embedded IPython
38 42
39 43 This function (after asking for confirmation) sets an internal flag so
40 44 that an embedded IPython will never activate again for the given call
41 45 location. This is useful to permanently disable a shell that is being
42 46 called inside a loop: once you've figured out what you needed from it,
43 47 you may then kill it and the program will then continue to run without
44 48 the interactive shell interfering again.
45 49
46 50
47 51 Kill Instance Option:
48 52
49 53 If for some reasons you need to kill the location where the instance
50 54 is created and not called, for example if you create a single
51 55 instance in one place and debug in many locations, you can use the
52 56 ``--instance`` option to kill this specific instance. Like for the
53 57 ``call location`` killing an "instance" should work even if it is
54 58 recreated within a loop.
55 59
56 60 .. note::
57 61
58 62 This was the default behavior before IPython 5.2
59 63
60 64 """
61 65
62 66 args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s)
63 67 print(args)
64 68 if args.instance:
65 69 # let no ask
66 70 if not args.yes:
67 71 kill = ask_yes_no(
68 72 "Are you sure you want to kill this embedded instance? [y/N] ", 'n')
69 73 else:
70 74 kill = True
71 75 if kill:
72 76 self.shell._disable_init_location()
73 77 print("This embedded IPython instance will not reactivate anymore "
74 78 "once you exit.")
75 79 else:
76 80 if not args.yes:
77 81 kill = ask_yes_no(
78 82 "Are you sure you want to kill this embedded call_location? [y/N] ", 'n')
79 83 else:
80 84 kill = True
81 85 if kill:
82 86 self.shell.embedded_active = False
83 87 print("This embedded IPython call location will not reactivate anymore "
84 88 "once you exit.")
85 89
86 90 if args.exit:
87 91 # Ask-exit does not really ask, it just set internals flags to exit
88 92 # on next loop.
89 93 self.shell.ask_exit()
90 94
91 95
92 96 @line_magic
93 97 def exit_raise(self, parameter_s=''):
94 98 """%exit_raise Make the current embedded kernel exit and raise and exception.
95 99
96 100 This function sets an internal flag so that an embedded IPython will
97 101 raise a `IPython.terminal.embed.KillEmbedded` Exception on exit, and then exit the current I. This is
98 102 useful to permanently exit a loop that create IPython embed instance.
99 103 """
100 104
101 105 self.shell.should_raise = True
102 106 self.shell.ask_exit()
103 107
104 108
105 109
106 110 class InteractiveShellEmbed(TerminalInteractiveShell):
107 111
108 112 dummy_mode = Bool(False)
109 113 exit_msg = Unicode('')
110 114 embedded = CBool(True)
111 115 should_raise = CBool(False)
112 116 # Like the base class display_banner is not configurable, but here it
113 117 # is True by default.
114 118 display_banner = CBool(True)
115 119 exit_msg = Unicode()
116 120
117 121 # When embedding, by default we don't change the terminal title
118 122 term_title = Bool(False,
119 123 help="Automatically set the terminal title"
120 124 ).tag(config=True)
121 125
122 126 _inactive_locations = set()
123 127
124 128 @property
125 129 def embedded_active(self):
126 130 return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\
127 131 and (self._init_location_id not in InteractiveShellEmbed._inactive_locations)
128 132
129 133 def _disable_init_location(self):
130 134 """Disable the current Instance creation location"""
131 135 InteractiveShellEmbed._inactive_locations.add(self._init_location_id)
132 136
133 137 @embedded_active.setter
134 138 def embedded_active(self, value):
135 139 if value:
136 140 InteractiveShellEmbed._inactive_locations.discard(
137 141 self._call_location_id)
138 142 InteractiveShellEmbed._inactive_locations.discard(
139 143 self._init_location_id)
140 144 else:
141 145 InteractiveShellEmbed._inactive_locations.add(
142 146 self._call_location_id)
143 147
144 148 def __init__(self, **kw):
145 149 if kw.get('user_global_ns', None) is not None:
146 150 raise DeprecationWarning(
147 151 "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.")
148 152
149 153 clid = kw.pop('_init_location_id', None)
150 154 if not clid:
151 155 frame = sys._getframe(1)
152 156 clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
153 157 self._init_location_id = clid
154 158
155 159 super(InteractiveShellEmbed,self).__init__(**kw)
156 160
157 161 # don't use the ipython crash handler so that user exceptions aren't
158 162 # trapped
159 163 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
160 164 mode=self.xmode,
161 165 call_pdb=self.pdb)
162 166
163 167 def init_sys_modules(self):
164 168 """
165 169 Explicitly overwrite :mod:`IPython.core.interactiveshell` to do nothing.
166 170 """
167 171 pass
168 172
169 173 def init_magics(self):
170 174 super(InteractiveShellEmbed, self).init_magics()
171 175 self.register_magics(EmbeddedMagics)
172 176
173 177 def __call__(self, header='', local_ns=None, module=None, dummy=None,
174 178 stack_depth=1, global_ns=None, compile_flags=None, **kw):
175 179 """Activate the interactive interpreter.
176 180
177 181 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
178 182 the interpreter shell with the given local and global namespaces, and
179 183 optionally print a header string at startup.
180 184
181 185 The shell can be globally activated/deactivated using the
182 186 dummy_mode attribute. This allows you to turn off a shell used
183 187 for debugging globally.
184 188
185 189 However, *each* time you call the shell you can override the current
186 190 state of dummy_mode with the optional keyword parameter 'dummy'. For
187 191 example, if you set dummy mode on with IPShell.dummy_mode = True, you
188 192 can still have a specific call work by making it as IPShell(dummy=False).
189 193 """
190 194
191 195 # we are called, set the underlying interactiveshell not to exit.
192 196 self.keep_running = True
193 197
194 198 # If the user has turned it off, go away
195 199 clid = kw.pop('_call_location_id', None)
196 200 if not clid:
197 201 frame = sys._getframe(1)
198 202 clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
199 203 self._call_location_id = clid
200 204
201 205 if not self.embedded_active:
202 206 return
203 207
204 208 # Normal exits from interactive mode set this flag, so the shell can't
205 209 # re-enter (it checks this variable at the start of interactive mode).
206 210 self.exit_now = False
207 211
208 212 # Allow the dummy parameter to override the global __dummy_mode
209 213 if dummy or (dummy != 0 and self.dummy_mode):
210 214 return
211 215
212 216 # self.banner is auto computed
213 217 if header:
214 218 self.old_banner2 = self.banner2
215 219 self.banner2 = self.banner2 + '\n' + header + '\n'
216 220 else:
217 221 self.old_banner2 = ''
218 222
219 223 if self.display_banner:
220 224 self.show_banner()
221 225
222 226 # Call the embedding code with a stack depth of 1 so it can skip over
223 227 # our call and get the original caller's namespaces.
224 228 self.mainloop(local_ns, module, stack_depth=stack_depth,
225 229 global_ns=global_ns, compile_flags=compile_flags)
226 230
227 231 self.banner2 = self.old_banner2
228 232
229 233 if self.exit_msg is not None:
230 234 print(self.exit_msg)
231 235
232 236 if self.should_raise:
233 237 raise KillEmbedded('Embedded IPython raising error, as user requested.')
234 238
235 239
236 240 def mainloop(self, local_ns=None, module=None, stack_depth=0,
237 241 display_banner=None, global_ns=None, compile_flags=None):
238 242 """Embeds IPython into a running python program.
239 243
240 244 Parameters
241 245 ----------
242 246
243 247 local_ns, module
244 248 Working local namespace (a dict) and module (a module or similar
245 249 object). If given as None, they are automatically taken from the scope
246 250 where the shell was called, so that program variables become visible.
247 251
248 252 stack_depth : int
249 253 How many levels in the stack to go to looking for namespaces (when
250 254 local_ns or module is None). This allows an intermediate caller to
251 255 make sure that this function gets the namespace from the intended
252 256 level in the stack. By default (0) it will get its locals and globals
253 257 from the immediate caller.
254 258
255 259 compile_flags
256 260 A bit field identifying the __future__ features
257 261 that are enabled, as passed to the builtin :func:`compile` function.
258 262 If given as None, they are automatically taken from the scope where
259 263 the shell was called.
260 264
261 265 """
262 266
263 267 if (global_ns is not None) and (module is None):
264 268 raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.")
265 269
266 270 if (display_banner is not None):
267 271 warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning)
268 272
269 273 # Get locals and globals from caller
270 274 if ((local_ns is None or module is None or compile_flags is None)
271 275 and self.default_user_namespaces):
272 276 call_frame = sys._getframe(stack_depth).f_back
273 277
274 278 if local_ns is None:
275 279 local_ns = call_frame.f_locals
276 280 if module is None:
277 281 global_ns = call_frame.f_globals
278 282 try:
279 283 module = sys.modules[global_ns['__name__']]
280 284 except KeyError:
281 285 warnings.warn("Failed to get module %s" % \
282 286 global_ns.get('__name__', 'unknown module')
283 287 )
284 288 module = DummyMod()
285 289 module.__dict__ = global_ns
286 290 if compile_flags is None:
287 291 compile_flags = (call_frame.f_code.co_flags &
288 292 compilerop.PyCF_MASK)
289 293
290 294 # Save original namespace and module so we can restore them after
291 295 # embedding; otherwise the shell doesn't shut down correctly.
292 296 orig_user_module = self.user_module
293 297 orig_user_ns = self.user_ns
294 298 orig_compile_flags = self.compile.flags
295 299
296 300 # Update namespaces and fire up interpreter
297 301
298 302 # The global one is easy, we can just throw it in
299 303 if module is not None:
300 304 self.user_module = module
301 305
302 306 # But the user/local one is tricky: ipython needs it to store internal
303 307 # data, but we also need the locals. We'll throw our hidden variables
304 308 # like _ih and get_ipython() into the local namespace, but delete them
305 309 # later.
306 310 if local_ns is not None:
307 311 reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()}
308 312 self.user_ns = reentrant_local_ns
309 313 self.init_user_ns()
310 314
311 315 # Compiler flags
312 316 if compile_flags is not None:
313 317 self.compile.flags = compile_flags
314 318
315 319 # make sure the tab-completer has the correct frame information, so it
316 320 # actually completes using the frame's locals/globals
317 321 self.set_completer_frame()
318 322
319 323 with self.builtin_trap, self.display_trap:
320 324 self.interact()
321 325
322 326 # now, purge out the local namespace of IPython's hidden variables.
323 327 if local_ns is not None:
324 328 local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()})
325 329
326 330
327 331 # Restore original namespace so shell can shut down when we exit.
328 332 self.user_module = orig_user_module
329 333 self.user_ns = orig_user_ns
330 334 self.compile.flags = orig_compile_flags
331 335
332 336
333 337 def embed(**kwargs):
334 338 """Call this to embed IPython at the current point in your program.
335 339
336 340 The first invocation of this will create an :class:`InteractiveShellEmbed`
337 341 instance and then call it. Consecutive calls just call the already
338 342 created instance.
339 343
340 344 If you don't want the kernel to initialize the namespace
341 345 from the scope of the surrounding function,
342 346 and/or you want to load full IPython configuration,
343 347 you probably want `IPython.start_ipython()` instead.
344 348
345 349 Here is a simple example::
346 350
347 351 from IPython import embed
348 352 a = 10
349 353 b = 20
350 354 embed(header='First time')
351 355 c = 30
352 356 d = 40
353 357 embed()
354 358
355 359 Full customization can be done by passing a :class:`Config` in as the
356 360 config argument.
357 361 """
358 362 config = kwargs.get('config')
359 363 header = kwargs.pop('header', u'')
360 364 compile_flags = kwargs.pop('compile_flags', None)
361 365 if config is None:
362 366 config = load_default_config()
363 367 config.InteractiveShellEmbed = config.TerminalInteractiveShell
364 368 kwargs['config'] = config
365 369 #save ps1/ps2 if defined
366 370 ps1 = None
367 371 ps2 = None
368 372 try:
369 373 ps1 = sys.ps1
370 374 ps2 = sys.ps2
371 375 except AttributeError:
372 376 pass
373 377 #save previous instance
374 378 saved_shell_instance = InteractiveShell._instance
375 379 if saved_shell_instance is not None:
376 380 cls = type(saved_shell_instance)
377 381 cls.clear_instance()
378 382 frame = sys._getframe(1)
379 383 shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % (
380 384 frame.f_code.co_filename, frame.f_lineno), **kwargs)
381 385 shell(header=header, stack_depth=2, compile_flags=compile_flags,
382 386 _call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno))
383 387 InteractiveShellEmbed.clear_instance()
384 388 #restore previous instance
385 389 if saved_shell_instance is not None:
386 390 cls = type(saved_shell_instance)
387 391 cls.clear_instance()
388 392 for subclass in cls._walk_mro():
389 393 subclass._instance = saved_shell_instance
390 394 if ps1 is not None:
391 395 sys.ps1 = ps1
392 396 sys.ps2 = ps2
General Comments 0
You need to be logged in to leave comments. Login now