From f4e83e0ad8d12bec889fb3b96ffedec183bf5267 Mon Sep 17 00:00:00 2001 From: Christophe Bornet Date: Mon, 8 Sep 2025 17:44:15 +0200 Subject: [PATCH] chore(core): fix some docstrings (from DOC preview rule) (#32833) * Add `Raises` sections * Add `Returns` sections * Add `Yields` sections --------- Co-authored-by: Mason Daugherty --- .../langchain_core/_api/beta_decorator.py | 3 + libs/core/langchain_core/_api/deprecation.py | 12 ++ libs/core/langchain_core/_api/path.py | 21 ++- libs/core/langchain_core/_import_utils.py | 7 + libs/core/langchain_core/agents.py | 8 +- libs/core/langchain_core/callbacks/base.py | 2 +- libs/core/langchain_core/callbacks/manager.py | 66 ++++---- libs/core/langchain_core/callbacks/usage.py | 3 + libs/core/langchain_core/chat_history.py | 3 + .../langchain_core/document_loaders/base.py | 30 +++- .../document_loaders/langsmith.py | 3 + libs/core/langchain_core/documents/base.py | 40 ++++- .../langchain_core/example_selectors/base.py | 12 ++ libs/core/langchain_core/exceptions.py | 7 + libs/core/langchain_core/indexing/api.py | 9 + libs/core/langchain_core/indexing/base.py | 11 +- .../core/langchain_core/indexing/in_memory.py | 26 ++- .../langchain_core/language_models/base.py | 6 + .../language_models/chat_models.py | 65 ++++++- .../language_models/fake_chat_models.py | 12 +- .../langchain_core/language_models/llms.py | 47 ++++- libs/core/langchain_core/load/load.py | 16 +- libs/core/langchain_core/load/serializable.py | 17 +- libs/core/langchain_core/messages/ai.py | 36 +++- libs/core/langchain_core/messages/base.py | 12 +- .../langchain_core/messages/content_blocks.py | 25 ++- libs/core/langchain_core/messages/tool.py | 27 ++- libs/core/langchain_core/messages/utils.py | 4 + .../langchain_core/output_parsers/list.py | 26 +-- .../output_parsers/openai_functions.py | 3 + .../output_parsers/openai_tools.py | 7 +- .../langchain_core/output_parsers/pydantic.py | 4 + .../langchain_core/output_parsers/string.py | 3 +- .../core/langchain_core/output_parsers/xml.py | 3 - .../langchain_core/outputs/chat_generation.py | 25 ++- .../core/langchain_core/outputs/generation.py | 17 +- .../core/langchain_core/outputs/llm_result.py | 9 +- libs/core/langchain_core/prompt_values.py | 14 +- libs/core/langchain_core/prompts/base.py | 11 +- libs/core/langchain_core/prompts/chat.py | 34 +++- libs/core/langchain_core/prompts/dict.py | 24 ++- libs/core/langchain_core/prompts/few_shot.py | 4 +- .../prompts/few_shot_with_templates.py | 6 +- libs/core/langchain_core/prompts/image.py | 17 +- libs/core/langchain_core/prompts/message.py | 8 +- libs/core/langchain_core/prompts/pipeline.py | 6 +- libs/core/langchain_core/prompts/prompt.py | 16 +- libs/core/langchain_core/prompts/string.py | 6 +- .../core/langchain_core/prompts/structured.py | 7 +- libs/core/langchain_core/retrievers.py | 1 + libs/core/langchain_core/runnables/base.py | 160 +++++++++++++++--- libs/core/langchain_core/runnables/branch.py | 14 +- libs/core/langchain_core/runnables/config.py | 9 +- .../langchain_core/runnables/configurable.py | 6 + .../langchain_core/runnables/fallbacks.py | 10 +- libs/core/langchain_core/runnables/graph.py | 14 +- .../langchain_core/runnables/graph_ascii.py | 33 +++- .../langchain_core/runnables/graph_png.py | 18 +- .../langchain_core/runnables/passthrough.py | 20 ++- libs/core/langchain_core/runnables/router.py | 8 +- libs/core/langchain_core/runnables/utils.py | 68 +++----- libs/core/langchain_core/stores.py | 20 +-- libs/core/langchain_core/tools/base.py | 23 ++- libs/core/langchain_core/tools/convert.py | 11 ++ libs/core/langchain_core/tools/simple.py | 38 ++++- libs/core/langchain_core/tools/structured.py | 27 ++- libs/core/langchain_core/tracers/base.py | 4 +- libs/core/langchain_core/tracers/context.py | 6 +- libs/core/langchain_core/tracers/core.py | 110 +++++++++--- .../langchain_core/tracers/event_stream.py | 31 +++- libs/core/langchain_core/tracers/langchain.py | 7 +- .../langchain_core/tracers/langchain_v1.py | 12 +- .../core/langchain_core/tracers/log_stream.py | 56 +++++- libs/core/langchain_core/tracers/schemas.py | 6 +- libs/core/langchain_core/utils/aiter.py | 18 +- libs/core/langchain_core/utils/env.py | 3 + .../langchain_core/utils/function_calling.py | 21 ++- .../langchain_core/utils/interactive_env.py | 6 +- libs/core/langchain_core/utils/iter.py | 14 +- libs/core/langchain_core/utils/json.py | 3 + libs/core/langchain_core/utils/json_schema.py | 7 + libs/core/langchain_core/utils/loading.py | 6 +- libs/core/langchain_core/utils/mustache.py | 37 ++-- libs/core/langchain_core/utils/pydantic.py | 36 +++- libs/core/langchain_core/utils/utils.py | 30 +++- libs/core/langchain_core/vectorstores/base.py | 6 - .../langchain_core/vectorstores/in_memory.py | 2 - 87 files changed, 1281 insertions(+), 400 deletions(-) diff --git a/libs/core/langchain_core/_api/beta_decorator.py b/libs/core/langchain_core/_api/beta_decorator.py index 76955b435f4..786f371ad21 100644 --- a/libs/core/langchain_core/_api/beta_decorator.py +++ b/libs/core/langchain_core/_api/beta_decorator.py @@ -63,6 +63,9 @@ def beta( addendum : str, optional Additional text appended directly to the final message. + Returns: + A decorator which can be used to mark functions or classes as beta. + Examples: .. code-block:: python diff --git a/libs/core/langchain_core/_api/deprecation.py b/libs/core/langchain_core/_api/deprecation.py index dc83afa2d17..7999d8a3216 100644 --- a/libs/core/langchain_core/_api/deprecation.py +++ b/libs/core/langchain_core/_api/deprecation.py @@ -129,6 +129,9 @@ def deprecated( package: str, optional The package of the deprecated object. + Returns: + A decorator to mark a function or class as deprecated. + Examples: .. code-block:: python @@ -544,6 +547,15 @@ def rename_parameter( is passed to *func*, a DeprecationWarning is emitted, and its value is used, even if *new* is also passed by keyword. + Args: + since: The version in which the parameter was renamed. + removal: The version in which the old parameter will be removed. + old: The old parameter name. + new: The new parameter name. + + Returns: + A decorator indicating that a parameter was renamed. + Example: .. code-block:: python diff --git a/libs/core/langchain_core/_api/path.py b/libs/core/langchain_core/_api/path.py index 0589ae44956..0d70b5a23a3 100644 --- a/libs/core/langchain_core/_api/path.py +++ b/libs/core/langchain_core/_api/path.py @@ -12,7 +12,15 @@ SEPARATOR = os.sep def get_relative_path( file: Union[Path, str], *, relative_to: Path = PACKAGE_DIR ) -> str: - """Get the path of the file as a relative path to the package directory.""" + """Get the path of the file as a relative path to the package directory. + + Args: + file: The file path to convert. + relative_to: The base path to make the file path relative to. + + Returns: + The relative path as a string. + """ if isinstance(file, str): file = Path(file) return str(file.relative_to(relative_to)) @@ -24,7 +32,16 @@ def as_import_path( suffix: Optional[str] = None, relative_to: Path = PACKAGE_DIR, ) -> str: - """Path of the file as a LangChain import exclude langchain top namespace.""" + """Path of the file as a LangChain import exclude langchain top namespace. + + Args: + file: The file path to convert. + suffix: An optional suffix to append to the import path. + relative_to: The base path to make the file path relative to. + + Returns: + The import path as a string. + """ if isinstance(file, str): file = Path(file) path = get_relative_path(file, relative_to=relative_to) diff --git a/libs/core/langchain_core/_import_utils.py b/libs/core/langchain_core/_import_utils.py index 6f4d0a5df2b..6e0ce0bbee9 100644 --- a/libs/core/langchain_core/_import_utils.py +++ b/libs/core/langchain_core/_import_utils.py @@ -17,6 +17,13 @@ def import_attr( module_name: The name of the module to import from. If None, the attribute is imported from the package itself. package: The name of the package where the module is located. + + Raises: + ImportError: If the module cannot be found. + AttributeError: If the attribute does not exist in the module or package. + + Returns: + The imported attribute. """ if module_name == "__module__" or module_name is None: try: diff --git a/libs/core/langchain_core/agents.py b/libs/core/langchain_core/agents.py index 8fa3fde3888..dae02a86f13 100644 --- a/libs/core/langchain_core/agents.py +++ b/libs/core/langchain_core/agents.py @@ -86,7 +86,8 @@ class AgentAction(Serializable): def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Default is ["langchain", "schema", "agent"]. + Returns: + ``["langchain", "schema", "agent"]`` """ return ["langchain", "schema", "agent"] @@ -155,14 +156,15 @@ class AgentFinish(Serializable): @classmethod def is_lc_serializable(cls) -> bool: - """Return whether or not the class is serializable.""" + """Return True as this class is serializable.""" return True @classmethod def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Default namespace is ["langchain", "schema", "agent"]. + Returns: + ``["langchain", "schema", "agent"]`` """ return ["langchain", "schema", "agent"] diff --git a/libs/core/langchain_core/callbacks/base.py b/libs/core/langchain_core/callbacks/base.py index 68c4e4a254b..3f3fd178cfd 100644 --- a/libs/core/langchain_core/callbacks/base.py +++ b/libs/core/langchain_core/callbacks/base.py @@ -922,7 +922,7 @@ class BaseCallbackManager(CallbackManagerMixin): self.inheritable_metadata = inheritable_metadata or {} def copy(self) -> Self: - """Copy the callback manager.""" + """Return a copy of the callback manager.""" return self.__class__( handlers=self.handlers.copy(), inheritable_handlers=self.inheritable_handlers.copy(), diff --git a/libs/core/langchain_core/callbacks/manager.py b/libs/core/langchain_core/callbacks/manager.py index 8498995f86d..4851a1c1c1d 100644 --- a/libs/core/langchain_core/callbacks/manager.py +++ b/libs/core/langchain_core/callbacks/manager.py @@ -88,8 +88,8 @@ def trace_as_chain_group( Must have ``LANGCHAIN_TRACING_V2`` env var set to true to see the trace in LangSmith. - Returns: - CallbackManagerForChainGroup: The callback manager for the chain group. + Yields: + The callback manager for the chain group. Example: .. code-block:: python @@ -170,8 +170,8 @@ async def atrace_as_chain_group( metadata (dict[str, Any], optional): The metadata to apply to all runs. Defaults to None. - Returns: - AsyncCallbackManager: The async callback manager for the chain group. + Yields: + The async callback manager for the chain group. .. note: Must have ``LANGCHAIN_TRACING_V2`` env var set to true to see the trace in @@ -519,15 +519,12 @@ class RunManager(BaseRunManager): self, text: str, **kwargs: Any, - ) -> Any: + ) -> None: """Run when a text is received. Args: text (str): The received text. **kwargs (Any): Additional keyword arguments. - - Returns: - Any: The result of the callback. """ if not self.handlers: return @@ -607,16 +604,12 @@ class AsyncRunManager(BaseRunManager, ABC): self, text: str, **kwargs: Any, - ) -> Any: + ) -> None: """Run when a text is received. Args: text (str): The received text. **kwargs (Any): Additional keyword arguments. - - Returns: - Any: The result of the callback. - """ if not self.handlers: return @@ -914,16 +907,12 @@ class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin): **kwargs, ) - def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any: + def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None: """Run when agent action is received. Args: action (AgentAction): The agent action. **kwargs (Any): Additional keyword arguments. - - Returns: - Any: The result of the callback. - """ if not self.handlers: return @@ -938,16 +927,12 @@ class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin): **kwargs, ) - def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> Any: + def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None: """Run when agent finish is received. Args: finish (AgentFinish): The agent finish. **kwargs (Any): Additional keyword arguments. - - Returns: - Any: The result of the callback. - """ if not self.handlers: return @@ -1033,16 +1018,12 @@ class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin): **kwargs, ) - async def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any: + async def on_agent_action(self, action: AgentAction, **kwargs: Any) -> None: """Run when agent action is received. Args: action (AgentAction): The agent action. **kwargs (Any): Additional keyword arguments. - - Returns: - Any: The result of the callback. - """ if not self.handlers: return @@ -1057,16 +1038,12 @@ class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin): **kwargs, ) - async def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> Any: + async def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None: """Run when agent finish is received. Args: finish (AgentFinish): The agent finish. **kwargs (Any): Additional keyword arguments. - - Returns: - Any: The result of the callback. - """ if not self.handlers: return @@ -1562,6 +1539,8 @@ class CallbackManager(BaseCallbackManager): parent_run_id (UUID, optional): The ID of the parent run. Defaults to None. **kwargs (Any): Additional keyword arguments. + Returns: + The callback manager for the retriever run. """ if run_id is None: run_id = uuid.uuid4() @@ -1608,6 +1587,9 @@ class CallbackManager(BaseCallbackManager): data: The data for the adhoc event. run_id: The ID of the run. Defaults to None. + Raises: + ValueError: If additional keyword arguments are passed. + .. versionadded:: 0.2.14 """ @@ -1710,8 +1692,8 @@ class CallbackManagerForChainGroup(CallbackManager): self.parent_run_manager = parent_run_manager self.ended = False + @override def copy(self) -> CallbackManagerForChainGroup: - """Copy the callback manager.""" return self.__class__( handlers=self.handlers.copy(), inheritable_handlers=self.inheritable_handlers.copy(), @@ -2099,6 +2081,9 @@ class AsyncCallbackManager(BaseCallbackManager): data: The data for the adhoc event. run_id: The ID of the run. Defaults to None. + Raises: + ValueError: If additional keyword arguments are passed. + .. versionadded:: 0.2.14 """ if not self.handlers: @@ -2249,7 +2234,7 @@ class AsyncCallbackManagerForChainGroup(AsyncCallbackManager): self.ended = False def copy(self) -> AsyncCallbackManagerForChainGroup: - """Copy the async callback manager.""" + """Return a copy the async callback manager.""" return self.__class__( handlers=self.handlers.copy(), inheritable_handlers=self.inheritable_handlers.copy(), @@ -2385,6 +2370,9 @@ def _configure( local_metadata (Optional[dict[str, Any]], optional): The local metadata. Defaults to None. + Raises: + RuntimeError: If `LANGCHAIN_TRACING` is set but `LANGCHAIN_TRACING_V2` is not. + Returns: T: The configured callback manager. """ @@ -2557,6 +2545,10 @@ async def adispatch_custom_event( this is not enforced. config: Optional config object. Mirrors the async API but not strictly needed. + Raises: + RuntimeError: If there is no parent run ID available to associate + the event with. + Example: .. code-block:: python @@ -2678,6 +2670,10 @@ def dispatch_custom_event( this is not enforced. config: Optional config object. Mirrors the async API but not strictly needed. + Raises: + RuntimeError: If there is no parent run ID available to associate + the event with. + Example: .. code-block:: python diff --git a/libs/core/langchain_core/callbacks/usage.py b/libs/core/langchain_core/callbacks/usage.py index 0249cadec1f..497b6ff4912 100644 --- a/libs/core/langchain_core/callbacks/usage.py +++ b/libs/core/langchain_core/callbacks/usage.py @@ -101,6 +101,9 @@ def get_usage_metadata_callback( name (str): The name of the context variable. Defaults to ``'usage_metadata_callback'``. + Yields: + The usage metadata callback. + Example: .. code-block:: python diff --git a/libs/core/langchain_core/chat_history.py b/libs/core/langchain_core/chat_history.py index 19138005162..0091b240b69 100644 --- a/libs/core/langchain_core/chat_history.py +++ b/libs/core/langchain_core/chat_history.py @@ -109,6 +109,9 @@ class BaseChatMessageHistory(ABC): In general, fetching messages may involve IO to the underlying persistence layer. + + Returns: + The messages. """ from langchain_core.runnables.config import run_in_executor diff --git a/libs/core/langchain_core/document_loaders/base.py b/libs/core/langchain_core/document_loaders/base.py index 0d4054c2b99..7208529da17 100644 --- a/libs/core/langchain_core/document_loaders/base.py +++ b/libs/core/langchain_core/document_loaders/base.py @@ -28,11 +28,19 @@ class BaseLoader(ABC): # noqa: B024 # Sub-classes should not implement this method directly. Instead, they # should implement the lazy load method. def load(self) -> list[Document]: - """Load data into Document objects.""" + """Load data into Document objects. + + Returns: + the documents. + """ return list(self.lazy_load()) async def aload(self) -> list[Document]: - """Load data into Document objects.""" + """Load data into Document objects. + + Returns: + the documents. + """ return [document async for document in self.alazy_load()] def load_and_split( @@ -44,7 +52,11 @@ class BaseLoader(ABC): # noqa: B024 Args: text_splitter: TextSplitter instance to use for splitting documents. - Defaults to RecursiveCharacterTextSplitter. + Defaults to RecursiveCharacterTextSplitter. + + Raises: + ImportError: If langchain-text-splitters is not installed + and no text_splitter is provided. Returns: List of Documents. @@ -69,14 +81,22 @@ class BaseLoader(ABC): # noqa: B024 # Attention: This method will be upgraded into an abstractmethod once it's # implemented in all the existing subclasses. def lazy_load(self) -> Iterator[Document]: - """A lazy loader for Documents.""" + """A lazy loader for Documents. + + Yields: + the documents. + """ if type(self).load != BaseLoader.load: return iter(self.load()) msg = f"{self.__class__.__name__} does not implement lazy_load()" raise NotImplementedError(msg) async def alazy_load(self) -> AsyncIterator[Document]: - """A lazy loader for Documents.""" + """A lazy loader for Documents. + + Yields: + the documents. + """ iterator = await run_in_executor(None, self.lazy_load) done = object() while True: diff --git a/libs/core/langchain_core/document_loaders/langsmith.py b/libs/core/langchain_core/document_loaders/langsmith.py index 67089f520a3..81d9f26c3db 100644 --- a/libs/core/langchain_core/document_loaders/langsmith.py +++ b/libs/core/langchain_core/document_loaders/langsmith.py @@ -84,6 +84,9 @@ class LangSmithLoader(BaseLoader): client: LangSmith Client. If not provided will be initialized from below args. client_kwargs: Keyword args to pass to LangSmith client init. Should only be specified if ``client`` isn't. + + Raises: + ValueError: If both ``client`` and ``client_kwargs`` are provided. """ # noqa: E501 if client and client_kwargs: raise ValueError diff --git a/libs/core/langchain_core/documents/base.py b/libs/core/langchain_core/documents/base.py index 99ae9b62892..adc42ac0182 100644 --- a/libs/core/langchain_core/documents/base.py +++ b/libs/core/langchain_core/documents/base.py @@ -145,7 +145,14 @@ class Blob(BaseMedia): return values def as_string(self) -> str: - """Read data as a string.""" + """Read data as a string. + + Raises: + ValueError: If the blob cannot be represented as a string. + + Returns: + The data as a string. + """ if self.data is None and self.path: return Path(self.path).read_text(encoding=self.encoding) if isinstance(self.data, bytes): @@ -156,7 +163,14 @@ class Blob(BaseMedia): raise ValueError(msg) def as_bytes(self) -> bytes: - """Read data as bytes.""" + """Read data as bytes. + + Raises: + ValueError: If the blob cannot be represented as bytes. + + Returns: + The data as bytes. + """ if isinstance(self.data, bytes): return self.data if isinstance(self.data, str): @@ -168,7 +182,14 @@ class Blob(BaseMedia): @contextlib.contextmanager def as_bytes_io(self) -> Generator[Union[BytesIO, BufferedReader], None, None]: - """Read data as a byte stream.""" + """Read data as a byte stream. + + Raises: + NotImplementedError: If the blob cannot be represented as a byte stream. + + Yields: + The data as a byte stream. + """ if isinstance(self.data, bytes): yield BytesIO(self.data) elif self.data is None and self.path: @@ -246,7 +267,7 @@ class Blob(BaseMedia): ) def __repr__(self) -> str: - """Define the blob representation.""" + """Return the blob representation.""" str_repr = f"Blob {id(self)}" if self.source: str_repr += f" {self.source}" @@ -280,19 +301,24 @@ class Document(BaseMedia): @classmethod def is_lc_serializable(cls) -> bool: - """Return whether this class is serializable.""" + """Return True as this class is serializable.""" return True @classmethod def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Default namespace is ["langchain", "schema", "document"]. + Returns: + ["langchain", "schema", "document"] """ return ["langchain", "schema", "document"] def __str__(self) -> str: - """Override __str__ to restrict it to page_content and metadata.""" + """Override __str__ to restrict it to page_content and metadata. + + Returns: + A string representation of the Document. + """ # The format matches pydantic format for __str__. # # The purpose of this change is to make sure that user code that diff --git a/libs/core/langchain_core/example_selectors/base.py b/libs/core/langchain_core/example_selectors/base.py index e344e80551f..ec845cfc2e9 100644 --- a/libs/core/langchain_core/example_selectors/base.py +++ b/libs/core/langchain_core/example_selectors/base.py @@ -16,6 +16,9 @@ class BaseExampleSelector(ABC): Args: example: A dictionary with keys as input variables and values as their values. + + Returns: + Any return value. """ async def aadd_example(self, example: dict[str, str]) -> Any: @@ -24,6 +27,9 @@ class BaseExampleSelector(ABC): Args: example: A dictionary with keys as input variables and values as their values. + + Returns: + Any return value. """ return await run_in_executor(None, self.add_example, example) @@ -34,6 +40,9 @@ class BaseExampleSelector(ABC): Args: input_variables: A dictionary with keys as input variables and values as their values. + + Returns: + A list of examples. """ async def aselect_examples(self, input_variables: dict[str, str]) -> list[dict]: @@ -42,5 +51,8 @@ class BaseExampleSelector(ABC): Args: input_variables: A dictionary with keys as input variables and values as their values. + + Returns: + A list of examples. """ return await run_in_executor(None, self.select_examples, input_variables) diff --git a/libs/core/langchain_core/exceptions.py b/libs/core/langchain_core/exceptions.py index cde6d6ff8ce..6aa8d89bc1f 100644 --- a/libs/core/langchain_core/exceptions.py +++ b/libs/core/langchain_core/exceptions.py @@ -42,6 +42,10 @@ class OutputParserException(ValueError, LangChainException): # noqa: N818 previous output was improperly structured, in the hopes that it will update the output to the correct format. Defaults to False. + + Raises: + ValueError: If ``send_to_llm`` is True but either observation or + ``llm_output`` are not provided. """ if isinstance(error, str): error = create_message( @@ -77,6 +81,9 @@ def create_message(*, message: str, error_code: ErrorCode) -> str: Args: message: The message to display. error_code: The error code to display. + + Returns: + The full message with the troubleshooting link. """ return ( f"{message}\n" diff --git a/libs/core/langchain_core/indexing/api.py b/libs/core/langchain_core/indexing/api.py index bb232b298fe..7e938355fb1 100644 --- a/libs/core/langchain_core/indexing/api.py +++ b/libs/core/langchain_core/indexing/api.py @@ -185,6 +185,9 @@ def _get_document_with_hash( When changing the key encoder, you must change the index as well to avoid duplicated documents in the cache. + Raises: + ValueError: If the metadata cannot be serialized using json. + Returns: Document with a unique identifier based on the hash of the content and metadata. """ @@ -374,6 +377,9 @@ def index( ValueError: If vectorstore does not have "delete" and "add_documents" required methods. ValueError: If source_id_key is not None, but is not a string or callable. + TypeError: If ``vectorstore`` is not a VectorStore or a DocumentIndex. + AssertionError: If ``source_id`` is None when cleanup mode is incremental. + (should be unreachable code). .. version_modified:: 0.3.25 @@ -708,6 +714,9 @@ async def aindex( ValueError: If vectorstore does not have "adelete" and "aadd_documents" required methods. ValueError: If source_id_key is not None, but is not a string or callable. + TypeError: If ``vector_store`` is not a VectorStore or DocumentIndex. + AssertionError: If ``source_id_key`` is None when cleanup mode is + incremental or ``scoped_full`` (should be unreachable). .. version_modified:: 0.3.25 diff --git a/libs/core/langchain_core/indexing/base.py b/libs/core/langchain_core/indexing/base.py index 0de0b8cdee2..6e638ebd722 100644 --- a/libs/core/langchain_core/indexing/base.py +++ b/libs/core/langchain_core/indexing/base.py @@ -7,6 +7,8 @@ import time from abc import ABC, abstractmethod from typing import TYPE_CHECKING, Any, Optional, TypedDict +from typing_extensions import override + from langchain_core._api import beta from langchain_core.retrievers import BaseRetriever from langchain_core.runnables import run_in_executor @@ -256,12 +258,12 @@ class InMemoryRecordManager(RecordManager): async def acreate_schema(self) -> None: """In-memory schema creation is simply ensuring the structure is initialized.""" + @override def get_time(self) -> float: - """Get the current server time as a high resolution timestamp!""" return time.time() + @override async def aget_time(self) -> float: - """Async get the current server time as a high resolution timestamp!""" return self.get_time() def update( @@ -322,11 +324,6 @@ class InMemoryRecordManager(RecordManager): raise an error. This is meant to help prevent time-drift issues since time may not be monotonically increasing! - - Raises: - ValueError: If the length of keys doesn't match the length of group - ids. - ValueError: If time_at_least is in the future. """ self.update(keys, group_ids=group_ids, time_at_least=time_at_least) diff --git a/libs/core/langchain_core/indexing/in_memory.py b/libs/core/langchain_core/indexing/in_memory.py index 34609a0370d..02c11ffd198 100644 --- a/libs/core/langchain_core/indexing/in_memory.py +++ b/libs/core/langchain_core/indexing/in_memory.py @@ -32,7 +32,17 @@ class InMemoryDocumentIndex(DocumentIndex): @override def upsert(self, items: Sequence[Document], /, **kwargs: Any) -> UpsertResponse: - """Upsert items into the index.""" + """Upsert documents into the index. + + Args: + items: Sequence of documents to add to the index. + **kwargs: Additional keyword arguments. + + Returns: + A response object that contains the list of IDs that were + successfully added or updated in the index and the list of IDs that + failed to be added or updated. + """ ok_ids = [] for item in items: @@ -51,7 +61,18 @@ class InMemoryDocumentIndex(DocumentIndex): @override def delete(self, ids: Optional[list[str]] = None, **kwargs: Any) -> DeleteResponse: - """Delete by ID.""" + """Delete by IDs. + + Args: + ids: List of ids to delete. + + Raises: + ValueError: If ids is None. + + Returns: + A response object that contains the list of IDs that were successfully + deleted and the list of IDs that failed to be deleted. + """ if ids is None: msg = "IDs must be provided for deletion" raise ValueError(msg) @@ -69,7 +90,6 @@ class InMemoryDocumentIndex(DocumentIndex): @override def get(self, ids: Sequence[str], /, **kwargs: Any) -> list[Document]: - """Get by ids.""" return [self.store[id_] for id_ in ids if id_ in self.store] @override diff --git a/libs/core/langchain_core/language_models/base.py b/libs/core/langchain_core/language_models/base.py index 9f9856d7c6c..80be6ff7305 100644 --- a/libs/core/langchain_core/language_models/base.py +++ b/libs/core/langchain_core/language_models/base.py @@ -59,6 +59,12 @@ def get_tokenizer() -> Any: This function is cached to avoid re-loading the tokenizer every time it is called. + Raises: + ImportError: If the transformers package is not installed. + + Returns: + The GPT-2 tokenizer instance. + """ try: from transformers import GPT2TokenizerFast # type: ignore[import-not-found] diff --git a/libs/core/langchain_core/language_models/chat_models.py b/libs/core/langchain_core/language_models/chat_models.py index 2ab0d6bb759..f4ec3d48af9 100644 --- a/libs/core/langchain_core/language_models/chat_models.py +++ b/libs/core/langchain_core/language_models/chat_models.py @@ -161,6 +161,9 @@ def generate_from_stream(stream: Iterator[ChatGenerationChunk]) -> ChatResult: Args: stream: Iterator of ``ChatGenerationChunk``. + Raises: + ValueError: If no generations are found in the stream. + Returns: ChatResult: Chat result. @@ -328,7 +331,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): @model_validator(mode="before") @classmethod def raise_deprecation(cls, values: dict) -> Any: - """Raise deprecation warning if ``callback_manager`` is used. + """Emit deprecation warning if ``callback_manager`` is used. Args: values (Dict): Values to validate. @@ -336,9 +339,6 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): Returns: Dict: Validated values. - Raises: - DeprecationWarning: If ``callback_manager`` is used. - """ if values.get("callback_manager") is not None: warnings.warn( @@ -1185,7 +1185,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: - """Top Level call.""" + """Generate the result. + + Args: + messages: The messages to generate from. + stop: Optional list of stop words to use when generating. + run_manager: Optional callback manager to use for this call. + **kwargs: Additional keyword arguments to pass to the model. + + Returns: + The chat result. + """ async def _agenerate( self, @@ -1194,7 +1204,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: - """Top Level call.""" + """Generate the result. + + Args: + messages: The messages to generate from. + stop: Optional list of stop words to use when generating. + run_manager: Optional callback manager to use for this call. + **kwargs: Additional keyword arguments to pass to the model. + + Returns: + The chat result. + """ return await run_in_executor( None, self._generate, @@ -1211,6 +1231,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> Iterator[ChatGenerationChunk]: + """Stream the output of the model. + + Args: + messages: The messages to generate from. + stop: Optional list of stop words to use when generating. + run_manager: Optional callback manager to use for this call. + **kwargs: Additional keyword arguments to pass to the model. + + Yields: + The chat generation chunks. + """ raise NotImplementedError async def _astream( @@ -1220,6 +1251,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> AsyncIterator[ChatGenerationChunk]: + """Stream the output of the model. + + Args: + messages: The messages to generate from. + stop: Optional list of stop words to use when generating. + run_manager: Optional callback manager to use for this call. + **kwargs: Additional keyword arguments to pass to the model. + + Yields: + The chat generation chunks. + """ iterator = await run_in_executor( None, self._stream, @@ -1259,6 +1301,9 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): **kwargs: Arbitrary additional keyword arguments. These are usually passed to the model provider API call. + Raises: + ValueError: If the generation is not a chat generation. + Returns: The model output message. @@ -1320,6 +1365,9 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): **kwargs: Arbitrary additional keyword arguments. These are usually passed to the model provider API call. + Raises: + ValueError: If the output is not a string. + Returns: The predicted output string. @@ -1434,6 +1482,11 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC): will be caught and returned as well. The final output is always a dict with keys ``'raw'``, ``'parsed'``, and ``'parsing_error'``. + Raises: + ValueError: If there are any unsupported ``kwargs``. + NotImplementedError: If the model does not implement + ``with_structured_output()``. + Returns: A Runnable that takes same inputs as a :class:`langchain_core.language_models.chat.BaseChatModel`. diff --git a/libs/core/langchain_core/language_models/fake_chat_models.py b/libs/core/langchain_core/language_models/fake_chat_models.py index c6e78b5389a..3b90259e525 100644 --- a/libs/core/langchain_core/language_models/fake_chat_models.py +++ b/libs/core/langchain_core/language_models/fake_chat_models.py @@ -75,12 +75,13 @@ class FakeListChatModel(SimpleChatModel): @override def _call( self, - messages: list[BaseMessage], - stop: Optional[list[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, + *args: Any, **kwargs: Any, ) -> str: - """First try to lookup in queries, else return 'foo' or 'bar'.""" + """Return the next response in the list. + + Cycle back to the start if at the end. + """ if self.sleep is not None: time.sleep(self.sleep) response = self.responses[self.i] @@ -239,7 +240,6 @@ class GenericFakeChatModel(BaseChatModel): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: - """Top Level call.""" message = next(self.messages) message_ = AIMessage(content=message) if isinstance(message, str) else message generation = ChatGeneration(message=message_) @@ -252,7 +252,6 @@ class GenericFakeChatModel(BaseChatModel): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> Iterator[ChatGenerationChunk]: - """Stream the output of the model.""" chat_result = self._generate( messages, stop=stop, run_manager=run_manager, **kwargs ) @@ -362,7 +361,6 @@ class ParrotFakeChatModel(BaseChatModel): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: - """Top Level call.""" return ChatResult(generations=[ChatGeneration(message=messages[-1])]) @property diff --git a/libs/core/langchain_core/language_models/llms.py b/libs/core/langchain_core/language_models/llms.py index 10a5f06121f..c274e02310d 100644 --- a/libs/core/langchain_core/language_models/llms.py +++ b/libs/core/langchain_core/language_models/llms.py @@ -664,7 +664,18 @@ class BaseLLM(BaseLanguageModel[str], ABC): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> LLMResult: - """Run the LLM on the given prompts.""" + """Run the LLM on the given prompts. + + Args: + prompts: The prompts to generate from. + stop: Stop words to use when generating. Model output is cut off at the + first occurrence of any of the stop substrings. + If stop tokens are not supported consider raising NotImplementedError. + run_manager: Callback manager for the run. + + Returns: + The LLM result. + """ async def _agenerate( self, @@ -673,7 +684,18 @@ class BaseLLM(BaseLanguageModel[str], ABC): run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> LLMResult: - """Run the LLM on the given prompts.""" + """Run the LLM on the given prompts. + + Args: + prompts: The prompts to generate from. + stop: Stop words to use when generating. Model output is cut off at the + first occurrence of any of the stop substrings. + If stop tokens are not supported consider raising NotImplementedError. + run_manager: Callback manager for the run. + + Returns: + The LLM result. + """ return await run_in_executor( None, self._generate, @@ -706,8 +728,8 @@ class BaseLLM(BaseLanguageModel[str], ABC): **kwargs: Arbitrary additional keyword arguments. These are usually passed to the model provider API call. - Returns: - An iterator of GenerationChunks. + Yields: + Generation chunks. """ raise NotImplementedError @@ -732,8 +754,8 @@ class BaseLLM(BaseLanguageModel[str], ABC): **kwargs: Arbitrary additional keyword arguments. These are usually passed to the model provider API call. - Returns: - An async iterator of GenerationChunks. + Yields: + Generation chunks. """ iterator = await run_in_executor( None, @@ -854,6 +876,11 @@ class BaseLLM(BaseLanguageModel[str], ABC): **kwargs: Arbitrary additional keyword arguments. These are usually passed to the model provider API call. + Raises: + ValueError: If prompts is not a list. + ValueError: If the length of ``callbacks``, ``tags``, ``metadata``, or + ``run_name`` (if provided) does not match the length of prompts. + Returns: An LLMResult, which contains a list of candidate Generations for each input prompt and additional model provider-specific output. @@ -1114,6 +1141,10 @@ class BaseLLM(BaseLanguageModel[str], ABC): **kwargs: Arbitrary additional keyword arguments. These are usually passed to the model provider API call. + Raises: + ValueError: If the length of ``callbacks``, ``tags``, ``metadata``, or + ``run_name`` (if provided) does not match the length of prompts. + Returns: An LLMResult, which contains a list of candidate Generations for each input prompt and additional model provider-specific output. @@ -1389,7 +1420,7 @@ class BaseLLM(BaseLanguageModel[str], ABC): return AIMessage(content=content) def __str__(self) -> str: - """Get a string representation of the object for printing.""" + """Return a string representation of the object for printing.""" cls_name = f"\033[1m{self.__class__.__name__}\033[0m" return f"{cls_name}\nParams: {self._identifying_params}" @@ -1537,7 +1568,6 @@ class LLM(BaseLLM): run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> LLMResult: - """Run the LLM on the given prompt and input.""" # TODO: add caching here. generations = [] new_arg_supported = inspect.signature(self._call).parameters.get("run_manager") @@ -1557,7 +1587,6 @@ class LLM(BaseLLM): run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> LLMResult: - """Async run the LLM on the given prompt and input.""" generations = [] new_arg_supported = inspect.signature(self._acall).parameters.get("run_manager") for prompt in prompts: diff --git a/libs/core/langchain_core/load/load.py b/libs/core/langchain_core/load/load.py index 0c2cbf1f65e..52f4e2080b8 100644 --- a/libs/core/langchain_core/load/load.py +++ b/libs/core/langchain_core/load/load.py @@ -95,7 +95,21 @@ class Reviver: self.ignore_unserializable_fields = ignore_unserializable_fields def __call__(self, value: dict[str, Any]) -> Any: - """Revive the value.""" + """Revive the value. + + Args: + value: The value to revive. + + Returns: + The revived value. + + Raises: + ValueError: If the namespace is invalid. + ValueError: If trying to deserialize something that cannot + be deserialized in the current version of langchain-core. + NotImplementedError: If the object is not implemented and + ``ignore_unserializable_fields`` is False. + """ if ( value.get("lc") == 1 and value.get("type") == "secret" diff --git a/libs/core/langchain_core/load/serializable.py b/libs/core/langchain_core/load/serializable.py index fde77e69932..b9d612be45c 100644 --- a/libs/core/langchain_core/load/serializable.py +++ b/libs/core/langchain_core/load/serializable.py @@ -79,9 +79,6 @@ def try_neq_default(value: Any, key: str, model: BaseModel) -> bool: Returns: Whether the value is different from the default. - - Raises: - Exception: If the key is not in the model. """ field = type(model).model_fields[key] return _try_neq_default(value, field) @@ -148,6 +145,9 @@ class Serializable(BaseModel, ABC): For example, if the class is `langchain.llms.openai.OpenAI`, then the namespace is ["langchain", "llms", "openai"] + + Returns: + The namespace as a list of strings. """ return cls.__module__.split(".") @@ -171,7 +171,7 @@ class Serializable(BaseModel, ABC): @classmethod def lc_id(cls) -> list[str]: - """A unique identifier for this class for serialization purposes. + """Return a unique identifier for this class for serialization purposes. The unique identifier is a list of strings that describes the path to the object. @@ -203,6 +203,9 @@ class Serializable(BaseModel, ABC): def to_json(self) -> Union[SerializedConstructor, SerializedNotImplemented]: """Serialize the object to JSON. + Raises: + ValueError: If the class has deprecated attributes. + Returns: A json serializable object or a SerializedNotImplemented object. """ @@ -276,7 +279,11 @@ class Serializable(BaseModel, ABC): } def to_json_not_implemented(self) -> SerializedNotImplemented: - """Serialize a "not implemented" object.""" + """Serialize a "not implemented" object. + + Returns: + SerializedNotImplemented. + """ return to_json_not_implemented(self) diff --git a/libs/core/langchain_core/messages/ai.py b/libs/core/langchain_core/messages/ai.py index 86d48ec3254..e8640545649 100644 --- a/libs/core/langchain_core/messages/ai.py +++ b/libs/core/langchain_core/messages/ai.py @@ -310,14 +310,8 @@ class AIMessageChunk(AIMessage, BaseMessageChunk): def init_tool_calls(self) -> Self: """Initialize tool calls from tool call chunks. - Args: - values: The values to validate. - Returns: - The values with tool calls initialized. - - Raises: - ValueError: If the tool call chunks are malformed. + This ``AIMessageChunk``. """ if not self.tool_call_chunks: if self.tool_calls: @@ -392,7 +386,19 @@ class AIMessageChunk(AIMessage, BaseMessageChunk): def add_ai_message_chunks( left: AIMessageChunk, *others: AIMessageChunk ) -> AIMessageChunk: - """Add multiple AIMessageChunks together.""" + """Add multiple ``AIMessageChunk``s together. + + Args: + left: The first ``AIMessageChunk``. + *others: Other ``AIMessageChunk``s to add. + + Raises: + ValueError: If the example values of the chunks are not the same. + + Returns: + The resulting ``AIMessageChunk``. + + """ if any(left.example != o.example for o in others): msg = "Cannot concatenate AIMessageChunks with different example values." raise ValueError(msg) @@ -491,6 +497,13 @@ def add_usage( output_token_details=OutputTokenDetails(reasoning=4), ) + Args: + left: The first ``UsageMetadata`` object. + right: The second ``UsageMetadata`` object. + + Returns: + The sum of the two ``UsageMetadata`` objects. + """ if not (left or right): return UsageMetadata(input_tokens=0, output_tokens=0, total_tokens=0) @@ -548,6 +561,13 @@ def subtract_usage( output_token_details=OutputTokenDetails(reasoning=0), ) + Args: + left: The first ``UsageMetadata`` object. + right: The second ``UsageMetadata`` object. + + Returns: + The resulting ``UsageMetadata`` after subtraction. + """ if not (left or right): return UsageMetadata(input_tokens=0, output_tokens=0, total_tokens=0) diff --git a/libs/core/langchain_core/messages/base.py b/libs/core/langchain_core/messages/base.py index ba976286b75..2f831d79d02 100644 --- a/libs/core/langchain_core/messages/base.py +++ b/libs/core/langchain_core/messages/base.py @@ -84,7 +84,8 @@ class BaseMessage(Serializable): def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Default is ["langchain", "schema", "messages"]. + Returns: + ``["langchain", "schema", "messages"]`` """ return ["langchain", "schema", "messages"] @@ -109,7 +110,14 @@ class BaseMessage(Serializable): ) def __add__(self, other: Any) -> ChatPromptTemplate: - """Concatenate this message with another message.""" + """Concatenate this message with another message. + + Args: + other: Another message to concatenate with this one. + + Returns: + A ChatPromptTemplate containing both messages. + """ from langchain_core.prompts.chat import ChatPromptTemplate prompt = ChatPromptTemplate(messages=[self]) diff --git a/libs/core/langchain_core/messages/content_blocks.py b/libs/core/langchain_core/messages/content_blocks.py index 83a66fb123a..e90426ebb13 100644 --- a/libs/core/langchain_core/messages/content_blocks.py +++ b/libs/core/langchain_core/messages/content_blocks.py @@ -88,7 +88,18 @@ def is_data_content_block( def convert_to_openai_image_block(content_block: dict[str, Any]) -> dict: - """Convert image content block to format expected by OpenAI Chat Completions API.""" + """Convert image content block to format expected by OpenAI Chat Completions API. + + Args: + content_block: The content block to convert. + + Raises: + ValueError: If the source type is not supported or if ``mime_type`` is missing + for base64 data. + + Returns: + A dictionary formatted for OpenAI's API. + """ if content_block["source_type"] == "url": return { "type": "image_url", @@ -112,7 +123,17 @@ def convert_to_openai_image_block(content_block: dict[str, Any]) -> dict: def convert_to_openai_data_block(block: dict) -> dict: - """Format standard data content block to format expected by OpenAI.""" + """Format standard data content block to format expected by OpenAI. + + Args: + block: A data content block. + + Raises: + ValueError: If the block type or source type is not supported. + + Returns: + A dictionary formatted for OpenAI's API. + """ if block["type"] == "image": formatted_block = convert_to_openai_image_block(block) diff --git a/libs/core/langchain_core/messages/tool.py b/libs/core/langchain_core/messages/tool.py index 4d847c86d97..b2f858d8138 100644 --- a/libs/core/langchain_core/messages/tool.py +++ b/libs/core/langchain_core/messages/tool.py @@ -217,6 +217,9 @@ def tool_call( name: The name of the tool to be called. args: The arguments to the tool call. id: An identifier associated with the tool call. + + Returns: + The created tool call. """ return ToolCall(name=name, args=args, id=id, type="tool_call") @@ -267,6 +270,9 @@ def tool_call_chunk( args: The arguments to the tool call. id: An identifier associated with the tool call. index: The index of the tool call in a sequence. + + Returns: + The created tool call chunk. """ return ToolCallChunk( name=name, args=args, id=id, index=index, type="tool_call_chunk" @@ -305,6 +311,9 @@ def invalid_tool_call( args: The arguments to the tool call. id: An identifier associated with the tool call. error: An error message associated with the tool call. + + Returns: + The created invalid tool call. """ return InvalidToolCall( name=name, args=args, id=id, error=error, type="invalid_tool_call" @@ -314,7 +323,14 @@ def invalid_tool_call( def default_tool_parser( raw_tool_calls: list[dict], ) -> tuple[list[ToolCall], list[InvalidToolCall]]: - """Best-effort parsing of tools.""" + """Best-effort parsing of tools. + + Args: + raw_tool_calls: List of raw tool call dicts to parse. + + Returns: + A list of tool calls and invalid tool calls. + """ tool_calls = [] invalid_tool_calls = [] for raw_tool_call in raw_tool_calls: @@ -342,7 +358,14 @@ def default_tool_parser( def default_tool_chunk_parser(raw_tool_calls: list[dict]) -> list[ToolCallChunk]: - """Best-effort parsing of tool chunks.""" + """Best-effort parsing of tool chunks. + + Args: + raw_tool_calls: List of raw tool call dicts to parse. + + Returns: + List of parsed ToolCallChunk objects. + """ tool_call_chunks = [] for tool_call in raw_tool_calls: if "function" not in tool_call: diff --git a/libs/core/langchain_core/messages/utils.py b/libs/core/langchain_core/messages/utils.py index 16285eaefb2..c63f5b1c421 100644 --- a/libs/core/langchain_core/messages/utils.py +++ b/libs/core/langchain_core/messages/utils.py @@ -1046,6 +1046,10 @@ def convert_to_openai_messages( with a single content block of type 'text'. If a message has content blocks these are left as is. + Raises: + ValueError: if an unrecognized ``text_format`` is specified, or if a message + content block is missing expected keys. + Returns: The return type depends on the input type: - dict: diff --git a/libs/core/langchain_core/output_parsers/list.py b/libs/core/langchain_core/output_parsers/list.py index d60afe3554d..cc8ca4238cb 100644 --- a/libs/core/langchain_core/output_parsers/list.py +++ b/libs/core/langchain_core/output_parsers/list.py @@ -143,10 +143,7 @@ class CommaSeparatedListOutputParser(ListOutputParser): @classmethod def is_lc_serializable(cls) -> bool: - """Check if the langchain object is serializable. - - Returns True. - """ + """Return True as this class is serializable.""" return True @classmethod @@ -154,8 +151,7 @@ class CommaSeparatedListOutputParser(ListOutputParser): """Get the namespace of the langchain object. Returns: - A list of strings. - Default is ["langchain", "output_parsers", "list"]. + ``["langchain", "output_parsers", "list"]`` """ return ["langchain", "output_parsers", "list"] @@ -213,15 +209,8 @@ class NumberedListOutputParser(ListOutputParser): """ return re.findall(self.pattern, text) + @override def parse_iter(self, text: str) -> Iterator[re.Match]: - """Parse the output of an LLM call. - - Args: - text: The output of an LLM call. - - Yields: - A match object for each part of the output. - """ return re.finditer(self.pattern, text) @property @@ -250,15 +239,8 @@ class MarkdownListOutputParser(ListOutputParser): """ return re.findall(self.pattern, text, re.MULTILINE) + @override def parse_iter(self, text: str) -> Iterator[re.Match]: - """Parse the output of an LLM call. - - Args: - text: The output of an LLM call. - - Yields: - A match object for each part of the output. - """ return re.finditer(self.pattern, text, re.MULTILINE) @property diff --git a/libs/core/langchain_core/output_parsers/openai_functions.py b/libs/core/langchain_core/output_parsers/openai_functions.py index 129c9855061..5518f36a78e 100644 --- a/libs/core/langchain_core/output_parsers/openai_functions.py +++ b/libs/core/langchain_core/output_parsers/openai_functions.py @@ -261,6 +261,9 @@ class PydanticOutputFunctionsParser(OutputFunctionsParser): result: The result of the LLM call. partial: Whether to parse partial JSON objects. Default is False. + Raises: + ValueError: If the pydantic schema is not valid. + Returns: The parsed JSON object. """ diff --git a/libs/core/langchain_core/output_parsers/openai_tools.py b/libs/core/langchain_core/output_parsers/openai_tools.py index 5c2e0cd6644..44563e9a3c2 100644 --- a/libs/core/langchain_core/output_parsers/openai_tools.py +++ b/libs/core/langchain_core/output_parsers/openai_tools.py @@ -231,6 +231,9 @@ class JsonOutputKeyToolsParser(JsonOutputToolsParser): If False, the output will be the full JSON object. Default is False. + Raises: + OutputParserException: If the generation is not a chat generation. + Returns: The parsed tool calls. """ @@ -316,7 +319,9 @@ class PydanticToolsParser(JsonOutputToolsParser): The parsed Pydantic objects. Raises: - OutputParserException: If the output is not valid JSON. + ValueError: If the tool call arguments are not a dict. + ValidationError: If the tool call arguments do not conform + to the Pydantic model. """ json_results = super().parse_result(result, partial=partial) if not json_results: diff --git a/libs/core/langchain_core/output_parsers/pydantic.py b/libs/core/langchain_core/output_parsers/pydantic.py index b543df55768..1785cbc60fa 100644 --- a/libs/core/langchain_core/output_parsers/pydantic.py +++ b/libs/core/langchain_core/output_parsers/pydantic.py @@ -54,6 +54,10 @@ class PydanticOutputParser(JsonOutputParser, Generic[TBaseModel]): all the keys that have been returned so far. Defaults to False. + Raises: + OutputParserException: If the result is not valid JSON + or does not conform to the pydantic model. + Returns: The parsed pydantic object. """ diff --git a/libs/core/langchain_core/output_parsers/string.py b/libs/core/langchain_core/output_parsers/string.py index 4f952c68892..c2194e8bddf 100644 --- a/libs/core/langchain_core/output_parsers/string.py +++ b/libs/core/langchain_core/output_parsers/string.py @@ -19,7 +19,8 @@ class StrOutputParser(BaseTransformOutputParser[str]): def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Default is ["langchain", "schema", "output_parser"]. + Returns: + ``["langchain", "schema", "output_parser"]`` """ return ["langchain", "schema", "output_parser"] diff --git a/libs/core/langchain_core/output_parsers/xml.py b/libs/core/langchain_core/output_parsers/xml.py index 483d9871c1a..fcbd68a89d0 100644 --- a/libs/core/langchain_core/output_parsers/xml.py +++ b/libs/core/langchain_core/output_parsers/xml.py @@ -136,9 +136,6 @@ class _StreamingParser: """Close the parser. This should be called after all chunks have been parsed. - - Raises: - xml.etree.ElementTree.ParseError: If the XML is not well-formed. """ # Ignore ParseError. This will ignore any incomplete XML at the end of the input with contextlib.suppress(xml.etree.ElementTree.ParseError): diff --git a/libs/core/langchain_core/outputs/chat_generation.py b/libs/core/langchain_core/outputs/chat_generation.py index d42f2038d34..594066f2fb7 100644 --- a/libs/core/langchain_core/outputs/chat_generation.py +++ b/libs/core/langchain_core/outputs/chat_generation.py @@ -47,9 +47,6 @@ class ChatGeneration(Generation): Returns: The values of the object with the text attribute set. - - Raises: - ValueError: If the message is not a string or a list. """ text = "" if isinstance(self.message.content, str): @@ -83,11 +80,18 @@ class ChatGenerationChunk(ChatGeneration): def __add__( self, other: Union[ChatGenerationChunk, list[ChatGenerationChunk]] ) -> ChatGenerationChunk: - """Concatenate two ChatGenerationChunks. + """Concatenate two ``ChatGenerationChunk``s. Args: - other: The other ChatGenerationChunk or list of ChatGenerationChunks to - concatenate. + other: The other ``ChatGenerationChunk`` or list of ``ChatGenerationChunk`` + to concatenate. + + Raises: + TypeError: If other is not a ``ChatGenerationChunk`` or list of + ``ChatGenerationChunk``. + + Returns: + A new ``ChatGenerationChunk`` concatenated from self and other. """ if isinstance(other, ChatGenerationChunk): generation_info = merge_dicts( @@ -116,7 +120,14 @@ class ChatGenerationChunk(ChatGeneration): def merge_chat_generation_chunks( chunks: list[ChatGenerationChunk], ) -> Union[ChatGenerationChunk, None]: - """Merge a list of ChatGenerationChunks into a single ChatGenerationChunk.""" + """Merge a list of ``ChatGenerationChunk``s into a single ``ChatGenerationChunk``. + + Args: + chunks: A list of ``ChatGenerationChunk`` to merge. + + Returns: + A merged ``ChatGenerationChunk``, or None if the input list is empty. + """ if not chunks: return None diff --git a/libs/core/langchain_core/outputs/generation.py b/libs/core/langchain_core/outputs/generation.py index 1167616d6bc..cd06c20e673 100644 --- a/libs/core/langchain_core/outputs/generation.py +++ b/libs/core/langchain_core/outputs/generation.py @@ -39,14 +39,15 @@ class Generation(Serializable): @classmethod def is_lc_serializable(cls) -> bool: - """Return whether this class is serializable.""" + """Return True as this class is serializable.""" return True @classmethod def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Default namespace is ["langchain", "schema", "output"]. + Returns: + ``["langchain", "schema", "output"]`` """ return ["langchain", "schema", "output"] @@ -55,7 +56,17 @@ class GenerationChunk(Generation): """Generation chunk, which can be concatenated with other Generation chunks.""" def __add__(self, other: GenerationChunk) -> GenerationChunk: - """Concatenate two GenerationChunks.""" + """Concatenate two ``GenerationChunk``s. + + Args: + other: Another ``GenerationChunk`` to concatenate with. + + Raises: + TypeError: If other is not a ``GenerationChunk``. + + Returns: + A new ``GenerationChunk`` concatenated from self and other. + """ if isinstance(other, GenerationChunk): generation_info = merge_dicts( self.generation_info or {}, diff --git a/libs/core/langchain_core/outputs/llm_result.py b/libs/core/langchain_core/outputs/llm_result.py index 08e5e78f2a7..088b909755c 100644 --- a/libs/core/langchain_core/outputs/llm_result.py +++ b/libs/core/langchain_core/outputs/llm_result.py @@ -91,7 +91,14 @@ class LLMResult(BaseModel): return llm_results def __eq__(self, other: object) -> bool: - """Check for LLMResult equality by ignoring any metadata related to runs.""" + """Check for ``LLMResult`` equality by ignoring any metadata related to runs. + + Args: + other: Another ``LLMResult`` object to compare against. + + Returns: + True if the generations and ``llm_output`` are equal, False otherwise. + """ if not isinstance(other, LLMResult): return NotImplemented return ( diff --git a/libs/core/langchain_core/prompt_values.py b/libs/core/langchain_core/prompt_values.py index 7652bd76e3c..5b7c2e414bb 100644 --- a/libs/core/langchain_core/prompt_values.py +++ b/libs/core/langchain_core/prompt_values.py @@ -30,7 +30,7 @@ class PromptValue(Serializable, ABC): @classmethod def is_lc_serializable(cls) -> bool: - """Return whether this class is serializable. Defaults to True.""" + """Return True as this class is serializable.""" return True @classmethod @@ -38,7 +38,9 @@ class PromptValue(Serializable, ABC): """Get the namespace of the langchain object. This is used to determine the namespace of the object when serializing. - Defaults to ["langchain", "schema", "prompt"]. + + Returns: + ``["langchain", "schema", "prompt"]`` """ return ["langchain", "schema", "prompt"] @@ -63,7 +65,9 @@ class StringPromptValue(PromptValue): """Get the namespace of the langchain object. This is used to determine the namespace of the object when serializing. - Defaults to ["langchain", "prompts", "base"]. + + Returns: + ``["langchain", "prompts", "base"]`` """ return ["langchain", "prompts", "base"] @@ -98,7 +102,9 @@ class ChatPromptValue(PromptValue): """Get the namespace of the langchain object. This is used to determine the namespace of the object when serializing. - Defaults to ["langchain", "prompts", "chat"]. + + Returns: + ``["langchain", "prompts", "chat"]`` """ return ["langchain", "prompts", "chat"] diff --git a/libs/core/langchain_core/prompts/base.py b/libs/core/langchain_core/prompts/base.py index f36c69be8e6..6581c56902c 100644 --- a/libs/core/langchain_core/prompts/base.py +++ b/libs/core/langchain_core/prompts/base.py @@ -101,16 +101,14 @@ class BasePromptTemplate( def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Returns ["langchain", "schema", "prompt_template"]. + Returns: + ``["langchain", "schema", "prompt_template"]`` """ return ["langchain", "schema", "prompt_template"] @classmethod def is_lc_serializable(cls) -> bool: - """Return whether this class is serializable. - - Returns True. - """ + """Return True as this class is serializable.""" return True model_config = ConfigDict( @@ -341,9 +339,6 @@ class BasePromptTemplate( Returns: Dict: Dictionary representation of the prompt. - - Raises: - NotImplementedError: If the prompt type is not implemented. """ prompt_dict = super().model_dump(**kwargs) with contextlib.suppress(NotImplementedError): diff --git a/libs/core/langchain_core/prompts/chat.py b/libs/core/langchain_core/prompts/chat.py index 12728ef76e8..93bcb29730a 100644 --- a/libs/core/langchain_core/prompts/chat.py +++ b/libs/core/langchain_core/prompts/chat.py @@ -740,10 +740,18 @@ class BaseChatPromptTemplate(BasePromptTemplate, ABC): @abstractmethod def format_messages(self, **kwargs: Any) -> list[BaseMessage]: - """Format kwargs into a list of messages.""" + """Format kwargs into a list of messages. + + Returns: + List of messages. + """ async def aformat_messages(self, **kwargs: Any) -> list[BaseMessage]: - """Async format kwargs into a list of messages.""" + """Async format kwargs into a list of messages. + + Returns: + List of messages. + """ return self.format_messages(**kwargs) def pretty_repr( @@ -925,9 +933,6 @@ class ChatPromptTemplate(BaseChatPromptTemplate): input_types: A dictionary of the types of the variables the prompt template expects. If not provided, all variables are assumed to be strings. - Returns: - A chat prompt template. - Examples: Instantiation from a list of message templates: @@ -981,7 +986,11 @@ class ChatPromptTemplate(BaseChatPromptTemplate): @classmethod def get_lc_namespace(cls) -> list[str]: - """Get the namespace of the langchain object.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "prompts", "chat"]`` + """ return ["langchain", "prompts", "chat"] def __add__(self, other: Any) -> ChatPromptTemplate: @@ -1185,6 +1194,9 @@ class ChatPromptTemplate(BaseChatPromptTemplate): **kwargs: keyword arguments to use for filling in template variables in all the template messages in this chat template. + Raises: + ValueError: if messages are of unexpected types. + Returns: list of formatted messages. """ @@ -1295,7 +1307,13 @@ class ChatPromptTemplate(BaseChatPromptTemplate): def __getitem__( self, index: Union[int, slice] ) -> Union[MessageLike, ChatPromptTemplate]: - """Use to index into the chat template.""" + """Use to index into the chat template. + + Returns: + If index is an int, returns the message at that index. + If index is a slice, returns a new ``ChatPromptTemplate`` + containing the messages in that slice. + """ if isinstance(index, slice): start, stop, step = index.indices(len(self.messages)) messages = self.messages[start:stop:step] @@ -1303,7 +1321,7 @@ class ChatPromptTemplate(BaseChatPromptTemplate): return self.messages[index] def __len__(self) -> int: - """Get the length of the chat template.""" + """Return the length of the chat template.""" return len(self.messages) @property diff --git a/libs/core/langchain_core/prompts/dict.py b/libs/core/langchain_core/prompts/dict.py index 0b5ee5072a2..135f8021b9d 100644 --- a/libs/core/langchain_core/prompts/dict.py +++ b/libs/core/langchain_core/prompts/dict.py @@ -31,18 +31,25 @@ class DictPromptTemplate(RunnableSerializable[dict, dict]): return _get_input_variables(self.template, self.template_format) def format(self, **kwargs: Any) -> dict[str, Any]: - """Format the prompt with the inputs.""" + """Format the prompt with the inputs. + + Returns: + A formatted dict. + """ return _insert_input_variables(self.template, kwargs, self.template_format) async def aformat(self, **kwargs: Any) -> dict[str, Any]: - """Format the prompt with the inputs.""" + """Format the prompt with the inputs. + + Returns: + A formatted dict. + """ return self.format(**kwargs) @override def invoke( self, input: dict, config: Optional[RunnableConfig] = None, **kwargs: Any ) -> dict: - """Invoke the prompt.""" return self._call_with_config( lambda x: self.format(**x), input, @@ -62,15 +69,16 @@ class DictPromptTemplate(RunnableSerializable[dict, dict]): @classmethod def is_lc_serializable(cls) -> bool: - """Return whether or not the class is serializable. - - Returns: True. - """ + """Return True as this class is serializable.""" return True @classmethod def get_lc_namespace(cls) -> list[str]: - """Serialization namespace.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain_core", "prompts", "dict"]`` + """ return ["langchain_core", "prompts", "dict"] def pretty_repr(self, *, html: bool = False) -> str: diff --git a/libs/core/langchain_core/prompts/few_shot.py b/libs/core/langchain_core/prompts/few_shot.py index ddb09c2e320..70c95038208 100644 --- a/libs/core/langchain_core/prompts/few_shot.py +++ b/libs/core/langchain_core/prompts/few_shot.py @@ -117,7 +117,7 @@ class FewShotPromptTemplate(_FewShotPromptTemplateMixin, StringPromptTemplate): @classmethod def is_lc_serializable(cls) -> bool: - """Return whether or not the class is serializable.""" + """Return False as this class is not serializable.""" return False validate_template: bool = False @@ -367,7 +367,7 @@ class FewShotChatMessagePromptTemplate( @classmethod def is_lc_serializable(cls) -> bool: - """Return whether or not the class is serializable.""" + """Return False as this class is not serializable.""" return False model_config = ConfigDict( 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 eaf8ab0fd15..5f3ad91fe48 100644 --- a/libs/core/langchain_core/prompts/few_shot_with_templates.py +++ b/libs/core/langchain_core/prompts/few_shot_with_templates.py @@ -46,7 +46,11 @@ class FewShotPromptWithTemplates(StringPromptTemplate): @classmethod def get_lc_namespace(cls) -> list[str]: - """Get the namespace of the langchain object.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "prompts", "few_shot_with_templates"]`` + """ return ["langchain", "prompts", "few_shot_with_templates"] @model_validator(mode="before") diff --git a/libs/core/langchain_core/prompts/image.py b/libs/core/langchain_core/prompts/image.py index 4240b6bdec0..95776dbba00 100644 --- a/libs/core/langchain_core/prompts/image.py +++ b/libs/core/langchain_core/prompts/image.py @@ -23,7 +23,12 @@ class ImagePromptTemplate(BasePromptTemplate[ImageURL]): Options are: 'f-string', 'mustache', 'jinja2'.""" def __init__(self, **kwargs: Any) -> None: - """Create an image prompt template.""" + """Create an image prompt template. + + Raises: + ValueError: If the input variables contain ``'url'``, ``'path'``, or + ``'detail'``. + """ if "input_variables" not in kwargs: kwargs["input_variables"] = [] @@ -44,7 +49,11 @@ class ImagePromptTemplate(BasePromptTemplate[ImageURL]): @classmethod def get_lc_namespace(cls) -> list[str]: - """Get the namespace of the langchain object.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "prompts", "image"]`` + """ return ["langchain", "prompts", "image"] def format_prompt(self, **kwargs: Any) -> PromptValue: @@ -84,6 +93,7 @@ class ImagePromptTemplate(BasePromptTemplate[ImageURL]): Raises: ValueError: If the url is not provided. ValueError: If the url is not a string. + ValueError: If ``'path'`` is provided in the template or kwargs. Example: @@ -128,9 +138,6 @@ class ImagePromptTemplate(BasePromptTemplate[ImageURL]): Returns: A formatted string. - - Raises: - ValueError: If the path or url is not a string. """ return await run_in_executor(None, self.format, **kwargs) diff --git a/libs/core/langchain_core/prompts/message.py b/libs/core/langchain_core/prompts/message.py index 668374a19f0..409f54320b1 100644 --- a/libs/core/langchain_core/prompts/message.py +++ b/libs/core/langchain_core/prompts/message.py @@ -18,17 +18,15 @@ class BaseMessagePromptTemplate(Serializable, ABC): @classmethod def is_lc_serializable(cls) -> bool: - """Return whether or not the class is serializable. - - Returns: True. - """ + """Return True as this class is serializable.""" return True @classmethod def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Default namespace is ["langchain", "prompts", "chat"]. + Returns: + ``["langchain", "prompts", "chat"]`` """ return ["langchain", "prompts", "chat"] diff --git a/libs/core/langchain_core/prompts/pipeline.py b/libs/core/langchain_core/prompts/pipeline.py index bb11fda48fd..ee4ea4b0dca 100644 --- a/libs/core/langchain_core/prompts/pipeline.py +++ b/libs/core/langchain_core/prompts/pipeline.py @@ -55,7 +55,11 @@ class PipelinePromptTemplate(BasePromptTemplate): @classmethod def get_lc_namespace(cls) -> list[str]: - """Get the namespace of the langchain object.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "prompts", "pipeline"]`` + """ return ["langchain", "prompts", "pipeline"] @model_validator(mode="before") diff --git a/libs/core/langchain_core/prompts/prompt.py b/libs/core/langchain_core/prompts/prompt.py index 0066445a050..11a9922f92b 100644 --- a/libs/core/langchain_core/prompts/prompt.py +++ b/libs/core/langchain_core/prompts/prompt.py @@ -69,6 +69,11 @@ class PromptTemplate(StringPromptTemplate): @classmethod @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "prompts", "prompt"]`` + """ return ["langchain", "prompts", "prompt"] template: str @@ -135,7 +140,16 @@ class PromptTemplate(StringPromptTemplate): return mustache_schema(self.template) def __add__(self, other: Any) -> PromptTemplate: - """Override the + operator to allow for combining prompt templates.""" + """Override the + operator to allow for combining prompt templates. + + Raises: + ValueError: If the template formats are not f-string or if there are + conflicting partial variables. + NotImplementedError: If the other object is not a ``PromptTemplate`` or str. + + Returns: + A new ``PromptTemplate`` that is the combination of the two. + """ # Allow for easy combining if isinstance(other, PromptTemplate): if self.template_format != "f-string": diff --git a/libs/core/langchain_core/prompts/string.py b/libs/core/langchain_core/prompts/string.py index 69b3fd64c82..12357bf3a27 100644 --- a/libs/core/langchain_core/prompts/string.py +++ b/libs/core/langchain_core/prompts/string.py @@ -268,7 +268,11 @@ class StringPromptTemplate(BasePromptTemplate, ABC): @classmethod def get_lc_namespace(cls) -> list[str]: - """Get the namespace of the langchain object.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "prompts", "base"]`` + """ return ["langchain", "prompts", "base"] def format_prompt(self, **kwargs: Any) -> PromptValue: diff --git a/libs/core/langchain_core/prompts/structured.py b/libs/core/langchain_core/prompts/structured.py index d05ace21ccf..0d2c5d90b0f 100644 --- a/libs/core/langchain_core/prompts/structured.py +++ b/libs/core/langchain_core/prompts/structured.py @@ -68,8 +68,11 @@ class StructuredPrompt(ChatPromptTemplate): def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - For example, if the class is `langchain.llms.openai.OpenAI`, then the - namespace is ["langchain", "llms", "openai"] + For example, if the class is ``langchain.llms.openai.OpenAI``, then the + namespace is ``["langchain", "llms", "openai"]`` + + Returns: + The namespace of the langchain object. """ return cls.__module__.split(".") diff --git a/libs/core/langchain_core/retrievers.py b/libs/core/langchain_core/retrievers.py index 2a7cb681ff8..8e1acf56c16 100644 --- a/libs/core/langchain_core/retrievers.py +++ b/libs/core/langchain_core/retrievers.py @@ -362,6 +362,7 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC): Args: query: String to find relevant documents for run_manager: The callback handler to use + Returns: List of relevant documents """ diff --git a/libs/core/langchain_core/runnables/base.py b/libs/core/langchain_core/runnables/base.py index c065cc7afbf..1f90b2f608c 100644 --- a/libs/core/langchain_core/runnables/base.py +++ b/libs/core/langchain_core/runnables/base.py @@ -245,7 +245,15 @@ class Runnable(ABC, Generic[Input, Output]): def get_name( self, suffix: Optional[str] = None, *, name: Optional[str] = None ) -> str: - """Get the name of the ``Runnable``.""" + """Get the name of the ``Runnable``. + + Args: + suffix: An optional suffix to append to the name. + name: An optional name to use instead of the ``Runnable``'s name. + + Returns: + The name of the ``Runnable``. + """ if name: name_ = name elif hasattr(self, "name") and self.name: @@ -276,7 +284,13 @@ class Runnable(ABC, Generic[Input, Output]): @property def InputType(self) -> type[Input]: # noqa: N802 - """The type of input this ``Runnable`` accepts specified as a type annotation.""" # noqa: E501 + """Input type. + + The type of input this ``Runnable`` accepts specified as a type annotation. + + Raises: + TypeError: If the input type cannot be inferred. + """ # First loop through all parent classes and if any of them is # a pydantic model, we will pick up the generic parameterization # from that model via the __pydantic_generic_metadata__ attribute. @@ -302,7 +316,13 @@ class Runnable(ABC, Generic[Input, Output]): @property def OutputType(self) -> type[Output]: # noqa: N802 - """The type of output this ``Runnable`` produces specified as a type annotation.""" # noqa: E501 + """Output Type. + + The type of output this ``Runnable`` produces specified as a type annotation. + + Raises: + TypeError: If the output type cannot be inferred. + """ # First loop through bases -- this will help generic # any pydantic models. for base in self.__class__.mro(): @@ -583,7 +603,17 @@ class Runnable(ABC, Generic[Input, Output]): Mapping[str, Union[Runnable[Any, Other], Callable[[Any], Other], Any]], ], ) -> RunnableSerializable[Input, Other]: - """Compose this ``Runnable`` with another object to create a ``RunnableSequence``.""" # noqa: E501 + """Runnable "or" operator. + + Compose this ``Runnable`` with another object to create a + ``RunnableSequence``. + + Args: + other: Another ``Runnable`` or a ``Runnable``-like object. + + Returns: + A new ``Runnable``. + """ return RunnableSequence(self, coerce_to_runnable(other)) def __ror__( @@ -596,7 +626,17 @@ class Runnable(ABC, Generic[Input, Output]): Mapping[str, Union[Runnable[Other, Any], Callable[[Other], Any], Any]], ], ) -> RunnableSerializable[Other, Output]: - """Compose this ``Runnable`` with another object to create a ``RunnableSequence``.""" # noqa: E501 + """Runnable "reverse-or" operator. + + Compose this ``Runnable`` with another object to create a + ``RunnableSequence``. + + Args: + other: Another ``Runnable`` or a ``Runnable``-like object. + + Returns: + A new ``Runnable``. + """ return RunnableSequence(coerce_to_runnable(other), self) def pipe( @@ -604,11 +644,15 @@ class Runnable(ABC, Generic[Input, Output]): *others: Union[Runnable[Any, Other], Callable[[Any], Other]], name: Optional[str] = None, ) -> RunnableSerializable[Input, Other]: - """Compose this ``Runnable`` with ``Runnable``-like objects to make a ``RunnableSequence``. + """Pipe runnables. + + Compose this ``Runnable`` with ``Runnable``-like objects to make a + ``RunnableSequence``. Equivalent to ``RunnableSequence(self, *others)`` or ``self | others[0] | ...`` Example: + .. code-block:: python from langchain_core.runnables import RunnableLambda @@ -636,13 +680,20 @@ class Runnable(ABC, Generic[Input, Output]): await sequence.abatch([1, 2, 3]) # -> [4, 6, 8] - """ # noqa: E501 + Args: + *others: Other ``Runnable`` or ``Runnable``-like objects to compose + name: An optional name for the resulting ``RunnableSequence``. + + Returns: + A new ``Runnable``. + """ return RunnableSequence(self, *others, name=name) def pick(self, keys: Union[str, list[str]]) -> RunnableSerializable[Any, Any]: """Pick keys from the output dict of this ``Runnable``. Pick single key: + .. code-block:: python import json @@ -661,6 +712,7 @@ class Runnable(ABC, Generic[Input, Output]): # -> [1, 2, 3] Pick list of keys: + .. code-block:: python from typing import Any @@ -688,6 +740,12 @@ class Runnable(ABC, Generic[Input, Output]): json_and_bytes_chain.invoke("[1, 2, 3]") # -> {"json": [1, 2, 3], "bytes": b"[1, 2, 3]"} + Args: + keys: A key or list of keys to pick from the output dict. + + Returns: + a new ``Runnable``. + """ from langchain_core.runnables.passthrough import RunnablePick @@ -706,8 +764,6 @@ class Runnable(ABC, Generic[Input, Output]): ) -> RunnableSerializable[Any, Any]: """Assigns new fields to the dict output of this ``Runnable``. - Returns a new ``Runnable``. - .. code-block:: python from langchain_community.llms.fake import FakeStreamingListLLM @@ -734,6 +790,13 @@ class Runnable(ABC, Generic[Input, Output]): {'str': {'title': 'Str', 'type': 'string'}, 'hello': {'title': 'Hello', 'type': 'string'}}} + Args: + **kwargs: A mapping of keys to ``Runnable`` or ``Runnable``-like objects + that will be invoked with the entire output dict of this ``Runnable``. + + Returns: + A new ``Runnable``. + """ from langchain_core.runnables.passthrough import RunnableAssign @@ -769,12 +832,18 @@ class Runnable(ABC, Generic[Input, Output]): config: Optional[RunnableConfig] = None, **kwargs: Any, ) -> Output: - """Default implementation of ``ainvoke``, calls ``invoke`` from a thread. + """Transform a single input into an output. - The default implementation allows usage of async code even if - the ``Runnable`` did not implement a native async version of ``invoke``. + Args: + input: The input to the ``Runnable``. + config: A config to use when invoking the ``Runnable``. + The config supports standard keys like ``'tags'``, ``'metadata'`` for + tracing purposes, ``'max_concurrency'`` for controlling how much work to + do in parallel, and other keys. Please refer to the ``RunnableConfig`` + for more details. Defaults to None. - Subclasses should override this method if they can run asynchronously. + Returns: + The output of the ``Runnable``. """ return await run_in_executor(config, self.invoke, input, config, **kwargs) @@ -794,6 +863,20 @@ class Runnable(ABC, Generic[Input, Output]): Subclasses should override this method if they can batch more efficiently; e.g., if the underlying ``Runnable`` uses an API which supports a batch mode. + Args: + inputs: A list of inputs to the ``Runnable``. + config: A config to use when invoking the ``Runnable``. + The config supports standard keys like ``'tags'``, ``'metadata'`` for + tracing purposes, ``'max_concurrency'`` for controlling how much work + to do in parallel, and other keys. Please refer to the + ``RunnableConfig`` for more details. Defaults to None. + return_exceptions: Whether to return exceptions instead of raising them. + Defaults to False. + **kwargs: Additional keyword arguments to pass to the ``Runnable``. + + Returns: + A list of outputs from the ``Runnable``. + """ if not inputs: return [] @@ -848,6 +931,20 @@ class Runnable(ABC, Generic[Input, Output]): Yields results as they complete. + Args: + inputs: A list of inputs to the ``Runnable``. + config: A config to use when invoking the ``Runnable``. + The config supports standard keys like ``'tags'``, ``'metadata'`` for + tracing purposes, ``'max_concurrency'`` for controlling how much work to + do in parallel, and other keys. Please refer to the ``RunnableConfig`` + for more details. Defaults to None. + return_exceptions: Whether to return exceptions instead of raising them. + Defaults to False. + **kwargs: Additional keyword arguments to pass to the ``Runnable``. + + Yields: + Tuples of the index of the input and the output from the ``Runnable``. + """ if not inputs: return @@ -912,7 +1009,7 @@ class Runnable(ABC, Generic[Input, Output]): for more details. Defaults to None. return_exceptions: Whether to return exceptions instead of raising them. Defaults to False. - kwargs: Additional keyword arguments to pass to the ``Runnable``. + **kwargs: Additional keyword arguments to pass to the ``Runnable``. Returns: A list of outputs from the ``Runnable``. @@ -2560,6 +2657,9 @@ class RunnableSerializable(Serializable, Runnable[Input, Output]): Args: **kwargs: A dictionary of ``ConfigurableField`` instances to configure. + Raises: + ValueError: If a configuration key is not found in the ``Runnable``. + Returns: A new ``Runnable`` with the fields configured. @@ -2873,6 +2973,11 @@ class RunnableSequence(RunnableSerializable[Input, Output]): @classmethod @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] @property @@ -2887,14 +2992,7 @@ class RunnableSequence(RunnableSerializable[Input, Output]): @classmethod @override def is_lc_serializable(cls) -> bool: - """Check if the object is serializable. - - Returns: - True if the object is serializable, False otherwise. - - Defaults to True. - - """ + """Return True as this class is serializable.""" return True model_config = ConfigDict( @@ -3666,11 +3764,17 @@ class RunnableParallel(RunnableSerializable[Input, dict[str, Any]]): @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] model_config = ConfigDict( @@ -4700,7 +4804,7 @@ class RunnableLambda(Runnable[Input, Output]): __hash__ = None # type: ignore[assignment] def __repr__(self) -> str: - """A string representation of this ``Runnable``.""" + """Return a string representation of this ``Runnable``.""" if self._repr is None: if hasattr(self, "func") and isinstance(self.func, itemgetter): self._repr = f"RunnableLambda({str(self.func)[len('operator.') :]})" @@ -5213,11 +5317,17 @@ class RunnableEachBase(RunnableSerializable[list[Input], list[Output]]): @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] def _invoke( @@ -5537,6 +5647,7 @@ class RunnableBindingBase(RunnableSerializable[Input, Output]): # type: ignore[ @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod @@ -5544,7 +5655,8 @@ class RunnableBindingBase(RunnableSerializable[Input, Output]): # type: ignore[ def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Defaults to ``["langchain", "schema", "runnable"]``. + Returns: + ``["langchain", "schema", "runnable"]`` """ return ["langchain", "schema", "runnable"] diff --git a/libs/core/langchain_core/runnables/branch.py b/libs/core/langchain_core/runnables/branch.py index cecc8f34b5f..bd8e8c64a76 100644 --- a/libs/core/langchain_core/runnables/branch.py +++ b/libs/core/langchain_core/runnables/branch.py @@ -144,12 +144,17 @@ class RunnableBranch(RunnableSerializable[Input, Output]): @classmethod def is_lc_serializable(cls) -> bool: - """RunnableBranch is serializable if all its branches are serializable.""" + """Return True as this class is serializable.""" return True @classmethod @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] @override @@ -260,7 +265,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]): async def ainvoke( self, input: Input, config: Optional[RunnableConfig] = None, **kwargs: Any ) -> Output: - """Async version of invoke.""" config = ensure_config(config) callback_manager = get_async_callback_manager_for_config(config) run_manager = await callback_manager.on_chain_start( @@ -321,9 +325,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]): Yields: The output of the branch that was run. - - Raises: - BaseException: If an error occurs during the execution of the Runnable. """ config = ensure_config(config) callback_manager = get_callback_manager_for_config(config) @@ -408,9 +409,6 @@ class RunnableBranch(RunnableSerializable[Input, Output]): Yields: The output of the branch that was run. - - Raises: - BaseException: If an error occurs during the execution of the Runnable. """ config = ensure_config(config) callback_manager = get_async_callback_manager_for_config(config) diff --git a/libs/core/langchain_core/runnables/config.py b/libs/core/langchain_core/runnables/config.py index cc36622b914..98090872a34 100644 --- a/libs/core/langchain_core/runnables/config.py +++ b/libs/core/langchain_core/runnables/config.py @@ -125,6 +125,9 @@ def _set_config_context( Args: config (RunnableConfig): The config to set. + + Returns: + The token to reset the config and the previous tracing context. """ from langchain_core.tracers.langchain import LangChainTracer @@ -160,6 +163,9 @@ def set_config_context(config: RunnableConfig) -> Generator[Context, None, None] Args: config (RunnableConfig): The config to set. + + Yields: + The config context. """ from langsmith.run_helpers import _set_tracing_context @@ -598,9 +604,6 @@ async def run_in_executor( Returns: Output: The output of the function. - - Raises: - RuntimeError: If the function raises a StopIteration. """ def wrapper() -> T: diff --git a/libs/core/langchain_core/runnables/configurable.py b/libs/core/langchain_core/runnables/configurable.py index a0f9f53a06d..46138b64adf 100644 --- a/libs/core/langchain_core/runnables/configurable.py +++ b/libs/core/langchain_core/runnables/configurable.py @@ -70,11 +70,17 @@ class DynamicRunnable(RunnableSerializable[Input, Output]): @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] @property diff --git a/libs/core/langchain_core/runnables/fallbacks.py b/libs/core/langchain_core/runnables/fallbacks.py index 7b0b845c206..ede6fcb572d 100644 --- a/libs/core/langchain_core/runnables/fallbacks.py +++ b/libs/core/langchain_core/runnables/fallbacks.py @@ -140,6 +140,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]): @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod @@ -147,13 +148,18 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]): def get_lc_namespace(cls) -> list[str]: """Get the namespace of the langchain object. - Defaults to ["langchain", "schema", "runnable"]. + Returns: + ``["langchain", "schema", "runnable"]`` """ return ["langchain", "schema", "runnable"] @property def runnables(self) -> Iterator[Runnable[Input, Output]]: - """Iterator over the Runnable and its fallbacks.""" + """Iterator over the Runnable and its fallbacks. + + Yields: + The Runnable then its fallbacks. + """ yield self.runnable yield from self.fallbacks diff --git a/libs/core/langchain_core/runnables/graph.py b/libs/core/langchain_core/runnables/graph.py index 20a841d51a8..7dc5ffc2329 100644 --- a/libs/core/langchain_core/runnables/graph.py +++ b/libs/core/langchain_core/runnables/graph.py @@ -475,6 +475,10 @@ class Graph: If there is no such node, or there are multiple, return None. When drawing the graph, this node would be the origin. + + Returns: + The first node, or None if there is no such node or multiple + candidates. """ return _first_node(self) @@ -483,6 +487,10 @@ class Graph: If there is no such node, or there are multiple, return None. When drawing the graph, this node would be the destination. + + Returns: + The last node, or None if there is no such node or multiple + candidates. """ return _last_node(self) @@ -513,7 +521,11 @@ class Graph: self.remove_node(last_node) def draw_ascii(self) -> str: - """Draw the graph as an ASCII art string.""" + """Draw the graph as an ASCII art string. + + Returns: + The ASCII art string. + """ from langchain_core.runnables.graph_ascii import draw_ascii return draw_ascii( diff --git a/libs/core/langchain_core/runnables/graph_ascii.py b/libs/core/langchain_core/runnables/graph_ascii.py index c33353148d8..9c11c585cd1 100644 --- a/libs/core/langchain_core/runnables/graph_ascii.py +++ b/libs/core/langchain_core/runnables/graph_ascii.py @@ -50,8 +50,11 @@ class AsciiCanvas: """Create an ASCII canvas. Args: - cols (int): number of columns in the canvas. Should be > 1. - lines (int): number of lines in the canvas. Should be > 1. + cols: number of columns in the canvas. Should be ``> 1``. + lines: number of lines in the canvas. Should be ``> 1``. + + Raises: + ValueError: if canvas dimensions are invalid. """ if cols <= 1 or lines <= 1: msg = "Canvas dimensions should be > 1" @@ -63,7 +66,11 @@ class AsciiCanvas: self.canvas = [[" "] * cols for line in range(lines)] def draw(self) -> str: - """Draws ASCII canvas on the screen.""" + """Draws ASCII canvas on the screen. + + Returns: + The ASCII canvas string. + """ lines = map("".join, self.canvas) return os.linesep.join(lines) @@ -71,12 +78,16 @@ class AsciiCanvas: """Create a point on ASCII canvas. Args: - x (int): x coordinate. Should be >= 0 and < number of columns in + x: x coordinate. Should be ``>= 0`` and ``<`` number of columns in the canvas. - y (int): y coordinate. Should be >= 0 an < number of lines in the + y: y coordinate. Should be ``>= 0`` an ``<`` number of lines in the canvas. - char (str): character to place in the specified point on the + char: character to place in the specified point on the canvas. + + Raises: + ValueError: if char is not a single character or if + coordinates are out of bounds. """ if len(char) != 1: msg = "char should be a single character" @@ -225,11 +236,15 @@ def draw_ascii(vertices: Mapping[str, str], edges: Sequence[LangEdge]) -> str: """Build a DAG and draw it in ASCII. Args: - vertices (list): list of graph vertices. - edges (list): list of graph edges. + vertices: list of graph vertices. + edges: list of graph edges. + + Raises: + ValueError: if the canvas dimensions are invalid or if + edge coordinates are invalid. Returns: - str: ASCII representation + ASCII representation Example: diff --git a/libs/core/langchain_core/runnables/graph_png.py b/libs/core/langchain_core/runnables/graph_png.py index 504236188ce..c7d15c85127 100644 --- a/libs/core/langchain_core/runnables/graph_png.py +++ b/libs/core/langchain_core/runnables/graph_png.py @@ -85,9 +85,6 @@ class PngDrawer: Args: viz: The graphviz object. node: The node to add. - - Returns: - None """ viz.add_node( node, @@ -114,9 +111,6 @@ class PngDrawer: target: The target node. label: The label for the edge. Defaults to None. conditional: Whether the edge is conditional. Defaults to False. - - Returns: - None """ viz.add_edge( source, @@ -131,8 +125,16 @@ class PngDrawer: """Draw the given state graph into a PNG file. Requires `graphviz` and `pygraphviz` to be installed. - :param graph: The graph to draw - :param output_path: The path to save the PNG. If None, PNG bytes are returned. + + Args: + graph: The graph to draw + output_path: The path to save the PNG. If None, PNG bytes are returned. + + Raises: + ImportError: If ``pygraphviz`` is not installed. + + Returns: + The PNG bytes if ``output_path`` is None, else None. """ try: import pygraphviz as pgv # type: ignore[import-not-found] diff --git a/libs/core/langchain_core/runnables/passthrough.py b/libs/core/langchain_core/runnables/passthrough.py index afc28e54d42..848bf264c63 100644 --- a/libs/core/langchain_core/runnables/passthrough.py +++ b/libs/core/langchain_core/runnables/passthrough.py @@ -193,11 +193,16 @@ class RunnablePassthrough(RunnableSerializable[Other, Other]): @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod - @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] @property @@ -417,11 +422,17 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]): @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod @override def get_lc_namespace(cls) -> list[str]: + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] @override @@ -721,12 +732,17 @@ class RunnablePick(RunnableSerializable[dict[str, Any], dict[str, Any]]): @classmethod @override def is_lc_serializable(cls) -> bool: + """Return True as this class is serializable.""" return True @classmethod @override def get_lc_namespace(cls) -> list[str]: - """Get the namespace of the langchain object.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] @override diff --git a/libs/core/langchain_core/runnables/router.py b/libs/core/langchain_core/runnables/router.py index 7cc947fe9a8..827e75c6624 100644 --- a/libs/core/langchain_core/runnables/router.py +++ b/libs/core/langchain_core/runnables/router.py @@ -98,13 +98,17 @@ class RouterRunnable(RunnableSerializable[RouterInput, Output]): @classmethod @override def is_lc_serializable(cls) -> bool: - """Return whether this class is serializable.""" + """Return True as this class is serializable.""" return True @classmethod @override def get_lc_namespace(cls) -> list[str]: - """Get the namespace of the langchain object.""" + """Get the namespace of the langchain object. + + Returns: + ``["langchain", "schema", "runnable"]`` + """ return ["langchain", "schema", "runnable"] @override diff --git a/libs/core/langchain_core/runnables/utils.py b/libs/core/langchain_core/runnables/utils.py index 3a740e868eb..eb4c0cd43d5 100644 --- a/libs/core/langchain_core/runnables/utils.py +++ b/libs/core/langchain_core/runnables/utils.py @@ -122,7 +122,12 @@ def accepts_context(callable: Callable[..., Any]) -> bool: # noqa: A002 @lru_cache(maxsize=1) def asyncio_accepts_context() -> bool: - """Cache the result of checking if asyncio.create_task accepts a ``context`` arg.""" + """Cache the result of checking if asyncio.create_task accepts a ``context`` arg. + + Returns: + bool: True if ``asyncio.create_task`` accepts a context argument, False + otherwise. + """ return accepts_context(asyncio.create_task) @@ -160,14 +165,11 @@ class IsLocalDict(ast.NodeVisitor): self.keys = keys @override - def visit_Subscript(self, node: ast.Subscript) -> Any: + def visit_Subscript(self, node: ast.Subscript) -> None: """Visit a subscript node. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ if ( isinstance(node.ctx, ast.Load) @@ -180,14 +182,11 @@ class IsLocalDict(ast.NodeVisitor): self.keys.add(node.slice.value) @override - def visit_Call(self, node: ast.Call) -> Any: + def visit_Call(self, node: ast.Call) -> None: """Visit a call node. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ if ( isinstance(node.func, ast.Attribute) @@ -210,14 +209,11 @@ class IsFunctionArgDict(ast.NodeVisitor): self.keys: set[str] = set() @override - def visit_Lambda(self, node: ast.Lambda) -> Any: + def visit_Lambda(self, node: ast.Lambda) -> None: """Visit a lambda function. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ if not node.args.args: return @@ -225,14 +221,11 @@ class IsFunctionArgDict(ast.NodeVisitor): IsLocalDict(input_arg_name, self.keys).visit(node.body) @override - def visit_FunctionDef(self, node: ast.FunctionDef) -> Any: + def visit_FunctionDef(self, node: ast.FunctionDef) -> None: """Visit a function definition. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ if not node.args.args: return @@ -240,14 +233,11 @@ class IsFunctionArgDict(ast.NodeVisitor): IsLocalDict(input_arg_name, self.keys).visit(node) @override - def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> Any: + def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None: """Visit an async function definition. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ if not node.args.args: return @@ -264,14 +254,11 @@ class NonLocals(ast.NodeVisitor): self.stores: set[str] = set() @override - def visit_Name(self, node: ast.Name) -> Any: + def visit_Name(self, node: ast.Name) -> None: """Visit a name node. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ if isinstance(node.ctx, ast.Load): self.loads.add(node.id) @@ -279,14 +266,11 @@ class NonLocals(ast.NodeVisitor): self.stores.add(node.id) @override - def visit_Attribute(self, node: ast.Attribute) -> Any: + def visit_Attribute(self, node: ast.Attribute) -> None: """Visit an attribute node. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ if isinstance(node.ctx, ast.Load): parent = node.value @@ -321,42 +305,33 @@ class FunctionNonLocals(ast.NodeVisitor): self.nonlocals: set[str] = set() @override - def visit_FunctionDef(self, node: ast.FunctionDef) -> Any: + def visit_FunctionDef(self, node: ast.FunctionDef) -> None: """Visit a function definition. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ visitor = NonLocals() visitor.visit(node) self.nonlocals.update(visitor.loads - visitor.stores) @override - def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> Any: + def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None: """Visit an async function definition. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ visitor = NonLocals() visitor.visit(node) self.nonlocals.update(visitor.loads - visitor.stores) @override - def visit_Lambda(self, node: ast.Lambda) -> Any: + def visit_Lambda(self, node: ast.Lambda) -> None: """Visit a lambda function. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ visitor = NonLocals() visitor.visit(node) @@ -372,14 +347,11 @@ class GetLambdaSource(ast.NodeVisitor): self.count = 0 @override - def visit_Lambda(self, node: ast.Lambda) -> Any: + def visit_Lambda(self, node: ast.Lambda) -> None: """Visit a lambda function. Args: node: The node to visit. - - Returns: - Any: The result of the visit. """ self.count += 1 if hasattr(ast, "unparse"): @@ -496,6 +468,9 @@ class AddableDict(dict[str, Any]): Args: other: The other dictionary to add. + + Returns: + A dictionary that is the result of adding the two dictionaries. """ chunk = AddableDict(self) for key in other: @@ -514,6 +489,9 @@ class AddableDict(dict[str, Any]): Args: other: The other dictionary to be added to. + + Returns: + A dictionary that is the result of adding the two dictionaries. """ chunk = AddableDict(other) for key in self: diff --git a/libs/core/langchain_core/stores.py b/libs/core/langchain_core/stores.py index e6df8fd93eb..7f51b4c4b5a 100644 --- a/libs/core/langchain_core/stores.py +++ b/libs/core/langchain_core/stores.py @@ -16,6 +16,8 @@ from typing import ( Union, ) +from typing_extensions import override + from langchain_core.exceptions import LangChainException from langchain_core.runnables import run_in_executor @@ -206,27 +208,13 @@ class InMemoryBaseStore(BaseStore[str, V], Generic[V]): """ return self.mget(keys) + @override def mset(self, key_value_pairs: Sequence[tuple[str, V]]) -> None: - """Set the values for the given keys. - - Args: - key_value_pairs (Sequence[tuple[str, V]]): A sequence of key-value pairs. - - Returns: - None - """ for key, value in key_value_pairs: self.store[key] = value + @override async def amset(self, key_value_pairs: Sequence[tuple[str, V]]) -> None: - """Async set the values for the given keys. - - Args: - key_value_pairs (Sequence[tuple[str, V]]): A sequence of key-value pairs. - - Returns: - None - """ return self.mset(key_value_pairs) def mdelete(self, keys: Sequence[str]) -> None: diff --git a/libs/core/langchain_core/tools/base.py b/libs/core/langchain_core/tools/base.py index e93cb74dc6b..d1b18a3aa42 100644 --- a/libs/core/langchain_core/tools/base.py +++ b/libs/core/langchain_core/tools/base.py @@ -506,7 +506,12 @@ class ChildTool(BaseTool): """ def __init__(self, **kwargs: Any) -> None: - """Initialize the tool.""" + """Initialize the tool. + + Raises: + TypeError: If ``args_schema`` is not a subclass of pydantic ``BaseModel`` or + dict. + """ if ( "args_schema" in kwargs and kwargs["args_schema"] is not None @@ -628,9 +633,10 @@ class ChildTool(BaseTool): The parsed and validated input. Raises: - ValueError: If string input is provided with JSON schema or if - InjectedToolCallId is required but not provided. - NotImplementedError: If args_schema is not a supported type. + ValueError: If string input is provided with JSON schema ``args_schema``. + ValueError: If InjectedToolCallId is required but ``tool_call_id`` is not + provided. + TypeError: If args_schema is not a Pydantic ``BaseModel`` or dict. """ input_args = self.args_schema if isinstance(tool_input, str): @@ -725,6 +731,9 @@ class ChildTool(BaseTool): Add run_manager: Optional[CallbackManagerForToolRun] = None to child implementations to enable tracing. + + Returns: + The result of the tool execution. """ async def _arun(self, *args: Any, **kwargs: Any) -> Any: @@ -732,6 +741,9 @@ class ChildTool(BaseTool): Add run_manager: Optional[AsyncCallbackManagerForToolRun] = None to child implementations to enable tracing. + + Returns: + The result of the tool execution. """ if kwargs.get("run_manager") and signature(self._run).parameters.get( "run_manager" @@ -1312,6 +1324,9 @@ def get_all_basemodel_annotations( Args: cls: The Pydantic BaseModel class. default_to_bound: Whether to default to the bound of a TypeVar if it exists. + + Returns: + A dictionary of field names to their type annotations. """ # cls has no subscript: cls = FooBar if isinstance(cls, type): diff --git a/libs/core/langchain_core/tools/convert.py b/libs/core/langchain_core/tools/convert.py index 2693ce80150..84b328f0bed 100644 --- a/libs/core/langchain_core/tools/convert.py +++ b/libs/core/langchain_core/tools/convert.py @@ -119,6 +119,17 @@ def tool( whether to raise ValueError on invalid Google Style docstrings. Defaults to True. + Raises: + ValueError: If too many positional arguments are provided. + ValueError: If a runnable is provided without a string name. + ValueError: If the first argument is not a string or callable with + a ``__name__`` attribute. + ValueError: If the function does not have a docstring and description + is not provided and ``infer_schema`` is False. + ValueError: If ``parse_docstring`` is True and the function has an invalid + Google-style docstring and ``error_on_invalid_docstring`` is True. + ValueError: If a Runnable is provided that does not have an object schema. + Returns: The tool. diff --git a/libs/core/langchain_core/tools/simple.py b/libs/core/langchain_core/tools/simple.py index 05dc1917644..40c58e372e1 100644 --- a/libs/core/langchain_core/tools/simple.py +++ b/libs/core/langchain_core/tools/simple.py @@ -76,7 +76,19 @@ class Tool(BaseTool): def _to_args_and_kwargs( self, tool_input: Union[str, dict], tool_call_id: Optional[str] ) -> tuple[tuple, dict]: - """Convert tool input to pydantic model.""" + """Convert tool input to pydantic model. + + Args: + tool_input: The input to the tool. + tool_call_id: The ID of the tool call. + + Raises: + ToolException: If the tool input is invalid. + + Returns: + the pydantic model args and kwargs. + + """ args, kwargs = super()._to_args_and_kwargs(tool_input, tool_call_id) # For backwards compatibility. The tool must be run with a single input all_args = list(args) + list(kwargs.values()) @@ -96,7 +108,17 @@ class Tool(BaseTool): run_manager: Optional[CallbackManagerForToolRun] = None, **kwargs: Any, ) -> Any: - """Use the tool.""" + """Use the tool. + + Args: + *args: Positional arguments to pass to the tool + config: Configuration for the run + run_manager: Optional callback manager to use for the run + **kwargs: Keyword arguments to pass to the tool + + Returns: + The result of the tool execution + """ if self.func: if run_manager and signature(self.func).parameters.get("callbacks"): kwargs["callbacks"] = run_manager.get_child() @@ -113,7 +135,17 @@ class Tool(BaseTool): run_manager: Optional[AsyncCallbackManagerForToolRun] = None, **kwargs: Any, ) -> Any: - """Use the tool asynchronously.""" + """Use the tool asynchronously. + + Args: + *args: Positional arguments to pass to the tool + config: Configuration for the run + run_manager: Optional callback manager to use for the run + **kwargs: Keyword arguments to pass to the tool + + Returns: + The result of the tool execution + """ if self.coroutine: if run_manager and signature(self.coroutine).parameters.get("callbacks"): kwargs["callbacks"] = run_manager.get_child() diff --git a/libs/core/langchain_core/tools/structured.py b/libs/core/langchain_core/tools/structured.py index 7fcc3c26e5a..08078e92771 100644 --- a/libs/core/langchain_core/tools/structured.py +++ b/libs/core/langchain_core/tools/structured.py @@ -84,7 +84,17 @@ class StructuredTool(BaseTool): run_manager: Optional[CallbackManagerForToolRun] = None, **kwargs: Any, ) -> Any: - """Use the tool.""" + """Use the tool. + + Args: + *args: Positional arguments to pass to the tool + config: Configuration for the run + run_manager: Optional callback manager to use for the run + **kwargs: Keyword arguments to pass to the tool + + Returns: + The result of the tool execution + """ if self.func: if run_manager and signature(self.func).parameters.get("callbacks"): kwargs["callbacks"] = run_manager.get_child() @@ -101,7 +111,17 @@ class StructuredTool(BaseTool): run_manager: Optional[AsyncCallbackManagerForToolRun] = None, **kwargs: Any, ) -> Any: - """Use the tool asynchronously.""" + """Use the tool asynchronously. + + Args: + *args: Positional arguments to pass to the tool + config: Configuration for the run + run_manager: Optional callback manager to use for the run + **kwargs: Keyword arguments to pass to the tool + + Returns: + The result of the tool execution + """ if self.coroutine: if run_manager and signature(self.coroutine).parameters.get("callbacks"): kwargs["callbacks"] = run_manager.get_child() @@ -164,6 +184,9 @@ class StructuredTool(BaseTool): Raises: ValueError: If the function is not provided. + ValueError: If the function does not have a docstring and description + is not provided. + TypeError: If the ``args_schema`` is not a ``BaseModel`` or dict. Examples: diff --git a/libs/core/langchain_core/tracers/base.py b/libs/core/langchain_core/tracers/base.py index ee588606165..e33f0339af7 100644 --- a/libs/core/langchain_core/tracers/base.py +++ b/libs/core/langchain_core/tracers/base.py @@ -520,11 +520,11 @@ class BaseTracer(_TracerCore, BaseCallbackHandler, ABC): return retrieval_run def __deepcopy__(self, memo: dict) -> BaseTracer: - """Deepcopy the tracer.""" + """Return self.""" return self def __copy__(self) -> BaseTracer: - """Copy the tracer.""" + """Return self.""" return self diff --git a/libs/core/langchain_core/tracers/context.py b/libs/core/langchain_core/tracers/context.py index 58471a09ecc..838eaa6d8f5 100644 --- a/libs/core/langchain_core/tracers/context.py +++ b/libs/core/langchain_core/tracers/context.py @@ -43,7 +43,11 @@ run_collector_var: ContextVar[Optional[RunCollectorCallbackHandler]] = ContextVa def tracing_enabled( session_name: str = "default", # noqa: ARG001 ) -> Generator[TracerSessionV1, None, None]: - """Throw an error because this has been replaced by tracing_v2_enabled.""" + """Throw an error because this has been replaced by ``tracing_v2_enabled``. + + Raises: + RuntimeError: Always, because this function is deprecated. + """ msg = ( "tracing_enabled is no longer supported. Please use tracing_enabled_v2 instead." ) diff --git a/libs/core/langchain_core/tracers/core.py b/libs/core/langchain_core/tracers/core.py index 0a10b06ecaf..54261a2c224 100644 --- a/libs/core/langchain_core/tracers/core.py +++ b/libs/core/langchain_core/tracers/core.py @@ -71,7 +71,7 @@ class _TracerCore(ABC): for streaming events. - 'original+chat' is a format that is the same as 'original' except it does NOT raise an attribute error on_chat_model_start - kwargs: Additional keyword arguments that will be passed to + **kwargs: Additional keyword arguments that will be passed to the superclass. """ super().__init__(**kwargs) @@ -531,27 +531,43 @@ class _TracerCore(ABC): return retrieval_run def __deepcopy__(self, memo: dict) -> _TracerCore: - """Deepcopy the tracer.""" + """Return self deepcopied.""" return self def __copy__(self) -> _TracerCore: - """Copy the tracer.""" + """Return self copied.""" return self def _end_trace(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """End a trace for a run.""" + """End a trace for a run. + + Args: + run: The run. + """ return None def _on_run_create(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process a run upon creation.""" + """Process a run upon creation. + + Args: + run: The created run. + """ return None def _on_run_update(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process a run upon update.""" + """Process a run upon update. + + Args: + run: The updated run. + """ return None def _on_llm_start(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the LLM Run upon start.""" + """Process the LLM Run upon start. + + Args: + run: The LLM run. + """ return None def _on_llm_new_token( @@ -560,53 +576,107 @@ class _TracerCore(ABC): token: str, # noqa: ARG002 chunk: Optional[Union[GenerationChunk, ChatGenerationChunk]], # noqa: ARG002 ) -> Union[None, Coroutine[Any, Any, None]]: - """Process new LLM token.""" + """Process new LLM token. + + Args: + run: The LLM run. + token: The new token. + chunk: Optional chunk. + """ return None def _on_llm_end(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the LLM Run.""" + """Process the LLM Run. + + Args: + run: The LLM run. + """ return None def _on_llm_error(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the LLM Run upon error.""" + """Process the LLM Run upon error. + + Args: + run: The LLM run. + """ return None def _on_chain_start(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Chain Run upon start.""" + """Process the Chain Run upon start. + + Args: + run: The chain run. + """ return None def _on_chain_end(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Chain Run.""" + """Process the Chain Run. + + Args: + run: The chain run. + """ return None def _on_chain_error(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Chain Run upon error.""" + """Process the Chain Run upon error. + + Args: + run: The chain run. + """ return None def _on_tool_start(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Tool Run upon start.""" + """Process the Tool Run upon start. + + Args: + run: The tool run. + """ return None def _on_tool_end(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Tool Run.""" + """Process the Tool Run. + + Args: + run: The tool run. + """ return None def _on_tool_error(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Tool Run upon error.""" + """Process the Tool Run upon error. + + Args: + run: The tool run. + """ return None def _on_chat_model_start(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Chat Model Run upon start.""" + """Process the Chat Model Run upon start. + + Args: + run: The chat model run. + """ return None def _on_retriever_start(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Retriever Run upon start.""" + """Process the Retriever Run upon start. + + Args: + run: The retriever run. + """ return None def _on_retriever_end(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Retriever Run.""" + """Process the Retriever Run. + + Args: + run: The retriever run. + """ return None def _on_retriever_error(self, run: Run) -> Union[None, Coroutine[Any, Any, None]]: # noqa: ARG002 - """Process the Retriever Run upon error.""" + """Process the Retriever Run upon error. + + Args: + run: The retriever run. + """ return None diff --git a/libs/core/langchain_core/tracers/event_stream.py b/libs/core/langchain_core/tracers/event_stream.py index eff11bbb06a..b0e44d4eca1 100644 --- a/libs/core/langchain_core/tracers/event_stream.py +++ b/libs/core/langchain_core/tracers/event_stream.py @@ -155,7 +155,11 @@ class _AstreamEventsCallbackHandler(AsyncCallbackHandler, _StreamingCallbackHand self.send_stream.send_nowait(event) def __aiter__(self) -> AsyncIterator[Any]: - """Iterate over the receive stream.""" + """Iterate over the receive stream. + + Returns: + An async iterator over the receive stream. + """ return self.receive_stream.__aiter__() async def tap_output_aiter( @@ -412,7 +416,6 @@ class _AstreamEventsCallbackHandler(AsyncCallbackHandler, _StreamingCallbackHand parent_run_id: Optional[UUID] = None, **kwargs: Any, ) -> None: - """Run on new LLM token. Only available when streaming is enabled.""" run_info = self.run_map.get(run_id) chunk_: Union[GenerationChunk, BaseMessageChunk] @@ -458,7 +461,15 @@ class _AstreamEventsCallbackHandler(AsyncCallbackHandler, _StreamingCallbackHand async def on_llm_end( self, response: LLMResult, *, run_id: UUID, **kwargs: Any ) -> None: - """End a trace for an LLM run.""" + """End a trace for an LLM run. + + Args: + response (LLMResult): The response which was generated. + run_id (UUID): The run ID. This is the ID of the current run. + + Raises: + ValueError: If the run type is not ``'llm'`` or ``'chat_model'``. + """ run_info = self.run_map.pop(run_id) inputs_ = run_info["inputs"] @@ -636,7 +647,15 @@ class _AstreamEventsCallbackHandler(AsyncCallbackHandler, _StreamingCallbackHand @override async def on_tool_end(self, output: Any, *, run_id: UUID, **kwargs: Any) -> None: - """End a trace for a tool run.""" + """End a trace for a tool run. + + Args: + output: The output of the tool. + run_id: The run ID. This is the ID of the current run. + + Raises: + AssertionError: If the run ID is a tool call and does not have inputs + """ run_info = self.run_map.pop(run_id) if "inputs" not in run_info: msg = ( @@ -730,11 +749,11 @@ class _AstreamEventsCallbackHandler(AsyncCallbackHandler, _StreamingCallbackHand ) def __deepcopy__(self, memo: dict) -> _AstreamEventsCallbackHandler: - """Deepcopy the tracer.""" + """Return self.""" return self def __copy__(self) -> _AstreamEventsCallbackHandler: - """Copy the tracer.""" + """Return self.""" return self diff --git a/libs/core/langchain_core/tracers/langchain.py b/libs/core/langchain_core/tracers/langchain.py index 4a6d0d82344..07e6618573e 100644 --- a/libs/core/langchain_core/tracers/langchain.py +++ b/libs/core/langchain_core/tracers/langchain.py @@ -53,7 +53,11 @@ def wait_for_all_tracers() -> None: def get_client() -> Client: - """Get the client.""" + """Get the client. + + Returns: + The LangSmith client. + """ return rt.get_cached_client() @@ -235,7 +239,6 @@ class LangChainTracer(BaseTracer): chunk: Optional[Union[GenerationChunk, ChatGenerationChunk]] = None, parent_run_id: Optional[UUID] = None, ) -> Run: - """Append token event to LLM run and return the run.""" run_id_str = str(run_id) if run_id_str not in self.run_has_token_event_map: self.run_has_token_event_map[run_id_str] = True diff --git a/libs/core/langchain_core/tracers/langchain_v1.py b/libs/core/langchain_core/tracers/langchain_v1.py index 63aab51eeea..92634f5c912 100644 --- a/libs/core/langchain_core/tracers/langchain_v1.py +++ b/libs/core/langchain_core/tracers/langchain_v1.py @@ -7,7 +7,11 @@ from typing import Any def get_headers(*args: Any, **kwargs: Any) -> Any: # noqa: ARG001 - """Throw an error because this has been replaced by get_headers.""" + """Throw an error because this has been replaced by get_headers. + + Raises: + RuntimeError: Always, because this function is deprecated. + """ msg = ( "get_headers for LangChainTracerV1 is no longer supported. " "Please use LangChainTracer instead." @@ -16,7 +20,11 @@ def get_headers(*args: Any, **kwargs: Any) -> Any: # noqa: ARG001 def LangChainTracerV1(*args: Any, **kwargs: Any) -> Any: # noqa: N802,ARG001 - """Throw an error because this has been replaced by LangChainTracer.""" + """Throw an error because this has been replaced by ``LangChainTracer``. + + Raises: + RuntimeError: Always, because this class is deprecated. + """ msg = ( "LangChainTracerV1 is no longer supported. Please use LangChainTracer instead." ) diff --git a/libs/core/langchain_core/tracers/log_stream.py b/libs/core/langchain_core/tracers/log_stream.py index dbf5ef2a6ae..2821ade0dc5 100644 --- a/libs/core/langchain_core/tracers/log_stream.py +++ b/libs/core/langchain_core/tracers/log_stream.py @@ -110,7 +110,17 @@ class RunLogPatch: self.ops = list(ops) def __add__(self, other: Union[RunLogPatch, Any]) -> RunLog: - """Combine two RunLogPatch instances.""" + """Combine two ``RunLogPatch`` instances. + + Args: + other: The other ``RunLogPatch`` to combine with. + + Raises: + TypeError: If the other object is not a ``RunLogPatch``. + + Returns: + A new ``RunLog`` representing the combination of the two. + """ if type(other) is RunLogPatch: ops = self.ops + other.ops state = jsonpatch.apply_patch(None, copy.deepcopy(ops)) @@ -150,7 +160,17 @@ class RunLog(RunLogPatch): self.state = state def __add__(self, other: Union[RunLogPatch, Any]) -> RunLog: - """Combine two RunLogs.""" + """Combine two ``RunLog``s. + + Args: + other: The other ``RunLog`` or ``RunLogPatch`` to combine with. + + Raises: + TypeError: If the other object is not a ``RunLog`` or ``RunLogPatch``. + + Returns: + A new ``RunLog`` representing the combination of the two. + """ if type(other) is RunLogPatch: ops = self.ops + other.ops state = jsonpatch.apply_patch(self.state, other.ops) @@ -167,7 +187,14 @@ class RunLog(RunLogPatch): @override def __eq__(self, other: object) -> bool: - """Check if two RunLogs are equal.""" + """Check if two ``RunLog``s are equal. + + Args: + other: The other ``RunLog`` to compare to. + + Returns: + True if the ``RunLog``s are equal, False otherwise. + """ # First compare that the state is the same if not isinstance(other, RunLog): return False @@ -250,7 +277,11 @@ class LogStreamCallbackHandler(BaseTracer, _StreamingCallbackHandler): self.root_id: Optional[UUID] = None def __aiter__(self) -> AsyncIterator[RunLogPatch]: - """Iterate over the stream of run logs.""" + """Iterate over the stream of run logs. + + Returns: + An async iterator over the run log patches. + """ return self.receive_stream.__aiter__() def send(self, *ops: dict[str, Any]) -> bool: @@ -623,6 +654,23 @@ async def _astream_log_implementation( The implementation has been factored out (at least temporarily) as both astream_log and astream_events relies on it. + + Args: + runnable: The runnable to run in streaming mode. + value: The input to the runnable. + config: The config to pass to the runnable. + stream: The stream to send the run logs to. + diff: Whether to yield run log patches (True) or full run logs (False). + with_streamed_output_list: Whether to include a list of all streamed + outputs in each patch. If False, only the final output will be included + in the patches. + **kwargs: Additional keyword arguments to pass to the runnable. + + Raises: + ValueError: If the callbacks in the config are of an unexpected type. + + Yields: + The run log patches or states, depending on the value of ``diff``. """ import jsonpatch diff --git a/libs/core/langchain_core/tracers/schemas.py b/libs/core/langchain_core/tracers/schemas.py index ea06cb2f9dc..cd3dd71fea7 100644 --- a/libs/core/langchain_core/tracers/schemas.py +++ b/libs/core/langchain_core/tracers/schemas.py @@ -18,7 +18,11 @@ from langchain_core._api import deprecated @deprecated("0.1.0", alternative="Use string instead.", removal="1.0") def RunTypeEnum() -> type[RunTypeEnumDep]: # noqa: N802 - """RunTypeEnum.""" + """``RunTypeEnum``. + + Returns: + The ``RunTypeEnum`` class. + """ warnings.warn( "RunTypeEnum is deprecated. Please directly use a string instead" " (e.g. 'llm', 'chain', 'tool').", diff --git a/libs/core/langchain_core/utils/aiter.py b/libs/core/langchain_core/utils/aiter.py index 701a2321726..7a0477c658e 100644 --- a/libs/core/langchain_core/utils/aiter.py +++ b/libs/core/langchain_core/utils/aiter.py @@ -94,7 +94,7 @@ class NoLock: exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> bool: - """Exception not handled.""" + """Return False, exception not suppressed.""" return False @@ -236,7 +236,11 @@ class Tee(Generic[T]): return self._children[item] def __iter__(self) -> Iterator[AsyncIterator[T]]: - """Iterate over the child iterators.""" + """Iterate over the child iterators. + + Yields: + The child iterators. + """ yield from self._children async def __aenter__(self) -> "Tee[T]": @@ -249,7 +253,11 @@ class Tee(Generic[T]): exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> bool: - """Close all child iterators.""" + """Close all child iterators. + + Returns: + False, exceptions not suppressed. + """ await self.aclose() return False @@ -318,8 +326,8 @@ async def abatch_iterate( size: The size of the batch. iterable: The async iterable to batch. - Returns: - An async iterator over the batches. + Yields: + The batches. """ batch: list[T] = [] async for element in iterable: diff --git a/libs/core/langchain_core/utils/env.py b/libs/core/langchain_core/utils/env.py index 9f37b3c4f47..51fd3d66e21 100644 --- a/libs/core/langchain_core/utils/env.py +++ b/libs/core/langchain_core/utils/env.py @@ -39,6 +39,9 @@ def get_from_dict_or_env( in the dictionary. default: The default value to return if the key is not in the dictionary or the environment. Defaults to None. + + Returns: + The dict value or the environment variable value. """ if isinstance(key, (list, tuple)): for k in key: diff --git a/libs/core/langchain_core/utils/function_calling.py b/libs/core/langchain_core/utils/function_calling.py index 61849113d1b..fff700651ea 100644 --- a/libs/core/langchain_core/utils/function_calling.py +++ b/libs/core/langchain_core/utils/function_calling.py @@ -146,6 +146,9 @@ def _convert_pydantic_to_openai_function( of the schema will be used. rm_titles: Whether to remove titles from the schema. Defaults to True. + Raises: + TypeError: If the model is not a Pydantic model. + Returns: The function description. """ @@ -323,6 +326,9 @@ def _format_tool_to_openai_function(tool: BaseTool) -> FunctionDescription: Args: tool: The tool to format. + Raises: + ValueError: If the tool call schema is not supported. + Returns: The function description. """ @@ -602,7 +608,20 @@ def convert_to_json_schema( *, strict: Optional[bool] = None, ) -> dict[str, Any]: - """Convert a schema representation to a JSON schema.""" + """Convert a schema representation to a JSON schema. + + Args: + schema: The schema to convert. + strict: If True, model output is guaranteed to exactly match the JSON Schema + provided in the function definition. If None, ``strict`` argument will not + be included in function definition. + + Raises: + ValueError: If the input is not a valid OpenAI-format tool. + + Returns: + A JSON schema representation of the input schema. + """ openai_tool = convert_to_openai_tool(schema, strict=strict) if ( not isinstance(openai_tool, dict) diff --git a/libs/core/langchain_core/utils/interactive_env.py b/libs/core/langchain_core/utils/interactive_env.py index 12676d0bd52..b974b3091eb 100644 --- a/libs/core/langchain_core/utils/interactive_env.py +++ b/libs/core/langchain_core/utils/interactive_env.py @@ -2,7 +2,11 @@ def is_interactive_env() -> bool: - """Determine if running within IPython or Jupyter.""" + """Determine if running within IPython or Jupyter. + + Returns: + True if running in an interactive environment, False otherwise. + """ import sys return hasattr(sys, "ps2") diff --git a/libs/core/langchain_core/utils/iter.py b/libs/core/langchain_core/utils/iter.py index ecd4ba60976..5ef7c98b048 100644 --- a/libs/core/langchain_core/utils/iter.py +++ b/libs/core/langchain_core/utils/iter.py @@ -31,7 +31,7 @@ class NoLock: exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> Literal[False]: - """Exception not handled.""" + """Return False (exception not suppressed).""" return False @@ -173,7 +173,11 @@ class Tee(Generic[T]): return self._children[item] def __iter__(self) -> Iterator[Iterator[T]]: - """Return an iterator over the child iterators.""" + """Return an iterator over the child iterators. + + Yields: + The child iterators. + """ yield from self._children def __enter__(self) -> "Tee[T]": @@ -186,7 +190,11 @@ class Tee(Generic[T]): exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> Literal[False]: - """Close all child iterators.""" + """Close all child iterators. + + Returns: + False (exception not suppressed). + """ self.close() return False diff --git a/libs/core/langchain_core/utils/json.py b/libs/core/langchain_core/utils/json.py index 98450587e1c..1306bb9d73c 100644 --- a/libs/core/langchain_core/utils/json.py +++ b/libs/core/langchain_core/utils/json.py @@ -26,6 +26,9 @@ def _custom_parser(multiline_string: Union[str, bytes, bytearray]) -> str: string containing unescaped newlines, tabs or quotes. This function replaces those characters with their escaped counterparts. (newlines in JSON must be double-escaped: `\\n`). + + Returns: + The modified string with escaped newlines, tabs and quotes. """ if isinstance(multiline_string, (bytes, bytearray)): multiline_string = multiline_string.decode() diff --git a/libs/core/langchain_core/utils/json_schema.py b/libs/core/langchain_core/utils/json_schema.py index 5463c245b41..2c0672ab645 100644 --- a/libs/core/langchain_core/utils/json_schema.py +++ b/libs/core/langchain_core/utils/json_schema.py @@ -49,10 +49,14 @@ def _dereference_refs_helper( """Inline every pure {'$ref':...}. But: + - if shallow_refs=True: only break cycles, do not inline nested refs - if shallow_refs=False: deep-inline all nested refs Also skip recursion under any key in skip_keys. + + Returns: + The object with refs dereferenced. """ if processed_refs is None: processed_refs = set() @@ -118,6 +122,9 @@ def dereference_refs( shallow-inline refs. - If provided (even as an empty list), we will recurse under every key and deep-inline all refs. + + Returns: + The schema with refs dereferenced. """ full = full_schema or schema_obj keys_to_skip = list(skip_keys) if skip_keys is not None else ["$defs"] diff --git a/libs/core/langchain_core/utils/loading.py b/libs/core/langchain_core/utils/loading.py index 7921f6a06c1..55066a7bf45 100644 --- a/libs/core/langchain_core/utils/loading.py +++ b/libs/core/langchain_core/utils/loading.py @@ -19,7 +19,11 @@ def try_load_from_hub( *args: Any, # noqa: ARG001 **kwargs: Any, # noqa: ARG001 ) -> Any: - """[DEPRECATED] Try to load from the old Hub.""" + """[DEPRECATED] Try to load from the old Hub. + + Returns: + None always, indicating that we shouldn't load from the old hub. + """ warnings.warn( "Loading from the deprecated github-based Hub is no longer supported. " "Please use the new LangChain Hub at https://smith.langchain.com/hub instead.", diff --git a/libs/core/langchain_core/utils/mustache.py b/libs/core/langchain_core/utils/mustache.py index 12cab8da0a3..fd2ae359176 100644 --- a/libs/core/langchain_core/utils/mustache.py +++ b/libs/core/langchain_core/utils/mustache.py @@ -214,17 +214,22 @@ def tokenize( def_rdel: The default right delimiter ("}}" by default, as in spec compliant mustache) - Returns: - A generator of mustache tags in the form of a tuple (tag_type, tag_key) - Where tag_type is one of: - * literal - * section - * inverted section - * end - * partial - * no escape - And tag_key is either the key or in the case of a literal tag, - the literal itself. + Yields: + Mustache tags in the form of a tuple (tag_type, tag_key) + where tag_type is one of: + + * literal + * section + * inverted section + * end + * partial + * no escape + + and tag_key is either the key or in the case of a literal tag, + the literal itself. + + Raises: + ChevronError: If there is a syntax error in the template. """ global _CURRENT_LINE, _LAST_TAG_LINE _CURRENT_LINE = 1 @@ -326,7 +331,7 @@ def tokenize( def _html_escape(string: str) -> str: - """HTML escape all of these " & < >.""" + """Return the HTML-escaped string with these characters escaped: ``" & < >``.""" html_codes = { '"': """, "<": "<", @@ -349,7 +354,7 @@ def _get_key( def_ldel: str, def_rdel: str, ) -> Any: - """Get a key from the current scope.""" + """Return a key from the current scope.""" # If the key is a dot if key == ".": # Then just return the current scope @@ -407,7 +412,11 @@ def _get_key( def _get_partial(name: str, partials_dict: Mapping[str, str]) -> str: - """Load a partial.""" + """Load a partial. + + Returns: + The partial. + """ try: # Maybe the partial is in the dictionary return partials_dict[name] diff --git a/libs/core/langchain_core/utils/pydantic.py b/libs/core/langchain_core/utils/pydantic.py index 08cd7c4522f..272868032d3 100644 --- a/libs/core/langchain_core/utils/pydantic.py +++ b/libs/core/langchain_core/utils/pydantic.py @@ -57,6 +57,9 @@ def get_pydantic_major_version() -> int: """DEPRECATED - Get the major version of Pydantic. Use PYDANTIC_VERSION.major instead. + + Returns: + The major version of Pydantic. """ return PYDANTIC_VERSION.major @@ -74,12 +77,20 @@ TBaseModel = TypeVar("TBaseModel", bound=PydanticBaseModel) def is_pydantic_v1_subclass(cls: type) -> bool: - """Check if the installed Pydantic version is 1.x-like.""" + """Check if the given class is Pydantic v1-like. + + Returns: + True if the given class is a subclass of Pydantic ``BaseModel`` 1.x. + """ return issubclass(cls, BaseModelV1) def is_pydantic_v2_subclass(cls: type) -> bool: - """Check if the installed Pydantic version is 1.x-like.""" + """Check if the given class is Pydantic v2-like. + + Returns: + True if the given class is a subclass of Pydantic BaseModel 2.x. + """ return issubclass(cls, BaseModel) @@ -90,6 +101,9 @@ def is_basemodel_subclass(cls: type) -> bool: * pydantic.BaseModel in Pydantic 2.x * pydantic.v1.BaseModel in Pydantic 2.x + + Returns: + True if the given class is a subclass of Pydantic ``BaseModel``. """ # Before we can use issubclass on the cls we need to check if it is a class if not inspect.isclass(cls) or isinstance(cls, GenericAlias): @@ -105,6 +119,9 @@ def is_basemodel_instance(obj: Any) -> bool: * pydantic.BaseModel in Pydantic 2.x * pydantic.v1.BaseModel in Pydantic 2.x + + Returns: + True if the given class is an instance of Pydantic ``BaseModel``. """ return isinstance(obj, (BaseModel, BaseModelV1)) @@ -262,7 +279,11 @@ def _create_subset_model( descriptions: Optional[dict] = None, fn_description: Optional[str] = None, ) -> type[BaseModel]: - """Create subset model using the same pydantic version as the input model.""" + """Create subset model using the same pydantic version as the input model. + + Returns: + The created subset model. + """ if issubclass(model, BaseModelV1): return _create_subset_model_v1( name, @@ -299,7 +320,14 @@ def get_fields(model: BaseModelV1) -> dict[str, ModelField]: ... def get_fields( model: Union[type[Union[BaseModel, BaseModelV1]], BaseModel, BaseModelV1], ) -> Union[dict[str, FieldInfoV2], dict[str, ModelField]]: - """Get the field names of a Pydantic model.""" + """Return the field names of a Pydantic model. + + Args: + model: The Pydantic model or instance. + + Raises: + TypeError: If the model is not a Pydantic model. + """ if hasattr(model, "model_fields"): return model.model_fields diff --git a/libs/core/langchain_core/utils/utils.py b/libs/core/langchain_core/utils/utils.py index a7467ec51e9..1a41b63dc28 100644 --- a/libs/core/langchain_core/utils/utils.py +++ b/libs/core/langchain_core/utils/utils.py @@ -21,17 +21,14 @@ from langchain_core.utils.pydantic import ( def xor_args(*arg_groups: tuple[str, ...]) -> Callable: - """Validate specified keyword args are mutually exclusive.". + """Validate specified keyword args are mutually exclusive. Args: *arg_groups (tuple[str, ...]): Groups of mutually exclusive keyword args. Returns: Callable: Decorator that validates the specified keyword args - are mutually exclusive - - Raises: - ValueError: If more than one arg in a group is defined. + are mutually exclusive. """ def decorator(func: Callable) -> Callable: @@ -381,10 +378,21 @@ def from_env( error_message: the error message which will be raised if the key is not found and no default value is provided. This will be raised as a ValueError. + + Returns: + factory method that will look up the value from the environment. """ def get_from_env_fn() -> Optional[str]: - """Get a value from an environment variable.""" + """Get a value from an environment variable. + + Raises: + ValueError: If the environment variable is not set and no default is + provided. + + Returns: + The value from the environment. + """ if isinstance(key, (list, tuple)): for k in key: if k in os.environ: @@ -445,7 +453,15 @@ def secret_from_env( """ def get_secret_from_env() -> Optional[SecretStr]: - """Get a value from an environment variable.""" + """Get a value from an environment variable. + + Raises: + ValueError: If the environment variable is not set and no default is + provided. + + Returns: + The secret from the environment. + """ if isinstance(key, (list, tuple)): for k in key: if k in os.environ: diff --git a/libs/core/langchain_core/vectorstores/base.py b/libs/core/langchain_core/vectorstores/base.py index 17fa6592c72..2c4425c9c5a 100644 --- a/libs/core/langchain_core/vectorstores/base.py +++ b/libs/core/langchain_core/vectorstores/base.py @@ -270,9 +270,6 @@ class VectorStore(ABC): Returns: List of IDs of the added texts. - - Raises: - ValueError: If the number of ids does not match the number of documents. """ if type(self).add_texts != VectorStore.add_texts: if "ids" not in kwargs: @@ -303,9 +300,6 @@ class VectorStore(ABC): Returns: List of IDs of the added texts. - - Raises: - ValueError: If the number of IDs does not match the number of documents. """ # If the async method has been overridden, we'll use that. if type(self).aadd_texts != VectorStore.aadd_texts: diff --git a/libs/core/langchain_core/vectorstores/in_memory.py b/libs/core/langchain_core/vectorstores/in_memory.py index e7787f8a882..0395478dfe9 100644 --- a/libs/core/langchain_core/vectorstores/in_memory.py +++ b/libs/core/langchain_core/vectorstores/in_memory.py @@ -189,7 +189,6 @@ class InMemoryVectorStore(VectorStore): ids: Optional[list[str]] = None, **kwargs: Any, ) -> list[str]: - """Add documents to the store.""" texts = [doc.page_content for doc in documents] vectors = self.embedding.embed_documents(texts) @@ -223,7 +222,6 @@ class InMemoryVectorStore(VectorStore): async def aadd_documents( self, documents: list[Document], ids: Optional[list[str]] = None, **kwargs: Any ) -> list[str]: - """Add documents to the store.""" texts = [doc.page_content for doc in documents] vectors = await self.embedding.aembed_documents(texts)