mirror of
https://github.com/hwchase17/langchain.git
synced 2025-08-11 22:04:37 +00:00
chore(core): bump mypy version to 1.17 (#32390)
Co-authored-by: Mason Daugherty <mason@langchain.dev>
This commit is contained in:
parent
42c1159991
commit
499dc35cfb
@ -144,7 +144,7 @@ def beta(
|
|||||||
obj.__init__ = functools.wraps(obj.__init__)( # type: ignore[misc]
|
obj.__init__ = functools.wraps(obj.__init__)( # type: ignore[misc]
|
||||||
warn_if_direct_instance
|
warn_if_direct_instance
|
||||||
)
|
)
|
||||||
return cast("T", obj)
|
return obj
|
||||||
|
|
||||||
elif isinstance(obj, property):
|
elif isinstance(obj, property):
|
||||||
# note(erick): this block doesn't seem to be used?
|
# note(erick): this block doesn't seem to be used?
|
||||||
|
@ -225,7 +225,7 @@ def deprecated(
|
|||||||
obj.__init__ = functools.wraps(obj.__init__)( # type: ignore[misc]
|
obj.__init__ = functools.wraps(obj.__init__)( # type: ignore[misc]
|
||||||
warn_if_direct_instance
|
warn_if_direct_instance
|
||||||
)
|
)
|
||||||
return cast("T", obj)
|
return obj
|
||||||
|
|
||||||
elif isinstance(obj, FieldInfoV1):
|
elif isinstance(obj, FieldInfoV1):
|
||||||
wrapped = None
|
wrapped = None
|
||||||
|
@ -107,7 +107,11 @@ class _StreamingParser:
|
|||||||
self.buffer = ""
|
self.buffer = ""
|
||||||
# yield all events
|
# yield all events
|
||||||
try:
|
try:
|
||||||
for event, elem in self.pull_parser.read_events():
|
for raw_event in self.pull_parser.read_events():
|
||||||
|
if len(raw_event) <= 1:
|
||||||
|
continue
|
||||||
|
event, elem = raw_event
|
||||||
|
if isinstance(elem, ET.Element):
|
||||||
if event == "start":
|
if event == "start":
|
||||||
# update current path
|
# update current path
|
||||||
self.current_path.append(elem.tag)
|
self.current_path.append(elem.tag)
|
||||||
|
@ -5300,7 +5300,7 @@ class RunnableBindingBase(RunnableSerializable[Input, Output]):
|
|||||||
kwargs.
|
kwargs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config: RunnableConfig = Field(default_factory=RunnableConfig) # type: ignore[arg-type]
|
config: RunnableConfig = Field(default_factory=RunnableConfig)
|
||||||
"""The config to bind to the underlying Runnable."""
|
"""The config to bind to the underlying Runnable."""
|
||||||
|
|
||||||
config_factories: list[Callable[[RunnableConfig], RunnableConfig]] = Field(
|
config_factories: list[Callable[[RunnableConfig], RunnableConfig]] = Field(
|
||||||
|
@ -5,7 +5,7 @@ import inspect
|
|||||||
import typing
|
import typing
|
||||||
from collections.abc import AsyncIterator, Iterator, Sequence
|
from collections.abc import AsyncIterator, Iterator, Sequence
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import TYPE_CHECKING, Any, Optional, Union
|
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict
|
from pydantic import BaseModel, ConfigDict
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
@ -397,7 +397,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
to_return = {}
|
to_return: dict[int, Union[Output, BaseException]] = {}
|
||||||
run_again = dict(enumerate(inputs))
|
run_again = dict(enumerate(inputs))
|
||||||
handled_exceptions: dict[int, BaseException] = {}
|
handled_exceptions: dict[int, BaseException] = {}
|
||||||
first_to_raise = None
|
first_to_raise = None
|
||||||
@ -447,7 +447,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
|
|||||||
if not return_exceptions and sorted_handled_exceptions:
|
if not return_exceptions and sorted_handled_exceptions:
|
||||||
raise sorted_handled_exceptions[0][1]
|
raise sorted_handled_exceptions[0][1]
|
||||||
to_return.update(handled_exceptions)
|
to_return.update(handled_exceptions)
|
||||||
return [output for _, output in sorted(to_return.items())] # type: ignore[misc]
|
return [cast("Output", output) for _, output in sorted(to_return.items())]
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def stream(
|
def stream(
|
||||||
@ -569,7 +569,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
|
|||||||
async for chunk in stream:
|
async for chunk in stream:
|
||||||
yield chunk
|
yield chunk
|
||||||
try:
|
try:
|
||||||
output = output + chunk
|
output = output + chunk # type: ignore[operator]
|
||||||
except TypeError:
|
except TypeError:
|
||||||
output = None
|
output = None
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
|
@ -177,7 +177,7 @@ class RunLog(RunLogPatch):
|
|||||||
# Then compare that the ops are the same
|
# Then compare that the ops are the same
|
||||||
return super().__eq__(other)
|
return super().__eq__(other)
|
||||||
|
|
||||||
__hash__ = None # type: ignore[assignment]
|
__hash__ = None
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
@ -277,7 +277,7 @@ def _convert_any_typed_dicts_to_pydantic(
|
|||||||
)
|
)
|
||||||
fields: dict = {}
|
fields: dict = {}
|
||||||
for arg, arg_type in annotations_.items():
|
for arg, arg_type in annotations_.items():
|
||||||
if get_origin(arg_type) is Annotated:
|
if get_origin(arg_type) is Annotated: # type: ignore[comparison-overlap]
|
||||||
annotated_args = get_args(arg_type)
|
annotated_args = get_args(arg_type)
|
||||||
new_arg_type = _convert_any_typed_dicts_to_pydantic(
|
new_arg_type = _convert_any_typed_dicts_to_pydantic(
|
||||||
annotated_args[0], depth=depth + 1, visited=visited
|
annotated_args[0], depth=depth + 1, visited=visited
|
||||||
|
@ -417,7 +417,7 @@ class AIMessageChunk(AIMessage):
|
|||||||
self._tool_call_chunks = [
|
self._tool_call_chunks = [
|
||||||
block for block in self.content if types.is_tool_call_chunk(block)
|
block for block in self.content if types.is_tool_call_chunk(block)
|
||||||
]
|
]
|
||||||
return cast("list[types.ToolCallChunk]", self._tool_call_chunks)
|
return self._tool_call_chunks
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tool_calls(self) -> list[types.ToolCall]:
|
def tool_calls(self) -> list[types.ToolCall]:
|
||||||
|
@ -28,7 +28,7 @@ repository = "https://github.com/langchain-ai/langchain"
|
|||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
lint = ["ruff<0.13,>=0.12.2"]
|
lint = ["ruff<0.13,>=0.12.2"]
|
||||||
typing = [
|
typing = [
|
||||||
"mypy<1.16,>=1.15",
|
"mypy<1.18,>=1.17.1",
|
||||||
"types-pyyaml<7.0.0.0,>=6.0.12.2",
|
"types-pyyaml<7.0.0.0,>=6.0.12.2",
|
||||||
"types-requests<3.0.0.0,>=2.28.11.5",
|
"types-requests<3.0.0.0,>=2.28.11.5",
|
||||||
"langchain-text-splitters",
|
"langchain-text-splitters",
|
||||||
|
@ -479,28 +479,12 @@ class TestFactoryTypeConsistency:
|
|||||||
|
|
||||||
|
|
||||||
class TestExtraItems:
|
class TestExtraItems:
|
||||||
"""Test that content blocks support extra items via __extra_items__ field."""
|
"""Test that content blocks support extra items."""
|
||||||
|
|
||||||
def test_text_block_extra_items(self) -> None:
|
|
||||||
"""Test that TextContentBlock can store extra provider-specific fields."""
|
|
||||||
block = create_text_block("Hello world")
|
|
||||||
|
|
||||||
block["openai_metadata"] = {"model": "gpt-4", "temperature": 0.7} # type: ignore[typeddict-unknown-key]
|
|
||||||
block["anthropic_usage"] = {"input_tokens": 10, "output_tokens": 20} # type: ignore[typeddict-unknown-key]
|
|
||||||
block["custom_field"] = "any value" # type: ignore[typeddict-unknown-key]
|
|
||||||
|
|
||||||
assert block["type"] == "text"
|
|
||||||
assert block["text"] == "Hello world"
|
|
||||||
assert "id" in block
|
|
||||||
assert block.get("openai_metadata") == {"model": "gpt-4", "temperature": 0.7}
|
|
||||||
assert block.get("anthropic_usage") == {"input_tokens": 10, "output_tokens": 20}
|
|
||||||
assert block.get("custom_field") == "any value"
|
|
||||||
|
|
||||||
def test_text_block_extras_field(self) -> None:
|
def test_text_block_extras_field(self) -> None:
|
||||||
"""Test that TextContentBlock properly supports the explicit extras field."""
|
"""Test that TextContentBlock properly supports the extras field."""
|
||||||
block = create_text_block("Hello world")
|
block = create_text_block("Hello world")
|
||||||
|
|
||||||
# Test direct assignment to extras field
|
|
||||||
block["extras"] = {
|
block["extras"] = {
|
||||||
"openai_metadata": {"model": "gpt-4", "temperature": 0.7},
|
"openai_metadata": {"model": "gpt-4", "temperature": 0.7},
|
||||||
"anthropic_usage": {"input_tokens": 10, "output_tokens": 20},
|
"anthropic_usage": {"input_tokens": 10, "output_tokens": 20},
|
||||||
@ -518,32 +502,6 @@ class TestExtraItems:
|
|||||||
assert extras.get("anthropic_usage") == expected_usage
|
assert extras.get("anthropic_usage") == expected_usage
|
||||||
assert extras.get("custom_field") == "any value"
|
assert extras.get("custom_field") == "any value"
|
||||||
|
|
||||||
def test_mixed_extra_items_types(self) -> None:
|
|
||||||
"""Test that extra items can be various types (str, int, bool, dict, list)."""
|
|
||||||
block = create_text_block("Test content")
|
|
||||||
|
|
||||||
# Add various types of extra fields
|
|
||||||
block["string_field"] = "string value" # type: ignore[typeddict-unknown-key]
|
|
||||||
block["int_field"] = 42 # type: ignore[typeddict-unknown-key]
|
|
||||||
block["float_field"] = 3.14 # type: ignore[typeddict-unknown-key]
|
|
||||||
block["bool_field"] = True # type: ignore[typeddict-unknown-key]
|
|
||||||
block["list_field"] = ["item1", "item2", "item3"] # type: ignore[typeddict-unknown-key]
|
|
||||||
block["dict_field"] = {"nested": {"deeply": "nested value"}} # type: ignore[typeddict-unknown-key]
|
|
||||||
block["none_field"] = None # type: ignore[typeddict-unknown-key]
|
|
||||||
|
|
||||||
# Verify all types are preserved
|
|
||||||
assert block.get("string_field") == "string value"
|
|
||||||
assert block.get("int_field") == 42
|
|
||||||
assert block.get("float_field") == 3.14
|
|
||||||
assert block.get("bool_field") is True
|
|
||||||
assert block.get("list_field") == ["item1", "item2", "item3"]
|
|
||||||
dict_field = block.get("dict_field", {})
|
|
||||||
assert isinstance(dict_field, dict)
|
|
||||||
nested = dict_field.get("nested", {})
|
|
||||||
assert isinstance(nested, dict)
|
|
||||||
assert nested.get("deeply") == "nested value"
|
|
||||||
assert block.get("none_field") is None
|
|
||||||
|
|
||||||
def test_extra_items_do_not_interfere_with_standard_fields(self) -> None:
|
def test_extra_items_do_not_interfere_with_standard_fields(self) -> None:
|
||||||
"""Test that extra items don't interfere with standard field access."""
|
"""Test that extra items don't interfere with standard field access."""
|
||||||
block = create_text_block("Original text", index=1)
|
block = create_text_block("Original text", index=1)
|
||||||
@ -567,22 +525,21 @@ class TestExtraItems:
|
|||||||
block = create_image_block(url="https://example.com/image.jpg")
|
block = create_image_block(url="https://example.com/image.jpg")
|
||||||
|
|
||||||
# Add an extra field
|
# Add an extra field
|
||||||
block["status"] = "pending" # type: ignore[typeddict-unknown-key]
|
block["extras"] = {"status": "pending"}
|
||||||
assert block.get("status") == "pending"
|
assert block["extras"].get("status") == "pending"
|
||||||
|
|
||||||
# Modify the extra field
|
# Modify the extra field
|
||||||
block["status"] = "processed" # type: ignore[typeddict-unknown-key]
|
block["extras"] = {"status": "processed"}
|
||||||
assert block.get("status") == "processed"
|
assert block["extras"].get("status") == "processed"
|
||||||
|
|
||||||
# Add more fields
|
# Add more fields
|
||||||
block["metadata"] = {"version": 1} # type: ignore[typeddict-unknown-key]
|
block["extras"] = {"metadata": {"version": 1}}
|
||||||
metadata = block.get("metadata", {})
|
metadata = block["extras"].get("metadata", {})
|
||||||
assert isinstance(metadata, dict)
|
assert isinstance(metadata, dict)
|
||||||
assert metadata.get("version") == 1
|
assert metadata.get("version") == 1
|
||||||
|
|
||||||
# Modify nested extra field
|
# Modify nested extra field
|
||||||
block["metadata"]["version"] = 2 # type: ignore[typeddict-item]
|
metadata["version"] = 2
|
||||||
metadata = block.get("metadata", {})
|
|
||||||
assert isinstance(metadata, dict)
|
assert isinstance(metadata, dict)
|
||||||
assert metadata.get("version") == 2
|
assert metadata.get("version") == 2
|
||||||
|
|
||||||
@ -590,40 +547,36 @@ class TestExtraItems:
|
|||||||
"""Test that all content block types support extra items."""
|
"""Test that all content block types support extra items."""
|
||||||
# Test each content block type
|
# Test each content block type
|
||||||
text_block = create_text_block("test")
|
text_block = create_text_block("test")
|
||||||
text_block["extra"] = "text_extra" # type: ignore[typeddict-unknown-key]
|
text_block["extras"] = {"text_extra": "a"}
|
||||||
assert text_block.get("extra") == "text_extra"
|
assert text_block.get("extras") == {"text_extra": "a"}
|
||||||
|
|
||||||
image_block = create_image_block(url="https://example.com/image.jpg")
|
image_block = create_image_block(url="https://example.com/image.jpg")
|
||||||
image_block["extra"] = "image_extra" # type: ignore[typeddict-unknown-key]
|
image_block["extras"] = {"image_extra": "a"}
|
||||||
assert image_block.get("extra") == "image_extra"
|
assert image_block.get("extras") == {"image_extra": "a"}
|
||||||
|
|
||||||
video_block = create_video_block(url="https://example.com/video.mp4")
|
video_block = create_video_block(url="https://example.com/video.mp4")
|
||||||
video_block["extra"] = "video_extra" # type: ignore[typeddict-unknown-key]
|
video_block["extras"] = {"video_extra": "a"}
|
||||||
assert video_block.get("extra") == "video_extra"
|
assert video_block.get("extras") == {"video_extra": "a"}
|
||||||
|
|
||||||
audio_block = create_audio_block(url="https://example.com/audio.mp3")
|
audio_block = create_audio_block(url="https://example.com/audio.mp3")
|
||||||
audio_block["extra"] = "audio_extra" # type: ignore[typeddict-unknown-key]
|
audio_block["extras"] = {"audio_extra": "a"}
|
||||||
assert audio_block.get("extra") == "audio_extra"
|
assert audio_block.get("extras") == {"audio_extra": "a"}
|
||||||
|
|
||||||
file_block = create_file_block(url="https://example.com/file.pdf")
|
file_block = create_file_block(url="https://example.com/file.pdf")
|
||||||
file_block["extra"] = "file_extra" # type: ignore[typeddict-unknown-key]
|
file_block["extras"] = {"file_extra": "a"}
|
||||||
assert file_block.get("extra") == "file_extra"
|
assert file_block.get("extras") == {"file_extra": "a"}
|
||||||
|
|
||||||
plain_text_block = create_plaintext_block("content")
|
plain_text_block = create_plaintext_block("content")
|
||||||
plain_text_block["extra"] = "plaintext_extra" # type: ignore[typeddict-unknown-key]
|
plain_text_block["extras"] = {"plaintext_extra": "a"}
|
||||||
assert plain_text_block.get("extra") == "plaintext_extra"
|
assert plain_text_block.get("extras") == {"plaintext_extra": "a"}
|
||||||
|
|
||||||
tool_call = create_tool_call("tool", {"arg": "value"})
|
tool_call = create_tool_call("tool", {"arg": "value"})
|
||||||
tool_call["extra"] = "tool_extra" # type: ignore[typeddict-unknown-key]
|
tool_call["extras"] = {"tool_extra": "a"}
|
||||||
assert tool_call.get("extra") == "tool_extra"
|
assert tool_call.get("extras") == {"tool_extra": "a"}
|
||||||
|
|
||||||
reasoning_block = create_reasoning_block("reasoning")
|
reasoning_block = create_reasoning_block("reasoning")
|
||||||
reasoning_block["extra"] = "reasoning_extra" # type: ignore[typeddict-unknown-key]
|
reasoning_block["extras"] = {"reasoning_extra": "a"}
|
||||||
assert reasoning_block.get("extra") == "reasoning_extra"
|
assert reasoning_block.get("extras") == {"reasoning_extra": "a"}
|
||||||
|
|
||||||
non_standard_block = create_non_standard_block({"data": "value"})
|
|
||||||
non_standard_block["extra"] = "non_standard_extra" # type: ignore[typeddict-unknown-key]
|
|
||||||
assert non_standard_block.get("extra") == "non_standard_extra"
|
|
||||||
|
|
||||||
|
|
||||||
class TestExtrasField:
|
class TestExtrasField:
|
||||||
|
@ -81,7 +81,7 @@ def test_structured_prompt_dict() -> None:
|
|||||||
|
|
||||||
chain = loads(dumps(prompt)) | model
|
chain = loads(dumps(prompt)) | model
|
||||||
|
|
||||||
assert chain.invoke({"hello": "there"}) == {"name": 1, "value": 42} # type: ignore[comparison-overlap]
|
assert chain.invoke({"hello": "there"}) == {"name": 1, "value": 42}
|
||||||
|
|
||||||
|
|
||||||
def test_structured_prompt_kwargs() -> None:
|
def test_structured_prompt_kwargs() -> None:
|
||||||
@ -104,7 +104,7 @@ def test_structured_prompt_kwargs() -> None:
|
|||||||
assert chain.invoke({"hello": "there"}) == {"name": 1, "value": 7} # type: ignore[comparison-overlap]
|
assert chain.invoke({"hello": "there"}) == {"name": 1, "value": 7} # type: ignore[comparison-overlap]
|
||||||
assert loads(dumps(prompt)).model_dump() == prompt.model_dump()
|
assert loads(dumps(prompt)).model_dump() == prompt.model_dump()
|
||||||
chain = loads(dumps(prompt)) | model
|
chain = loads(dumps(prompt)) | model
|
||||||
assert chain.invoke({"hello": "there"}) == {"name": 1, "value": 7} # type: ignore[comparison-overlap]
|
assert chain.invoke({"hello": "there"}) == {"name": 1, "value": 7}
|
||||||
|
|
||||||
class OutputSchema(BaseModel):
|
class OutputSchema(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
|
1081
libs/core/uv.lock
1081
libs/core/uv.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user