mirror of
https://github.com/hwchase17/langchain.git
synced 2026-07-01 06:42:37 +00:00
fix(core): add messages to bare raise ValueError calls (#38158)
Closes #35727 --- Several internal code paths raised a bare `ValueError` with no message, so when one of these conditions tripped, users saw a traceback with no explanation of what actually went wrong. This adds descriptive messages to each of those `raise ValueError` calls: - `FewShotPromptWithTemplates._get_examples` / `_aget_examples` — when neither `examples` nor `example_selector` is set. - Prompt `loading` — when a referenced template file uses an unsupported (non-`.txt`) format. - The LangSmith document loader — when both `client` and `client_kwargs` are supplied. - The Anthropic file-search middleware brace expansion — for unbalanced or empty brace patterns. Made by [Open SWE](https://openswe.vercel.app) --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"}},
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user