diff --git a/libs/core/langchain_core/document_loaders/langsmith.py b/libs/core/langchain_core/document_loaders/langsmith.py index 3c6a04b8868..10b07abbe44 100644 --- a/libs/core/langchain_core/document_loaders/langsmith.py +++ b/libs/core/langchain_core/document_loaders/langsmith.py @@ -94,7 +94,8 @@ class LangSmithLoader(BaseLoader): ValueError: If both `client` and `client_kwargs` are provided. """ # noqa: E501 if client and client_kwargs: - raise ValueError + msg = "Only one of 'client' and 'client_kwargs' should be provided." + raise ValueError(msg) self._client = client or LangSmithClient(**client_kwargs) self.content_key = list(content_key.split(".")) if content_key else [] self.format_content = format_content or _stringify diff --git a/libs/core/langchain_core/prompts/few_shot_with_templates.py b/libs/core/langchain_core/prompts/few_shot_with_templates.py index f70cdc6e664..d82801c0e42 100644 --- a/libs/core/langchain_core/prompts/few_shot_with_templates.py +++ b/libs/core/langchain_core/prompts/few_shot_with_templates.py @@ -111,14 +111,16 @@ class FewShotPromptWithTemplates(StringPromptTemplate): return self.examples if self.example_selector is not None: return self.example_selector.select_examples(kwargs) - raise ValueError + msg = "One of 'examples' and 'example_selector' should be provided" + raise ValueError(msg) async def _aget_examples(self, **kwargs: Any) -> list[dict[str, Any]]: if self.examples is not None: return self.examples if self.example_selector is not None: return await self.example_selector.aselect_examples(kwargs) - raise ValueError + msg = "One of 'examples' and 'example_selector' should be provided" + raise ValueError(msg) def format(self, **kwargs: Any) -> str: """Format the prompt with the inputs. diff --git a/libs/core/langchain_core/prompts/loading.py b/libs/core/langchain_core/prompts/loading.py index 612dcf1dbdd..4195c661768 100644 --- a/libs/core/langchain_core/prompts/loading.py +++ b/libs/core/langchain_core/prompts/loading.py @@ -104,7 +104,11 @@ def _load_template( if resolved_path.suffix == ".txt": template = resolved_path.read_text(encoding="utf-8") else: - raise ValueError + msg = ( + f"Unsupported template file format: '{resolved_path.suffix}'. " + "Only '.txt' files are supported." + ) + raise ValueError(msg) # Set the template variable to the extracted variable. config[var_name] = template return config diff --git a/libs/core/tests/unit_tests/document_loaders/test_langsmith.py b/libs/core/tests/unit_tests/document_loaders/test_langsmith.py index 30750578da6..6de3c67d39a 100644 --- a/libs/core/tests/unit_tests/document_loaders/test_langsmith.py +++ b/libs/core/tests/unit_tests/document_loaders/test_langsmith.py @@ -2,6 +2,7 @@ import datetime import uuid from unittest.mock import MagicMock, patch +import pytest from langsmith.schemas import Example from langchain_core.document_loaders import LangSmithLoader @@ -13,6 +14,12 @@ def test_init() -> None: LangSmithLoader(api_key="secret") +def test_init_client_and_client_kwargs_conflict() -> None: + """Passing both `client` and `client_kwargs` should raise.""" + with pytest.raises(ValueError, match="Only one of 'client' and 'client_kwargs'"): + LangSmithLoader(client=MagicMock(), api_key="secret") + + EXAMPLES = [ Example( inputs={"first": {"second": "foo"}}, diff --git a/libs/core/tests/unit_tests/prompts/test_few_shot_with_templates.py b/libs/core/tests/unit_tests/prompts/test_few_shot_with_templates.py index ecfad95be60..675d6d5ccb5 100644 --- a/libs/core/tests/unit_tests/prompts/test_few_shot_with_templates.py +++ b/libs/core/tests/unit_tests/prompts/test_few_shot_with_templates.py @@ -81,3 +81,26 @@ def test_prompttemplate_validation() -> None: example_prompt=EXAMPLE_PROMPT, example_separator="\n", ).input_variables == ["content", "new_content"] + + +async def test_get_examples_requires_examples_or_selector() -> None: + """Both `_get_examples` and `_aget_examples` raise when neither is set. + + The constructor validator forbids the neither-provided case, so the fields + are cleared after construction to reach the guard inside the getters. + """ + suffix = PromptTemplate(input_variables=[], template="end") + prompt = FewShotPromptWithTemplates( + suffix=suffix, + input_variables=[], + examples=[{"question": "foo", "answer": "bar"}], + example_prompt=EXAMPLE_PROMPT, + ) + prompt.examples = None + prompt.example_selector = None + + match = "One of 'examples' and 'example_selector' should be provided" + with pytest.raises(ValueError, match=match): + prompt._get_examples() + with pytest.raises(ValueError, match=match): + await prompt._aget_examples() diff --git a/libs/core/tests/unit_tests/prompts/test_loading.py b/libs/core/tests/unit_tests/prompts/test_loading.py index 6c0569ef8b3..3c87ff1aaa7 100644 --- a/libs/core/tests/unit_tests/prompts/test_loading.py +++ b/libs/core/tests/unit_tests/prompts/test_loading.py @@ -316,7 +316,7 @@ def test_symlink_txt_to_py_is_blocked(tmp_path: Path) -> None: os.chdir(tmp_path) with ( suppress_langchain_deprecation_warning(), - pytest.raises(ValueError), # noqa: PT011 + pytest.raises(ValueError, match="files are supported"), ): load_prompt_from_config(config) finally: @@ -341,7 +341,7 @@ def test_symlink_jinja2_rce_is_blocked(tmp_path: Path) -> None: } with ( suppress_langchain_deprecation_warning(), - pytest.raises(ValueError), # noqa: PT011 + pytest.raises(ValueError, match="files are supported"), ): load_prompt_from_config(config, allow_dangerous_paths=True) diff --git a/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py b/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py index 0f4fd42c567..775e2511241 100644 --- a/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py +++ b/libs/partners/anthropic/langchain_anthropic/middleware/file_search.py @@ -35,13 +35,15 @@ def _expand_include_patterns(pattern: str) -> list[str] | None: end = current.find("}", start) if end == -1: - raise ValueError + msg = f"Unbalanced brace in pattern: '{current}' is missing a '}}'." + raise ValueError(msg) prefix = current[:start] suffix = current[end + 1 :] inner = current[start + 1 : end] if not inner: - raise ValueError + msg = f"Empty brace expansion in pattern: '{current}'." + raise ValueError(msg) for option in inner.split(","): _expand(prefix + option + suffix)