From fd7c067a3fd23e263693b8e3f46605f5aebc503f Mon Sep 17 00:00:00 2001 From: hjiang Date: Thu, 7 Nov 2024 18:26:35 +0000 Subject: [PATCH 1/3] check uv existence before install Signed-off-by: hjiang --- python/ray/_private/runtime_env/uv.py | 42 +++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/python/ray/_private/runtime_env/uv.py b/python/ray/_private/runtime_env/uv.py index 5d0c5db980c9..c09757b713c5 100644 --- a/python/ray/_private/runtime_env/uv.py +++ b/python/ray/_private/runtime_env/uv.py @@ -34,6 +34,8 @@ def __init__( logger.debug("Setting up uv for runtime_env: %s", runtime_env) self._target_dir = target_dir + # An empty directory is created to execute cmd. + self._exec_cwd = os.path.join(self._target_dir, "exec_cwd") self._runtime_env = runtime_env self._logger = logger @@ -62,6 +64,28 @@ async def _install_uv( logger.info("Installing package uv to %s", virtualenv_path) await check_output_cmd(uv_install_cmd, logger=logger, cwd=cwd, env=pip_env) + # TODO(hjiang): Add an integration test for existence check after + # PR (https://github.com/ray-project/ray/pull/48619) gets merged. + async def _check_uv_existence( + self, path: str, cwd: str, env: dict, logger: logging.Logger + ) -> bool: + """Check and return the existence of `uv` in system executable path.""" + python = virtualenv_utils.get_virtualenv_python(path) + + check_existence_cmd = [ + python, + "-m", + "uv", + "version", + ] + + try: + # If `uv` doesn't exist, exception will be thrown. + await check_output_cmd(check_existence_cmd, logger=logger, cwd=cwd, env=env) + return True + except Exception: + return False + async def _install_uv_packages( self, path: str, @@ -70,13 +94,18 @@ async def _install_uv_packages( pip_env: Dict, logger: logging.Logger, ): + """Install required python packages via `uv`.""" virtualenv_path = virtualenv_utils.get_virtualenv_path(path) python = virtualenv_utils.get_virtualenv_python(path) # TODO(fyrestone): Support -i, --no-deps, --no-cache-dir, ... requirements_file = dependency_utils.get_requirements_file(path, uv_packages) + # Check existence for `uv` and see if we could skip `uv` installation. + uv_exists = await self._check_uv_existence(python, cwd, pip_env, logger) + # Install uv, which acts as the default package manager. - await self._install_uv(path, cwd, pip_env, logger) + if not uv_exists: + await self._install_uv(path, cwd, pip_env, logger) # Avoid blocking the event loop. loop = get_running_loop() @@ -109,17 +138,18 @@ async def _run(self): # We create an empty directory for exec cmd so that the cmd will # run more stable. e.g. if cwd has ray, then checking ray will # look up ray in cwd instead of site packages. - exec_cwd = os.path.join(path, "exec_cwd") - os.makedirs(exec_cwd, exist_ok=True) + os.makedirs(self._exec_cwd, exist_ok=True) try: - await virtualenv_utils.create_or_get_virtualenv(path, exec_cwd, logger) + await virtualenv_utils.create_or_get_virtualenv( + path, self._exec_cwd, logger + ) python = virtualenv_utils.get_virtualenv_python(path) - async with dependency_utils.check_ray(python, exec_cwd, logger): + async with dependency_utils.check_ray(python, self._exec_cwd, logger): # Install packages with uv. await self._install_uv_packages( path, uv_packages, - exec_cwd, + self._exec_cwd, self._uv_env, logger, ) From 0c25579343c356bdacea4e9535c59bf9981b97b9 Mon Sep 17 00:00:00 2001 From: dentiny Date: Fri, 8 Nov 2024 20:23:38 +0000 Subject: [PATCH 2/3] cleanup incorrect TODO Signed-off-by: dentiny --- python/ray/_private/runtime_env/uv.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/ray/_private/runtime_env/uv.py b/python/ray/_private/runtime_env/uv.py index 0dde3b19bda1..817acf219e66 100644 --- a/python/ray/_private/runtime_env/uv.py +++ b/python/ray/_private/runtime_env/uv.py @@ -93,8 +93,6 @@ async def _install_uv( logger.info("Installing package uv to %s", virtualenv_path) await check_output_cmd(uv_install_cmd, logger=logger, cwd=cwd, env=pip_env) - # TODO(hjiang): Add an integration test for existence check after - # PR (https://github.com/ray-project/ray/pull/48619) gets merged. async def _check_uv_existence( self, path: str, cwd: str, env: dict, logger: logging.Logger ) -> bool: From f1b5f69d0d4103ec2a2ba007bf08e374150343e6 Mon Sep 17 00:00:00 2001 From: dentiny Date: Fri, 8 Nov 2024 20:24:01 +0000 Subject: [PATCH 3/3] fix comment Signed-off-by: dentiny --- python/ray/_private/runtime_env/uv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ray/_private/runtime_env/uv.py b/python/ray/_private/runtime_env/uv.py index 817acf219e66..345c37b6c30b 100644 --- a/python/ray/_private/runtime_env/uv.py +++ b/python/ray/_private/runtime_env/uv.py @@ -96,7 +96,7 @@ async def _install_uv( async def _check_uv_existence( self, path: str, cwd: str, env: dict, logger: logging.Logger ) -> bool: - """Check and return the existence of `uv` in system executable path.""" + """Check and return the existence of `uv` in virtual env.""" python = virtualenv_utils.get_virtualenv_python(path) check_existence_cmd = [