| 697 | return self |
| 698 | |
| 699 | async def __aexit__(self, *exc_details): |
| 700 | exc = exc_details[1] |
| 701 | received_exc = exc is not None |
| 702 | |
| 703 | # We manipulate the exception state so it behaves as though |
| 704 | # we were actually nesting multiple with statements |
| 705 | frame_exc = sys.exception() |
| 706 | def _fix_exception_context(new_exc, old_exc): |
| 707 | # Context may not be correct, so find the end of the chain |
| 708 | while 1: |
| 709 | exc_context = new_exc.__context__ |
| 710 | if exc_context is None or exc_context is old_exc: |
| 711 | # Context is already set correctly (see issue 20317) |
| 712 | return |
| 713 | if exc_context is frame_exc: |
| 714 | break |
| 715 | new_exc = exc_context |
| 716 | # Change the end of the chain to point to the exception |
| 717 | # we expect it to reference |
| 718 | new_exc.__context__ = old_exc |
| 719 | |
| 720 | # Callbacks are invoked in LIFO order to match the behaviour of |
| 721 | # nested context managers |
| 722 | suppressed_exc = False |
| 723 | pending_raise = False |
| 724 | while self._exit_callbacks: |
| 725 | is_sync, cb = self._exit_callbacks.pop() |
| 726 | try: |
| 727 | if exc is None: |
| 728 | exc_details = None, None, None |
| 729 | else: |
| 730 | exc_details = type(exc), exc, exc.__traceback__ |
| 731 | if is_sync: |
| 732 | cb_suppress = cb(*exc_details) |
| 733 | else: |
| 734 | cb_suppress = await cb(*exc_details) |
| 735 | |
| 736 | if cb_suppress: |
| 737 | suppressed_exc = True |
| 738 | pending_raise = False |
| 739 | exc = None |
| 740 | except BaseException as new_exc: |
| 741 | # simulate the stack of exceptions by setting the context |
| 742 | _fix_exception_context(new_exc, exc) |
| 743 | pending_raise = True |
| 744 | exc = new_exc |
| 745 | |
| 746 | if pending_raise: |
| 747 | try: |
| 748 | # bare "raise exc" replaces our carefully |
| 749 | # set-up context |
| 750 | fixed_ctx = exc.__context__ |
| 751 | raise exc |
| 752 | except BaseException: |
| 753 | exc.__context__ = fixed_ctx |
| 754 | raise |
| 755 | return received_exc and suppressed_exc |
| 756 | |