diff --git a/python/packages/anthropic/pyproject.toml b/python/packages/anthropic/pyproject.toml index 91ff2919101..db2884b00ae 100644 --- a/python/packages/anthropic/pyproject.toml +++ b/python/packages/anthropic/pyproject.toml @@ -85,6 +85,10 @@ exclude_dirs = ["tests"] executor.type = "uv" include = "../../shared_tasks.toml" +[tool.poe.tasks.dependency-pyright] +help = "Run Pyright over Anthropic implementation files for isolated dependency validation." +cmd = "pyright --project pyrightconfig.dependency.json" + [tool.poe.tasks.mypy] help = "Run MyPy for this package." cmd = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_anthropic" diff --git a/python/packages/anthropic/pyrightconfig.dependency.json b/python/packages/anthropic/pyrightconfig.dependency.json new file mode 100644 index 00000000000..6a3c479a49c --- /dev/null +++ b/python/packages/anthropic/pyrightconfig.dependency.json @@ -0,0 +1,9 @@ +{ + "extends": "../../pyproject.toml", + "include": [ + "agent_framework_anthropic" + ], + "exclude": [ + "agent_framework_anthropic/_vertex_client.py" + ] +} diff --git a/python/packages/openai/pyproject.toml b/python/packages/openai/pyproject.toml index f1df50c9269..a8d7a9a1c96 100644 --- a/python/packages/openai/pyproject.toml +++ b/python/packages/openai/pyproject.toml @@ -84,6 +84,10 @@ exclude_dirs = ["tests"] executor.type = "uv" include = "../../shared_tasks.toml" +[tool.poe.tasks.dependency-pyright] +help = "Run Pyright over OpenAI implementation files for isolated dependency validation." +cmd = "pyright --project pyrightconfig.dependency.json" + [tool.poe.tasks.mypy] help = "Run MyPy for this package." cmd = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_openai" diff --git a/python/packages/openai/pyrightconfig.dependency.json b/python/packages/openai/pyrightconfig.dependency.json new file mode 100644 index 00000000000..6298bac03b6 --- /dev/null +++ b/python/packages/openai/pyrightconfig.dependency.json @@ -0,0 +1,6 @@ +{ + "extends": "../../pyproject.toml", + "include": [ + "agent_framework_openai" + ] +} diff --git a/python/scripts/dependencies/tests/test_dependency_bounds_runtime.py b/python/scripts/dependencies/tests/test_dependency_bounds_runtime.py index 12e184057c5..3776295e82e 100644 --- a/python/scripts/dependencies/tests/test_dependency_bounds_runtime.py +++ b/python/scripts/dependencies/tests/test_dependency_bounds_runtime.py @@ -1,5 +1,6 @@ # Copyright (c) Microsoft. All rights reserved. +import json from collections.abc import Callable from pathlib import Path @@ -196,3 +197,34 @@ def test_dependency_pyright_reuses_root_test_requirements(tmp_path: Path) -> Non "mcp[ws]", ] assert command[-3:-1] == ["python", "-c"] + + +@pytest.mark.parametrize( + ("package", "module"), + [("anthropic", "agent_framework_anthropic"), ("openai", "agent_framework_openai")], +) +def test_optional_namespace_packages_define_their_own_dependency_pyright_task(package: str, module: str) -> None: + """Packages that type-check against deliberately optional namespaces need the probe escape hatch. + + ``agent_framework_anthropic`` references ``google.auth`` and ``agent_framework_openai`` references + ``azure.core``/``azure.identity``, in both cases without declaring them, because those surfaces are + optional. A full workspace sync resolves them transitively, so repo-wide Pyright passes; an isolated + dependency probe does not, and the resulting ``reportMissingImports`` aborts the whole bounds gate. + """ + workspace_root = Path(__file__).resolve().parents[3] + + plans = _build_test_plans(workspace_root, package) + + assert [plan.typing_task for plan in plans] == ["dependency-pyright"] + + config = json.loads((workspace_root / f"packages/{package}/pyrightconfig.dependency.json").read_text()) + assert config["include"] == [module] + + +def test_anthropic_dependency_pyright_config_excludes_the_vertex_client() -> None: + workspace_root = Path(__file__).resolve().parents[3] + config_path = workspace_root / "packages/anthropic/pyrightconfig.dependency.json" + + config = json.loads(config_path.read_text()) + + assert config["exclude"] == ["agent_framework_anthropic/_vertex_client.py"]