/
_yieldfromtests.py.3only
167 lines (130 loc) · 4.23 KB
/
_yieldfromtests.py.3only
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# -*- test-case-name: twisted.internet.test.test_coroutines -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for C{yield from} support in Deferreds.
These tests can only work and be imported on Python 3!
"""
import types
from twisted.internet.defer import Deferred, ensureDeferred, fail
from twisted.trial.unittest import TestCase
from twisted.internet.task import Clock
class YieldFromTests(TestCase):
"""
Tests for using Deferreds in conjunction with PEP-380.
"""
def test_ensureDeferred(self):
"""
L{ensureDeferred} will turn a coroutine into a L{Deferred}.
"""
def run():
d = Deferred()
d.callback("bar")
yield from d
res = yield from run2()
return res
def run2():
d = Deferred()
d.callback("foo")
res = yield from d
return res
# It's a generator...
r = run()
self.assertIsInstance(r, types.GeneratorType)
# Now it's a Deferred.
d = ensureDeferred(r)
self.assertIsInstance(d, Deferred)
# The Deferred has the result we want.
res = self.successResultOf(d)
self.assertEqual(res, "foo")
def test_basic(self):
"""
L{ensureDeferred} allows a function to C{yield from} a L{Deferred}.
"""
def run():
d = Deferred()
d.callback("foo")
res = yield from d
return res
d = ensureDeferred(run())
res = self.successResultOf(d)
self.assertEqual(res, "foo")
def test_exception(self):
"""
An exception in a generator wrapped with L{ensureDeferred} will cause
the returned L{Deferred} to fire with a failure.
"""
def run():
d = Deferred()
d.callback("foo")
yield from d
raise ValueError("Oh no!")
d = ensureDeferred(run())
res = self.failureResultOf(d)
self.assertEqual(type(res.value), ValueError)
self.assertEqual(res.value.args, ("Oh no!",))
def test_twoDeep(self):
"""
An exception in a generator wrapped with L{ensureDeferred} will cause
the returned L{Deferred} to fire with a failure.
"""
reactor = Clock()
sections = []
def runone():
sections.append(2)
d = Deferred()
reactor.callLater(1, d.callback, None)
yield from d
sections.append(3)
return "Yay!"
def run():
sections.append(1)
result = yield from runone()
sections.append(4)
d = Deferred()
reactor.callLater(1, d.callback, None)
yield from d
sections.append(5)
return result
d = ensureDeferred(run())
reactor.advance(0.9)
self.assertEqual(sections, [1, 2])
reactor.advance(0.1)
self.assertEqual(sections, [1, 2, 3, 4])
reactor.advance(0.9)
self.assertEqual(sections, [1, 2, 3, 4])
reactor.advance(0.1)
self.assertEqual(sections, [1, 2, 3, 4, 5])
res = self.successResultOf(d)
self.assertEqual(res, "Yay!")
def test_reraise(self):
"""
Yielding from an already failed Deferred will raise the exception.
"""
def test():
try:
yield from fail(ValueError("Boom"))
except ValueError as e:
self.assertEqual(e.args, ("Boom",))
return 1
return 0
res = self.successResultOf(ensureDeferred(test()))
self.assertEqual(res, 1)
def test_chained(self):
"""
Yielding from a paused & chained Deferred will give the result when it
has one.
"""
reactor = Clock()
def test():
d = Deferred()
d2 = Deferred()
d.addCallback(lambda ignored: d2)
d.callback(None)
reactor.callLater(0, d2.callback, "bye")
res = yield from d
return res
d = ensureDeferred(test())
reactor.advance(0.1)
res = self.successResultOf(d)
self.assertEqual(res, "bye")