Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
93d5abf
Add fixtures for detecting if langchain, langgraph and deepagents are…
dagardner-nv May 15, 2026
fcb8880
Move fixtures
dagardner-nv May 15, 2026
106da78
Merge branch 'release/0.2' of github.com:NVIDIA/NeMo-Flow into david-…
dagardner-nv May 15, 2026
8a2021b
Rename 'langchain' dir to prevent 'import langchain' from accidentall…
dagardner-nv May 15, 2026
231d150
Remove unneeded fixture dependency
dagardner-nv May 15, 2026
f129828
Merge branch 'main' of github.com:NVIDIA/NeMo-Flow into david-path-fi…
dagardner-nv May 15, 2026
d2ceaed
Make langchain tests skippable when not installed
dagardner-nv May 15, 2026
1aa9087
Instruct the agent how to write fixtures
dagardner-nv May 15, 2026
b119ece
Refactor _model_request and _tool_call_request as fixtures
dagardner-nv May 15, 2026
f7a7b32
WIP
dagardner-nv May 15, 2026
96110f9
Merge branch 'main' of github.com:NVIDIA/NeMo-Flow into david-path-fi…
dagardner-nv May 15, 2026
535040c
Rename tool_request fixture to tool_call_request
dagardner-nv May 15, 2026
2ffa713
Rename langgraph test dir to not conflict with the langgraph package
dagardner-nv May 18, 2026
9c6350c
Rename deepagents test dir to not conflict with the deepagents package
dagardner-nv May 18, 2026
df7f356
Perform langgraph imports lazily [skip ci]
dagardner-nv May 18, 2026
b915df0
Remove constructor, avoids warning about not being able to collect th…
dagardner-nv May 18, 2026
59332a3
Perform lazy imports for deepagents tests
dagardner-nv May 18, 2026
317c902
WIP
dagardner-nv May 18, 2026
39e77fa
Exlude integration tests from coverage reports
dagardner-nv May 18, 2026
93670c9
Seperate the just recipes for python [skip ci]
dagardner-nv May 18, 2026
661d505
Optionally run Python LC integration tests
dagardner-nv May 18, 2026
58decb5
Formatting/linting
dagardner-nv May 18, 2026
6b22798
Use return to match return type hint
dagardner-nv May 18, 2026
0341d2c
Linting fixes
dagardner-nv May 18, 2026
9add9b5
Formatting
dagardner-nv May 18, 2026
c044f9d
Avoid installing LC deps if we don't need to
dagardner-nv May 18, 2026
4e48df5
Linting fix
dagardner-nv May 18, 2026
8d6c142
Linting fix
dagardner-nv May 18, 2026
d4737b6
Linting
dagardner-nv May 18, 2026
12793ee
Fix handling of uv sync flags
dagardner-nv May 18, 2026
005b767
Fix recipe name
dagardner-nv May 18, 2026
cc72e20
Formatting
dagardner-nv May 18, 2026
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
7 changes: 7 additions & 0 deletions .agents/skills/test-python-binding/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ Use this skill when the change is primarily in `python/nemo_flow`,
- The name of the mocked class should be prefixed with `mock`, not `fake`.
- Prefer pytest fixtures over helper methods.
- Do not repeat fixtures, if a fixture is needed in multiple test files, place it in a `conftest.py` file.
- When creating a fixture follow this pattern:
```python
@pytest.fixture(name="<fixture_name>"[, scope="<scope>"])
def <fixture_name>_fixture() -> <return_type>:
...
```
Comment thread
dagardner-nv marked this conversation as resolved.
Only specify the scope argument when the value is something other than "function".
- Prefer `pytest.mark.parametrize` over creating individual tests for
different input types.

Expand Down
14 changes: 14 additions & 0 deletions .github/ci-path-filters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ python_package:
- 'rust-toolchain.toml'
- 'uv.lock'

python_integration_langchain:
# Includes LangGraph and DeepAgents integrations as well
- 'justfile'
- 'pyproject.toml'
- 'python/nemo_flow/integrations/deepagents/**'
- 'python/nemo_flow/integrations/langchain/**'
- 'python/nemo_flow/integrations/langgraph/**'
- 'python/tests/integrations/conftest.py'
- 'python/tests/integrations/deepagents_tests/**'
- 'python/tests/integrations/langchain_tests/**'
- 'python/tests/integrations/langgraph_tests/**'
- 'rust-toolchain.toml'
- 'uv.lock'

wasm_package:
- 'Cargo.lock'
- 'Cargo.toml'
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ jobs:
with:
full_ci: ${{ needs.prepare.outputs.full_ci == 'true' }}
base: ${{ needs.ci_changes.outputs.base }}
run_python_integration_langchain: ${{ needs.ci_changes.outputs.run_python_integration_langchain == 'true' }}

ci_license_diff:
name: License Diff
Expand Down Expand Up @@ -203,15 +204,16 @@ jobs:
name: Python
needs: [prepare, ci_changes, ci_check]
uses: ./.github/workflows/ci_python.yml
if: ${{ needs.ci_check.result == 'success' && needs.ci_changes.outputs.run_python == 'true' }}
if: ${{ needs.ci_check.result == 'success' && ( needs.ci_changes.outputs.run_python == 'true' || needs.ci_changes.outputs.run_python_integration_langchain == 'true' ) }}
permissions:
contents: read
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
ref_type: ${{ github.ref_type }}
ref_name: ${{ github.ref_name }}
run_package: ${{ needs.ci_changes.outputs.run_python_package == 'true' }}
run_package: ${{ ( needs.ci_changes.outputs.run_python == 'true' || needs.ci_changes.outputs.run_python_integration_langchain == 'true' ) }}
Comment thread
dagardner-nv marked this conversation as resolved.
run_integration_langchain: ${{ needs.ci_changes.outputs.run_python_integration_langchain == 'true' }}

ci_wasm:
name: WebAssembly
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ci_changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ on:
run_python:
description: 'Whether Python jobs should run'
value: ${{ jobs.changes.outputs.run_python }}
run_python_integration_langchain:
description: 'Whether LangChain, LangGraph, and DeepAgents Python integration jobs should run'
value: ${{ jobs.changes.outputs.run_python_integration_langchain }}
run_python_package:
description: 'Whether Python packaging jobs should run'
value: ${{ jobs.changes.outputs.run_python_package }}
Expand Down Expand Up @@ -80,6 +83,7 @@ jobs:
run_node_package: ${{ inputs.full_ci || steps.filter.outputs.ci == 'true' || steps.filter.outputs.node_package == 'true' }}
run_openclaw: ${{ inputs.full_ci || steps.filter.outputs.ci == 'true' || steps.filter.outputs.shared == 'true' || steps.filter.outputs.node == 'true' || steps.filter.outputs.openclaw == 'true' }}
run_python: ${{ inputs.full_ci || steps.filter.outputs.ci == 'true' || steps.filter.outputs.shared == 'true' || steps.filter.outputs.python == 'true' }}
run_python_integration_langchain: ${{ inputs.full_ci || steps.filter.outputs.ci == 'true' || steps.filter.outputs.shared == 'true' || steps.filter.outputs.python_integration_langchain == 'true' }}
run_python_package: ${{ inputs.full_ci || steps.filter.outputs.ci == 'true' || steps.filter.outputs.python_package == 'true' }}
run_rust: ${{ inputs.full_ci || steps.filter.outputs.ci == 'true' || steps.filter.outputs.shared == 'true' || steps.filter.outputs.rust == 'true' }}
run_rust_package: ${{ inputs.full_ci || steps.filter.outputs.ci == 'true' || steps.filter.outputs.rust_package == 'true' }}
Expand Down
13 changes: 12 additions & 1 deletion .github/workflows/ci_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ on:
required: false
default: false
type: boolean
run_python_integration_langchain:
description: 'Whether LangChain, LangGraph, and DeepAgents Python integration checks may need optional extras'
required: false
default: false
type: boolean
base:
description: 'The comparison base used for filtered pre-commit checks'
required: false
Expand Down Expand Up @@ -104,12 +109,18 @@ jobs:
FULL_CI: ${{ inputs.full_ci }}
PRE_COMMIT_BASE: ${{ inputs.base }}
PRE_COMMIT_HOME: ${{ runner.temp }}/.cache/pre-commit
PYTHON_INTEGRATION_LANGCHAIN: ${{ inputs.run_python_integration_langchain }}
# The attribution hook syncs docs deps; do not apply repo warning policy to third-party Rust builds.
RUSTFLAGS: ""
run: |
set -e
uv tool install pre-commit==${{ steps.ci-config.outputs.pre_commit_version }}
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents
FLOW_CI_UV_SYNC_EXTRA_ARGS=()
if [[ "$PYTHON_INTEGRATION_LANGCHAIN" == "true" ]]; then
FLOW_CI_UV_SYNC_EXTRA_ARGS+=(--extra langchain --extra langgraph --extra deepagents)
fi

uv sync --inexact --no-install-project --no-install-package nemo-flow "${FLOW_CI_UV_SYNC_EXTRA_ARGS[@]}"
if [[ "$FULL_CI" == "true" || -z "$PRE_COMMIT_BASE" ]]; then
pre-commit run --all-files --show-diff-on-failure
else
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/ci_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ on:
required: false
default: true
type: boolean
run_integration_langchain:
description: 'Whether to run LangChain, LangGraph, and DeepAgents Python integration tests'
required: false
default: false
type: boolean
secrets:
CODECOV_TOKEN:
required: false
Expand Down Expand Up @@ -131,6 +136,11 @@ jobs:
working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }}
run: just --set ci true --set output_dir "${{ github.workspace }}" test-python

- name: Run Python LangChain integration tests
if: ${{ inputs.run_integration_langchain == 'true' }}
working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }}
run: just --set ci true --set output_dir "${{ github.workspace }}" test-python-langchain

- name: Upload Python coverage to Codecov
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6
with:
Expand Down
21 changes: 18 additions & 3 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -854,12 +854,12 @@ test-python:
fi
cargo test -p nemo-flow-python --lib
fi
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents
uv sync --inexact --no-install-project --no-install-package nemo-flow
activate_project_venv
python_executable="$(project_python_executable)"
use_project_python_source "$python_executable"
"$python_executable" -m maturin develop --skip-install
"$python_executable" -m "${pytest_cmd[@]}"
"$python_executable" -m "${pytest_cmd[@]}" --ignore=python/tests/integrations
if is_true "{{ ci }}" && [[ -n "$rust_coverage_out" ]]; then
cargo llvm-cov report \
-p nemo-flow-python \
Expand All @@ -868,6 +868,21 @@ test-python:
--output-path "$rust_coverage_out"
fi

test-python-langchain:
#!/usr/bin/env bash
{{ bash_helpers }}
pytest_cmd=(pytest)
cd "$NEMO_FLOW_REPO_ROOT"
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents
activate_project_venv
python_executable="$(project_python_executable)"
use_project_python_source "$python_executable"
"$python_executable" -m maturin develop --skip-install
"$python_executable" -m "${pytest_cmd[@]}" \
python/tests/integrations/deepagents_tests \
python/tests/integrations/langchain_tests \
python/tests/integrations/langgraph_tests

# --set [output_dir=<path>] [ci=true|false]
test-go:
#!/usr/bin/env bash
Expand Down Expand Up @@ -1012,7 +1027,7 @@ test-wasm:
fi

# --set [output_dir=<path>] [ci=true|false]
test-all: test-rust test-python test-go test-node test-openclaw test-wasm
test-all: test-rust test-python test-python-langchain test-go test-node test-openclaw test-wasm

# [version] or --set ref_name=<version>
set-version version="":
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ package = true
testpaths = ["python/tests", "third_party/langgraph_tests"]
asyncio_mode = "auto"

[tool.coverage.run]
# Exclude integration tests from coverage, since we don't run these by default
omit = ["python/nemo_flow/integrations/*"]

[tool.ty.analysis]
# nemo_flow._native is a compiled Rust extension (built by maturin) that only
# exists after `uv sync` / `pip install -e .`. Suppress unresolved-import for it.
Expand Down
45 changes: 45 additions & 0 deletions python/tests/integrations/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import types

import pytest


@pytest.fixture(name="integration_langchain", scope="session")
def integration_langchain_fixture() -> types.ModuleType:
"""
Use for integration tests that require LangChain to be installed.
"""
try:
import langchain

return langchain
except Exception:
pytest.skip(reason="langchain must be installed to run LangChain based tests")
Comment thread
dagardner-nv marked this conversation as resolved.


@pytest.fixture(name="integration_langgraph", scope="session")
def integration_langgraph_fixture(integration_langchain: types.ModuleType) -> types.ModuleType:
"""
Use for integration tests that require LangGraph to be installed.
"""
try:
import langgraph

return langgraph
except Exception:
pytest.skip(reason="langgraph must be installed to run LangGraph based tests")


@pytest.fixture(name="integration_deepagents", scope="session")
def integration_deepagents_fixture(integration_langgraph: types.ModuleType) -> types.ModuleType:
"""
Use for integration tests that require Deep Agents to be installed.
"""
try:
import deepagents

return deepagents
except Exception:
pytest.skip(reason="deepagents must be installed to run Deep Agents based tests")
14 changes: 14 additions & 0 deletions python/tests/integrations/deepagents_tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import types

import pytest


@pytest.fixture(name="integration_deepagents", scope="session", autouse=True)
def integration_deepagents_fixture(integration_deepagents: types.ModuleType) -> types.ModuleType:
"""
Override the integration_deepagents fixture to make it autouse
"""
return integration_deepagents
Loading
Loading