diff --git a/python/ray/_private/runtime_env/validation.py b/python/ray/_private/runtime_env/validation.py index 0bc2a6097..0e41bb6b3 100644 --- a/python/ray/_private/runtime_env/validation.py +++ b/python/ray/_private/runtime_env/validation.py @@ -144,6 +144,27 @@ def parse_and_validate_container(container: List[str], return container +def parse_and_validate_excludes(excludes: List[str], + is_task_or_actor: bool = False) -> List[str]: + """Parses and validates a user-provided 'excludes' option. + + This is validated to verify that it is of type List[str]. + + If an empty list is passed, we return `None` for consistency. + """ + assert excludes is not None + + if isinstance(excludes, list) and len(excludes) == 0: + return None + + if (isinstance(excludes, list) + and all(isinstance(path, str) for path in excludes)): + return excludes + else: + raise TypeError("runtime_env['excludes'] must be of type " + f"List[str], got {type(excludes)}") + + def parse_and_validate_env_vars(env_vars: Dict[str, str], is_task_or_actor: bool = False ) -> Optional[Dict[str, str]]: @@ -170,6 +191,7 @@ def parse_and_validate_env_vars(env_vars: Dict[str, str], # validate them. OPTION_TO_VALIDATION_FN = { "working_dir": parse_and_validate_working_dir, + "excludes": parse_and_validate_excludes, "conda": parse_and_validate_conda, "pip": parse_and_validate_pip, "uris": parse_and_validate_uris, diff --git a/python/ray/tests/test_runtime_env_validation.py b/python/ray/tests/test_runtime_env_validation.py index dd73db1c3..1f3fc254c 100644 --- a/python/ray/tests/test_runtime_env_validation.py +++ b/python/ray/tests/test_runtime_env_validation.py @@ -6,8 +6,9 @@ from pathlib import Path import yaml from ray._private.runtime_env.validation import ( - parse_and_validate_working_dir, parse_and_validate_conda, - parse_and_validate_pip, parse_and_validate_env_vars, ParsedRuntimeEnv, + parse_and_validate_excludes, parse_and_validate_working_dir, + parse_and_validate_conda, parse_and_validate_pip, + parse_and_validate_env_vars, ParsedRuntimeEnv, override_task_or_actor_runtime_env) CONDA_DICT = {"dependencies": ["pip", {"pip": ["pip-install-test==0.5"]}]} @@ -83,6 +84,24 @@ class TestValidateWorkingDir: }, is_task_or_actor=True) +class TestValidateExcludes: + def test_validate_excludes_invalid_types(self): + with pytest.raises(TypeError): + parse_and_validate_excludes(1) + + with pytest.raises(TypeError): + parse_and_validate_excludes(True) + + with pytest.raises(TypeError): + parse_and_validate_excludes("string") + + with pytest.raises(TypeError): + parse_and_validate_excludes(["string", 1]) + + def test_validate_excludes_empty_list(self): + assert ParsedRuntimeEnv({"excludes": []}) == {} + + @pytest.mark.skipif( sys.platform == "win32", reason="Conda option not supported on Windows.") class TestValidateConda: