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