3
print "hey python-mode, stop thinking I want 8-char indentation"
6
utilities to be compatible with both Twisted-1.3 and 2.0
8
implements. Use this like the following.
10
from buildbot.tcompat import implements
15
__implements__ = IFoo,
18
from buildbot.tcompat import Interface
22
from buildbot.tcompat import providedBy
23
assert providedBy(obj, IFoo)
26
from twisted.copyright import version
27
from twisted.python import components
29
# does our Twisted use zope.interface?
30
if hasattr(components, "interface"):
32
from zope.interface import implements
33
from zope.interface import Interface
34
def providedBy(obj, iface):
35
return iface.providedBy(obj)
39
from twisted.python.components import Interface
40
providedBy = components.implements
42
# are we using a version of Trial that allows setUp/testFoo/tearDown to
44
oldtrial = version.startswith("1.3")
46
# use this at the end of setUp/testFoo/tearDown methods
47
def maybeWait(d, timeout="none"):
48
from twisted.trial import unittest
50
# this is required for oldtrial (twisted-1.3.0) compatibility. When we
51
# move to retrial (twisted-2.0.0), replace these with a simple 'return
54
unittest.deferredResult(d)
56
unittest.deferredResult(d, timeout)
60
# waitForDeferred and getProcessOutputAndValue are twisted-2.0 things. If
61
# we're running under 1.3, patch them into place. These versions are copied
62
# from twisted somewhat after 2.0.1 .
64
from twisted.internet import defer
65
if not hasattr(defer, 'waitForDeferred'):
66
Deferred = defer.Deferred
67
class waitForDeferred:
69
API Stability: semi-stable
71
Maintainer: U{Christopher Armstrong<mailto:radix@twistedmatrix.com>}
73
waitForDeferred and deferredGenerator help you write
74
Deferred-using code that looks like it's blocking (but isn't
75
really), with the help of generators.
77
There are two important functions involved: waitForDeferred, and
81
thing = waitForDeferred(makeSomeRequestResultingInDeferred())
83
thing = thing.getResult()
84
print thing #the result! hoorj!
85
thingummy = deferredGenerator(thingummy)
87
waitForDeferred returns something that you should immediately yield;
88
when your generator is resumed, calling thing.getResult() will either
89
give you the result of the Deferred if it was a success, or raise an
90
exception if it was a failure.
92
deferredGenerator takes one of these waitForDeferred-using
93
generator functions and converts it into a function that returns a
94
Deferred. The result of the Deferred will be the last
95
value that your generator yielded (remember that 'return result' won't
96
work; use 'yield result; return' in place of that).
98
Note that not yielding anything from your generator will make the
99
Deferred result in None. Yielding a Deferred from your generator
100
is also an error condition; always yield waitForDeferred(d)
103
The Deferred returned from your deferred generator may also
104
errback if your generator raised an exception.
107
thing = waitForDeferred(makeSomeRequestResultingInDeferred())
109
thing = thing.getResult()
110
if thing == 'I love Twisted':
111
# will become the result of the Deferred
112
yield 'TWISTED IS GREAT!'
115
# will trigger an errback
116
raise Exception('DESTROY ALL LIFE')
117
thingummy = deferredGenerator(thingummy)
119
Put succinctly, these functions connect deferred-using code with this
120
'fake blocking' style in both directions: waitForDeferred converts from
121
a Deferred to the 'blocking' style, and deferredGenerator converts from
122
the 'blocking' style to a Deferred.
124
def __init__(self, d):
125
if not isinstance(d, Deferred):
126
raise TypeError("You must give waitForDeferred a Deferred. You gave it %r." % (d,))
130
if hasattr(self, 'failure'):
131
self.failure.raiseException()
134
def _deferGenerator(g, deferred=None, result=None):
136
See L{waitForDeferred}.
140
deferred = defer.Deferred()
143
except StopIteration:
144
deferred.callback(result)
150
# Deferred.callback(Deferred) raises an error; we catch this case
151
# early here and give a nicer error message to the user in case
152
# they yield a Deferred. Perhaps eventually these semantics may
154
if isinstance(result, defer.Deferred):
155
return fail(TypeError("Yield waitForDeferred(d), not d!"))
157
if isinstance(result, waitForDeferred):
159
# Pass vars in so they don't get changed going around the loop
160
def gotResult(r, waiting=waiting, result=result):
166
_deferGenerator(g, deferred, r)
167
def gotError(f, waiting=waiting, result=result):
173
_deferGenerator(g, deferred, f)
174
result.d.addCallbacks(gotResult, gotError)
176
# Haven't called back yet, set flag so that we get reinvoked
177
# and return from the loop
183
def func_metamerge(f, g):
185
Merge function metadata from f -> g and return g
188
g.__doc__ = f.__doc__
189
g.__dict__.update(f.__dict__)
190
g.__name__ = f.__name__
191
except (TypeError, AttributeError):
195
def deferredGenerator(f):
197
See L{waitForDeferred}.
199
def unwindGenerator(*args, **kwargs):
200
return _deferGenerator(f(*args, **kwargs))
201
return func_metamerge(f, unwindGenerator)
203
defer.waitForDeferred = waitForDeferred
204
defer.deferredGenerator = deferredGenerator
206
from twisted.internet import utils
207
if not hasattr(utils, "getProcessOutputAndValue"):
208
from twisted.internet import reactor, protocol
209
_callProtocolWithDeferred = utils._callProtocolWithDeferred
211
import cStringIO as StringIO
215
class _EverythingGetter(protocol.ProcessProtocol):
217
def __init__(self, deferred):
218
self.deferred = deferred
219
self.outBuf = StringIO.StringIO()
220
self.errBuf = StringIO.StringIO()
221
self.outReceived = self.outBuf.write
222
self.errReceived = self.errBuf.write
224
def processEnded(self, reason):
225
out = self.outBuf.getvalue()
226
err = self.errBuf.getvalue()
230
self.deferred.errback((out, err, e.signal))
232
self.deferred.callback((out, err, code))
234
def getProcessOutputAndValue(executable, args=(), env={}, path='.',
236
"""Spawn a process and returns a Deferred that will be called back
237
with its output (from stdout and stderr) and it's exit code as (out,
238
err, code) If a signal is raised, the Deferred will errback with the
239
stdout and stderr up to that point, along with the signal, as (out,
242
return _callProtocolWithDeferred(_EverythingGetter,
243
executable, args, env, path,
245
utils.getProcessOutputAndValue = getProcessOutputAndValue