OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.test.test_iutils -*- | |
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
3 # See LICENSE for details. | |
4 | |
5 """Utility methods.""" | |
6 | |
7 import sys, warnings | |
8 | |
9 from twisted.internet import protocol, defer | |
10 from twisted.python import failure, util as tputil | |
11 | |
12 try: | |
13 import cStringIO as StringIO | |
14 except ImportError: | |
15 import StringIO | |
16 | |
17 def _callProtocolWithDeferred(protocol, executable, args, env, path, reactor=Non
e): | |
18 if reactor is None: | |
19 from twisted.internet import reactor | |
20 | |
21 d = defer.Deferred() | |
22 p = protocol(d) | |
23 reactor.spawnProcess(p, executable, (executable,)+tuple(args), env, path) | |
24 return d | |
25 | |
26 | |
27 class _BackRelay(protocol.ProcessProtocol): | |
28 | |
29 def __init__(self, deferred, errortoo=0): | |
30 self.deferred = deferred | |
31 self.s = StringIO.StringIO() | |
32 if errortoo: | |
33 self.errReceived = self.errReceivedIsGood | |
34 else: | |
35 self.errReceived = self.errReceivedIsBad | |
36 | |
37 def errReceivedIsBad(self, text): | |
38 if self.deferred is not None: | |
39 self.deferred.errback(failure.Failure(IOError("got stderr: %r" % tex
t))) | |
40 self.deferred = None | |
41 self.transport.loseConnection() | |
42 | |
43 def errReceivedIsGood(self, text): | |
44 self.s.write(text) | |
45 | |
46 def outReceived(self, text): | |
47 self.s.write(text) | |
48 | |
49 def processEnded(self, reason): | |
50 if self.deferred is not None: | |
51 self.deferred.callback(self.s.getvalue()) | |
52 | |
53 | |
54 def getProcessOutput(executable, args=(), env={}, path='.', reactor=None, | |
55 errortoo=0): | |
56 """Spawn a process and return its output as a deferred returning a string. | |
57 | |
58 @param executable: The file name to run and get the output of - the | |
59 full path should be used. | |
60 | |
61 @param args: the command line arguments to pass to the process; a | |
62 sequence of strings. The first string should *NOT* be the | |
63 executable's name. | |
64 | |
65 @param env: the environment variables to pass to the processs; a | |
66 dictionary of strings. | |
67 | |
68 @param path: the path to run the subprocess in - defaults to the | |
69 current directory. | |
70 | |
71 @param reactor: the reactor to use - defaults to the default reactor | |
72 @param errortoo: if 1, capture stderr too | |
73 """ | |
74 return _callProtocolWithDeferred(lambda d: | |
75 _BackRelay(d, errortoo=errortoo), | |
76 executable, args, env, path, | |
77 reactor) | |
78 | |
79 | |
80 class _ValueGetter(protocol.ProcessProtocol): | |
81 | |
82 def __init__(self, deferred): | |
83 self.deferred = deferred | |
84 | |
85 def processEnded(self, reason): | |
86 self.deferred.callback(reason.value.exitCode) | |
87 | |
88 | |
89 def getProcessValue(executable, args=(), env={}, path='.', reactor=None): | |
90 """Spawn a process and return its exit code as a Deferred.""" | |
91 return _callProtocolWithDeferred(_ValueGetter, executable, args, env, path, | |
92 reactor) | |
93 | |
94 | |
95 class _EverythingGetter(protocol.ProcessProtocol): | |
96 | |
97 def __init__(self, deferred): | |
98 self.deferred = deferred | |
99 self.outBuf = StringIO.StringIO() | |
100 self.errBuf = StringIO.StringIO() | |
101 self.outReceived = self.outBuf.write | |
102 self.errReceived = self.errBuf.write | |
103 | |
104 def processEnded(self, reason): | |
105 out = self.outBuf.getvalue() | |
106 err = self.errBuf.getvalue() | |
107 e = reason.value | |
108 code = e.exitCode | |
109 if e.signal: | |
110 self.deferred.errback((out, err, e.signal)) | |
111 else: | |
112 self.deferred.callback((out, err, code)) | |
113 | |
114 def getProcessOutputAndValue(executable, args=(), env={}, path='.', | |
115 reactor=None): | |
116 """Spawn a process and returns a Deferred that will be called back with | |
117 its output (from stdout and stderr) and it's exit code as (out, err, code) | |
118 If a signal is raised, the Deferred will errback with the stdout and | |
119 stderr up to that point, along with the signal, as (out, err, signalNum) | |
120 """ | |
121 return _callProtocolWithDeferred(_EverythingGetter, executable, args, env, p
ath, | |
122 reactor) | |
123 | |
124 def _resetWarningFilters(passthrough, addedFilters): | |
125 for f in addedFilters: | |
126 try: | |
127 warnings.filters.remove(f) | |
128 except ValueError: | |
129 pass | |
130 return passthrough | |
131 | |
132 | |
133 def runWithWarningsSuppressed(suppressedWarnings, f, *a, **kw): | |
134 """Run the function C{f}, but with some warnings suppressed. | |
135 | |
136 @param suppressedWarnings: A list of arguments to pass to filterwarnings. | |
137 Must be a sequence of 2-tuples (args, kwargs). | |
138 @param f: A callable, followed by its arguments and keyword arguments | |
139 """ | |
140 for args, kwargs in suppressedWarnings: | |
141 warnings.filterwarnings(*args, **kwargs) | |
142 addedFilters = warnings.filters[:len(suppressedWarnings)] | |
143 try: | |
144 result = f(*a, **kw) | |
145 except: | |
146 exc_info = sys.exc_info() | |
147 _resetWarningFilters(None, addedFilters) | |
148 raise exc_info[0], exc_info[1], exc_info[2] | |
149 else: | |
150 if isinstance(result, defer.Deferred): | |
151 result.addBoth(_resetWarningFilters, addedFilters) | |
152 else: | |
153 _resetWarningFilters(None, addedFilters) | |
154 return result | |
155 | |
156 | |
157 def suppressWarnings(f, *suppressedWarnings): | |
158 """ | |
159 Wrap C{f} in a callable which suppresses the indicated warnings before | |
160 invoking C{f} and unsuppresses them afterwards. If f returns a Deferred, | |
161 warnings will remain suppressed until the Deferred fires. | |
162 """ | |
163 def warningSuppressingWrapper(*a, **kw): | |
164 return runWithWarningsSuppressed(suppressedWarnings, f, *a, **kw) | |
165 return tputil.mergeFunctionMetadata(f, warningSuppressingWrapper) | |
166 | |
167 | |
168 __all__ = [ | |
169 "runWithWarningsSuppressed", "suppressWarnings", | |
170 | |
171 "getProcessOutput", "getProcessValue", "getProcessOutputAndValue", | |
172 ] | |
OLD | NEW |