Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: stacktraces for custom exception handling #3343

Merged
merged 9 commits into from
Dec 17, 2024
62 changes: 19 additions & 43 deletions src/awkward/_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from __future__ import annotations

import builtins
import sys
import threading
import warnings
from collections.abc import Callable, Collection, Iterable, Mapping
Expand Down Expand Up @@ -51,11 +49,6 @@ def __call__(self):
return self.func(*self.args, **self.kwargs)


class KeyError(builtins.KeyError):
def __str__(self):
return super(Exception, self).__str__()


class ErrorContext:
# Any other threads should get a completely independent _slate.
_slate = threading.local()
Expand All @@ -75,50 +68,33 @@ def __enter__(self):
self._slate.__dict__["__primary_context__"] = self

def __exit__(self, exception_type, exception_value, traceback):
try:
if (
exception_type is not None
and issubclass(exception_type, Exception)
and self.primary() is self
):
# Step out of the way so that another ErrorContext can become primary.
# Is this necessary to do here? (We're about to raise an exception anyway)
self._slate.__dict__.clear()
# Handle caught exception
if (
exception_type is not None
and issubclass(exception_type, Exception)
and self.primary() is self
):
self.handle_exception(exception_type, exception_value)
finally:
raise self.decorate_exception(exception_type, exception_value)
else:
# Step out of the way so that another ErrorContext can become primary.
if self.primary() is self:
self._slate.__dict__.clear()

def handle_exception(self, cls: type[E], exception: E):
if sys.version_info >= (3, 11, 0, "final"):
self.decorate_exception(cls, exception)
else:
raise self.decorate_exception(cls, exception)

def decorate_exception(self, cls: type[E], exception: E) -> Exception:
if sys.version_info >= (3, 11, 0, "final"):
if issubclass(cls, (NotImplementedError, AssertionError)):
exception.add_note(
"\n\nSee if this has been reported at https://github.com/scikit-hep/awkward/issues"
)
def _add_note(exception: E, note: str) -> E:
if hasattr(exception, "add_note"):
exception.add_note(note)
else:
exception.add_note(self.note)
exception.__notes__ = [note]
return exception
else:
new_exception: Exception
if issubclass(cls, (NotImplementedError, AssertionError)):
# Raise modified exception
new_exception = cls(
str(exception)
+ "\n\nSee if this has been reported at https://github.com/scikit-hep/awkward/issues"
)
new_exception.__cause__ = exception
elif issubclass(cls, builtins.KeyError):
new_exception = KeyError(self.format_exception(exception))
new_exception.__cause__ = exception
else:
new_exception = cls(self.format_exception(exception))
new_exception.__cause__ = exception
return new_exception

note = self.note
if issubclass(cls, (NotImplementedError, AssertionError)):
note = "\n\nSee if this has been reported at https://github.com/scikit-hep/awkward/issues"
return _add_note(exception, note)

def format_argument(self, width, value):
from awkward import contents, highlevel, record
Expand Down
Loading