Support accessing underlying attributes in RayTaskErrors (#9210)

This commit is contained in:
Edward Oakes
2020-07-01 10:49:38 -05:00
committed by GitHub
parent b4c0b942fe
commit 21cad5250a
3 changed files with 34 additions and 22 deletions
+2 -2
View File
@@ -486,10 +486,10 @@ cdef execute_task(
if isinstance(error, RayTaskError):
# Avoid recursive nesting of RayTaskError.
failure_object = RayTaskError(function_name, backtrace,
error.cause_cls, proctitle=title)
error.cause, proctitle=title)
else:
failure_object = RayTaskError(function_name, backtrace,
error.__class__, proctitle=title)
error, proctitle=title)
errors = []
for _ in range(c_return_ids.size()):
errors.append(failure_object)
+23 -19
View File
@@ -41,17 +41,12 @@ class RayTaskError(RayError):
retrieved from the object store, the Python method that retrieved it checks
to see if the object is a RayTaskError and if it is then an exception is
thrown propagating the error message.
Attributes:
function_name (str): The name of the function that failed and produced
the RayTaskError.
traceback_str (str): The traceback from the exception.
"""
def __init__(self,
function_name,
traceback_str,
cause_cls,
cause,
proctitle=None,
pid=None,
ip=None):
@@ -64,34 +59,43 @@ class RayTaskError(RayError):
self.ip = ip or ray.services.get_node_ip_address()
self.function_name = function_name
self.traceback_str = traceback_str
self.cause_cls = cause_cls
# TODO(edoakes): should we handle non-serializable exception objects?
self.cause = cause
assert traceback_str is not None
def as_instanceof_cause(self):
"""Returns copy that is an instance of the cause's Python class.
"""Returns an exception that is an instance of the cause's class.
The returned exception will inherit from both RayTaskError and the
cause class.
cause class and will contain all of the attributes of the cause
exception.
"""
if issubclass(RayTaskError, self.cause_cls):
cause_cls = self.cause.__class__
if issubclass(RayTaskError, cause_cls):
return self # already satisfied
if issubclass(self.cause_cls, RayError):
if issubclass(cause_cls, RayError):
return self # don't try to wrap ray internal errors
class cls(RayTaskError, self.cause_cls):
def __init__(self, function_name, traceback_str, cause_cls,
proctitle, pid, ip):
RayTaskError.__init__(self, function_name, traceback_str,
cause_cls, proctitle, pid, ip)
cause = self.cause
error_msg = str(self)
name = "RayTaskError({})".format(self.cause_cls.__name__)
class cls(RayTaskError, cause_cls):
def __init__(self):
pass
def __getattr__(self, name):
return getattr(cause, name)
def __str__(self):
return error_msg
name = "RayTaskError({})".format(cause_cls.__name__)
cls.__name__ = name
cls.__qualname__ = name
return cls(self.function_name, self.traceback_str, self.cause_cls,
self.proctitle, self.pid, self.ip)
return cls()
def __str__(self):
"""Format a RayTaskError as a string."""
+9 -1
View File
@@ -63,7 +63,12 @@ def test_failed_task(ray_start_regular):
assert False
class CustomException(ValueError):
pass
def __init__(self, msg):
super().__init__(msg)
self.field = 1
def f(self):
return 2
@ray.remote
def f():
@@ -73,9 +78,12 @@ def test_failed_task(ray_start_regular):
ray.get(f.remote())
except Exception as e:
assert "This function failed." in str(e)
assert isinstance(e, ValueError)
assert isinstance(e, CustomException)
assert isinstance(e, ray.exceptions.RayTaskError)
assert "RayTaskError(CustomException)" in repr(e)
assert e.field == 1
assert e.f() == 2
else:
# ray.get should throw an exception.
assert False