##// END OF EJS Templates
Fix bug with Popen call on windows....
Fernando Perez -
Show More
@@ -1,119 +1,120 b''
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 The IPython Development Team
8 # Copyright (C) 2010 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 sys
18 import sys
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Function definitions
21 # Function definitions
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 def read_no_interrupt(p):
24 def read_no_interrupt(p):
25 """Read from a pipe ignoring EINTR errors.
25 """Read from a pipe ignoring EINTR errors.
26
26
27 This is necessary because when reading from pipes with GUI event loops
27 This is necessary because when reading from pipes with GUI event loops
28 running in the background, often interrupts are raised that stop the
28 running in the background, often interrupts are raised that stop the
29 command from completing."""
29 command from completing."""
30 import errno
30 import errno
31
31
32 try:
32 try:
33 return p.read()
33 return p.read()
34 except IOError, err:
34 except IOError, err:
35 if err.errno != errno.EINTR:
35 if err.errno != errno.EINTR:
36 raise
36 raise
37
37
38
38
39 def process_handler(cmd, callback, stderr=subprocess.PIPE):
39 def process_handler(cmd, callback, stderr=subprocess.PIPE):
40 """Open a command in a shell subprocess and execute a callback.
40 """Open a command in a shell subprocess and execute a callback.
41
41
42 This function provides common scaffolding for creating subprocess.Popen()
42 This function provides common scaffolding for creating subprocess.Popen()
43 calls. It creates a Popen object and then calls the callback with it.
43 calls. It creates a Popen object and then calls the callback with it.
44
44
45 Parameters
45 Parameters
46 ----------
46 ----------
47 cmd : str
47 cmd : str
48 A string to be executed with the underlying system shell (by calling
48 A string to be executed with the underlying system shell (by calling
49 :func:`Popen` with ``shell=True``.
49 :func:`Popen` with ``shell=True``.
50
50
51 callback : callable
51 callback : callable
52 A one-argument function that will be called with the Popen object.
52 A one-argument function that will be called with the Popen object.
53
53
54 stderr : file descriptor number, optional
54 stderr : file descriptor number, optional
55 By default this is set to ``subprocess.PIPE``, but you can also pass the
55 By default this is set to ``subprocess.PIPE``, but you can also pass the
56 value ``subprocess.STDOUT`` to force the subprocess' stderr to go into
56 value ``subprocess.STDOUT`` to force the subprocess' stderr to go into
57 the same file descriptor as its stdout. This is useful to read stdout
57 the same file descriptor as its stdout. This is useful to read stdout
58 and stderr combined in the order they are generated.
58 and stderr combined in the order they are generated.
59
59
60 Returns
60 Returns
61 -------
61 -------
62 The return value of the provided callback is returned.
62 The return value of the provided callback is returned.
63 """
63 """
64 sys.stdout.flush()
64 sys.stdout.flush()
65 sys.stderr.flush()
65 sys.stderr.flush()
66 close_fds = False if sys.platform=='win32' else True
66 p = subprocess.Popen(cmd, shell=True,
67 p = subprocess.Popen(cmd, shell=True,
67 stdin=subprocess.PIPE,
68 stdin=subprocess.PIPE,
68 stdout=subprocess.PIPE,
69 stdout=subprocess.PIPE,
69 stderr=stderr,
70 stderr=stderr,
70 close_fds=True)
71 close_fds=close_fds)
71
72
72 try:
73 try:
73 out = callback(p)
74 out = callback(p)
74 except KeyboardInterrupt:
75 except KeyboardInterrupt:
75 print('^C')
76 print('^C')
76 sys.stdout.flush()
77 sys.stdout.flush()
77 sys.stderr.flush()
78 sys.stderr.flush()
78 out = None
79 out = None
79 finally:
80 finally:
80 # Make really sure that we don't leave processes behind, in case the
81 # Make really sure that we don't leave processes behind, in case the
81 # call above raises an exception
82 # call above raises an exception
82 # We start by assuming the subprocess finished (to avoid NameErrors
83 # We start by assuming the subprocess finished (to avoid NameErrors
83 # later depending on the path taken)
84 # later depending on the path taken)
84 if p.returncode is None:
85 if p.returncode is None:
85 try:
86 try:
86 p.terminate()
87 p.terminate()
87 p.poll()
88 p.poll()
88 except OSError:
89 except OSError:
89 pass
90 pass
90 # One last try on our way out
91 # One last try on our way out
91 if p.returncode is None:
92 if p.returncode is None:
92 try:
93 try:
93 p.kill()
94 p.kill()
94 except OSError:
95 except OSError:
95 pass
96 pass
96
97
97 return out
98 return out
98
99
99
100
100 def getoutputerror(cmd):
101 def getoutputerror(cmd):
101 """Return (standard output, standard error) of executing cmd in a shell.
102 """Return (standard output, standard error) of executing cmd in a shell.
102
103
103 Accepts the same arguments as os.system().
104 Accepts the same arguments as os.system().
104
105
105 Parameters
106 Parameters
106 ----------
107 ----------
107 cmd : str
108 cmd : str
108 A command to be executed in the system shell.
109 A command to be executed in the system shell.
109
110
110 Returns
111 Returns
111 -------
112 -------
112 stdout : str
113 stdout : str
113 stderr : str
114 stderr : str
114 """
115 """
115
116
116 out_err = process_handler(cmd, lambda p: p.communicate())
117 out_err = process_handler(cmd, lambda p: p.communicate())
117 if out_err is None:
118 if out_err is None:
118 out_err = '', ''
119 out_err = '', ''
119 return out_err
120 return out_err
General Comments 0
You need to be logged in to leave comments. Login now