r"""Wraps an exception plus traceback to communicate across threads
| 688 | |
| 689 | |
| 690 | class ExceptionWrapper: |
| 691 | r"""Wraps an exception plus traceback to communicate across threads""" |
| 692 | |
| 693 | def __init__(self, exc_info=None, where="in background"): |
| 694 | # It is important that we don't store exc_info, see |
| 695 | # NOTE [ Python Traceback Reference Cycle Problem ] |
| 696 | if exc_info is None: |
| 697 | exc_info = sys.exc_info() |
| 698 | self.exc_type = exc_info[0] |
| 699 | self.exc_msg = "".join(traceback.format_exception(*exc_info)) |
| 700 | self.where = where |
| 701 | |
| 702 | def reraise(self): |
| 703 | r"""Reraises the wrapped exception in the current thread""" |
| 704 | # Format a message such as: "Caught ValueError in DataLoader worker |
| 705 | # process 2. Original Traceback:", followed by the traceback. |
| 706 | msg = f"Caught {self.exc_type.__name__} {self.where}.\nOriginal {self.exc_msg}" |
| 707 | if self.exc_type == KeyError: |
| 708 | # KeyError calls repr() on its argument (usually a dict key). This |
| 709 | # makes stack traces unreadable. It will not be changed in Python |
| 710 | # (https://bugs.python.org/issue2651), so we work around it. |
| 711 | msg = KeyErrorMessage(msg) |
| 712 | elif getattr(self.exc_type, "message", None): |
| 713 | # Some exceptions have first argument as non-str but explicitly |
| 714 | # have message field |
| 715 | raise self.exc_type(message=msg) |
| 716 | try: |
| 717 | exception = self.exc_type(msg) |
| 718 | except TypeError: |
| 719 | # If the exception takes multiple arguments, don't try to |
| 720 | # instantiate since we don't know how to |
| 721 | raise RuntimeError(msg) from None |
| 722 | raise exception |
| 723 | |
| 724 | |
| 725 | def _get_available_device_type(): |
no outgoing calls
searching dependent graphs…