@@ -107,19 +107,29 @@ def block_from_thread(d):
107
107
return blockingCallFromThread (_instances .reactor , lambda x : x , d )
108
108
109
109
110
- @decorator .decorator
111
- def inlineCallbacks (fun , * args , ** kw ):
112
- # TODO: it presumably doesn't matter but i really dislike how this
113
- # creates a new inlineCallbacks for each call. but, that's
114
- # a pretty irrelevant concern given that 1) it is just a function
115
- # call overhead and 2) lots of tests are only called once anyways.
116
- # but, this gets the feeling out of my head...
117
- return defer .inlineCallbacks (fun )(* args , ** kw )
110
+ def decorator_apply (dec , func ):
111
+ """
112
+ Decorate a function by preserving the signature even if dec
113
+ is not a signature-preserving decorator.
118
114
115
+ https://github.com/micheles/decorator/blob/55a68b5ef1951614c5c37a6d201b1f3b804dbce6/docs/documentation.md#dealing-with-third-party-decorators
116
+ """
117
+ return decorator .FunctionMaker .create (
118
+ func , 'return decfunc(%(signature)s)' ,
119
+ dict (decfunc = dec (func )), __wrapped__ = func )
119
120
120
- @decorator .decorator
121
- def ensureDeferred (fun , * args , ** kw ):
122
- return defer .ensureDeferred (fun (* args , ** kw ))
121
+
122
+ def inlineCallbacks (f ):
123
+ decorated = decorator_apply (defer .inlineCallbacks , f )
124
+ _set_mark (o = decorated , mark = 'inline_callbacks_test' )
125
+
126
+ return decorated
127
+
128
+
129
+ def ensureDeferred (f ):
130
+ _set_mark (o = f , mark = 'async_test' )
131
+
132
+ return f
123
133
124
134
125
135
def init_twisted_greenlet ():
@@ -140,6 +150,14 @@ def stop_twisted_greenlet():
140
150
_instances .gr_twisted .switch ()
141
151
142
152
153
+ def _get_mark (o , default = None ):
154
+ return getattr (o , _mark_attribute_name , default )
155
+
156
+
157
+ def _set_mark (o , mark ):
158
+ setattr (o , _mark_attribute_name , mark )
159
+
160
+
143
161
def _marked_async_fixture (mark ):
144
162
@functools .wraps (pytest .fixture )
145
163
def fixture (* args , ** kwargs ):
@@ -154,7 +172,7 @@ def fixture(*args, **kwargs):
154
172
raise AsyncFixtureUnsupportedScopeError .from_scope (scope = scope )
155
173
156
174
def decorator (f ):
157
- setattr ( f , _mark_attribute_name , mark )
175
+ _set_mark ( f , mark )
158
176
result = pytest .fixture (* args , ** kwargs )(f )
159
177
160
178
return result
@@ -172,15 +190,15 @@ def decorator(f):
172
190
def pytest_fixture_setup (fixturedef , request ):
173
191
"""Interface pytest to async setup for async and async yield fixtures."""
174
192
# TODO: what about _adding_ inlineCallbacks fixture support?
175
- maybe_mark = getattr (fixturedef .func , _mark_attribute_name , None )
193
+ maybe_mark = _get_mark (fixturedef .func )
176
194
if maybe_mark is None :
177
195
return None
178
196
179
197
mark = maybe_mark
180
198
181
199
run_inline_callbacks (_async_pytest_fixture_setup , fixturedef , request , mark )
182
200
183
- return True
201
+ return not None
184
202
185
203
186
204
@defer .inlineCallbacks
@@ -284,7 +302,7 @@ def pytest_pyfunc_call(pyfuncitem):
284
302
"""Interface to async test call handler."""
285
303
# TODO: only handle 'our' tests? what is the point of handling others?
286
304
run_inline_callbacks (_async_pytest_pyfunc_call , pyfuncitem )
287
- return True
305
+ return not None
288
306
289
307
290
308
@defer .inlineCallbacks
@@ -295,7 +313,16 @@ def _async_pytest_pyfunc_call(pyfuncitem):
295
313
for name , value in pyfuncitem .funcargs .items ()
296
314
if name in pyfuncitem ._fixtureinfo .argnames
297
315
}
298
- result = yield pyfuncitem .obj (** kwargs )
316
+
317
+ maybe_mark = _get_mark (pyfuncitem .obj )
318
+ if maybe_mark == 'async_test' :
319
+ result = yield defer .ensureDeferred (pyfuncitem .obj (** kwargs ))
320
+ elif maybe_mark == 'inline_callbacks_test' :
321
+ result = yield pyfuncitem .obj (** kwargs )
322
+ else :
323
+ # TODO: maybe deprecate this
324
+ result = yield pyfuncitem .obj (** kwargs )
325
+
299
326
defer .returnValue (result )
300
327
301
328
0 commit comments