| 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 |