diff --git a/python/ray/tests/test_basic.py b/python/ray/tests/test_basic.py index be879caf0..c076a2f20 100644 --- a/python/ray/tests/test_basic.py +++ b/python/ray/tests/test_basic.py @@ -111,6 +111,60 @@ def test_submit_api(shutdown_only): assert ray.get([id1, id2, id3, id4]) == [0, 1, "test", 2] +def test_invalid_arguments(shutdown_only): + ray.init(num_cpus=2) + + for opt in [np.random.randint(-100, -1), np.random.uniform(0, 1)]: + with pytest.raises( + ValueError, + match="The keyword 'num_return_vals' only accepts 0 or a" + " positive integer"): + + @ray.remote(num_return_vals=opt) + def g1(): + return 1 + + for opt in [np.random.randint(-100, -2), np.random.uniform(0, 1)]: + with pytest.raises( + ValueError, + match="The keyword 'max_retries' only accepts 0, -1 or a" + " positive integer"): + + @ray.remote(max_retries=opt) + def g2(): + return 1 + + for opt in [np.random.randint(-100, -1), np.random.uniform(0, 1)]: + with pytest.raises( + ValueError, + match="The keyword 'max_calls' only accepts 0 or a positive" + " integer"): + + @ray.remote(max_calls=opt) + def g3(): + return 1 + + for opt in [np.random.randint(-100, -2), np.random.uniform(0, 1)]: + with pytest.raises( + ValueError, + match="The keyword 'max_restarts' only accepts -1, 0 or a" + " positive integer"): + + @ray.remote(max_restarts=opt) + class A1: + x = 1 + + for opt in [np.random.randint(-100, -2), np.random.uniform(0, 1)]: + with pytest.raises( + ValueError, + match="The keyword 'max_task_retries' only accepts -1, 0 or a" + " positive integer"): + + @ray.remote(max_task_retries=opt) + class A2: + x = 1 + + def test_many_fractional_resources(shutdown_only): ray.init(num_cpus=2, num_gpus=2, resources={"Custom": 2}) diff --git a/python/ray/worker.py b/python/ray/worker.py index a0a6ec849..6f87e373e 100644 --- a/python/ray/worker.py +++ b/python/ray/worker.py @@ -1665,7 +1665,21 @@ def make_decorator(num_return_vals=None, if max_task_retries is not None: raise ValueError("The keyword 'max_task_retries' is not " "allowed for remote functions.") - + if num_return_vals is not None and (not isinstance( + num_return_vals, int) or num_return_vals < 0): + raise ValueError( + "The keyword 'num_return_vals' only accepts 0 or a" + " positive integer") + if max_retries is not None and (not isinstance(max_retries, int) + or max_retries < -1): + raise ValueError( + "The keyword 'max_retries' only accepts 0, -1 or a" + " positive integer") + if max_calls is not None and (not isinstance(max_calls, int) + or max_calls < 0): + raise ValueError( + "The keyword 'max_calls' only accepts 0 or a positive" + " integer") return ray.remote_function.RemoteFunction( Language.PYTHON, function_or_class, None, num_cpus, num_gpus, memory, object_store_memory, resources, num_return_vals, @@ -1679,7 +1693,16 @@ def make_decorator(num_return_vals=None, if max_calls is not None: raise TypeError("The keyword 'max_calls' is not " "allowed for actors.") - + if max_restarts is not None and (not isinstance(max_restarts, int) + or max_restarts < -1): + raise ValueError( + "The keyword 'max_restarts' only accepts -1, 0 or a" + " positive integer") + if max_task_retries is not None and (not isinstance( + max_task_retries, int) or max_task_retries < -1): + raise ValueError( + "The keyword 'max_task_retries' only accepts -1, 0 or a" + " positive integer") return ray.actor.make_actor(function_or_class, num_cpus, num_gpus, memory, object_store_memory, resources, max_restarts, max_task_retries)