feat: Customizable Pip Installer (#5098)

Let you set "pip_installer": "pip" (or uv) to handle corner cases in install compatibilities
This commit is contained in:
William FH
2025-06-13 10:35:28 -07:00
committed by GitHub
parent 0171e9a323
commit 4548a0ebe8
6 changed files with 199 additions and 4 deletions
+126
View File
@@ -1,3 +1,4 @@
import copy
import json
import os
import pathlib
@@ -40,6 +41,7 @@ def test_validate_config():
"python_version": "3.11",
"node_version": None,
"pip_config_file": None,
"pip_installer": "auto",
"image_distro": "debian",
"dockerfile_lines": [],
"env": {},
@@ -61,6 +63,7 @@ def test_validate_config():
"python_version": "3.12",
"node_version": None,
"pip_config_file": "pipconfig.txt",
"pip_installer": "auto",
"image_distro": "debian",
"dockerfile_lines": ["ARG meow"],
"dependencies": [".", "langchain"],
@@ -216,6 +219,74 @@ def test_validate_config_image_distro():
assert config["image_distro"] == "debian"
def test_validate_config_pip_installer():
"""Test validation of pip_installer field."""
# Valid pip_installer values should work
config = validate_config(
{
"python_version": "3.11",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"pip_installer": "auto",
}
)
assert config["pip_installer"] == "auto"
config = validate_config(
{
"python_version": "3.11",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"pip_installer": "pip",
}
)
assert config["pip_installer"] == "pip"
config = validate_config(
{
"python_version": "3.11",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"pip_installer": "uv",
}
)
assert config["pip_installer"] == "uv"
# Missing pip_installer should default to "auto"
config = validate_config(
{
"python_version": "3.11",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
}
)
assert config["pip_installer"] == "auto"
# Invalid pip_installer values should raise error
with pytest.raises(click.UsageError) as exc_info:
validate_config(
{
"python_version": "3.11",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"pip_installer": "conda",
}
)
assert "Invalid pip_installer: 'conda'" in str(exc_info.value)
assert "Must be 'auto', 'pip', or 'uv'" in str(exc_info.value)
with pytest.raises(click.UsageError) as exc_info:
validate_config(
{
"python_version": "3.11",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"pip_installer": "invalid",
}
)
assert "Invalid pip_installer: 'invalid'" in str(exc_info.value)
def test_validate_config_file():
with tempfile.TemporaryDirectory() as tmpdir:
tmpdir_path = pathlib.Path(tmpdir)
@@ -799,6 +870,61 @@ WORKDIR /deps/__outer_unit_tests/unit_tests"""
assert additional_contexts == {}
def test_config_to_docker_pip_installer():
"""Test that pip_installer setting affects the generated Dockerfile."""
graphs = {"agent": "./graphs/agent.py:graph"}
base_config = {
"python_version": "3.11",
"dependencies": ["."],
"graphs": graphs,
}
# Test default (auto) behavior with UV-supporting image
config_auto = validate_config(
{**copy.deepcopy(base_config), "pip_installer": "auto"}
)
docker_auto, _ = config_to_docker(
PATH_TO_CONFIG, config_auto, "langchain/langgraph-api:0.2.47"
)
assert "uv pip install --system" in docker_auto
assert "rm /usr/bin/uv /usr/bin/uvx" in docker_auto
# Test explicit pip setting
config_pip = validate_config({**copy.deepcopy(base_config), "pip_installer": "pip"})
docker_pip, _ = config_to_docker(
PATH_TO_CONFIG, config_pip, "langchain/langgraph-api:0.2.47"
)
assert "uv pip install --system" not in docker_pip
assert "pip install" in docker_pip
assert "rm /usr/bin/uv" not in docker_pip
# Test explicit uv setting
config_uv = validate_config({**copy.deepcopy(base_config), "pip_installer": "uv"})
docker_uv, _ = config_to_docker(
PATH_TO_CONFIG, config_uv, "langchain/langgraph-api:0.2.47"
)
assert "uv pip install --system" in docker_uv
assert "rm /usr/bin/uv /usr/bin/uvx" in docker_uv
# Test auto behavior with older image (should use pip)
config_auto_old = validate_config(
{**copy.deepcopy(base_config), "pip_installer": "auto"}
)
docker_auto_old, _ = config_to_docker(
PATH_TO_CONFIG, config_auto_old, "langchain/langgraph-api:0.2.46"
)
assert "uv pip install --system" not in docker_auto_old
assert "pip install" in docker_auto_old
assert "rm /usr/bin/uv" not in docker_auto_old
# Test that missing pip_installer defaults to auto behavior
config_default = validate_config(copy.deepcopy(base_config))
docker_default, _ = config_to_docker(
PATH_TO_CONFIG, config_default, "langchain/langgraph-api:0.2.47"
)
assert "uv pip install --system" in docker_default
# config_to_compose
def test_config_to_compose_simple_config():
graphs = {"agent": "./agent.py:graph"}