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