| 566 | return self |
| 567 | |
| 568 | def __exit__(self, *exc_details): |
| 569 | exc = exc_details[1] |
| 570 | received_exc = exc is not None |
| 571 | |
| 572 | # We manipulate the exception state so it behaves as though |
| 573 | # we were actually nesting multiple with statements |
| 574 | frame_exc = sys.exception() |
| 575 | def _fix_exception_context(new_exc, old_exc): |
| 576 | # Context may not be correct, so find the end of the chain |
| 577 | while 1: |
| 578 | exc_context = new_exc.__context__ |
| 579 | if exc_context is None or exc_context is old_exc: |
| 580 | # Context is already set correctly (see issue 20317) |
| 581 | return |
| 582 | if exc_context is frame_exc: |
| 583 | break |
| 584 | new_exc = exc_context |
| 585 | # Change the end of the chain to point to the exception |
| 586 | # we expect it to reference |
| 587 | new_exc.__context__ = old_exc |
| 588 | |
| 589 | # Callbacks are invoked in LIFO order to match the behaviour of |
| 590 | # nested context managers |
| 591 | suppressed_exc = False |
| 592 | pending_raise = False |
| 593 | while self._exit_callbacks: |
| 594 | is_sync, cb = self._exit_callbacks.pop() |
| 595 | assert is_sync |
| 596 | try: |
| 597 | if exc is None: |
| 598 | exc_details = None, None, None |
| 599 | else: |
| 600 | exc_details = type(exc), exc, exc.__traceback__ |
| 601 | if cb(*exc_details): |
| 602 | suppressed_exc = True |
| 603 | pending_raise = False |
| 604 | exc = None |
| 605 | except BaseException as new_exc: |
| 606 | # simulate the stack of exceptions by setting the context |
| 607 | _fix_exception_context(new_exc, exc) |
| 608 | pending_raise = True |
| 609 | exc = new_exc |
| 610 | |
| 611 | if pending_raise: |
| 612 | try: |
| 613 | # bare "raise exc" replaces our carefully |
| 614 | # set-up context |
| 615 | fixed_ctx = exc.__context__ |
| 616 | raise exc |
| 617 | except BaseException: |
| 618 | exc.__context__ = fixed_ctx |
| 619 | raise |
| 620 | return received_exc and suppressed_exc |
| 621 | |
| 622 | def close(self): |
| 623 | """Immediately unwind the context stack.""" |