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.twcompat import implements
15 __implements__ = IFoo,
18 from buildbot.tcompat import Interface
22 from buildbot.tcompat import providedBy
23 assert providedBy(obj, IFoo)
28 from twisted
.copyright
import version
29 from twisted
.python
import components
31 # does our Twisted use zope.interface?
33 if hasattr(components
, "interface"):
35 from zope
.interface
import implements
36 from zope
.interface
import Interface
37 def providedBy(obj
, iface
):
38 return iface
.providedBy(obj
)
41 from twisted
.python
.components
import Interface
42 providedBy
= components
.implements
44 # are we using a version of Trial that allows setUp/testFoo/tearDown to
46 oldtrial
= version
.startswith("1.3")
48 # use this at the end of setUp/testFoo/tearDown methods
49 def maybeWait(d
, timeout
="none"):
50 from twisted
.python
import failure
51 from twisted
.trial
import unittest
53 # this is required for oldtrial (twisted-1.3.0) compatibility. When we
54 # move to retrial (twisted-2.0.0), replace these with a simple 'return
58 unittest
.deferredResult(d
)
60 unittest
.deferredResult(d
, timeout
)
61 except failure
.Failure
, f
:
62 if f
.check(unittest
.SkipTest
):
68 # waitForDeferred and getProcessOutputAndValue are twisted-2.0 things. If
69 # we're running under 1.3, patch them into place. These versions are copied
70 # from twisted somewhat after 2.0.1 .
72 from twisted
.internet
import defer
73 if not hasattr(defer
, 'waitForDeferred'):
74 Deferred
= defer
.Deferred
75 class waitForDeferred
:
77 API Stability: semi-stable
79 Maintainer: U{Christopher Armstrong<mailto:radix@twistedmatrix.com>}
81 waitForDeferred and deferredGenerator help you write
82 Deferred-using code that looks like it's blocking (but isn't
83 really), with the help of generators.
85 There are two important functions involved: waitForDeferred, and
89 thing = waitForDeferred(makeSomeRequestResultingInDeferred())
91 thing = thing.getResult()
92 print thing #the result! hoorj!
93 thingummy = deferredGenerator(thingummy)
95 waitForDeferred returns something that you should immediately yield;
96 when your generator is resumed, calling thing.getResult() will either
97 give you the result of the Deferred if it was a success, or raise an
98 exception if it was a failure.
100 deferredGenerator takes one of these waitForDeferred-using
101 generator functions and converts it into a function that returns a
102 Deferred. The result of the Deferred will be the last
103 value that your generator yielded (remember that 'return result' won't
104 work; use 'yield result; return' in place of that).
106 Note that not yielding anything from your generator will make the
107 Deferred result in None. Yielding a Deferred from your generator
108 is also an error condition; always yield waitForDeferred(d)
111 The Deferred returned from your deferred generator may also
112 errback if your generator raised an exception.
115 thing = waitForDeferred(makeSomeRequestResultingInDeferred())
117 thing = thing.getResult()
118 if thing == 'I love Twisted':
119 # will become the result of the Deferred
120 yield 'TWISTED IS GREAT!'
123 # will trigger an errback
124 raise Exception('DESTROY ALL LIFE')
125 thingummy = deferredGenerator(thingummy)
127 Put succinctly, these functions connect deferred-using code with this
128 'fake blocking' style in both directions: waitForDeferred converts from
129 a Deferred to the 'blocking' style, and deferredGenerator converts from
130 the 'blocking' style to a Deferred.
132 def __init__(self
, d
):
133 if not isinstance(d
, Deferred
):
134 raise TypeError("You must give waitForDeferred a Deferred. You gave it %r." % (d
,))
138 if hasattr(self
, 'failure'):
139 self
.failure
.raiseException()
142 def _deferGenerator(g
, deferred
=None, result
=None):
144 See L{waitForDeferred}.
148 deferred
= defer
.Deferred()
151 except StopIteration:
152 deferred
.callback(result
)
158 # Deferred.callback(Deferred) raises an error; we catch this case
159 # early here and give a nicer error message to the user in case
160 # they yield a Deferred. Perhaps eventually these semantics may
162 if isinstance(result
, defer
.Deferred
):
163 return defer
.fail(TypeError("Yield waitForDeferred(d), not d!"))
165 if isinstance(result
, waitForDeferred
):
167 # Pass vars in so they don't get changed going around the loop
168 def gotResult(r
, waiting
=waiting
, result
=result
):
174 _deferGenerator(g
, deferred
, r
)
175 def gotError(f
, waiting
=waiting
, result
=result
):
181 _deferGenerator(g
, deferred
, f
)
182 result
.d
.addCallbacks(gotResult
, gotError
)
184 # Haven't called back yet, set flag so that we get reinvoked
185 # and return from the loop
191 def func_metamerge(f
, g
):
193 Merge function metadata from f -> g and return g
196 g
.__doc
__ = f
.__doc
__
197 g
.__dict
__.update(f
.__dict
__)
198 g
.__name
__ = f
.__name
__
199 except (TypeError, AttributeError):
203 def deferredGenerator(f
):
205 See L{waitForDeferred}.
207 def unwindGenerator(*args
, **kwargs
):
208 return _deferGenerator(f(*args
, **kwargs
))
209 return func_metamerge(f
, unwindGenerator
)
211 defer
.waitForDeferred
= waitForDeferred
212 defer
.deferredGenerator
= deferredGenerator
214 from twisted
.internet
import utils
215 if not hasattr(utils
, "getProcessOutputAndValue"):
216 from twisted
.internet
import reactor
, protocol
217 _callProtocolWithDeferred
= utils
._callProtocolWithDeferred
224 class _EverythingGetter(protocol
.ProcessProtocol
):
226 def __init__(self
, deferred
):
227 self
.deferred
= deferred
228 self
.outBuf
= StringIO
.StringIO()
229 self
.errBuf
= StringIO
.StringIO()
230 self
.outReceived
= self
.outBuf
.write
231 self
.errReceived
= self
.errBuf
.write
233 def processEnded(self
, reason
):
234 out
= self
.outBuf
.getvalue()
235 err
= self
.errBuf
.getvalue()
239 self
.deferred
.errback((out
, err
, e
.signal
))
241 self
.deferred
.callback((out
, err
, code
))
243 def getProcessOutputAndValue(executable
, args
=(), env
={}, path
='.',
245 """Spawn a process and returns a Deferred that will be called back
246 with its output (from stdout and stderr) and it's exit code as (out,
247 err, code) If a signal is raised, the Deferred will errback with the
248 stdout and stderr up to that point, along with the signal, as (out,
251 return _callProtocolWithDeferred(_EverythingGetter
,
252 executable
, args
, env
, path
,
254 utils
.getProcessOutputAndValue
= getProcessOutputAndValue
257 # copied from Twisted circa 2.2.0
258 def _which(name
, flags
=os
.X_OK
):
259 """Search PATH for executable files with the given name.
262 @param name: The name for which to search.
265 @param flags: Arguments to L{os.access}.
268 @return: A list of the full paths to files found, in the
269 order in which they were found.
272 exts
= filter(None, os
.environ
.get('PATHEXT', '').split(os
.pathsep
))
273 for p
in os
.environ
['PATH'].split(os
.pathsep
):
274 p
= os
.path
.join(p
, name
)
275 if os
.access(p
, flags
):
279 if os
.access(pext
, flags
):
285 from twisted
.python
.procutils
import which