##// END OF EJS Templates
Allow Embeded instances to raise on exit....
Matthias Bussonnier -
Show More
@@ -1,278 +1,317 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An embedded IPython shell.
3 An embedded IPython shell.
4 """
4 """
5 # Copyright (c) IPython Development Team.
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7
7
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from __future__ import print_function
9 from __future__ import print_function
10
10
11 import sys
11 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.magic import Magics, magics_class, line_magic
15 from IPython.core.magic import Magics, magics_class, line_magic
16 from IPython.core.interactiveshell import DummyMod
16 from IPython.core.interactiveshell import DummyMod
17 from IPython.core.interactiveshell import InteractiveShell
17 from IPython.core.interactiveshell import InteractiveShell
18 from IPython.terminal.interactiveshell import TerminalInteractiveShell
18 from IPython.terminal.interactiveshell import TerminalInteractiveShell
19 from IPython.terminal.ipapp import load_default_config
19 from IPython.terminal.ipapp import load_default_config
20
20
21 from traitlets import Bool, CBool, Unicode
21 from traitlets import Bool, CBool, Unicode
22 from IPython.utils.io import ask_yes_no
22 from IPython.utils.io import ask_yes_no
23
23
24 class KillEmbeded(Exception):pass
24
25
25 # This is an additional magic that is exposed in embedded shells.
26 # This is an additional magic that is exposed in embedded shells.
26 @magics_class
27 @magics_class
27 class EmbeddedMagics(Magics):
28 class EmbeddedMagics(Magics):
28
29
29 @line_magic
30 @line_magic
30 def kill_embedded(self, parameter_s=''):
31 def kill_embedded(self, parameter_s=''):
31 """%kill_embedded : deactivate for good the current embedded IPython.
32 """%kill_embedded : deactivate for good the current embedded IPython.
32
33
33 This function (after asking for confirmation) sets an internal flag so
34 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 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 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 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 the program will then continue to run without the interactive shell
38 interfering again.
39 interfering again.
39 """
40 """
40
41
41 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
42 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
42 "(y/n)? [y/N] ",'n')
43 "(y/n)? [y/N] ",'n')
43 if kill:
44 if kill:
44 self.shell.embedded_active = False
45 self.shell.embedded_active = False
45 print ("This embedded IPython will not reactivate anymore "
46 print ("This embedded IPython will not reactivate anymore "
46 "once you exit.")
47 "once you exit.")
47
48
49 @line_magic
50 def raise_on_exit(self, parameter_s=''):
51 """%raise_on_exit [True|False]: Make the current embeded kernel to raise an exception on exit.
52
53 You can change that again during current session by calling `%raise_on_exit` with `True`/`False` as parameter
54
55 This function (after asking for confirmation) sets an internal flag so
56 that an embedded IPython will raise a `KillEmbeded` Exception on exit. This is useful to
57 permanently exit a loop that create IPython embed instance.
58 """
59 parameter_s = parameter_s.strip().lower()
60
61 should_raise = None
62 if parameter_s in {'yes', 'raise', 'true', '1'}:
63 should_raise = True
64 elif parameter_s in {'no', 'false', '0', 'None'}:
65 should_raise = False
66 else:
67 if self.shell.should_raise :
68 print("The current embed instance will raise on exit, use `%raise_on_exit False` to disable")
69 return
70 else:
71 print("The current embed instance will not raise on exit, use `%raise_on_exit True` to enable")
72 return
73
74 if should_raise:
75 self.shell.should_raise = True
76 print ("This embedded IPython will raise while exiting.")
77 else :
78 self.shell.should_raise = False
79 print ("This embedded IPython will not raise while exiting.")
80
81
48
82
49 class InteractiveShellEmbed(TerminalInteractiveShell):
83 class InteractiveShellEmbed(TerminalInteractiveShell):
50
84
51 dummy_mode = Bool(False)
85 dummy_mode = Bool(False)
52 exit_msg = Unicode('')
86 exit_msg = Unicode('')
53 embedded = CBool(True)
87 embedded = CBool(True)
54 embedded_active = CBool(True)
88 embedded_active = CBool(True)
89 should_raise = CBool(False)
55 # Like the base class display_banner is not configurable, but here it
90 # Like the base class display_banner is not configurable, but here it
56 # is True by default.
91 # is True by default.
57 display_banner = CBool(True)
92 display_banner = CBool(True)
58 exit_msg = Unicode()
93 exit_msg = Unicode()
59
94
60
95
61 def __init__(self, **kw):
96 def __init__(self, **kw):
62
97
63
98
64 if kw.get('user_global_ns', None) is not None:
99 if kw.get('user_global_ns', None) is not None:
65 warnings.warn("user_global_ns has been replaced by user_module. The\
100 warnings.warn("user_global_ns has been replaced by user_module. The\
66 parameter will be ignored, and removed in IPython 5.0", DeprecationWarning)
101 parameter will be ignored, and removed in IPython 5.0", DeprecationWarning)
67
102
68 super(InteractiveShellEmbed,self).__init__(**kw)
103 super(InteractiveShellEmbed,self).__init__(**kw)
69
104
70 # don't use the ipython crash handler so that user exceptions aren't
105 # don't use the ipython crash handler so that user exceptions aren't
71 # trapped
106 # trapped
72 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
107 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
73 mode=self.xmode,
108 mode=self.xmode,
74 call_pdb=self.pdb)
109 call_pdb=self.pdb)
75
110
76 def init_sys_modules(self):
111 def init_sys_modules(self):
77 pass
112 pass
78
113
79 def init_magics(self):
114 def init_magics(self):
80 super(InteractiveShellEmbed, self).init_magics()
115 super(InteractiveShellEmbed, self).init_magics()
81 self.register_magics(EmbeddedMagics)
116 self.register_magics(EmbeddedMagics)
82
117
83 def __call__(self, header='', local_ns=None, module=None, dummy=None,
118 def __call__(self, header='', local_ns=None, module=None, dummy=None,
84 stack_depth=1, global_ns=None, compile_flags=None):
119 stack_depth=1, global_ns=None, compile_flags=None):
85 """Activate the interactive interpreter.
120 """Activate the interactive interpreter.
86
121
87 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
122 __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
88 the interpreter shell with the given local and global namespaces, and
123 the interpreter shell with the given local and global namespaces, and
89 optionally print a header string at startup.
124 optionally print a header string at startup.
90
125
91 The shell can be globally activated/deactivated using the
126 The shell can be globally activated/deactivated using the
92 dummy_mode attribute. This allows you to turn off a shell used
127 dummy_mode attribute. This allows you to turn off a shell used
93 for debugging globally.
128 for debugging globally.
94
129
95 However, *each* time you call the shell you can override the current
130 However, *each* time you call the shell you can override the current
96 state of dummy_mode with the optional keyword parameter 'dummy'. For
131 state of dummy_mode with the optional keyword parameter 'dummy'. For
97 example, if you set dummy mode on with IPShell.dummy_mode = True, you
132 example, if you set dummy mode on with IPShell.dummy_mode = True, you
98 can still have a specific call work by making it as IPShell(dummy=False).
133 can still have a specific call work by making it as IPShell(dummy=False).
99 """
134 """
100
135
101 # If the user has turned it off, go away
136 # If the user has turned it off, go away
102 if not self.embedded_active:
137 if not self.embedded_active:
103 return
138 return
104
139
105 # Normal exits from interactive mode set this flag, so the shell can't
140 # Normal exits from interactive mode set this flag, so the shell can't
106 # re-enter (it checks this variable at the start of interactive mode).
141 # re-enter (it checks this variable at the start of interactive mode).
107 self.exit_now = False
142 self.exit_now = False
108
143
109 # Allow the dummy parameter to override the global __dummy_mode
144 # Allow the dummy parameter to override the global __dummy_mode
110 if dummy or (dummy != 0 and self.dummy_mode):
145 if dummy or (dummy != 0 and self.dummy_mode):
111 return
146 return
112
147
113 if self.has_readline:
148 if self.has_readline:
114 self.set_readline_completer()
149 self.set_readline_completer()
115
150
116 # self.banner is auto computed
151 # self.banner is auto computed
117 if header:
152 if header:
118 self.old_banner2 = self.banner2
153 self.old_banner2 = self.banner2
119 self.banner2 = self.banner2 + '\n' + header + '\n'
154 self.banner2 = self.banner2 + '\n' + header + '\n'
120 else:
155 else:
121 self.old_banner2 = ''
156 self.old_banner2 = ''
122
157
123 # Call the embedding code with a stack depth of 1 so it can skip over
158 # Call the embedding code with a stack depth of 1 so it can skip over
124 # our call and get the original caller's namespaces.
159 # our call and get the original caller's namespaces.
125 self.mainloop(local_ns, module, stack_depth=stack_depth,
160 self.mainloop(local_ns, module, stack_depth=stack_depth,
126 global_ns=global_ns, compile_flags=compile_flags)
161 global_ns=global_ns, compile_flags=compile_flags)
127
162
128 self.banner2 = self.old_banner2
163 self.banner2 = self.old_banner2
129
164
130 if self.exit_msg is not None:
165 if self.exit_msg is not None:
131 print(self.exit_msg)
166 print(self.exit_msg)
132
167
168 if self.should_raise:
169 raise KillEmbeded('This instance has been marked as must raise on exit.')
170
171
133 def mainloop(self, local_ns=None, module=None, stack_depth=0,
172 def mainloop(self, local_ns=None, module=None, stack_depth=0,
134 display_banner=None, global_ns=None, compile_flags=None):
173 display_banner=None, global_ns=None, compile_flags=None):
135 """Embeds IPython into a running python program.
174 """Embeds IPython into a running python program.
136
175
137 Parameters
176 Parameters
138 ----------
177 ----------
139
178
140 local_ns, module
179 local_ns, module
141 Working local namespace (a dict) and module (a module or similar
180 Working local namespace (a dict) and module (a module or similar
142 object). If given as None, they are automatically taken from the scope
181 object). If given as None, they are automatically taken from the scope
143 where the shell was called, so that program variables become visible.
182 where the shell was called, so that program variables become visible.
144
183
145 stack_depth : int
184 stack_depth : int
146 How many levels in the stack to go to looking for namespaces (when
185 How many levels in the stack to go to looking for namespaces (when
147 local_ns or module is None). This allows an intermediate caller to
186 local_ns or module is None). This allows an intermediate caller to
148 make sure that this function gets the namespace from the intended
187 make sure that this function gets the namespace from the intended
149 level in the stack. By default (0) it will get its locals and globals
188 level in the stack. By default (0) it will get its locals and globals
150 from the immediate caller.
189 from the immediate caller.
151
190
152 compile_flags
191 compile_flags
153 A bit field identifying the __future__ features
192 A bit field identifying the __future__ features
154 that are enabled, as passed to the builtin :func:`compile` function.
193 that are enabled, as passed to the builtin :func:`compile` function.
155 If given as None, they are automatically taken from the scope where
194 If given as None, they are automatically taken from the scope where
156 the shell was called.
195 the shell was called.
157
196
158 """
197 """
159
198
160 if (global_ns is not None) and (module is None):
199 if (global_ns is not None) and (module is None):
161 warnings.warn("global_ns is deprecated, and will be removed in IPython 5.0 use module instead.", DeprecationWarning)
200 warnings.warn("global_ns is deprecated, and will be removed in IPython 5.0 use module instead.", DeprecationWarning)
162 module = DummyMod()
201 module = DummyMod()
163 module.__dict__ = global_ns
202 module.__dict__ = global_ns
164
203
165 # Get locals and globals from caller
204 # Get locals and globals from caller
166 if ((local_ns is None or module is None or compile_flags is None)
205 if ((local_ns is None or module is None or compile_flags is None)
167 and self.default_user_namespaces):
206 and self.default_user_namespaces):
168 call_frame = sys._getframe(stack_depth).f_back
207 call_frame = sys._getframe(stack_depth).f_back
169
208
170 if local_ns is None:
209 if local_ns is None:
171 local_ns = call_frame.f_locals
210 local_ns = call_frame.f_locals
172 if module is None:
211 if module is None:
173 global_ns = call_frame.f_globals
212 global_ns = call_frame.f_globals
174 module = sys.modules[global_ns['__name__']]
213 module = sys.modules[global_ns['__name__']]
175 if compile_flags is None:
214 if compile_flags is None:
176 compile_flags = (call_frame.f_code.co_flags &
215 compile_flags = (call_frame.f_code.co_flags &
177 compilerop.PyCF_MASK)
216 compilerop.PyCF_MASK)
178
217
179 # Save original namespace and module so we can restore them after
218 # Save original namespace and module so we can restore them after
180 # embedding; otherwise the shell doesn't shut down correctly.
219 # embedding; otherwise the shell doesn't shut down correctly.
181 orig_user_module = self.user_module
220 orig_user_module = self.user_module
182 orig_user_ns = self.user_ns
221 orig_user_ns = self.user_ns
183 orig_compile_flags = self.compile.flags
222 orig_compile_flags = self.compile.flags
184
223
185 # Update namespaces and fire up interpreter
224 # Update namespaces and fire up interpreter
186
225
187 # The global one is easy, we can just throw it in
226 # The global one is easy, we can just throw it in
188 if module is not None:
227 if module is not None:
189 self.user_module = module
228 self.user_module = module
190
229
191 # But the user/local one is tricky: ipython needs it to store internal
230 # But the user/local one is tricky: ipython needs it to store internal
192 # data, but we also need the locals. We'll throw our hidden variables
231 # data, but we also need the locals. We'll throw our hidden variables
193 # like _ih and get_ipython() into the local namespace, but delete them
232 # like _ih and get_ipython() into the local namespace, but delete them
194 # later.
233 # later.
195 if local_ns is not None:
234 if local_ns is not None:
196 reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()}
235 reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()}
197 self.user_ns = reentrant_local_ns
236 self.user_ns = reentrant_local_ns
198 self.init_user_ns()
237 self.init_user_ns()
199
238
200 # Compiler flags
239 # Compiler flags
201 if compile_flags is not None:
240 if compile_flags is not None:
202 self.compile.flags = compile_flags
241 self.compile.flags = compile_flags
203
242
204 # make sure the tab-completer has the correct frame information, so it
243 # make sure the tab-completer has the correct frame information, so it
205 # actually completes using the frame's locals/globals
244 # actually completes using the frame's locals/globals
206 self.set_completer_frame()
245 self.set_completer_frame()
207
246
208 with self.builtin_trap, self.display_trap:
247 with self.builtin_trap, self.display_trap:
209 self.interact(display_banner=display_banner)
248 self.interact(display_banner=display_banner)
210
249
211 # now, purge out the local namespace of IPython's hidden variables.
250 # now, purge out the local namespace of IPython's hidden variables.
212 if local_ns is not None:
251 if local_ns is not None:
213 local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()})
252 local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()})
214
253
215
254
216 # Restore original namespace so shell can shut down when we exit.
255 # Restore original namespace so shell can shut down when we exit.
217 self.user_module = orig_user_module
256 self.user_module = orig_user_module
218 self.user_ns = orig_user_ns
257 self.user_ns = orig_user_ns
219 self.compile.flags = orig_compile_flags
258 self.compile.flags = orig_compile_flags
220
259
221
260
222 def embed(**kwargs):
261 def embed(**kwargs):
223 """Call this to embed IPython at the current point in your program.
262 """Call this to embed IPython at the current point in your program.
224
263
225 The first invocation of this will create an :class:`InteractiveShellEmbed`
264 The first invocation of this will create an :class:`InteractiveShellEmbed`
226 instance and then call it. Consecutive calls just call the already
265 instance and then call it. Consecutive calls just call the already
227 created instance.
266 created instance.
228
267
229 If you don't want the kernel to initialize the namespace
268 If you don't want the kernel to initialize the namespace
230 from the scope of the surrounding function,
269 from the scope of the surrounding function,
231 and/or you want to load full IPython configuration,
270 and/or you want to load full IPython configuration,
232 you probably want `IPython.start_ipython()` instead.
271 you probably want `IPython.start_ipython()` instead.
233
272
234 Here is a simple example::
273 Here is a simple example::
235
274
236 from IPython import embed
275 from IPython import embed
237 a = 10
276 a = 10
238 b = 20
277 b = 20
239 embed(header='First time')
278 embed(header='First time')
240 c = 30
279 c = 30
241 d = 40
280 d = 40
242 embed()
281 embed()
243
282
244 Full customization can be done by passing a :class:`Config` in as the
283 Full customization can be done by passing a :class:`Config` in as the
245 config argument.
284 config argument.
246 """
285 """
247 config = kwargs.get('config')
286 config = kwargs.get('config')
248 header = kwargs.pop('header', u'')
287 header = kwargs.pop('header', u'')
249 compile_flags = kwargs.pop('compile_flags', None)
288 compile_flags = kwargs.pop('compile_flags', None)
250 if config is None:
289 if config is None:
251 config = load_default_config()
290 config = load_default_config()
252 config.InteractiveShellEmbed = config.TerminalInteractiveShell
291 config.InteractiveShellEmbed = config.TerminalInteractiveShell
253 kwargs['config'] = config
292 kwargs['config'] = config
254 #save ps1/ps2 if defined
293 #save ps1/ps2 if defined
255 ps1 = None
294 ps1 = None
256 ps2 = None
295 ps2 = None
257 try:
296 try:
258 ps1 = sys.ps1
297 ps1 = sys.ps1
259 ps2 = sys.ps2
298 ps2 = sys.ps2
260 except AttributeError:
299 except AttributeError:
261 pass
300 pass
262 #save previous instance
301 #save previous instance
263 saved_shell_instance = InteractiveShell._instance
302 saved_shell_instance = InteractiveShell._instance
264 if saved_shell_instance is not None:
303 if saved_shell_instance is not None:
265 cls = type(saved_shell_instance)
304 cls = type(saved_shell_instance)
266 cls.clear_instance()
305 cls.clear_instance()
267 shell = InteractiveShellEmbed.instance(**kwargs)
306 shell = InteractiveShellEmbed.instance(**kwargs)
268 shell(header=header, stack_depth=2, compile_flags=compile_flags)
307 shell(header=header, stack_depth=2, compile_flags=compile_flags)
269 InteractiveShellEmbed.clear_instance()
308 InteractiveShellEmbed.clear_instance()
270 #restore previous instance
309 #restore previous instance
271 if saved_shell_instance is not None:
310 if saved_shell_instance is not None:
272 cls = type(saved_shell_instance)
311 cls = type(saved_shell_instance)
273 cls.clear_instance()
312 cls.clear_instance()
274 for subclass in cls._walk_mro():
313 for subclass in cls._walk_mro():
275 subclass._instance = saved_shell_instance
314 subclass._instance = saved_shell_instance
276 if ps1 is not None:
315 if ps1 is not None:
277 sys.ps1 = ps1
316 sys.ps1 = ps1
278 sys.ps2 = ps2
317 sys.ps2 = ps2
General Comments 0
You need to be logged in to leave comments. Login now