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