##// END OF EJS Templates
Use the default shell to capture shell output....
Pavol Juhas -
Show More
@@ -1,215 +1,217
1 """Common utilities for the various process_* implementations.
1 """Common utilities for the various process_* implementations.
2
2
3 This file is only meant to be imported by the platform-specific implementations
3 This file is only meant to be imported by the platform-specific implementations
4 of subprocess utilities, and it contains tools that are common to all of them.
4 of subprocess utilities, and it contains tools that are common to all of them.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2010-2011 The IPython Development Team
8 # Copyright (C) 2010-2011 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 import subprocess
17 import subprocess
18 import shlex
18 import shlex
19 import sys
19 import sys
20 import os
20
21
21 from IPython.utils import py3compat
22 from IPython.utils import py3compat
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Function definitions
25 # Function definitions
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26
27
27 def read_no_interrupt(p):
28 def read_no_interrupt(p):
28 """Read from a pipe ignoring EINTR errors.
29 """Read from a pipe ignoring EINTR errors.
29
30
30 This is necessary because when reading from pipes with GUI event loops
31 This is necessary because when reading from pipes with GUI event loops
31 running in the background, often interrupts are raised that stop the
32 running in the background, often interrupts are raised that stop the
32 command from completing."""
33 command from completing."""
33 import errno
34 import errno
34
35
35 try:
36 try:
36 return p.read()
37 return p.read()
37 except IOError as err:
38 except IOError as err:
38 if err.errno != errno.EINTR:
39 if err.errno != errno.EINTR:
39 raise
40 raise
40
41
41
42
42 def process_handler(cmd, callback, stderr=subprocess.PIPE):
43 def process_handler(cmd, callback, stderr=subprocess.PIPE):
43 """Open a command in a shell subprocess and execute a callback.
44 """Open a command in a shell subprocess and execute a callback.
44
45
45 This function provides common scaffolding for creating subprocess.Popen()
46 This function provides common scaffolding for creating subprocess.Popen()
46 calls. It creates a Popen object and then calls the callback with it.
47 calls. It creates a Popen object and then calls the callback with it.
47
48
48 Parameters
49 Parameters
49 ----------
50 ----------
50 cmd : str or list
51 cmd : str or list
51 A command to be executed by the system, using :class:`subprocess.Popen`.
52 A command to be executed by the system, using :class:`subprocess.Popen`.
52 If a string is passed, it will be run in the system shell. If a list is
53 If a string is passed, it will be run in the system shell. If a list is
53 passed, it will be used directly as arguments.
54 passed, it will be used directly as arguments.
54
55
55 callback : callable
56 callback : callable
56 A one-argument function that will be called with the Popen object.
57 A one-argument function that will be called with the Popen object.
57
58
58 stderr : file descriptor number, optional
59 stderr : file descriptor number, optional
59 By default this is set to ``subprocess.PIPE``, but you can also pass the
60 By default this is set to ``subprocess.PIPE``, but you can also pass the
60 value ``subprocess.STDOUT`` to force the subprocess' stderr to go into
61 value ``subprocess.STDOUT`` to force the subprocess' stderr to go into
61 the same file descriptor as its stdout. This is useful to read stdout
62 the same file descriptor as its stdout. This is useful to read stdout
62 and stderr combined in the order they are generated.
63 and stderr combined in the order they are generated.
63
64
64 Returns
65 Returns
65 -------
66 -------
66 The return value of the provided callback is returned.
67 The return value of the provided callback is returned.
67 """
68 """
68 sys.stdout.flush()
69 sys.stdout.flush()
69 sys.stderr.flush()
70 sys.stderr.flush()
70 # On win32, close_fds can't be true when using pipes for stdin/out/err
71 # On win32, close_fds can't be true when using pipes for stdin/out/err
71 close_fds = sys.platform != 'win32'
72 close_fds = sys.platform != 'win32'
72 p = subprocess.Popen(cmd, shell=isinstance(cmd, py3compat.string_types),
73 p = subprocess.Popen(cmd, shell=isinstance(cmd, py3compat.string_types),
74 executable=os.environ.get('SHELL'),
73 stdin=subprocess.PIPE,
75 stdin=subprocess.PIPE,
74 stdout=subprocess.PIPE,
76 stdout=subprocess.PIPE,
75 stderr=stderr,
77 stderr=stderr,
76 close_fds=close_fds)
78 close_fds=close_fds)
77
79
78 try:
80 try:
79 out = callback(p)
81 out = callback(p)
80 except KeyboardInterrupt:
82 except KeyboardInterrupt:
81 print('^C')
83 print('^C')
82 sys.stdout.flush()
84 sys.stdout.flush()
83 sys.stderr.flush()
85 sys.stderr.flush()
84 out = None
86 out = None
85 finally:
87 finally:
86 # Make really sure that we don't leave processes behind, in case the
88 # Make really sure that we don't leave processes behind, in case the
87 # call above raises an exception
89 # call above raises an exception
88 # We start by assuming the subprocess finished (to avoid NameErrors
90 # We start by assuming the subprocess finished (to avoid NameErrors
89 # later depending on the path taken)
91 # later depending on the path taken)
90 if p.returncode is None:
92 if p.returncode is None:
91 try:
93 try:
92 p.terminate()
94 p.terminate()
93 p.poll()
95 p.poll()
94 except OSError:
96 except OSError:
95 pass
97 pass
96 # One last try on our way out
98 # One last try on our way out
97 if p.returncode is None:
99 if p.returncode is None:
98 try:
100 try:
99 p.kill()
101 p.kill()
100 except OSError:
102 except OSError:
101 pass
103 pass
102
104
103 return out
105 return out
104
106
105
107
106 def getoutput(cmd):
108 def getoutput(cmd):
107 """Run a command and return its stdout/stderr as a string.
109 """Run a command and return its stdout/stderr as a string.
108
110
109 Parameters
111 Parameters
110 ----------
112 ----------
111 cmd : str or list
113 cmd : str or list
112 A command to be executed in the system shell.
114 A command to be executed in the system shell.
113
115
114 Returns
116 Returns
115 -------
117 -------
116 output : str
118 output : str
117 A string containing the combination of stdout and stderr from the
119 A string containing the combination of stdout and stderr from the
118 subprocess, in whatever order the subprocess originally wrote to its
120 subprocess, in whatever order the subprocess originally wrote to its
119 file descriptors (so the order of the information in this string is the
121 file descriptors (so the order of the information in this string is the
120 correct order as would be seen if running the command in a terminal).
122 correct order as would be seen if running the command in a terminal).
121 """
123 """
122 out = process_handler(cmd, lambda p: p.communicate()[0], subprocess.STDOUT)
124 out = process_handler(cmd, lambda p: p.communicate()[0], subprocess.STDOUT)
123 if out is None:
125 if out is None:
124 return ''
126 return ''
125 return py3compat.bytes_to_str(out)
127 return py3compat.bytes_to_str(out)
126
128
127
129
128 def getoutputerror(cmd):
130 def getoutputerror(cmd):
129 """Return (standard output, standard error) of executing cmd in a shell.
131 """Return (standard output, standard error) of executing cmd in a shell.
130
132
131 Accepts the same arguments as os.system().
133 Accepts the same arguments as os.system().
132
134
133 Parameters
135 Parameters
134 ----------
136 ----------
135 cmd : str or list
137 cmd : str or list
136 A command to be executed in the system shell.
138 A command to be executed in the system shell.
137
139
138 Returns
140 Returns
139 -------
141 -------
140 stdout : str
142 stdout : str
141 stderr : str
143 stderr : str
142 """
144 """
143 return get_output_error_code(cmd)[:2]
145 return get_output_error_code(cmd)[:2]
144
146
145 def get_output_error_code(cmd):
147 def get_output_error_code(cmd):
146 """Return (standard output, standard error, return code) of executing cmd
148 """Return (standard output, standard error, return code) of executing cmd
147 in a shell.
149 in a shell.
148
150
149 Accepts the same arguments as os.system().
151 Accepts the same arguments as os.system().
150
152
151 Parameters
153 Parameters
152 ----------
154 ----------
153 cmd : str or list
155 cmd : str or list
154 A command to be executed in the system shell.
156 A command to be executed in the system shell.
155
157
156 Returns
158 Returns
157 -------
159 -------
158 stdout : str
160 stdout : str
159 stderr : str
161 stderr : str
160 returncode: int
162 returncode: int
161 """
163 """
162
164
163 out_err, p = process_handler(cmd, lambda p: (p.communicate(), p))
165 out_err, p = process_handler(cmd, lambda p: (p.communicate(), p))
164 if out_err is None:
166 if out_err is None:
165 return '', '', p.returncode
167 return '', '', p.returncode
166 out, err = out_err
168 out, err = out_err
167 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err), p.returncode
169 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err), p.returncode
168
170
169 def arg_split(s, posix=False, strict=True):
171 def arg_split(s, posix=False, strict=True):
170 """Split a command line's arguments in a shell-like manner.
172 """Split a command line's arguments in a shell-like manner.
171
173
172 This is a modified version of the standard library's shlex.split()
174 This is a modified version of the standard library's shlex.split()
173 function, but with a default of posix=False for splitting, so that quotes
175 function, but with a default of posix=False for splitting, so that quotes
174 in inputs are respected.
176 in inputs are respected.
175
177
176 if strict=False, then any errors shlex.split would raise will result in the
178 if strict=False, then any errors shlex.split would raise will result in the
177 unparsed remainder being the last element of the list, rather than raising.
179 unparsed remainder being the last element of the list, rather than raising.
178 This is because we sometimes use arg_split to parse things other than
180 This is because we sometimes use arg_split to parse things other than
179 command-line args.
181 command-line args.
180 """
182 """
181
183
182 # Unfortunately, python's shlex module is buggy with unicode input:
184 # Unfortunately, python's shlex module is buggy with unicode input:
183 # http://bugs.python.org/issue1170
185 # http://bugs.python.org/issue1170
184 # At least encoding the input when it's unicode seems to help, but there
186 # At least encoding the input when it's unicode seems to help, but there
185 # may be more problems lurking. Apparently this is fixed in python3.
187 # may be more problems lurking. Apparently this is fixed in python3.
186 is_unicode = False
188 is_unicode = False
187 if (not py3compat.PY3) and isinstance(s, unicode):
189 if (not py3compat.PY3) and isinstance(s, unicode):
188 is_unicode = True
190 is_unicode = True
189 s = s.encode('utf-8')
191 s = s.encode('utf-8')
190 lex = shlex.shlex(s, posix=posix)
192 lex = shlex.shlex(s, posix=posix)
191 lex.whitespace_split = True
193 lex.whitespace_split = True
192 # Extract tokens, ensuring that things like leaving open quotes
194 # Extract tokens, ensuring that things like leaving open quotes
193 # does not cause this to raise. This is important, because we
195 # does not cause this to raise. This is important, because we
194 # sometimes pass Python source through this (e.g. %timeit f(" ")),
196 # sometimes pass Python source through this (e.g. %timeit f(" ")),
195 # and it shouldn't raise an exception.
197 # and it shouldn't raise an exception.
196 # It may be a bad idea to parse things that are not command-line args
198 # It may be a bad idea to parse things that are not command-line args
197 # through this function, but we do, so let's be safe about it.
199 # through this function, but we do, so let's be safe about it.
198 lex.commenters='' #fix for GH-1269
200 lex.commenters='' #fix for GH-1269
199 tokens = []
201 tokens = []
200 while True:
202 while True:
201 try:
203 try:
202 tokens.append(next(lex))
204 tokens.append(next(lex))
203 except StopIteration:
205 except StopIteration:
204 break
206 break
205 except ValueError:
207 except ValueError:
206 if strict:
208 if strict:
207 raise
209 raise
208 # couldn't parse, get remaining blob as last token
210 # couldn't parse, get remaining blob as last token
209 tokens.append(lex.token)
211 tokens.append(lex.token)
210 break
212 break
211
213
212 if is_unicode:
214 if is_unicode:
213 # Convert the tokens back to unicode.
215 # Convert the tokens back to unicode.
214 tokens = [x.decode('utf-8') for x in tokens]
216 tokens = [x.decode('utf-8') for x in tokens]
215 return tokens
217 return tokens
General Comments 0
You need to be logged in to leave comments. Login now