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