diff --git a/libs/core/langchain_core/_api/beta_decorator.py b/libs/core/langchain_core/_api/beta_decorator.py index 4db13fa3b62..a095f425fa8 100644 --- a/libs/core/langchain_core/_api/beta_decorator.py +++ b/libs/core/langchain_core/_api/beta_decorator.py @@ -125,7 +125,7 @@ def beta( _name = _name or obj.__qualname__ old_doc = obj.__doc__ - def finalize(wrapper: Callable[..., Any], new_doc: str) -> T: # noqa: ARG001 + def finalize(_: Callable[..., Any], new_doc: str, /) -> T: """Finalize the annotation of a class.""" # Can't set new_doc on some extension objects. with contextlib.suppress(AttributeError): @@ -168,7 +168,7 @@ def beta( emit_warning() obj.fdel(instance) - def finalize(_wrapper: Callable[..., Any], new_doc: str) -> Any: + def finalize(_: Callable[..., Any], new_doc: str, /) -> Any: """Finalize the property.""" return property(fget=_fget, fset=_fset, fdel=_fdel, doc=new_doc) @@ -181,7 +181,7 @@ def beta( wrapped = obj old_doc = wrapped.__doc__ - def finalize(wrapper: Callable[..., Any], new_doc: str) -> T: + def finalize(wrapper: Callable[..., Any], new_doc: str, /) -> T: """Wrap the wrapped function using the wrapper and update the docstring. Args: diff --git a/libs/core/langchain_core/_api/deprecation.py b/libs/core/langchain_core/_api/deprecation.py index ede02915fd8..06fa1a2a547 100644 --- a/libs/core/langchain_core/_api/deprecation.py +++ b/libs/core/langchain_core/_api/deprecation.py @@ -222,7 +222,7 @@ def deprecated( _name = _name or obj.__qualname__ old_doc = obj.__doc__ - def finalize(wrapper: Callable[..., Any], new_doc: str) -> T: # noqa: ARG001 + def finalize(_: Callable[..., Any], new_doc: str, /) -> T: """Finalize the deprecation of a class.""" # Can't set new_doc on some extension objects. with contextlib.suppress(AttributeError): @@ -257,7 +257,7 @@ def deprecated( raise ValueError(msg) old_doc = obj.description - def finalize(wrapper: Callable[..., Any], new_doc: str) -> T: # noqa: ARG001 + def finalize(_: Callable[..., Any], new_doc: str, /) -> T: return cast( "T", FieldInfoV1( @@ -278,7 +278,7 @@ def deprecated( raise ValueError(msg) old_doc = obj.description - def finalize(wrapper: Callable[..., Any], new_doc: str) -> T: # noqa: ARG001 + def finalize(_: Callable[..., Any], new_doc: str, /) -> T: return cast( "T", FieldInfo( @@ -336,7 +336,7 @@ def deprecated( if _name == "": _name = set_name - def finalize(wrapper: Callable[..., Any], new_doc: str) -> T: # noqa: ARG001 + def finalize(_: Callable[..., Any], new_doc: str, /) -> T: """Finalize the property.""" prop = _DeprecatedProperty( fget=obj.fget, fset=obj.fset, fdel=obj.fdel, doc=new_doc @@ -357,7 +357,7 @@ def deprecated( wrapped = obj old_doc = wrapped.__doc__ - def finalize(wrapper: Callable[..., Any], new_doc: str) -> T: + def finalize(wrapper: Callable[..., Any], new_doc: str, /) -> T: """Wrap the wrapped function using the wrapper and update the docstring. Args: diff --git a/libs/core/langchain_core/language_models/chat_models.py b/libs/core/langchain_core/language_models/chat_models.py index 739f31ff49c..4a1c3867745 100644 --- a/libs/core/langchain_core/language_models/chat_models.py +++ b/libs/core/langchain_core/language_models/chat_models.py @@ -5,7 +5,6 @@ from __future__ import annotations import asyncio import inspect import json -import typing from abc import ABC, abstractmethod from collections.abc import AsyncIterator, Callable, Iterator, Sequence from functools import cached_property @@ -74,6 +73,7 @@ from langchain_core.utils.pydantic import TypeBaseModel, is_basemodel_subclass from langchain_core.utils.utils import LC_ID_PREFIX, from_env if TYPE_CHECKING: + import builtins import uuid from langchain_core.output_parsers.base import OutputParserLike @@ -1520,9 +1520,7 @@ class BaseChatModel(BaseLanguageModel[AIMessage], ABC): def bind_tools( self, - tools: Sequence[ - typing.Dict[str, Any] | type | Callable | BaseTool # noqa: UP006 - ], + tools: Sequence[builtins.dict[str, Any] | type | Callable | BaseTool], *, tool_choice: str | None = None, **kwargs: Any, @@ -1541,11 +1539,11 @@ class BaseChatModel(BaseLanguageModel[AIMessage], ABC): def with_structured_output( self, - schema: typing.Dict | type, # noqa: UP006 + schema: builtins.dict[str, Any] | type, *, include_raw: bool = False, **kwargs: Any, - ) -> Runnable[LanguageModelInput, typing.Dict | BaseModel]: # noqa: UP006 + ) -> Runnable[LanguageModelInput, builtins.dict[str, Any] | BaseModel]: """Model wrapper that returns outputs formatted to match the given schema. Args: diff --git a/libs/core/langchain_core/load/_validation.py b/libs/core/langchain_core/load/_validation.py index a8adc36f040..a8502d34b29 100644 --- a/libs/core/langchain_core/load/_validation.py +++ b/libs/core/langchain_core/load/_validation.py @@ -20,6 +20,11 @@ NOT instantiated as LC objects. from typing import Any +from langchain_core.load.serializable import ( + Serializable, + to_json_not_implemented, +) + _LC_ESCAPED_KEY = "__lc_escaped__" """Sentinel key used to mark escaped user dicts during serialization. @@ -73,11 +78,6 @@ def _serialize_value(obj: Any) -> Any: Returns: The serialized value with user dicts escaped as needed. """ - from langchain_core.load.serializable import ( # noqa: PLC0415 - Serializable, - to_json_not_implemented, - ) - if isinstance(obj, Serializable): # This is an LC object - serialize it properly (not escaped) return _serialize_lc_object(obj) @@ -128,8 +128,6 @@ def _serialize_lc_object(obj: Any) -> dict[str, Any]: metadata) that contains `'lc'` keys. Secret fields (from `lc_secrets`) are skipped because `to_json()` replaces their values with secret markers. """ - from langchain_core.load.serializable import Serializable # noqa: PLC0415 - if not isinstance(obj, Serializable): msg = f"Expected Serializable, got {type(obj)}" raise TypeError(msg) diff --git a/libs/core/langchain_core/load/serializable.py b/libs/core/langchain_core/load/serializable.py index df69e8ca916..431ff02dbaa 100644 --- a/libs/core/langchain_core/load/serializable.py +++ b/libs/core/langchain_core/load/serializable.py @@ -133,12 +133,13 @@ class Serializable(BaseModel, ABC): def get_lc_namespace(cls) -> list[str]: """Get the namespace of the LangChain object. - For example, if the class is [`langchain.llms.openai.OpenAI`][langchain_openai.OpenAI], - then the namespace is `["langchain", "llms", "openai"]` + For example, if the class is + [`langchain.llms.openai.OpenAI`][langchain_openai.OpenAI], then the namespace is + `["langchain", "llms", "openai"]` Returns: The namespace. - """ # noqa: E501 + """ return cls.__module__.split(".") @property diff --git a/libs/core/langchain_core/messages/ai.py b/libs/core/langchain_core/messages/ai.py index 499b26bba78..4b64b4b2121 100644 --- a/libs/core/langchain_core/messages/ai.py +++ b/libs/core/langchain_core/messages/ai.py @@ -406,8 +406,8 @@ class AIMessageChunk(AIMessage, BaseMessageChunk): """ @property + @override def lc_attributes(self) -> dict: - """Attributes to be serialized, even if they are derived from other initialization args.""" # noqa: E501 return { "tool_calls": self.tool_calls, "invalid_tool_calls": self.invalid_tool_calls, @@ -564,7 +564,11 @@ class AIMessageChunk(AIMessage, BaseMessageChunk): @model_validator(mode="after") def init_server_tool_calls(self) -> Self: - """Parse `server_tool_call_chunks` from [`ServerToolCallChunk`][langchain.messages.ServerToolCallChunk] objects.""" # noqa: E501 + """Initialize server tool calls. + + Parse `server_tool_call_chunks` from + [`ServerToolCallChunk`][langchain.messages.ServerToolCallChunk] objects. + """ if ( self.chunk_position == "last" and self.response_metadata.get("output_version") == "v1" diff --git a/libs/core/langchain_core/messages/base.py b/libs/core/langchain_core/messages/base.py index af5d2ee98bb..1c52af9732a 100644 --- a/libs/core/langchain_core/messages/base.py +++ b/libs/core/langchain_core/messages/base.py @@ -8,6 +8,7 @@ from pydantic import ConfigDict, Field from langchain_core._api.deprecation import warn_deprecated from langchain_core.load.serializable import Serializable +from langchain_core.messages import content as types from langchain_core.utils import get_bolded_text from langchain_core.utils._merge import merge_dicts, merge_lists from langchain_core.utils.interactive_env import is_interactive_env @@ -17,7 +18,6 @@ if TYPE_CHECKING: from typing_extensions import Self - from langchain_core.messages import content as types from langchain_core.prompts.chat import ChatPromptTemplate @@ -204,7 +204,6 @@ class BaseMessage(Serializable): """ # Needed here to avoid circular import, as these classes import BaseMessages - from langchain_core.messages import content as types # noqa: PLC0415 from langchain_core.messages.block_translators.anthropic import ( # noqa: PLC0415 _convert_to_v1_from_anthropic_input, ) diff --git a/libs/core/langchain_core/messages/block_translators/google_genai.py b/libs/core/langchain_core/messages/block_translators/google_genai.py index 901538dc5df..dab6377c385 100644 --- a/libs/core/langchain_core/messages/block_translators/google_genai.py +++ b/libs/core/langchain_core/messages/block_translators/google_genai.py @@ -9,6 +9,13 @@ from langchain_core.messages import AIMessage, AIMessageChunk from langchain_core.messages import content as types from langchain_core.messages.content import Citation, create_citation +try: + import filetype # type: ignore[import-not-found] + + _HAS_FILETYPE = True +except ImportError: + _HAS_FILETYPE = False + def _bytes_to_b64_str(bytes_: bytes) -> str: """Convert bytes to base64 encoded string.""" @@ -391,9 +398,7 @@ def _convert_to_v1_from_genai(message: AIMessage) -> list[types.ContentBlock]: "base64": url, } - try: - import filetype # type: ignore[import-not-found] # noqa: PLC0415 - + if _HAS_FILETYPE: # Guess MIME type based on file bytes mime_type = None kind = filetype.guess(decoded_bytes) @@ -401,9 +406,6 @@ def _convert_to_v1_from_genai(message: AIMessage) -> list[types.ContentBlock]: mime_type = kind.mime if mime_type: image_url_b64_block["mime_type"] = mime_type - except ImportError: - # filetype library not available, skip type detection - pass converted_blocks.append( cast("types.ImageContentBlock", image_url_b64_block) diff --git a/libs/core/langchain_core/messages/block_translators/groq.py b/libs/core/langchain_core/messages/block_translators/groq.py index 84789a7a8ec..bcaa1a15b7d 100644 --- a/libs/core/langchain_core/messages/block_translators/groq.py +++ b/libs/core/langchain_core/messages/block_translators/groq.py @@ -105,15 +105,15 @@ def _convert_to_v1_from_groq(message: AIMessage) -> list[types.ContentBlock]: if isinstance(message.content, str) and message.content: content_blocks.append({"type": "text", "text": message.content}) - for tool_call in message.tool_calls: - content_blocks.append( # noqa: PERF401 - { - "type": "tool_call", - "name": tool_call["name"], - "args": tool_call["args"], - "id": tool_call.get("id"), - } - ) + content_blocks.extend( + { + "type": "tool_call", + "name": tool_call["name"], + "args": tool_call["args"], + "id": tool_call.get("id"), + } + for tool_call in message.tool_calls + ) return content_blocks diff --git a/libs/core/langchain_core/messages/block_translators/openai.py b/libs/core/langchain_core/messages/block_translators/openai.py index a3d4234dfd6..593e004c381 100644 --- a/libs/core/langchain_core/messages/block_translators/openai.py +++ b/libs/core/langchain_core/messages/block_translators/openai.py @@ -10,12 +10,13 @@ from langchain_core.language_models._utils import ( _parse_data_uri, is_openai_data_block, ) +from langchain_core.messages import AIMessageChunk from langchain_core.messages import content as types if TYPE_CHECKING: from collections.abc import Iterable - from langchain_core.messages import AIMessage, AIMessageChunk + from langchain_core.messages import AIMessage def convert_to_openai_image_block(block: dict[str, Any]) -> dict: @@ -192,8 +193,6 @@ def _convert_to_v1_from_chat_completions_input( Returns: Updated list with OpenAI blocks converted to v1 format. """ - from langchain_core.messages import content as types # noqa: PLC0415 - converted_blocks = [] unpacked_blocks: list[dict[str, Any]] = [ cast("dict[str, Any]", block) @@ -288,8 +287,6 @@ _FUNCTION_CALL_IDS_MAP_KEY = "__openai_function_call_ids__" def _convert_from_v03_ai_message(message: AIMessage) -> AIMessage: """Convert v0 AIMessage into `output_version="responses/v1"` format.""" - from langchain_core.messages import AIMessageChunk # noqa: PLC0415 - # Only update ChatOpenAI v0.3 AIMessages is_chatopenai_v03 = ( isinstance(message.content, list) @@ -706,8 +703,6 @@ def _convert_to_v1_from_responses(message: AIMessage) -> list[types.ContentBlock ) = None call_id = block.get("call_id", "") - from langchain_core.messages import AIMessageChunk # noqa: PLC0415 - if ( isinstance(message, AIMessageChunk) and len(message.tool_call_chunks) == 1 diff --git a/libs/core/langchain_core/messages/utils.py b/libs/core/langchain_core/messages/utils.py index 2ac913a12e5..609d8045ac2 100644 --- a/libs/core/langchain_core/messages/utils.py +++ b/libs/core/langchain_core/messages/utils.py @@ -563,6 +563,7 @@ def filter_messages( ): continue + new_msg = msg if isinstance(exclude_tool_calls, (list, tuple, set)): if isinstance(msg, AIMessage) and msg.tool_calls: tool_calls = [ @@ -586,7 +587,7 @@ def filter_messages( ) ] - msg = msg.model_copy( # noqa: PLW2901 + new_msg = msg.model_copy( update={"tool_calls": tool_calls, "content": content} ) elif ( @@ -597,11 +598,11 @@ def filter_messages( # default to inclusion when no inclusion criteria given. if ( not (include_types or include_ids or include_names) - or (include_names and msg.name in include_names) - or (include_types and _is_message_type(msg, include_types)) - or (include_ids and msg.id in include_ids) + or (include_names and new_msg.name in include_names) + or (include_types and _is_message_type(new_msg, include_types)) + or (include_ids and new_msg.id in include_ids) ): - filtered.append(msg) + filtered.append(new_msg) return filtered diff --git a/libs/core/langchain_core/output_parsers/base.py b/libs/core/langchain_core/output_parsers/base.py index 18d1d547533..7796e2e59ce 100644 --- a/libs/core/langchain_core/output_parsers/base.py +++ b/libs/core/langchain_core/output_parsers/base.py @@ -47,7 +47,7 @@ class BaseLLMOutputParser(ABC, Generic[T]): async def aparse_result( self, result: list[Generation], *, partial: bool = False ) -> T: - """Async parse a list of candidate model `Generation` objects into a specific format. + """Parse a list of candidate model `Generation` objects into a specific format. Args: result: A list of `Generation` to be parsed. The Generations are assumed @@ -57,7 +57,7 @@ class BaseLLMOutputParser(ABC, Generic[T]): Returns: Structured output. - """ # noqa: E501 + """ return await run_in_executor(None, self.parse_result, result, partial=partial) @@ -268,7 +268,7 @@ class BaseOutputParser( async def aparse_result( self, result: list[Generation], *, partial: bool = False ) -> T: - """Async parse a list of candidate model `Generation` objects into a specific format. + """Parse a list of candidate model `Generation` objects into a specific format. The return value is parsed from only the first `Generation` in the result, which is assumed to be the highest-likelihood `Generation`. @@ -281,7 +281,7 @@ class BaseOutputParser( Returns: Structured output. - """ # noqa: E501 + """ return await run_in_executor(None, self.parse_result, result, partial=partial) async def aparse(self, text: str) -> T: diff --git a/libs/core/langchain_core/prompts/base.py b/libs/core/langchain_core/prompts/base.py index dbe21834a24..6318d4e58dc 100644 --- a/libs/core/langchain_core/prompts/base.py +++ b/libs/core/langchain_core/prompts/base.py @@ -2,9 +2,9 @@ from __future__ import annotations +import builtins # noqa: TC003 import contextlib import json -import typing from abc import ABC, abstractmethod from collections.abc import Mapping # noqa: TC003 from functools import cached_property @@ -51,7 +51,7 @@ class BasePromptTemplate( These variables are auto inferred from the prompt and user need not provide them. """ - input_types: typing.Dict[str, Any] = Field(default_factory=dict, exclude=True) # noqa: UP006 + input_types: builtins.dict[str, Any] = Field(default_factory=dict, exclude=True) """A dictionary of the types of the variables the prompt template expects. If not provided, all variables are assumed to be strings. @@ -64,7 +64,7 @@ class BasePromptTemplate( Partial variables populate the template so that you don't need to pass them in every time you call the prompt. """ - metadata: typing.Dict[str, Any] | None = None # noqa: UP006 + metadata: builtins.dict[str, Any] | None = None """Metadata to be used for tracing.""" tags: list[str] | None = None """Tags to be used for tracing.""" diff --git a/libs/core/langchain_core/prompts/chat.py b/libs/core/langchain_core/prompts/chat.py index f58ba9d3f5a..607a9be61b6 100644 --- a/libs/core/langchain_core/prompts/chat.py +++ b/libs/core/langchain_core/prompts/chat.py @@ -845,9 +845,9 @@ class ChatPromptTemplate(BaseChatPromptTemplate): !!! note "Single-variable template" - If your prompt has only a single input variable (i.e., 1 instance of "{variable_nams}"), - and you invoke the template with a non-dict object, the prompt template will - inject the provided argument into that variable location. + If your prompt has only a single input variable (i.e., 1 instance of + "{variable_nams}"), and you invoke the template with a non-dict object, the + prompt template will inject the provided argument into that variable location. ```python from langchain_core.prompts import ChatPromptTemplate @@ -871,7 +871,7 @@ class ChatPromptTemplate(BaseChatPromptTemplate): # ] # ) ``` - """ # noqa: E501 + """ messages: Annotated[list[MessageLike], SkipValidation()] """List of messages consisting of either message prompt templates or messages.""" diff --git a/libs/core/langchain_core/runnables/base.py b/libs/core/langchain_core/runnables/base.py index b3435cfe6c4..8e385a1a2bf 100644 --- a/libs/core/langchain_core/runnables/base.py +++ b/libs/core/langchain_core/runnables/base.py @@ -369,7 +369,7 @@ class Runnable(ABC, Generic[Input, Output]): def get_input_schema( self, - config: RunnableConfig | None = None, # noqa: ARG002 + config: RunnableConfig | None = None, ) -> type[BaseModel]: """Get a Pydantic model that can be used to validate input to the `Runnable`. @@ -385,6 +385,7 @@ class Runnable(ABC, Generic[Input, Output]): Returns: A Pydantic model that can be used to validate input. """ + _ = config root_type = self.InputType if ( @@ -447,7 +448,7 @@ class Runnable(ABC, Generic[Input, Output]): def get_output_schema( self, - config: RunnableConfig | None = None, # noqa: ARG002 + config: RunnableConfig | None = None, ) -> type[BaseModel]: """Get a Pydantic model that can be used to validate output to the `Runnable`. @@ -463,6 +464,7 @@ class Runnable(ABC, Generic[Input, Output]): Returns: A Pydantic model that can be used to validate output. """ + _ = config root_type = self.OutputType if ( diff --git a/libs/core/langchain_core/tools/base.py b/libs/core/langchain_core/tools/base.py index aa85afc0e67..0b80fd27d7c 100644 --- a/libs/core/langchain_core/tools/base.py +++ b/libs/core/langchain_core/tools/base.py @@ -5,6 +5,7 @@ from __future__ import annotations import functools import inspect import json +import logging import typing import warnings from abc import ABC, abstractmethod @@ -82,6 +83,8 @@ TOOL_MESSAGE_BLOCK_TYPES = ( "file", ) +_logger = logging.getLogger(__name__) + class SchemaAnnotationError(TypeError): """Raised when args_schema is missing or has an incorrect type annotation.""" @@ -815,9 +818,12 @@ class ChildTool(BaseTool): for field_name, field_type in annotations.items(): if _is_injected_arg_type(field_type): filtered_keys.add(field_name) - except Exception: # noqa: S110 + except Exception: # If we can't get annotations, just use FILTERED_ARGS - pass + _logger.debug( + "Failed to get args_schema annotations for filtering.", + exc_info=True, + ) # Filter out the injected keys from tool_input return {k: v for k, v in tool_input.items() if k not in filtered_keys} diff --git a/libs/core/langchain_core/tracers/core.py b/libs/core/langchain_core/tracers/core.py index 17ef9b9521e..ebd0f989259 100644 --- a/libs/core/langchain_core/tracers/core.py +++ b/libs/core/langchain_core/tracers/core.py @@ -221,9 +221,10 @@ class _TracerCore(ABC): token: str, run_id: UUID, chunk: GenerationChunk | ChatGenerationChunk | None = None, - parent_run_id: UUID | None = None, # noqa: ARG002 + parent_run_id: UUID | None = None, ) -> Run: """Append token event to LLM run and return the run.""" + _ = parent_run_id llm_run = self._get_run(run_id, run_type={"llm", "chat_model"}) event_kwargs: dict[str, Any] = {"token": token} if chunk: @@ -538,43 +539,47 @@ class _TracerCore(ABC): """Return self copied.""" return self - def _end_trace(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _end_trace(self, run: Run) -> Coroutine[Any, Any, None] | None: """End a trace for a run. Args: run: The run. """ + _ = run return None - def _on_run_create(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_run_create(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process a run upon creation. Args: run: The created run. """ + _ = run return None - def _on_run_update(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_run_update(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process a run upon update. Args: run: The updated run. """ + _ = run return None - def _on_llm_start(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_llm_start(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the LLM Run upon start. Args: run: The LLM run. """ + _ = run return None def _on_llm_new_token( self, - run: Run, # noqa: ARG002 - token: str, # noqa: ARG002 - chunk: GenerationChunk | ChatGenerationChunk | None, # noqa: ARG002 + run: Run, + token: str, + chunk: GenerationChunk | ChatGenerationChunk | None, ) -> Coroutine[Any, Any, None] | None: """Process new LLM token. @@ -583,100 +588,113 @@ class _TracerCore(ABC): token: The new token. chunk: Optional chunk. """ + _ = (run, token, chunk) return None - def _on_llm_end(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_llm_end(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the LLM Run. Args: run: The LLM run. """ + _ = run return None - def _on_llm_error(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_llm_error(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the LLM Run upon error. Args: run: The LLM run. """ + _ = run return None - def _on_chain_start(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_chain_start(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Chain Run upon start. Args: run: The chain run. """ + _ = run return None - def _on_chain_end(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_chain_end(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Chain Run. Args: run: The chain run. """ + _ = run return None - def _on_chain_error(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_chain_error(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Chain Run upon error. Args: run: The chain run. """ + _ = run return None - def _on_tool_start(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_tool_start(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Tool Run upon start. Args: run: The tool run. """ + _ = run return None - def _on_tool_end(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_tool_end(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Tool Run. Args: run: The tool run. """ + _ = run return None - def _on_tool_error(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_tool_error(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Tool Run upon error. Args: run: The tool run. """ + _ = run return None - def _on_chat_model_start(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_chat_model_start(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Chat Model Run upon start. Args: run: The chat model run. """ + _ = run return None - def _on_retriever_start(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_retriever_start(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Retriever Run upon start. Args: run: The retriever run. """ + _ = run return None - def _on_retriever_end(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_retriever_end(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Retriever Run. Args: run: The retriever run. """ + _ = run return None - def _on_retriever_error(self, run: Run) -> Coroutine[Any, Any, None] | None: # noqa: ARG002 + def _on_retriever_error(self, run: Run) -> Coroutine[Any, Any, None] | None: """Process the Retriever Run upon error. Args: run: The retriever run. """ + _ = run return None diff --git a/libs/core/langchain_core/utils/json_schema.py b/libs/core/langchain_core/utils/json_schema.py index 11475accb0b..f07450556de 100644 --- a/libs/core/langchain_core/utils/json_schema.py +++ b/libs/core/langchain_core/utils/json_schema.py @@ -72,7 +72,7 @@ def _process_dict_properties( elif isinstance(value, (dict, list)): # Recursively process nested objects and arrays result[key] = _dereference_refs_helper( - value, full_schema, processed_refs, skip_keys, shallow_refs + value, full_schema, processed_refs, skip_keys, shallow_refs=shallow_refs ) else: # Copy primitive values directly @@ -85,7 +85,8 @@ def _dereference_refs_helper( full_schema: dict[str, Any], processed_refs: set[str] | None, skip_keys: Sequence[str], - shallow_refs: bool, # noqa: FBT001 + *, + shallow_refs: bool, ) -> Any: """Dereference JSON Schema $ref objects, handling both pure and mixed references. @@ -133,7 +134,11 @@ def _dereference_refs_helper( # Fetch and recursively resolve the referenced object referenced_object = deepcopy(_retrieve_ref(ref_path, full_schema)) resolved_reference = _dereference_refs_helper( - referenced_object, full_schema, processed_refs, skip_keys, shallow_refs + referenced_object, + full_schema, + processed_refs, + skip_keys, + shallow_refs=shallow_refs, ) # Clean up: remove from processing set before returning @@ -171,7 +176,7 @@ def _dereference_refs_helper( if isinstance(obj, list): return [ _dereference_refs_helper( - item, full_schema, processed_refs, skip_keys, shallow_refs + item, full_schema, processed_refs, skip_keys, shallow_refs=shallow_refs ) for item in obj ] @@ -260,5 +265,8 @@ def dereference_refs( keys_to_skip = list(skip_keys) if skip_keys is not None else ["$defs"] shallow = skip_keys is None return cast( - "dict", _dereference_refs_helper(schema_obj, full, None, keys_to_skip, shallow) + "dict", + _dereference_refs_helper( + schema_obj, full, None, keys_to_skip, shallow_refs=shallow + ), ) diff --git a/libs/core/tests/unit_tests/indexing/test_in_memory_indexer.py b/libs/core/tests/unit_tests/indexing/test_in_memory_indexer.py index decf9f67ac7..005cc66b45d 100644 --- a/libs/core/tests/unit_tests/indexing/test_in_memory_indexer.py +++ b/libs/core/tests/unit_tests/indexing/test_in_memory_indexer.py @@ -1,7 +1,5 @@ """Test in memory indexer.""" -from collections.abc import AsyncGenerator, Generator - import pytest from langchain_tests.integration_tests.indexer import ( AsyncDocumentIndexTestSuite, @@ -10,7 +8,6 @@ from langchain_tests.integration_tests.indexer import ( from typing_extensions import override from langchain_core.documents import Document -from langchain_core.indexing.base import DocumentIndex from langchain_core.indexing.in_memory import ( InMemoryDocumentIndex, ) @@ -19,16 +16,16 @@ from langchain_core.indexing.in_memory import ( class TestDocumentIndexerTestSuite(DocumentIndexerTestSuite): @pytest.fixture @override - def index(self) -> Generator[DocumentIndex, None, None]: - yield InMemoryDocumentIndex() # noqa: PT022 + def index(self) -> InMemoryDocumentIndex: + return InMemoryDocumentIndex() class TestAsyncDocumentIndexerTestSuite(AsyncDocumentIndexTestSuite): # Something funky is going on with mypy and async pytest fixture @pytest.fixture @override - async def index(self) -> AsyncGenerator[DocumentIndex, None]: - yield InMemoryDocumentIndex() # noqa: PT022 + async def index(self) -> InMemoryDocumentIndex: + return InMemoryDocumentIndex() def test_sync_retriever() -> None: diff --git a/libs/core/tests/unit_tests/prompts/test_chat.py b/libs/core/tests/unit_tests/prompts/test_chat.py index f395f5f9d9c..67f37496e79 100644 --- a/libs/core/tests/unit_tests/prompts/test_chat.py +++ b/libs/core/tests/unit_tests/prompts/test_chat.py @@ -1564,9 +1564,15 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": [], "template_format": "mustache", - "template": "Here is the expected answer or success criteria given by the teacher:", # noqa: E501 + "template": ( + "Here is the expected answer or success " + "criteria given by the teacher:" + ), "additional_content_fields": { - "text": "Here is the expected answer or success criteria given by the teacher:", # noqa: E501 + "text": ( + "Here is the expected answer or success " + "criteria given by the teacher:" + ), }, }, }, @@ -1600,9 +1606,17 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": [], "template_format": "mustache", - "template": "Note: This may be just one example of many possible correct ways for the student to respond.\n", # noqa: E501 + "template": ( + "Note: This may be just one example of many " + "possible correct ways for the student to " + "respond.\n" + ), "additional_content_fields": { - "text": "Note: This may be just one example of many possible correct ways for the student to respond.\n", # noqa: E501 + "text": ( + "Note: This may be just one example of " + "many possible correct ways for the " + "student to respond.\n" + ) }, }, }, @@ -1618,9 +1632,15 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": [], "template_format": "mustache", - "template": "For your evaluation of the student's response:\n", # noqa: E501 + "template": ( + "For your evaluation of the student's " + "response:\n" + ), "additional_content_fields": { - "text": "For your evaluation of the student's response:\n", # noqa: E501 + "text": ( + "For your evaluation of the student's " + "response:\n" + ), }, }, }, @@ -1636,9 +1656,15 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": [], "template_format": "mustache", - "template": "Here is a transcript of the student's explanation:", # noqa: E501 + "template": ( + "Here is a transcript of the student's " + "explanation:" + ), "additional_content_fields": { - "text": "Here is a transcript of the student's explanation:", # noqa: E501 + "text": ( + "Here is a transcript of the student's " + "explanation:" + ), }, }, }, @@ -1672,9 +1698,23 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": ["readingFluencyAnalysis"], "template_format": "mustache", - "template": "{{#readingFluencyAnalysis}} For this task, the student's reading pronunciation and fluency were important. Here is analysis of the student's oral response: \"{{readingFluencyAnalysis}}\" {{/readingFluencyAnalysis}}", # noqa: E501 + "template": ( + "{{#readingFluencyAnalysis}} For this task, " + "the student's reading pronunciation and " + "fluency were important. " + "Here is analysis of the student's oral " + 'response: "{{readingFluencyAnalysis}}" ' + "{{/readingFluencyAnalysis}}" + ), "additional_content_fields": { - "text": "{{#readingFluencyAnalysis}} For this task, the student's reading pronunciation and fluency were important. Here is analysis of the student's oral response: \"{{readingFluencyAnalysis}}\" {{/readingFluencyAnalysis}}", # noqa: E501 + "text": ( + "{{#readingFluencyAnalysis}} For this " + "task, the student's reading pronunciation " + "and fluency were important. " + "Here is analysis of the student's oral " + 'response: "{{readingFluencyAnalysis}}" ' + "{{/readingFluencyAnalysis}}" + ), }, }, }, @@ -1690,9 +1730,20 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": ["readingFluencyAnalysis"], "template_format": "mustache", - "template": "{{#readingFluencyAnalysis}}Root analysis of the student's response (step 3) in this oral analysis rather than inconsistencies in the transcript.{{/readingFluencyAnalysis}}", # noqa: E501 + "template": ( + "{{#readingFluencyAnalysis}}Root analysis of " + "the student's response (step 3) in this oral " + "analysis rather than inconsistencies in the " + "transcript.{{/readingFluencyAnalysis}}" + ), "additional_content_fields": { - "text": "{{#readingFluencyAnalysis}}Root analysis of the student's response (step 3) in this oral analysis rather than inconsistencies in the transcript.{{/readingFluencyAnalysis}}", # noqa: E501 + "text": ( + "{{#readingFluencyAnalysis}}Root analysis " + "of the student's response (step 3) in " + "this oral analysis rather than " + "inconsistencies in the transcript." + "{{/readingFluencyAnalysis}}" + ), }, }, }, @@ -1708,9 +1759,19 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": ["readingFluencyAnalysis"], "template_format": "mustache", - "template": "{{#readingFluencyAnalysis}}Remember this is a student, so we care about general fluency - not voice acting. {{/readingFluencyAnalysis}}\n", # noqa: E501 + "template": ( + "{{#readingFluencyAnalysis}}Remember this is a " + "student, so we care about general fluency - " + "not voice acting. " + "{{/readingFluencyAnalysis}}\n" + ), "additional_content_fields": { - "text": "{{#readingFluencyAnalysis}}Remember this is a student, so we care about general fluency - not voice acting. {{/readingFluencyAnalysis}}\n", # noqa: E501 + "text": ( + "{{#readingFluencyAnalysis}}Remember this " + "is a student, so we care about general " + "fluency - not voice acting. " + "{{/readingFluencyAnalysis}}\n" + ), }, }, }, @@ -1726,9 +1787,19 @@ def test_rendering_prompt_with_conditionals_no_empty_text_blocks() -> None: "kwargs": { "input_variables": ["multipleChoiceAnalysis"], "template_format": "mustache", - "template": "{{#multipleChoiceAnalysis}}Here is an analysis of the student's multiple choice response: {{multipleChoiceAnalysis}}{{/multipleChoiceAnalysis}}\n", # noqa: E501 + "template": ( + "{{#multipleChoiceAnalysis}}Here is an " + "analysis of the student's multiple choice " + "response: {{multipleChoiceAnalysis}}" + "{{/multipleChoiceAnalysis}}\n" + ), "additional_content_fields": { - "text": "{{#multipleChoiceAnalysis}}Here is an analysis of the student's multiple choice response: {{multipleChoiceAnalysis}}{{/multipleChoiceAnalysis}}\n", # noqa: E501 + "text": ( + "{{#multipleChoiceAnalysis}}Here is an " + "analysis of the student's multiple choice " + "response: {{multipleChoiceAnalysis}}" + "{{/multipleChoiceAnalysis}}\n" + ), }, }, }, diff --git a/libs/core/tests/unit_tests/runnables/test_configurable.py b/libs/core/tests/unit_tests/runnables/test_configurable.py index f397e249d9a..20732d76a51 100644 --- a/libs/core/tests/unit_tests/runnables/test_configurable.py +++ b/libs/core/tests/unit_tests/runnables/test_configurable.py @@ -43,15 +43,17 @@ class MyRunnable(RunnableSerializable[str, str]): def my_custom_function_w_config( self, - config: RunnableConfig | None = None, # noqa: ARG002 + config: RunnableConfig | None = None, ) -> str: + _ = config return self.my_property def my_custom_function_w_kw_config( self, *, - config: RunnableConfig | None = None, # noqa: ARG002 + config: RunnableConfig | None = None, ) -> str: + _ = config return self.my_property @@ -67,7 +69,8 @@ class MyOtherRunnable(RunnableSerializable[str, str]): def my_other_custom_function(self) -> str: return self.my_other_property - def my_other_custom_function_w_config(self, config: RunnableConfig) -> str: # noqa: ARG002 + def my_other_custom_function_w_config(self, config: RunnableConfig) -> str: + _ = config return self.my_other_property diff --git a/libs/core/tests/unit_tests/runnables/test_history.py b/libs/core/tests/unit_tests/runnables/test_history.py index 4dd492e5d60..3d6abf4ccc3 100644 --- a/libs/core/tests/unit_tests/runnables/test_history.py +++ b/libs/core/tests/unit_tests/runnables/test_history.py @@ -53,8 +53,10 @@ def _get_get_session_history( def test_input_messages() -> None: runnable = RunnableLambda( - lambda messages: "you said: " - + "\n".join(str(m.content) for m in messages if isinstance(m, HumanMessage)) + lambda messages: ( + "you said: " + + "\n".join(str(m.content) for m in messages if isinstance(m, HumanMessage)) + ) ) store: dict[str, InMemoryChatMessageHistory] = {} get_session_history = _get_get_session_history(store=store) @@ -82,8 +84,10 @@ def test_input_messages() -> None: async def test_input_messages_async() -> None: runnable = RunnableLambda( - lambda messages: "you said: " - + "\n".join(str(m.content) for m in messages if isinstance(m, HumanMessage)) + lambda messages: ( + "you said: " + + "\n".join(str(m.content) for m in messages if isinstance(m, HumanMessage)) + ) ) store: dict[str, InMemoryChatMessageHistory] = {} get_session_history = _get_get_session_history(store=store) @@ -114,9 +118,13 @@ async def test_input_messages_async() -> None: def test_input_dict() -> None: runnable = RunnableLambda( - lambda params: "you said: " - + "\n".join( - str(m.content) for m in params["messages"] if isinstance(m, HumanMessage) + lambda params: ( + "you said: " + + "\n".join( + str(m.content) + for m in params["messages"] + if isinstance(m, HumanMessage) + ) ) ) get_session_history = _get_get_session_history() @@ -134,9 +142,13 @@ def test_input_dict() -> None: async def test_input_dict_async() -> None: runnable = RunnableLambda( - lambda params: "you said: " - + "\n".join( - str(m.content) for m in params["messages"] if isinstance(m, HumanMessage) + lambda params: ( + "you said: " + + "\n".join( + str(m.content) + for m in params["messages"] + if isinstance(m, HumanMessage) + ) ) ) get_session_history = _get_get_session_history() @@ -156,10 +168,16 @@ async def test_input_dict_async() -> None: def test_input_dict_with_history_key() -> None: runnable = RunnableLambda( - lambda params: "you said: " - + "\n".join( - [str(m.content) for m in params["history"] if isinstance(m, HumanMessage)] - + [params["input"]] + lambda params: ( + "you said: " + + "\n".join( + [ + str(m.content) + for m in params["history"] + if isinstance(m, HumanMessage) + ] + + [params["input"]] + ) ) ) get_session_history = _get_get_session_history() @@ -178,10 +196,16 @@ def test_input_dict_with_history_key() -> None: async def test_input_dict_with_history_key_async() -> None: runnable = RunnableLambda( - lambda params: "you said: " - + "\n".join( - [str(m.content) for m in params["history"] if isinstance(m, HumanMessage)] - + [params["input"]] + lambda params: ( + "you said: " + + "\n".join( + [ + str(m.content) + for m in params["history"] + if isinstance(m, HumanMessage) + ] + + [params["input"]] + ) ) ) get_session_history = _get_get_session_history() @@ -832,8 +856,10 @@ class _RunnableLambdaWithRaiseError(RunnableLambda[Input, Output]): def test_get_output_messages_no_value_error() -> None: runnable = _RunnableLambdaWithRaiseError( - lambda messages: "you said: " - + "\n".join(str(m.content) for m in messages if isinstance(m, HumanMessage)) + lambda messages: ( + "you said: " + + "\n".join(str(m.content) for m in messages if isinstance(m, HumanMessage)) + ) ) get_session_history = _get_get_session_history() with_history = RunnableWithMessageHistory(runnable, get_session_history) diff --git a/libs/core/tests/unit_tests/runnables/test_runnable_events_v1.py b/libs/core/tests/unit_tests/runnables/test_runnable_events_v1.py index 1b0754e0032..dbe06ce6c4a 100644 --- a/libs/core/tests/unit_tests/runnables/test_runnable_events_v1.py +++ b/libs/core/tests/unit_tests/runnables/test_runnable_events_v1.py @@ -83,8 +83,9 @@ async def test_event_stream_with_simple_function_tool() -> None: return {"x": 5} @tool - def get_docs(x: int) -> list[Document]: # noqa: ARG001 + def get_docs(x: int) -> list[Document]: """Hello Doc.""" + _ = x return [Document(page_content="hello")] chain = RunnableLambda(foo) | get_docs @@ -1069,8 +1070,9 @@ async def test_event_streaming_with_tools() -> None: return "hello" @tool - def with_callbacks(callbacks: Callbacks) -> str: # noqa: ARG001 + def with_callbacks(callbacks: Callbacks) -> str: """A tool that does nothing.""" + _ = callbacks return "world" @tool @@ -1079,8 +1081,9 @@ async def test_event_streaming_with_tools() -> None: return {"x": x, "y": y} @tool - def with_parameters_and_callbacks(x: int, y: str, callbacks: Callbacks) -> dict: # noqa: ARG001 + def with_parameters_and_callbacks(x: int, y: str, callbacks: Callbacks) -> dict: """A tool that does nothing.""" + _ = callbacks return {"x": x, "y": y} # type ignores below because the tools don't appear to be runnables to type checkers diff --git a/libs/core/tests/unit_tests/runnables/test_runnable_events_v2.py b/libs/core/tests/unit_tests/runnables/test_runnable_events_v2.py index 3475b6d2cce..f6c94fa4be2 100644 --- a/libs/core/tests/unit_tests/runnables/test_runnable_events_v2.py +++ b/libs/core/tests/unit_tests/runnables/test_runnable_events_v2.py @@ -91,13 +91,15 @@ async def _collect_events( async def test_event_stream_with_simple_function_tool() -> None: """Test the event stream with a function and tool.""" - def foo(x: int) -> dict: # noqa: ARG001 + def foo(x: int) -> dict: """Foo.""" + _ = x return {"x": 5} @tool - def get_docs(x: int) -> list[Document]: # noqa: ARG001 + def get_docs(x: int) -> list[Document]: """Hello Doc.""" + _ = x return [Document(page_content="hello")] chain = RunnableLambda(foo) | get_docs @@ -1087,8 +1089,9 @@ async def test_event_streaming_with_tools() -> None: return "hello" @tool - def with_callbacks(callbacks: Callbacks) -> str: # noqa: ARG001 + def with_callbacks(callbacks: Callbacks) -> str: """A tool that does nothing.""" + _ = callbacks return "world" @tool @@ -1097,8 +1100,9 @@ async def test_event_streaming_with_tools() -> None: return {"x": x, "y": y} @tool - def with_parameters_and_callbacks(x: int, y: str, callbacks: Callbacks) -> dict: # noqa: ARG001 + def with_parameters_and_callbacks(x: int, y: str, callbacks: Callbacks) -> dict: """A tool that does nothing.""" + _ = callbacks return {"x": x, "y": y} # type ignores below because the tools don't appear to be runnables to type checkers diff --git a/libs/core/tests/unit_tests/utils/test_function_calling.py b/libs/core/tests/unit_tests/utils/test_function_calling.py index 1dcdf2ef637..953f488542e 100644 --- a/libs/core/tests/unit_tests/utils/test_function_calling.py +++ b/libs/core/tests/unit_tests/utils/test_function_calling.py @@ -1047,8 +1047,9 @@ def test__convert_typed_dict_to_openai_function_fail(typed_dict: type) -> None: def test_convert_union_type() -> None: @tool - def magic_function(value: int | str) -> str: # noqa: ARG001 + def magic_function(value: int | str) -> str: """Compute a magic function.""" + _ = value return "" result = convert_to_openai_function(magic_function)