Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions ado/utilities/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import logging
import os
from pathlib import Path

import ray
from packaging.requirements import Requirement
Expand Down Expand Up @@ -54,33 +55,43 @@ def extract_package_specs_from_job_env(
for requested_name in package_names:
# Search for this package in the job uv packages
for pkg_spec in job_uv_packages:
# Quick check: does the requested package name appear in this spec?
# Check the name as-is and with all dashes replaced by underscores
# Quick substring pre-filter: skip specs that clearly don't contain the name.
# Check the name as-is and with all dashes replaced by underscores.
pkg_spec_lower = pkg_spec.lower()
name_lower = requested_name.lower()
name_with_underscores = requested_name.replace("-", "_").lower()
if (
requested_name.lower() not in pkg_spec_lower
name_lower not in pkg_spec_lower
and name_with_underscores not in pkg_spec_lower
):
continue # Not a match, skip to next package

# Found a match - now parse using packaging.requirements.Requirement
# Check if it's a wheel file path
if pkg_spec.endswith(".whl") or "/" in pkg_spec:
# It's a wheel file path - can't use Requirement parser
source = pkg_spec.split("[")[0] if "[" in pkg_spec else pkg_spec
extras = None
if "[" in pkg_spec:
extras = pkg_spec.split("[", 1)[1].split("]")[0]
# Check if it's a path-like entry (wheel file or other archive).
if "/" in pkg_spec:
# Only .whl files have a parseable distribution name.
if not pkg_spec.endswith(".whl"):
continue
source, _, extras_str = pkg_spec.partition("[")
extras = extras_str.rstrip("]") or None
version = None
# Wheel filename format: {name}-{version}-{python}-{abi}-{platform}.whl
# Extract just the distribution name (first segment, normalised).
parsed_name = Path(source).stem.split("-")[0]
else:
# It's a PyPI package - use Requirement parser
# It's a PyPI package use Requirement for an exact name match.
req = Requirement(pkg_spec)
parsed_name = req.name
source = req.name
extras = ",".join(req.extras) if req.extras else None
# Convert specifier to string (e.g., "==1.2.3")
version = str(req.specifier) if req.specifier else None

# Exact name check (normalise dashes/underscores per PEP 503).
normalised_parsed = parsed_name.lower().replace("-", "_")
normalised_requested = name_lower.replace("-", "_")
if normalised_parsed != normalised_requested:
continue # Substring matched but names differ (e.g. "vllm" vs "ado-vllm-performance")

result[requested_name] = {
"source": source,
"version": version,
Expand Down
2 changes: 1 addition & 1 deletion plugins/actuators/vllm_performance/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.13.0
1.13.1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import logging
import uuid
from importlib.metadata import version
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path
from typing import Any

Expand Down Expand Up @@ -39,46 +39,34 @@


def _build_ray_runtime_env_with_extra(benchmark_tool: str) -> dict[str, list[Any]]:
packages = ["ado-core", "ado-vllm-performance", "ray", "vllm", "guidellm"]
specs = extract_package_specs_from_job_env(packages)

# Packages in this dict always use the given extras string, overriding the spec.
# Packages absent from the dict use the extras found in the spec (or none).
forced_extras: dict[str, str] = {"ado-vllm-performance": benchmark_tool}

# Check if ado-vllm-performance is in the job venv.
worker_deps = []
specs_from_job_env = extract_package_specs_from_job_env(
["ado-vllm-performance", "ado-core"]
)
for pkg in packages:
if pkg in specs:
source = specs[pkg]["source"]
pkg_version = specs[pkg].get("version") or ""
else:
try:
pkg_version = f"=={version(pkg)}"
except PackageNotFoundError:
logger.debug(
f"Package {pkg!r} not in job env and not installed locally, skipping"
)
continue
source = pkg

if "ado-core" in specs_from_job_env:
ado_source = specs_from_job_env["ado-core"]["source"]
ado_version: str | None = specs_from_job_env["ado-core"].get("version") or ""
extras = specs_from_job_env["ado-core"].get("extras")
ado_extras = f"[{extras}]" if extras else ""
else:
# If ado-core is not in the job env it means that it comes with the base and we assume
# it got installed with pypi.
# Just to be sure, we extract the version and make sure we get the same installed
# in the Ray task environment.
# Say the base image runs on an older version of ado-core, we want to avoid it to
# be upgraded to a newer version when starting the Ray task.
ado_source = "ado-core"
ado_version = f"=={version('ado-core')}"
ado_extras = ""

ado_dep = f"{ado_source}{ado_extras}{ado_version}"
worker_deps.append(ado_dep)

# Here we assume the actuator only has 'vllm' or 'guildellm' as extraw dependencies.
if "ado-vllm-performance" in specs_from_job_env:
actuator_source = specs_from_job_env["ado-vllm-performance"]["source"]
actuator_version: str | None = (
specs_from_job_env["ado-vllm-performance"].get("version") or ""
raw_extras = forced_extras.get(pkg) or (
specs[pkg].get("extras") if pkg in specs else None
)
else:
# Similarly to what we did with ado-core, we also extract the version of the
# actuator package.
actuator_source = "ado-vllm-performance"
actuator_version = f"=={version('ado-vllm-performance')}"

actuator_dep = f"{actuator_source}[{benchmark_tool}]{actuator_version}"
worker_deps.append(actuator_dep)
extras = f"[{raw_extras}]" if raw_extras else ""

worker_deps.append(f"{source}{extras}{pkg_version}")

return {"uv": worker_deps}

Expand Down
114 changes: 114 additions & 0 deletions plugins/actuators/vllm_performance/tests/test_actuator_runtime_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Copyright IBM Corporation 2025, 2026
# SPDX-License-Identifier: MIT

"""Tests for _build_ray_runtime_env_with_extra in actuator.py."""

from unittest.mock import MagicMock, patch

from ado_actuators.vllm_performance.actuator import _build_ray_runtime_env_with_extra

# Patch targets:
# RAY_CTX — where extract_package_specs_from_job_env calls Ray.
# PKG_VER — the already-imported `version` name inside the actuator module.
RAY_CTX = "ado.utilities.environment.ray.get_runtime_context"
PKG_VER = "ado_actuators.vllm_performance.actuator.version"


def _mock_runtime_context(uv_packages: list[str]) -> MagicMock:
"""Return a mock Ray runtime context with the given uv package list."""
ctx = MagicMock()
ctx.runtime_env = {"uv": {"packages": uv_packages}}
return ctx


class TestBuildRayRuntimeEnvWithExtra:
"""Unit tests for _build_ray_runtime_env_with_extra."""

def test_all_packages_from_job_env(self) -> None:
"""When all five packages are in the job env, their specs are forwarded."""
job_packages = [
"ado-core==1.0",
"ado-vllm-performance==2.0",
"ray==2.9.0",
"vllm==0.12.0",
"guidellm==0.5.0",
]
with patch(RAY_CTX, return_value=_mock_runtime_context(job_packages)):
result = _build_ray_runtime_env_with_extra("vllm")

deps = result["uv"]
assert any(d.startswith("ado-core") and "==1.0" in d for d in deps)
assert "ado-vllm-performance[vllm]==2.0" in deps
assert any(d.startswith("ray") and "==2.9.0" in d for d in deps)
assert any(d.startswith("vllm") and "==0.12.0" in d for d in deps)
assert any(d.startswith("guidellm") and "==0.5.0" in d for d in deps)

def test_benchmark_tool_extra_always_injected(self) -> None:
"""ado-vllm-performance always carries [benchmark_tool] regardless of job env."""
job_packages = ["ado-vllm-performance==2.0"]
with (
patch(RAY_CTX, return_value=_mock_runtime_context(job_packages)),
patch(PKG_VER, side_effect=lambda n: "1.0"),
):
result_vllm = _build_ray_runtime_env_with_extra("vllm")
result_guidellm = _build_ray_runtime_env_with_extra("guidellm")

assert any("[vllm]" in d for d in result_vllm["uv"])
assert any("[guidellm]" in d for d in result_guidellm["uv"])

def test_ado_core_extras_preserved_from_job_env(self) -> None:
"""ado-core extras from the job env spec are preserved."""
job_packages = ["ado-core[foo]==1.0"]
with (
patch(RAY_CTX, return_value=_mock_runtime_context(job_packages)),
patch(PKG_VER, side_effect=lambda n: "0.0"),
):
result = _build_ray_runtime_env_with_extra("vllm")

assert any("ado-core[foo]" in d for d in result["uv"])

def test_fallback_pins_installed_version_when_not_in_job_env(self) -> None:
"""When a package is absent from the job env, the installed version is pinned."""
installed = {
"ado-core": "1.1",
"ado-vllm-performance": "2.2",
"ray": "3.0",
"vllm": "0.9",
"guidellm": "0.5",
}
with (
patch(RAY_CTX, return_value=_mock_runtime_context([])),
patch(PKG_VER, side_effect=lambda n: installed[n]),
):
result = _build_ray_runtime_env_with_extra("vllm")

deps = result["uv"]
assert "ado-core==1.1" in deps
assert "ado-vllm-performance[vllm]==2.2" in deps
assert "ray==3.0" in deps
assert "vllm==0.9" in deps
assert "guidellm==0.5" in deps

def test_package_skipped_when_not_in_job_env_and_not_installed(self) -> None:
"""A package absent from both the job env and the local install is skipped silently."""
from importlib.metadata import PackageNotFoundError

job_packages = [
"ado-core==1.0",
"ado-vllm-performance==2.0",
"ray==2.9",
"vllm==0.12.0",
]

def fake_version(n: str) -> str:
if n == "guidellm":
raise PackageNotFoundError(n)
return "0.0"

with (
patch(RAY_CTX, return_value=_mock_runtime_context(job_packages)),
patch(PKG_VER, side_effect=fake_version),
):
result = _build_ray_runtime_env_with_extra("vllm")

assert not any(d.startswith("guidellm") for d in result["uv"])