cli: Add support for dependencies in parent directories

- Now supporting local dependencies in directories that are not contained in the docker context (ie. outside the folder containing langgraph.json)
- This is achieved by passing each parent directorty as an additional context to docker build
- This makes it a lot easier to build projects contained in monorepos where you need to include some sibling/parent folder as a dependency
- Also include additional comments in the generated dockerfile to delimit each section
This commit is contained in:
Nuno Campos
2025-02-17 11:43:55 -08:00
parent 9786be1ff7
commit 5a8624fdfd
6 changed files with 232 additions and 56 deletions
+30 -13
View File
@@ -303,7 +303,15 @@ def _build(
tag,
]
# apply config
stdin = langgraph_cli.config.config_to_docker(config, config_json, base_image)
stdin, additional_contexts = langgraph_cli.config.config_to_docker(
config, config_json, base_image
)
# add additional_contexts
if additional_contexts:
additional_contexts_str = ",".join(
f"{k}={v}" for k, v in additional_contexts.items()
)
args.extend(["--build-context", additional_contexts_str])
# run docker build
runner.run(
subp_exec(
@@ -439,20 +447,28 @@ def dockerfile(save_path: str, config: pathlib.Path, add_docker_compose: bool) -
secho("✅ Configuration validated!", fg="green")
secho(f"📝 Generating Dockerfile at {save_path}", fg="yellow")
dockerfile, additional_contexts = langgraph_cli.config.config_to_docker(
config,
config_json,
(
"langchain/langgraphjs-api"
if config_json.get("node_version")
else "langchain/langgraph-api"
),
)
with open(str(save_path), "w", encoding="utf-8") as f:
f.write(
langgraph_cli.config.config_to_docker(
config,
config_json,
(
"langchain/langgraphjs-api"
if config_json.get("node_version")
else "langchain/langgraph-api"
),
)
)
f.write(dockerfile)
secho("✅ Created: Dockerfile", fg="green")
if additional_contexts:
additional_contexts_str = ",".join(
f"{k}={v}" for k, v in additional_contexts.items()
)
secho(
f"""📝 Run docker build with these additional build contexts `--build-context {additional_contexts_str}`""",
fg="yellow",
)
if add_docker_compose:
# Add docker compose and related files
# Add .dockerignore file in the same directory as the Dockerfile
@@ -575,7 +591,7 @@ def dev(
):
"""CLI entrypoint for running the LangGraph API server."""
try:
from langgraph_api.cli import run_server
from langgraph_api.cli import run_server # type: ignore
except ImportError:
py_version_msg = ""
if sys.version_info < (3, 11):
@@ -662,6 +678,7 @@ def prepare_args_and_stdin(
debugger_base_url: Optional[str] = None,
postgres_uri: Optional[str] = None,
) -> Tuple[List[str], str]:
assert config_path.exists(), f"Config file not found: {config_path}"
# prepare args
stdin = langgraph_cli.docker.compose(
capabilities,
+91 -32
View File
@@ -2,6 +2,7 @@ import json
import os
import pathlib
import textwrap
from collections import Counter
from typing import NamedTuple, Optional, TypedDict, Union
import click
@@ -294,10 +295,10 @@ class LocalDeps(NamedTuple):
tuples. Each entry points to a local `requirements.txt` file and where
it should be placed inside the Docker container before running `pip install`.
real_pkgs: A dictionary mapping a local directory path (host side) to the
same dependency string from the config. These directories contain the
necessary files (e.g., `pyproject.toml` or `setup.py`) to be installed
as a standard Python package with pip.
real_pkgs: A dictionary mapping a local directory path (host side) to a
tuple of (dependency_string, container_package_path). These directories
contain the necessary files (e.g., `pyproject.toml` or `setup.py`) to be
installed as a standard Python package with pip.
faux_pkgs: A dictionary mapping a local directory path (host side) to a
tuple of (dependency_string, container_package_path). For these
@@ -310,16 +311,23 @@ class LocalDeps(NamedTuple):
directory. If the local dependency `"."` is present in the config, this
field captures the path where that dependency will appear in the
container (e.g., `/deps/<name>` or similar). Otherwise, it may be `None`.
additional_contexts: A list of paths to directories that contain local
dependencies in parent directories. These directories are added to the
Docker build context to ensure that the Dockerfile can access them.
"""
pip_reqs: list[tuple[str, str]]
real_pkgs: dict[pathlib.Path, str]
real_pkgs: dict[pathlib.Path, tuple[str, str]]
faux_pkgs: dict[pathlib.Path, tuple[str, str]]
# if . is in dependencies, use it as working_dir
working_dir: Optional[str] = None
# if there are local dependencies in parent directories, use additional_contexts
additional_contexts: list[pathlib.Path] = None
def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps:
config_path = config_path.resolve()
# ensure reserved package names are not used
reserved = {
"src",
@@ -336,6 +344,7 @@ def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps
"httpx",
"langsmith",
}
counter = Counter()
def check_reserved(name: str, ref: str):
if name in reserved:
@@ -348,7 +357,8 @@ def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps
pip_reqs = []
real_pkgs = {}
faux_pkgs = {}
working_dir = None
working_dir: Optional[str] = None
additional_contexts: list[pathlib.Path] = []
for local_dep in config["dependencies"]:
if not local_dep.startswith("."):
@@ -357,7 +367,7 @@ def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps
# Verify that the local dependency can be resolved
# (e.g., this would raise an informative error if a user mistyped a path).
resolved = config_path.parent / local_dep
resolved = (config_path.parent / local_dep).resolve()
# validate local dependency
if not resolved.exists():
@@ -366,25 +376,28 @@ def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps
raise NotADirectoryError(
f"Local dependency must be a directory: {resolved}"
)
elif not resolved.is_relative_to(config_path.parent):
raise ValueError(
f"Local dependency '{resolved}' must be a subdirectory of '{config_path.parent}'"
)
elif resolved == config_path.parent:
pass
elif config_path.parent not in resolved.parents:
additional_contexts.append(resolved)
# Check for pyproject.toml or setup.py
# If found, treat as a real package, if not treat as a faux package.
# For faux packages, we'll also check for presence of requirements.txt.
files = os.listdir(resolved)
if "pyproject.toml" in files:
if "pyproject.toml" in files or "setup.py" in files:
# real package
real_pkgs[resolved] = local_dep
# assign a unique folder name
container_name = resolved.name
if counter[container_name] > 0:
container_name += f"_{counter[container_name]}"
counter[container_name] += 1
# add to deps
real_pkgs[resolved] = (local_dep, container_name)
# set working_dir
if local_dep == ".":
working_dir = f"/deps/{resolved.name}"
elif "setup.py" in files:
# real package
real_pkgs[resolved] = local_dep
if local_dep == ".":
working_dir = f"/deps/{resolved.name}"
working_dir = f"/deps/{container_name}"
else:
# We could not find a pyproject.toml or setup.py, so treat as a faux package
if any(file == "__init__.py" for file in files):
@@ -428,7 +441,7 @@ def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps
)
)
return LocalDeps(pip_reqs, real_pkgs, faux_pkgs, working_dir)
return LocalDeps(pip_reqs, real_pkgs, faux_pkgs, working_dir, additional_contexts)
def _update_graph_paths(
@@ -556,7 +569,7 @@ def _update_auth_path(
def python_config_to_docker(
config_path: pathlib.Path, config: Config, base_image: str
) -> str:
) -> tuple[str, dict[str, str]]:
"""Generate a Dockerfile from the configuration."""
# configure pip
pip_install = (
@@ -591,7 +604,14 @@ def python_config_to_docker(
# https://setuptools.pypa.io/en/latest/userguide/datafiles.html#package-data
# https://til.simonwillison.net/python/pyproject
faux_pkgs_str = f"{os.linesep}{os.linesep}".join(
f"""ADD {relpath} {destpath}
(
f"""# -- Adding non-package dependency {fullpath.name} --
COPY --from=__outer_{fullpath.name} . {destpath}"""
if fullpath in local_deps.additional_contexts
else f"""# -- Adding non-package dependency {fullpath.name} --
ADD {relpath} {destpath}"""
)
+ f"""
RUN set -ex && \\
for line in '[project]' \\
'name = "{fullpath.name}"' \\
@@ -599,12 +619,20 @@ RUN set -ex && \\
'[tool.setuptools.package-data]' \\
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_{fullpath.name}/pyproject.toml; \\
done"""
done
# -- End of non-package dependency {fullpath.name} --"""
for fullpath, (relpath, destpath) in local_deps.faux_pkgs.items()
)
local_pkgs_str = os.linesep.join(
f"ADD {relpath} /deps/{fullpath.name}"
for fullpath, relpath in local_deps.real_pkgs.items()
f"""# -- Adding local package {relpath} --
COPY --from={name} . /deps/{name}
# -- End of local package {relpath} --"""
if fullpath in local_deps.additional_contexts
else f"""# -- Adding local package {relpath} --
ADD {relpath} /deps/{name}
# -- End of local package {relpath} --"""
for fullpath, (relpath, name) in local_deps.real_pkgs.items()
)
installs = f"{os.linesep}{os.linesep}".join(
@@ -638,15 +666,30 @@ RUN set -ex && \\
"",
installs,
"",
"# -- Installing all local dependencies --",
f"RUN {pip_install} -e /deps/*",
"# -- End of local dependencies install --",
os.linesep.join(env_vars),
"",
f"WORKDIR {local_deps.working_dir}" if local_deps.working_dir else "",
]
return os.linesep.join(docker_file_contents)
additional_contexts: dict[str, str] = {}
for p in local_deps.additional_contexts:
if p in local_deps.real_pkgs:
name = local_deps.real_pkgs[p][1]
elif p in local_deps.faux_pkgs:
name = f"__outer_{p.name}"
else:
raise RuntimeError(f"Unknown additional context: {p}")
additional_contexts[name] = str(p)
return os.linesep.join(docker_file_contents), additional_contexts
def node_config_to_docker(config_path: pathlib.Path, config: Config, base_image: str):
def node_config_to_docker(
config_path: pathlib.Path, config: Config, base_image: str
) -> tuple[str, dict[str, str]]:
faux_path = f"/deps/{config_path.parent.name}"
def test_file(file_name):
@@ -686,7 +729,8 @@ ENV LANGGRAPH_STORE='{json.dumps(store_config)}'
ENV LANGGRAPH_AUTH='{json.dumps(auth_config)}'
"""
return f"""FROM {base_image}:{config['node_version']}
return (
f"""FROM {base_image}:{config['node_version']}
{os.linesep.join(config["dockerfile_lines"])}
@@ -698,10 +742,14 @@ ENV LANGSERVE_GRAPHS='{json.dumps(config["graphs"])}'
WORKDIR {faux_path}
RUN (test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not found, skipping") || tsx /api/langgraph_api/js/build.mts"""
RUN (test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not found, skipping") || tsx /api/langgraph_api/js/build.mts""",
{},
)
def config_to_docker(config_path: pathlib.Path, config: Config, base_image: str):
def config_to_docker(
config_path: pathlib.Path, config: Config, base_image: str
) -> tuple[str, dict[str, str]]:
if config.get("node_version"):
return node_config_to_docker(config_path, config, base_image)
@@ -737,13 +785,24 @@ def config_to_compose(
else:
watch_str = ""
dockerfile, additional_contexts = config_to_docker(config_path, config, base_image)
additional_contexts_str = "\n".join(
f" - {name}: {path}"
for name, path in additional_contexts.items()
)
if additional_contexts_str:
additional_contexts_str = f"""
additional_contexts:
{additional_contexts_str}"""
return f"""
{textwrap.indent(env_vars_str, " ")}
{env_file_str}
pull_policy: build
build:
context: .
context: .{additional_contexts_str}
dockerfile_inline: |
{textwrap.indent(config_to_docker(config_path, config, base_image), " ")}
{textwrap.indent(dockerfile, " ")}
{watch_str}
"""
+16 -5
View File
@@ -40,9 +40,9 @@ def temporary_config_folder(config_content: dict):
def test_prepare_args_and_stdin() -> None:
# this basically serves as an end-to-end test for using config and docker helpers
config_path = pathlib.Path("./langgraph.json")
config_path = pathlib.Path(__file__).parent / "langgraph.json"
config = validate_config(
Config(dependencies=["."], graphs={"agent": "agent.py:graph"})
Config(dependencies=[".", "../../.."], graphs={"agent": "agent.py:graph"})
)
port = 8000
debugger_port = 8001
@@ -61,7 +61,7 @@ def test_prepare_args_and_stdin() -> None:
expected_args = [
"--project-directory",
".",
str(pathlib.Path(__file__).parent.absolute()),
"-f",
"custom-docker-compose.yml",
"-f",
@@ -129,18 +129,29 @@ services:
pull_policy: build
build:
context: .
additional_contexts:
- cli_1: /Users/nuno/dev/langgraph/libs/cli
dockerfile_inline: |
FROM langchain/langgraph-api:3.11
ADD . /deps/
# -- Adding local package . --
ADD . /deps/cli
# -- End of local package . --
# -- Adding local package ../../.. --
COPY --from=cli_1 . /deps/cli_1
# -- End of local package ../../.. --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "agent.py:graph"}}'
WORKDIR /deps/
WORKDIR /deps/cli
develop:
watch:
- path: langgraph.json
action: rebuild
- path: .
action: rebuild
- path: ../../..
action: rebuild\
"""
assert actual_args == expected_args
+95 -6
View File
@@ -177,13 +177,14 @@ def test_validate_config_file():
# config_to_docker
def test_config_to_docker_simple():
graphs = {"agent": "./agent.py:graph"}
actual_docker_stdin = config_to_docker(
actual_docker_stdin, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config({"dependencies": ["."], "graphs": graphs}),
"langchain/langgraph-api",
)
expected_docker_stdin = """\
FROM langchain/langgraph-api:3.11
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
@@ -193,16 +194,63 @@ RUN set -ex && \\
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests\
"""
assert clean_empty_lines(actual_docker_stdin) == expected_docker_stdin
assert additional_contexts == {}
def test_config_to_docker_outside_path():
graphs = {"agent": "./agent.py:graph"}
actual_docker_stdin, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config({"dependencies": [".", ".."], "graphs": graphs}),
"langchain/langgraph-api",
)
expected_docker_stdin = """\
FROM langchain/langgraph-api:3.11
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
'name = "unit_tests"' \\
'version = "0.1"' \\
'[tool.setuptools.package-data]' \\
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Adding non-package dependency tests --
COPY --from=__outer_tests . /deps/__outer_tests/tests
RUN set -ex && \\
for line in '[project]' \\
'name = "tests"' \\
'version = "0.1"' \\
'[tool.setuptools.package-data]' \\
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_tests/pyproject.toml; \\
done
# -- End of non-package dependency tests --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests\
"""
assert clean_empty_lines(actual_docker_stdin) == expected_docker_stdin
assert additional_contexts == {
"__outer_tests": "/Users/nuno/dev/langgraph/libs/cli/tests"
}
def test_config_to_docker_pipconfig():
graphs = {"agent": "./agent.py:graph"}
actual_docker_stdin = config_to_docker(
actual_docker_stdin, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
@@ -216,6 +264,7 @@ def test_config_to_docker_pipconfig():
expected_docker_stdin = """\
FROM langchain/langgraph-api:3.11
ADD pipconfig.txt /pipconfig.txt
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
@@ -225,11 +274,15 @@ RUN set -ex && \\
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Installing all local dependencies --
RUN PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests\
"""
assert clean_empty_lines(actual_docker_stdin) == expected_docker_stdin
assert additional_contexts == {}
def test_config_to_docker_invalid_inputs():
@@ -254,7 +307,7 @@ def test_config_to_docker_invalid_inputs():
def test_config_to_docker_local_deps():
graphs = {"agent": "./graphs/agent.py:graph"}
actual_docker_stdin = config_to_docker(
actual_docker_stdin, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
@@ -266,6 +319,7 @@ def test_config_to_docker_local_deps():
)
expected_docker_stdin = """\
FROM langchain/langgraph-api-custom:3.11
# -- Adding non-package dependency graphs --
ADD ./graphs /deps/__outer_graphs/src
RUN set -ex && \\
for line in '[project]' \\
@@ -275,10 +329,14 @@ RUN set -ex && \\
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_graphs/pyproject.toml; \\
done
# -- End of non-package dependency graphs --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_graphs/src/agent.py:graph"}'\
"""
assert clean_empty_lines(actual_docker_stdin) == expected_docker_stdin
assert additional_contexts == {}
def test_config_to_docker_pyproject():
@@ -291,7 +349,7 @@ dependencies = ["langchain"]"""
f.write(pyproject_str)
graphs = {"agent": "./graphs/agent.py:graph"}
actual_docker_stdin = config_to_docker(
actual_docker_stdin, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
@@ -303,16 +361,21 @@ dependencies = ["langchain"]"""
)
os.remove(pyproject_path)
expected_docker_stdin = """FROM langchain/langgraph-api:3.11
# -- Adding local package . --
ADD . /deps/unit_tests
# -- End of local package . --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/unit_tests/graphs/agent.py:graph"}'
WORKDIR /deps/unit_tests"""
assert clean_empty_lines(actual_docker_stdin) == expected_docker_stdin
assert additional_contexts == {}
def test_config_to_docker_end_to_end():
graphs = {"agent": "./graphs/agent.py:graph"}
actual_docker_stdin = config_to_docker(
actual_docker_stdin, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
@@ -330,6 +393,7 @@ ARG meow
ARG foo
ADD pipconfig.txt /pipconfig.txt
RUN PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt langchain langchain_openai
# -- Adding non-package dependency graphs --
ADD ./graphs/ /deps/__outer_graphs/src
RUN set -ex && \\
for line in '[project]' \\
@@ -339,15 +403,19 @@ RUN set -ex && \\
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_graphs/pyproject.toml; \\
done
# -- End of non-package dependency graphs --
# -- Installing all local dependencies --
RUN PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_graphs/src/agent.py:graph"}'"""
assert clean_empty_lines(actual_docker_stdin) == expected_docker_stdin
assert additional_contexts == {}
# node.js build used for LangGraph Cloud
def test_config_to_docker_nodejs():
graphs = {"agent": "./graphs/agent.js:graph"}
actual_docker_stdin = config_to_docker(
actual_docker_stdin, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
@@ -368,6 +436,7 @@ WORKDIR /deps/unit_tests
RUN (test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not found, skipping") || tsx /api/langgraph_api/js/build.mts"""
assert clean_empty_lines(actual_docker_stdin) == expected_docker_stdin
assert additional_contexts == {}
# config_to_compose
@@ -380,6 +449,7 @@ def test_config_to_compose_simple_config():
context: .
dockerfile_inline: |
FROM langchain/langgraph-api:3.11
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
@@ -389,7 +459,10 @@ def test_config_to_compose_simple_config():
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests
"""
@@ -410,6 +483,7 @@ def test_config_to_compose_env_vars():
context: .
dockerfile_inline: |
FROM langchain/langgraph-api-custom:3.11
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
@@ -419,7 +493,10 @@ def test_config_to_compose_env_vars():
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests
"""
@@ -447,6 +524,7 @@ def test_config_to_compose_env_file():
context: .
dockerfile_inline: |
FROM langchain/langgraph-api:3.11
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
@@ -456,7 +534,10 @@ def test_config_to_compose_env_file():
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests
"""
@@ -477,6 +558,7 @@ def test_config_to_compose_watch():
context: .
dockerfile_inline: |
FROM langchain/langgraph-api:3.11
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
@@ -486,7 +568,10 @@ def test_config_to_compose_watch():
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests
@@ -516,6 +601,7 @@ def test_config_to_compose_end_to_end():
context: .
dockerfile_inline: |
FROM langchain/langgraph-api:3.11
# -- Adding non-package dependency unit_tests --
ADD . /deps/__outer_unit_tests/unit_tests
RUN set -ex && \\
for line in '[project]' \\
@@ -525,7 +611,10 @@ def test_config_to_compose_end_to_end():
'"*" = ["**/*"]'; do \\
echo "$line" >> /deps/__outer_unit_tests/pyproject.toml; \\
done
# -- End of non-package dependency unit_tests --
# -- Installing all local dependencies --
RUN PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
# -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_unit_tests/unit_tests/agent.py:graph"}'
WORKDIR /deps/__outer_unit_tests/unit_tests