1
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
# Author: Clark Evans (cce@clarkevans.com)
10
This module provides the wrap() function in the flow module and
11
the private classes used for its implementation.
15
from twisted.python.failure import Failure
16
from twisted.internet.defer import Deferred
19
""" Wrapper for a string object; don't create directly use flow.wrap
21
This is probably the simplest stage of all. It is a
22
constant list of one item. See wrap for an example.
25
def __init__(self, str):
27
self.results.append(str)
33
""" Wrapper for lists and tuple objects; don't create directly
35
A simple stage, which admits the usage of instructions,
36
such as Cooperate() within the list. This would be
37
much simpler without logic to handle instructions.
40
def __init__(self, seq):
47
if isinstance(result, Instruction):
49
self.results.append(result)
52
class _DeferredInstruction(CallLater):
53
def __init__(self, deferred):
54
self.deferred = deferred
55
def callLater(self, callable):
56
self.deferred.addBoth(callable)
58
class _Iterable(Stage):
59
""" Wrapper for iterable objects, pass in a next() function
61
This wraps functions (or bound methods). Execution starts with
62
the initial function. If the return value is a Stage, then
63
control passes on to that stage for the next round of execution.
64
If the return value is Cooperate, then the chain of Stages is
65
put on hold, and this return value travels all the way up the
66
call stack so that the underlying mechanism can sleep, or
67
perform other tasks, etc. All other non-Instruction return
68
values, Failure objects included, are passed back to the
69
previous stage via self.result
71
All exceptions signal the end of the Stage. StopIteration
72
means to stop without providing a result, while all other
73
exceptions provide a Failure self.result followed by stoppage.
76
def __init__(self, iterable, *trap):
77
Stage.__init__(self, *trap)
78
self._iterable = iter(iterable)
82
""" executed during a yield statement """
83
if self.results or self.stop or self.failure:
88
instruction = next._yield()
93
result = self._iterable.next()
94
if isinstance(result, Instruction):
95
if isinstance(result, Stage):
99
if isinstance(result, Deferred):
102
return _DeferredInstruction(result)
103
self.results.append(result)
104
except StopIteration:
106
except Failure, fail:
109
self.failure = Failure()
112
class _Deferred(Stage):
113
""" Wraps a Deferred object into a stage; create with flow.wrap
115
This stage provides a callback 'catch' for errback and
116
callbacks. If not called, then this returns an Instruction
117
which will let the reactor execute other operations, such
118
as the producer for this deferred.
121
def __init__(self, deferred, *trap):
122
Stage.__init__(self, *trap)
124
deferred.addCallbacks(self._callback, self._errback)
125
self._cooperate = _DeferredInstruction(deferred)
127
def _callback(self, res):
131
def _errback(self, fail):
136
if self.results or self.stop or self.failure:
139
return self._cooperate
144
def wrap(obj, *trap):
146
Wraps various objects for use within a flow
148
The following example illustrates many different ways in which regular
149
objects can be wrapped by the flow module to behave in a cooperative
155
from __future__ import generators
156
from twisted.flow import flow
157
from twisted.internet import reactor, defer
159
# save this function, it is used everwhere
160
def printFlow(source):
162
source = flow.wrap(source)
166
d = flow.Deferred(printer(source))
167
d.addCallback(lambda _: reactor.stop())
173
source = ["one",flow.Cooperate(1),"two"]
178
yield flow.Cooperate()
183
reactor.callLater(1, lambda: source.callback("howdy"))
187
if isinstance(obj, Stage):
194
obj._trap = tuple(trap)
202
if typ is type([]) or typ is type(tuple()):
208
if isinstance(obj, Deferred):
209
return _Deferred(obj, *trap)
212
return _Iterable(obj, *trap)
216
raise ValueError, "A wrapper is not available for %r" % (obj,)