Files
ray-project--ray/python/ray/tests/test_baseexceptionandgroup.py
T
2026-07-13 13:17:40 +08:00

309 lines
8.3 KiB
Python

import sys
from textwrap import dedent
import pytest
import ray
from ray.exceptions import (
ActorDiedError,
RayTaskError,
TaskCancelledError,
WorkerCrashedError,
)
def test_baseexception_task(ray_start_regular_shared):
class MyBaseException(BaseException):
pass
@ray.remote
def task():
raise MyBaseException("abc")
with pytest.raises(MyBaseException):
ray.get(task.remote())
def test_baseexception_actor_task(ray_start_regular_shared):
class MyBaseException(BaseException):
pass
@ray.remote
class Actor:
def f(self):
raise MyBaseException("abc")
async def async_f(self):
raise MyBaseException("abc")
a = Actor.remote()
with pytest.raises(MyBaseException):
ray.get(a.f.remote())
with pytest.raises(MyBaseException):
ray.get(a.async_f.remote())
def test_baseexception_actor_creation(ray_start_regular_shared):
class MyBaseException(BaseException):
pass
@ray.remote
class Actor:
def __init__(self):
raise MyBaseException("abc")
with pytest.raises(ActorDiedError) as e:
a = Actor.remote()
ray.get(a.__ray_ready__.remote())
assert "MyBaseException" in str(e.value)
def test_baseexception_streaming_generator(ray_start_regular_shared):
class MyBaseException(BaseException):
pass
@ray.remote
def raise_at_beginning():
raise MyBaseException("rip")
yield 1
raise_at_beginning_ref = raise_at_beginning.remote()
with pytest.raises(MyBaseException):
ray.get(next(raise_at_beginning_ref))
@ray.remote
def raise_at_middle():
for i in range(1, 10):
if i == 5:
raise MyBaseException("rip")
yield i
raise_at_middle_ref = raise_at_middle.remote()
for i in range(1, 5):
assert i == ray.get(next(raise_at_middle_ref))
with pytest.raises(MyBaseException):
ray.get(next(raise_at_middle_ref))
@ray.remote(_generator_backpressure_num_objects=1)
def raise_after_backpressure():
for i in range(1, 10):
if i == 5:
raise MyBaseException("rip")
yield i
raise_after_backpressure_ref = raise_after_backpressure.remote()
for i in range(1, 5):
assert i == ray.get(next(raise_after_backpressure_ref))
with pytest.raises(MyBaseException):
ray.get(next(raise_after_backpressure_ref))
def test_raise_system_exit(ray_start_regular_shared):
@ray.remote
def task():
raise SystemExit("abc")
with pytest.raises(WorkerCrashedError):
ray.get(task.remote())
def test_raise_keyboard_interrupt(ray_start_regular_shared):
@ray.remote
def task():
raise KeyboardInterrupt("abc")
with pytest.raises(TaskCancelledError):
ray.get(task.remote())
skip_if_python_less_than_3_11 = pytest.mark.skipif(
sys.version_info < (3, 11),
reason="ExceptionGroup is only available in Python 3.11+",
)
@skip_if_python_less_than_3_11
def test_baseexceptiongroup_task(ray_start_regular_shared):
baseexceptiongroup = BaseExceptionGroup( # noqa: F821
"test baseexceptiongroup", [BaseException("abc")]
)
@ray.remote
def task():
raise baseexceptiongroup
with pytest.raises(ray.exceptions.RayTaskError): # noqa: F821
ray.get(task.remote())
@skip_if_python_less_than_3_11
def test_baseexceptiongroup_actor(ray_start_regular_shared):
baseexceptiongroup = BaseExceptionGroup( # noqa: F821
"test baseexceptiongroup", [BaseException("abc")]
)
@ray.remote
class Actor:
def f(self):
raise baseexceptiongroup
with pytest.raises(ray.exceptions.RayTaskError): # noqa: F821
a = Actor.remote()
ray.get(a.f.remote())
@skip_if_python_less_than_3_11
def test_except_exceptiongroup(ray_start_regular_shared):
exceptiongroup = ExceptionGroup( # noqa: F821
"test exceptiongroup", [ValueError(), TypeError()]
)
@ray.remote
def task():
raise exceptiongroup
@ray.remote
class Actor:
def f(self):
raise exceptiongroup
try:
ray.get(task.remote())
except Exception as ex:
assert isinstance(ex, RayTaskError)
assert isinstance(ex, ExceptionGroup) # noqa: F821
assert len(ex.exceptions) == 2
assert isinstance(ex.exceptions[0], ValueError)
assert isinstance(ex.exceptions[1], TypeError)
try:
a = Actor.remote()
ray.get(a.f.remote())
except Exception as ex:
assert isinstance(ex, RayTaskError)
assert isinstance(ex, ExceptionGroup) # noqa: F821
assert len(ex.exceptions) == 2
assert isinstance(ex.exceptions[0], ValueError)
assert isinstance(ex.exceptions[1], TypeError)
@skip_if_python_less_than_3_11
def test_except_star_exception(ray_start_regular_shared):
@ray.remote
def task():
raise ValueError
@ray.remote
class Actor:
def f(self):
raise ValueError
# TODO: Don't use exec() when we only support Python 3.11+
# Here the exec() is used to avoid SyntaxError for except* for Python < 3.11
python_code = dedent(
"""\
try:
ray.get(task.remote())
except* RayTaskError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], RayTaskError)
assert isinstance(ex.exceptions[0], ValueError)
try:
ray.get(task.remote())
except* ValueError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], RayTaskError)
assert isinstance(ex.exceptions[0], ValueError)
try:
a = Actor.remote()
ray.get(a.f.remote())
except* RayTaskError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], RayTaskError)
assert isinstance(ex.exceptions[0], ValueError)
try:
a = Actor.remote()
ray.get(a.f.remote())
except* ValueError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], RayTaskError)
assert isinstance(ex.exceptions[0], ValueError)
"""
)
exec(python_code)
@skip_if_python_less_than_3_11
def test_except_star_exceptiongroup(ray_start_regular_shared):
exceptiongroup = ExceptionGroup( # noqa: F821
"test exceptiongroup", [ValueError(), TypeError()]
)
@ray.remote
def task():
raise exceptiongroup
@ray.remote
class Actor:
def f(self):
raise exceptiongroup
# TODO: Don't use exec() when we only support Python 3.11+
# Here the exec() is used to avoid SyntaxError for except* for Python < 3.11
python_code = dedent(
"""\
try:
ray.get(task.remote())
except* RayTaskError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 2
assert isinstance(ex.exceptions[0], ValueError)
assert isinstance(ex.exceptions[1], TypeError)
try:
ray.get(task.remote())
except* ValueError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], ValueError)
except* TypeError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], TypeError)
try:
a = Actor.remote()
ray.get(a.f.remote())
except* RayTaskError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 2
assert isinstance(ex.exceptions[0], ValueError)
assert isinstance(ex.exceptions[1], TypeError)
try:
a = Actor.remote()
ray.get(a.f.remote())
except* ValueError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], ValueError)
except* TypeError as ex:
assert isinstance(ex, ExceptionGroup)
assert len(ex.exceptions) == 1
assert isinstance(ex.exceptions[0], TypeError)
"""
)
exec(python_code)
if __name__ == "__main__":
sys.exit(pytest.main(["-sv", __file__]))