(*args, **kwargs)
| 204 | |
| 205 | @functools.wraps(func) |
| 206 | def wrapper(*args, **kwargs): |
| 207 | # type: (*Any, **Any) -> Future[_T] |
| 208 | # This function is type-annotated with a comment to work around |
| 209 | # https://bitbucket.org/pypy/pypy/issues/2868/segfault-with-args-type-annotation-in |
| 210 | future = _create_future() |
| 211 | if contextvars is not None: |
| 212 | ctx_run = contextvars.copy_context().run # type: Callable |
| 213 | else: |
| 214 | ctx_run = _fake_ctx_run |
| 215 | try: |
| 216 | result = ctx_run(func, *args, **kwargs) |
| 217 | except (Return, StopIteration) as e: |
| 218 | result = _value_from_stopiteration(e) |
| 219 | except Exception: |
| 220 | future_set_exc_info(future, sys.exc_info()) |
| 221 | try: |
| 222 | return future |
| 223 | finally: |
| 224 | # Avoid circular references |
| 225 | future = None # type: ignore |
| 226 | else: |
| 227 | if isinstance(result, Generator): |
| 228 | # Inline the first iteration of Runner.run. This lets us |
| 229 | # avoid the cost of creating a Runner when the coroutine |
| 230 | # never actually yields, which in turn allows us to |
| 231 | # use "optional" coroutines in critical path code without |
| 232 | # performance penalty for the synchronous case. |
| 233 | try: |
| 234 | yielded = ctx_run(next, result) |
| 235 | except (StopIteration, Return) as e: |
| 236 | future_set_result_unless_cancelled( |
| 237 | future, _value_from_stopiteration(e) |
| 238 | ) |
| 239 | except Exception: |
| 240 | future_set_exc_info(future, sys.exc_info()) |
| 241 | else: |
| 242 | # Provide strong references to Runner objects as long |
| 243 | # as their result future objects also have strong |
| 244 | # references (typically from the parent coroutine's |
| 245 | # Runner). This keeps the coroutine's Runner alive. |
| 246 | # We do this by exploiting the public API |
| 247 | # add_done_callback() instead of putting a private |
| 248 | # attribute on the Future. |
| 249 | # (GitHub issues #1769, #2229). |
| 250 | runner = Runner(ctx_run, result, future, yielded) |
| 251 | future.add_done_callback(lambda _: runner) |
| 252 | yielded = None |
| 253 | try: |
| 254 | return future |
| 255 | finally: |
| 256 | # Subtle memory optimization: if next() raised an exception, |
| 257 | # the future's exc_info contains a traceback which |
| 258 | # includes this stack frame. This creates a cycle, |
| 259 | # which will be collected at the next full GC but has |
| 260 | # been shown to greatly increase memory usage of |
| 261 | # benchmarks (relative to the refcount-based scheme |
| 262 | # used in the absence of cycles). We can avoid the |
| 263 | # cycle by clearing the local variable after we return it. |
no test coverage detected