| 589 | |
| 590 | @functools.wraps(coro) |
| 591 | def post_coroutine(self, *args, **kwargs): |
| 592 | # type: (AsyncTestCase, *Any, **Any) -> None |
| 593 | try: |
| 594 | return self.io_loop.run_sync( |
| 595 | functools.partial(coro, self, *args, **kwargs), timeout=timeout |
| 596 | ) |
| 597 | except TimeoutError as e: |
| 598 | # run_sync raises an error with an unhelpful traceback. |
| 599 | # If the underlying generator is still running, we can throw the |
| 600 | # exception back into it so the stack trace is replaced by the |
| 601 | # point where the test is stopped. The only reason the generator |
| 602 | # would not be running would be if it were cancelled, which means |
| 603 | # a native coroutine, so we can rely on the cr_running attribute. |
| 604 | if self._test_generator is not None and getattr( |
| 605 | self._test_generator, "cr_running", True |
| 606 | ): |
| 607 | self._test_generator.throw(type(e), e) |
| 608 | # In case the test contains an overly broad except |
| 609 | # clause, we may get back here. |
| 610 | # Coroutine was stopped or didn't raise a useful stack trace, |
| 611 | # so re-raise the original exception which is better than nothing. |
| 612 | raise |
| 613 | |
| 614 | return post_coroutine |
| 615 | |