##// END OF EJS Templates
Prevent !cmd to try to run backgrounded (cmd &) processes.
Fernando Perez -
Show More
@@ -1,418 +1,427 b''
1 1 """A ZMQ-based subclass of InteractiveShell.
2 2
3 3 This code is meant to ease the refactoring of the base InteractiveShell into
4 4 something with a cleaner architecture for 2-process use, without actually
5 5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 6 we subclass and override what we want to fix. Once this is working well, we
7 7 can go back to the base class and refactor the code for a cleaner inheritance
8 8 implementation that doesn't rely on so much monkeypatching.
9 9
10 10 But this lets us maintain a fully working IPython as we develop the new
11 11 machinery. This should thus be thought of as scaffolding.
12 12 """
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
17
16 18 # Stdlib
17 19 import inspect
18 20 import os
19 21 import re
20 22 import sys
21 23
22 24 from subprocess import Popen, PIPE
23 25
24 26 # Our own
25 27 from IPython.core.interactiveshell import (
26 28 InteractiveShell, InteractiveShellABC
27 29 )
28 30 from IPython.core.displayhook import DisplayHook
29 31 from IPython.core.macro import Macro
30 32 from IPython.utils.path import get_py_filename
31 33 from IPython.utils.text import StringTypes
32 34 from IPython.utils.traitlets import Instance, Type, Dict
33 35 from IPython.utils.warn import warn
34 36 from IPython.zmq.session import extract_header
35 37 from IPython.core.payloadpage import install_payload_page
36 38 from session import Session
37 39
38 40 #-----------------------------------------------------------------------------
39 41 # Globals and side-effects
40 42 #-----------------------------------------------------------------------------
41 43
42 44 # Install the payload version of page.
43 45 install_payload_page()
44 46
45 47 #-----------------------------------------------------------------------------
46 48 # Functions and classes
47 49 #-----------------------------------------------------------------------------
48 50
49 51 class ZMQDisplayHook(DisplayHook):
50 52
51 53 session = Instance(Session)
52 54 pub_socket = Instance('zmq.Socket')
53 55 parent_header = Dict({})
54 56
55 57 def set_parent(self, parent):
56 58 """Set the parent for outbound messages."""
57 59 self.parent_header = extract_header(parent)
58 60
59 61 def start_displayhook(self):
60 62 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
61 63
62 64 def write_output_prompt(self):
63 65 """Write the output prompt."""
64 66 if self.do_full_cache:
65 67 self.msg['content']['output_sep'] = self.output_sep
66 68 self.msg['content']['prompt_string'] = str(self.prompt_out)
67 69 self.msg['content']['prompt_number'] = self.prompt_count
68 70 self.msg['content']['output_sep2'] = self.output_sep2
69 71
70 72 def write_result_repr(self, result_repr):
71 73 self.msg['content']['data'] = result_repr
72 74
73 75 def finish_displayhook(self):
74 76 """Finish up all displayhook activities."""
75 77 self.pub_socket.send_json(self.msg)
76 78 self.msg = None
77 79
78 80
79 81 class ZMQInteractiveShell(InteractiveShell):
80 82 """A subclass of InteractiveShell for ZMQ."""
81 83
82 84 displayhook_class = Type(ZMQDisplayHook)
83 85
84 86 def system(self, cmd):
85 cmd = self.var_expand(cmd, depth=2)
87 cmd = self.var_expand(cmd, depth=2).strip()
88
89 # Runnning a bacgkrounded process from within the gui isn't supported
90 # because we do p.wait() at the end. So instead of silently blocking
91 # we simply refuse to run in this mode, to avoid surprising the user.
92 if cmd.endswith('&'):
93 raise OSError("Background processes not supported.")
94
86 95 sys.stdout.flush()
87 96 sys.stderr.flush()
88 97 p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
89 98 for line in p.stdout.read().split('\n'):
90 99 if len(line) > 0:
91 print line
100 print(line)
92 101 for line in p.stderr.read().split('\n'):
93 102 if len(line) > 0:
94 print line
103 print(line, file=sys.stderr)
95 104 p.wait()
96 105
97 106 def init_io(self):
98 107 # This will just use sys.stdout and sys.stderr. If you want to
99 108 # override sys.stdout and sys.stderr themselves, you need to do that
100 109 # *before* instantiating this class, because Term holds onto
101 110 # references to the underlying streams.
102 111 import IPython.utils.io
103 112 Term = IPython.utils.io.IOTerm()
104 113 IPython.utils.io.Term = Term
105 114
106 115 def magic_edit(self,parameter_s='',last_call=['','']):
107 116 """Bring up an editor and execute the resulting code.
108 117
109 118 Usage:
110 119 %edit [options] [args]
111 120
112 121 %edit runs IPython's editor hook. The default version of this hook is
113 122 set to call the __IPYTHON__.rc.editor command. This is read from your
114 123 environment variable $EDITOR. If this isn't found, it will default to
115 124 vi under Linux/Unix and to notepad under Windows. See the end of this
116 125 docstring for how to change the editor hook.
117 126
118 127 You can also set the value of this editor via the command line option
119 128 '-editor' or in your ipythonrc file. This is useful if you wish to use
120 129 specifically for IPython an editor different from your typical default
121 130 (and for Windows users who typically don't set environment variables).
122 131
123 132 This command allows you to conveniently edit multi-line code right in
124 133 your IPython session.
125 134
126 135 If called without arguments, %edit opens up an empty editor with a
127 136 temporary file and will execute the contents of this file when you
128 137 close it (don't forget to save it!).
129 138
130 139
131 140 Options:
132 141
133 142 -n <number>: open the editor at a specified line number. By default,
134 143 the IPython editor hook uses the unix syntax 'editor +N filename', but
135 144 you can configure this by providing your own modified hook if your
136 145 favorite editor supports line-number specifications with a different
137 146 syntax.
138 147
139 148 -p: this will call the editor with the same data as the previous time
140 149 it was used, regardless of how long ago (in your current session) it
141 150 was.
142 151
143 152 -r: use 'raw' input. This option only applies to input taken from the
144 153 user's history. By default, the 'processed' history is used, so that
145 154 magics are loaded in their transformed version to valid Python. If
146 155 this option is given, the raw input as typed as the command line is
147 156 used instead. When you exit the editor, it will be executed by
148 157 IPython's own processor.
149 158
150 159 -x: do not execute the edited code immediately upon exit. This is
151 160 mainly useful if you are editing programs which need to be called with
152 161 command line arguments, which you can then do using %run.
153 162
154 163
155 164 Arguments:
156 165
157 166 If arguments are given, the following possibilites exist:
158 167
159 168 - The arguments are numbers or pairs of colon-separated numbers (like
160 169 1 4:8 9). These are interpreted as lines of previous input to be
161 170 loaded into the editor. The syntax is the same of the %macro command.
162 171
163 172 - If the argument doesn't start with a number, it is evaluated as a
164 173 variable and its contents loaded into the editor. You can thus edit
165 174 any string which contains python code (including the result of
166 175 previous edits).
167 176
168 177 - If the argument is the name of an object (other than a string),
169 178 IPython will try to locate the file where it was defined and open the
170 179 editor at the point where it is defined. You can use `%edit function`
171 180 to load an editor exactly at the point where 'function' is defined,
172 181 edit it and have the file be executed automatically.
173 182
174 183 If the object is a macro (see %macro for details), this opens up your
175 184 specified editor with a temporary file containing the macro's data.
176 185 Upon exit, the macro is reloaded with the contents of the file.
177 186
178 187 Note: opening at an exact line is only supported under Unix, and some
179 188 editors (like kedit and gedit up to Gnome 2.8) do not understand the
180 189 '+NUMBER' parameter necessary for this feature. Good editors like
181 190 (X)Emacs, vi, jed, pico and joe all do.
182 191
183 192 - If the argument is not found as a variable, IPython will look for a
184 193 file with that name (adding .py if necessary) and load it into the
185 194 editor. It will execute its contents with execfile() when you exit,
186 195 loading any code in the file into your interactive namespace.
187 196
188 197 After executing your code, %edit will return as output the code you
189 198 typed in the editor (except when it was an existing file). This way
190 199 you can reload the code in further invocations of %edit as a variable,
191 200 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
192 201 the output.
193 202
194 203 Note that %edit is also available through the alias %ed.
195 204
196 205 This is an example of creating a simple function inside the editor and
197 206 then modifying it. First, start up the editor:
198 207
199 208 In [1]: ed
200 209 Editing... done. Executing edited code...
201 210 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
202 211
203 212 We can then call the function foo():
204 213
205 214 In [2]: foo()
206 215 foo() was defined in an editing session
207 216
208 217 Now we edit foo. IPython automatically loads the editor with the
209 218 (temporary) file where foo() was previously defined:
210 219
211 220 In [3]: ed foo
212 221 Editing... done. Executing edited code...
213 222
214 223 And if we call foo() again we get the modified version:
215 224
216 225 In [4]: foo()
217 226 foo() has now been changed!
218 227
219 228 Here is an example of how to edit a code snippet successive
220 229 times. First we call the editor:
221 230
222 231 In [5]: ed
223 232 Editing... done. Executing edited code...
224 233 hello
225 234 Out[5]: "print 'hello'n"
226 235
227 236 Now we call it again with the previous output (stored in _):
228 237
229 238 In [6]: ed _
230 239 Editing... done. Executing edited code...
231 240 hello world
232 241 Out[6]: "print 'hello world'n"
233 242
234 243 Now we call it with the output #8 (stored in _8, also as Out[8]):
235 244
236 245 In [7]: ed _8
237 246 Editing... done. Executing edited code...
238 247 hello again
239 248 Out[7]: "print 'hello again'n"
240 249
241 250
242 251 Changing the default editor hook:
243 252
244 253 If you wish to write your own editor hook, you can put it in a
245 254 configuration file which you load at startup time. The default hook
246 255 is defined in the IPython.core.hooks module, and you can use that as a
247 256 starting example for further modifications. That file also has
248 257 general instructions on how to set a new hook for use once you've
249 258 defined it."""
250 259
251 260 # FIXME: This function has become a convoluted mess. It needs a
252 261 # ground-up rewrite with clean, simple logic.
253 262
254 263 def make_filename(arg):
255 264 "Make a filename from the given args"
256 265 try:
257 266 filename = get_py_filename(arg)
258 267 except IOError:
259 268 if args.endswith('.py'):
260 269 filename = arg
261 270 else:
262 271 filename = None
263 272 return filename
264 273
265 274 # custom exceptions
266 275 class DataIsObject(Exception): pass
267 276
268 277 opts,args = self.parse_options(parameter_s,'prn:')
269 278 # Set a few locals from the options for convenience:
270 279 opts_p = opts.has_key('p')
271 280 opts_r = opts.has_key('r')
272 281
273 282 # Default line number value
274 283 lineno = opts.get('n',None)
275 284 if lineno is not None:
276 285 try:
277 286 lineno = int(lineno)
278 287 except:
279 288 warn("The -n argument must be an integer.")
280 289 return
281 290
282 291 if opts_p:
283 292 args = '_%s' % last_call[0]
284 293 if not self.shell.user_ns.has_key(args):
285 294 args = last_call[1]
286 295
287 296 # use last_call to remember the state of the previous call, but don't
288 297 # let it be clobbered by successive '-p' calls.
289 298 try:
290 299 last_call[0] = self.shell.displayhook.prompt_count
291 300 if not opts_p:
292 301 last_call[1] = parameter_s
293 302 except:
294 303 pass
295 304
296 305 # by default this is done with temp files, except when the given
297 306 # arg is a filename
298 307 use_temp = 1
299 308
300 309 if re.match(r'\d',args):
301 310 # Mode where user specifies ranges of lines, like in %macro.
302 311 # This means that you can't edit files whose names begin with
303 312 # numbers this way. Tough.
304 313 ranges = args.split()
305 314 data = ''.join(self.extract_input_slices(ranges,opts_r))
306 315 elif args.endswith('.py'):
307 316 filename = make_filename(args)
308 317 data = ''
309 318 use_temp = 0
310 319 elif args:
311 320 try:
312 321 # Load the parameter given as a variable. If not a string,
313 322 # process it as an object instead (below)
314 323
315 324 #print '*** args',args,'type',type(args) # dbg
316 325 data = eval(args,self.shell.user_ns)
317 326 if not type(data) in StringTypes:
318 327 raise DataIsObject
319 328
320 329 except (NameError,SyntaxError):
321 330 # given argument is not a variable, try as a filename
322 331 filename = make_filename(args)
323 332 if filename is None:
324 333 warn("Argument given (%s) can't be found as a variable "
325 334 "or as a filename." % args)
326 335 return
327 336
328 337 data = ''
329 338 use_temp = 0
330 339 except DataIsObject:
331 340
332 341 # macros have a special edit function
333 342 if isinstance(data,Macro):
334 343 self._edit_macro(args,data)
335 344 return
336 345
337 346 # For objects, try to edit the file where they are defined
338 347 try:
339 348 filename = inspect.getabsfile(data)
340 349 if 'fakemodule' in filename.lower() and inspect.isclass(data):
341 350 # class created by %edit? Try to find source
342 351 # by looking for method definitions instead, the
343 352 # __module__ in those classes is FakeModule.
344 353 attrs = [getattr(data, aname) for aname in dir(data)]
345 354 for attr in attrs:
346 355 if not inspect.ismethod(attr):
347 356 continue
348 357 filename = inspect.getabsfile(attr)
349 358 if filename and 'fakemodule' not in filename.lower():
350 359 # change the attribute to be the edit target instead
351 360 data = attr
352 361 break
353 362
354 363 datafile = 1
355 364 except TypeError:
356 365 filename = make_filename(args)
357 366 datafile = 1
358 367 warn('Could not find file where `%s` is defined.\n'
359 368 'Opening a file named `%s`' % (args,filename))
360 369 # Now, make sure we can actually read the source (if it was in
361 370 # a temp file it's gone by now).
362 371 if datafile:
363 372 try:
364 373 if lineno is None:
365 374 lineno = inspect.getsourcelines(data)[1]
366 375 except IOError:
367 376 filename = make_filename(args)
368 377 if filename is None:
369 378 warn('The file `%s` where `%s` was defined cannot '
370 379 'be read.' % (filename,data))
371 380 return
372 381 use_temp = 0
373 382 else:
374 383 data = ''
375 384
376 385 if use_temp:
377 386 filename = self.shell.mktempfile(data)
378 print 'IPython will make a temporary file named:',filename
387 print('IPython will make a temporary file named:', filename)
379 388
380 389 # Make sure we send to the client an absolute path, in case the working
381 390 # directory of client and kernel don't match
382 391 filename = os.path.abspath(filename)
383 392
384 393 payload = {
385 394 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
386 395 'filename' : filename,
387 396 'line_number' : lineno
388 397 }
389 398 self.payload_manager.write_payload(payload)
390 399
391 400
392 401 def _showtraceback(self, etype, evalue, stb):
393 402
394 403 exc_content = {
395 404 u'status' : u'error',
396 405 u'traceback' : stb,
397 406 u'ename' : unicode(etype.__name__),
398 407 u'evalue' : unicode(evalue)
399 408 }
400 409
401 410 dh = self.displayhook
402 411 exc_msg = dh.session.msg(u'pyerr', exc_content, dh.parent_header)
403 412 # Send exception info over pub socket for other clients than the caller
404 413 # to pick up
405 414 dh.pub_socket.send_json(exc_msg)
406 415
407 416 # FIXME - Hack: store exception info in shell object. Right now, the
408 417 # caller is reading this info after the fact, we need to fix this logic
409 418 # to remove this hack.
410 419 self._reply_content = exc_content
411 420 # /FIXME
412 421
413 422 return exc_content
414 423
415 424 def runlines(self, lines, clean=False):
416 425 return InteractiveShell.runlines(self, lines, clean)
417 426
418 427 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now