diff --git a/libs/partners/ollama/Makefile b/libs/partners/ollama/Makefile index 97b63798e9d..9d78cf3cae6 100644 --- a/libs/partners/ollama/Makefile +++ b/libs/partners/ollama/Makefile @@ -41,13 +41,14 @@ lint_tests: PYTHON_FILES=tests lint_tests: MYPY_CACHE=.mypy_cache_test lint lint_diff lint_package lint_tests: - [ "$(PYTHON_FILES)" = "" ] || uv run --all-groups ruff $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || uv run --all-groups ruff check $(PYTHON_FILES) [ "$(PYTHON_FILES)" = "" ] || uv run --all-groups ruff format $(PYTHON_FILES) --diff [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && uv run --all-groups mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) format format_diff: [ "$(PYTHON_FILES)" = "" ] || uv run --all-groups ruff format $(PYTHON_FILES) - [ "$(PYTHON_FILES)" = "" ] || uv run --all-groups ruff --fix $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || uv run --all-groups ruff check --fix $(PYTHON_FILES) + spell_check: uv run --all-groups codespell --toml pyproject.toml diff --git a/libs/partners/ollama/langchain_ollama/__init__.py b/libs/partners/ollama/langchain_ollama/__init__.py index 5edbd2236be..51860755d7b 100644 --- a/libs/partners/ollama/langchain_ollama/__init__.py +++ b/libs/partners/ollama/langchain_ollama/__init__.py @@ -18,7 +18,7 @@ del metadata # optional, avoids polluting the results of dir(__package__) __all__ = [ "ChatOllama", - "OllamaLLM", "OllamaEmbeddings", + "OllamaLLM", "__version__", ] diff --git a/libs/partners/ollama/langchain_ollama/_utils.py b/libs/partners/ollama/langchain_ollama/_utils.py index 076a2cc164a..89eb25ee6b4 100644 --- a/libs/partners/ollama/langchain_ollama/_utils.py +++ b/libs/partners/ollama/langchain_ollama/_utils.py @@ -20,18 +20,21 @@ def validate_model(client: Client, model_name: str) -> None: if not any( model_name == m or m.startswith(f"{model_name}:") for m in model_names ): - raise ValueError( + msg = ( f"Model `{model_name}` not found in Ollama. Please pull the " f"model (using `ollama pull {model_name}`) or specify a valid " f"model name. Available local models: {', '.join(model_names)}" ) + raise ValueError(msg) except ConnectError as e: - raise ValueError( + msg = ( "Connection to Ollama failed. Please make sure Ollama is running " f"and accessible at {client._client.base_url}. " - ) from e + ) + raise ValueError(msg) from e except ResponseError as e: - raise ValueError( + msg = ( "Received an error from the Ollama API. " "Please check your Ollama server logs." - ) from e + ) + raise ValueError(msg) from e diff --git a/libs/partners/ollama/langchain_ollama/chat_models.py b/libs/partners/ollama/langchain_ollama/chat_models.py index 47ec78df011..cb2a1a9e84e 100644 --- a/libs/partners/ollama/langchain_ollama/chat_models.py +++ b/libs/partners/ollama/langchain_ollama/chat_models.py @@ -1,5 +1,7 @@ """Ollama chat models.""" +from __future__ import annotations + import json from collections.abc import AsyncIterator, Iterator, Mapping, Sequence from operator import itemgetter @@ -74,7 +76,9 @@ def _get_usage_metadata_from_generation_info( def _parse_json_string( - json_string: str, raw_tool_call: dict[str, Any], skip: bool + json_string: str, + raw_tool_call: dict[str, Any], + skip: bool, # noqa: FBT001 ) -> Any: """Attempt to parse a JSON string for tool calling. @@ -148,16 +152,19 @@ def _get_tool_calls_from_response( ) -> list[ToolCall]: """Get tool calls from ollama response.""" tool_calls = [] - if "message" in response: - if raw_tool_calls := response["message"].get("tool_calls"): - for tc in raw_tool_calls: - tool_calls.append( - tool_call( - id=str(uuid4()), - name=tc["function"]["name"], - args=_parse_arguments_from_tool_call(tc) or {}, - ) + if "message" in response and ( + raw_tool_calls := response["message"].get("tool_calls") + ): + tool_calls.extend( + [ + tool_call( + id=str(uuid4()), + name=tc["function"]["name"], + args=_parse_arguments_from_tool_call(tc) or {}, ) + for tc in raw_tool_calls + ] + ) return tool_calls @@ -178,14 +185,12 @@ def _get_image_from_data_content_block(block: dict) -> str: if block["type"] == "image": if block["source_type"] == "base64": return block["data"] - else: - error_message = "Image data only supported through in-line base64 format." - raise ValueError(error_message) - - else: - error_message = f"Blocks of type {block['type']} not supported." + error_message = "Image data only supported through in-line base64 format." raise ValueError(error_message) + error_message = f"Blocks of type {block['type']} not supported." + raise ValueError(error_message) + def _is_pydantic_class(obj: Any) -> bool: return isinstance(obj, type) and is_basemodel_subclass(obj) @@ -459,7 +464,7 @@ class ChatOllama(BaseChatModel): """Base url the model is hosted under.""" client_kwargs: Optional[dict] = {} - """Additional kwargs to pass to the httpx clients. + """Additional kwargs to pass to the httpx clients. These arguments are passed to both synchronous and async clients. Use sync_client_kwargs and async_client_kwargs to pass different arguments to synchronous and asynchronous clients. @@ -496,7 +501,8 @@ class ChatOllama(BaseChatModel): ollama_messages = self._convert_messages_to_ollama_messages(messages) if self.stop is not None and stop is not None: - raise ValueError("`stop` found in both the input and default params.") + msg = "`stop` found in both the input and default params." + raise ValueError(msg) if self.stop is not None: stop = self.stop @@ -584,7 +590,8 @@ class ChatOllama(BaseChatModel): role = "tool" tool_call_id = message.tool_call_id else: - raise ValueError("Received unsupported message type for Ollama.") + msg = "Received unsupported message type for Ollama." + raise ValueError(msg) content = "" images = [] @@ -608,10 +615,11 @@ class ChatOllama(BaseChatModel): ): image_url = temp_image_url["url"] else: - raise ValueError( + msg = ( "Only string image_url or dict with string 'url' " "inside content parts are supported." ) + raise ValueError(msg) image_url_components = image_url.split(",") # Support data:image/jpeg;base64, format @@ -624,22 +632,24 @@ class ChatOllama(BaseChatModel): image = _get_image_from_data_content_block(content_part) images.append(image) else: - raise ValueError( + msg = ( "Unsupported message content type. " "Must either have type 'text' or type 'image_url' " "with a string 'image_url' field." ) - # Should convert to ollama.Message once role includes tool, and tool_call_id is in Message # noqa: E501 - msg: dict = { + raise ValueError(msg) + # Should convert to ollama.Message once role includes tool, + # and tool_call_id is in Message + msg_: dict = { "role": role, "content": content, "images": images, } if tool_calls: - msg["tool_calls"] = tool_calls + msg_["tool_calls"] = tool_calls if tool_call_id: - msg["tool_call_id"] = tool_call_id - ollama_messages.append(msg) + msg_["tool_call_id"] = tool_call_id + ollama_messages.append(msg_) return ollama_messages @@ -677,7 +687,7 @@ class ChatOllama(BaseChatModel): messages: list[BaseMessage], stop: Optional[list[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, - verbose: bool = False, + verbose: bool = False, # noqa: FBT001, FBT002 **kwargs: Any, ) -> ChatGenerationChunk: final_chunk = None @@ -693,7 +703,8 @@ class ChatOllama(BaseChatModel): verbose=verbose, ) if final_chunk is None: - raise ValueError("No data received from Ollama stream.") + msg = "No data received from Ollama stream." + raise ValueError(msg) return final_chunk @@ -702,7 +713,7 @@ class ChatOllama(BaseChatModel): messages: list[BaseMessage], stop: Optional[list[str]] = None, run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - verbose: bool = False, + verbose: bool = False, # noqa: FBT001, FBT002 **kwargs: Any, ) -> ChatGenerationChunk: final_chunk = None @@ -718,7 +729,8 @@ class ChatOllama(BaseChatModel): verbose=verbose, ) if final_chunk is None: - raise ValueError("No data received from Ollama stream.") + msg = "No data received from Ollama stream." + raise ValueError(msg) return final_chunk @@ -908,7 +920,7 @@ class ChatOllama(BaseChatModel): self, tools: Sequence[Union[dict[str, Any], type, Callable, BaseTool]], *, - tool_choice: Optional[Union[dict, str, Literal["auto", "any"], bool]] = None, + tool_choice: Optional[Union[dict, str, Literal["auto", "any"], bool]] = None, # noqa: PYI051 **kwargs: Any, ) -> Runnable[LanguageModelInput, BaseMessage]: """Bind tool-like objects to this chat model. @@ -923,7 +935,7 @@ class ChatOllama(BaseChatModel): is currently ignored as it is not supported by Ollama.** kwargs: Any additional parameters are passed directly to ``self.bind(**kwargs)``. - """ # noqa: E501 + """ formatted_tools = [convert_to_openai_tool(tool) for tool in tools] return super().bind(tools=formatted_tools, **kwargs) @@ -1180,14 +1192,16 @@ class ChatOllama(BaseChatModel): """ # noqa: E501, D301 _ = kwargs.pop("strict", None) if kwargs: - raise ValueError(f"Received unsupported arguments {kwargs}") + msg = f"Received unsupported arguments {kwargs}" + raise ValueError(msg) is_pydantic_schema = _is_pydantic_class(schema) if method == "function_calling": if schema is None: - raise ValueError( + msg = ( "schema must be specified when method is not 'json_mode'. " "Received None." ) + raise ValueError(msg) formatted_tool = convert_to_openai_tool(schema) tool_name = formatted_tool["function"]["name"] llm = self.bind_tools( @@ -1222,10 +1236,11 @@ class ChatOllama(BaseChatModel): ) elif method == "json_schema": if schema is None: - raise ValueError( + msg = ( "schema must be specified when method is not 'json_mode'. " "Received None." ) + raise ValueError(msg) if is_pydantic_schema: schema = cast(TypeBaseModel, schema) if issubclass(schema, BaseModelV1): @@ -1259,10 +1274,11 @@ class ChatOllama(BaseChatModel): ) output_parser = JsonOutputParser() else: - raise ValueError( + msg = ( f"Unrecognized method argument. Expected one of 'function_calling', " f"'json_schema', or 'json_mode'. Received: '{method}'" ) + raise ValueError(msg) if include_raw: parser_assign = RunnablePassthrough.assign( diff --git a/libs/partners/ollama/langchain_ollama/embeddings.py b/libs/partners/ollama/langchain_ollama/embeddings.py index 7e589bd291b..cfc9d174471 100644 --- a/libs/partners/ollama/langchain_ollama/embeddings.py +++ b/libs/partners/ollama/langchain_ollama/embeddings.py @@ -1,5 +1,7 @@ """Ollama embeddings models.""" +from __future__ import annotations + from typing import Any, Optional from langchain_core.embeddings import Embeddings @@ -132,7 +134,7 @@ class OllamaEmbeddings(BaseModel, Embeddings): """Base url the model is hosted under.""" client_kwargs: Optional[dict] = {} - """Additional kwargs to pass to the httpx clients. + """Additional kwargs to pass to the httpx clients. These arguments are passed to both synchronous and async clients. Use sync_client_kwargs and async_client_kwargs to pass different arguments to synchronous and asynchronous clients. @@ -271,14 +273,14 @@ class OllamaEmbeddings(BaseModel, Embeddings): def embed_documents(self, texts: list[str]) -> list[list[float]]: """Embed search docs.""" if not self._client: - raise ValueError( + msg = ( "Ollama client is not initialized. " "Please ensure Ollama is running and the model is loaded." ) - embedded_docs = self._client.embed( + raise ValueError(msg) + return self._client.embed( self.model, texts, options=self._default_params, keep_alive=self.keep_alive )["embeddings"] - return embedded_docs def embed_query(self, text: str) -> list[float]: """Embed query text.""" @@ -287,16 +289,16 @@ class OllamaEmbeddings(BaseModel, Embeddings): async def aembed_documents(self, texts: list[str]) -> list[list[float]]: """Embed search docs.""" if not self._async_client: - raise ValueError( + msg = ( "Ollama client is not initialized. " "Please ensure Ollama is running and the model is loaded." ) - embedded_docs = ( + raise ValueError(msg) + return ( await self._async_client.embed( self.model, texts, keep_alive=self.keep_alive ) )["embeddings"] - return embedded_docs async def aembed_query(self, text: str) -> list[float]: """Embed query text.""" diff --git a/libs/partners/ollama/langchain_ollama/llms.py b/libs/partners/ollama/langchain_ollama/llms.py index f488ea73d1a..8e17061103e 100644 --- a/libs/partners/ollama/langchain_ollama/llms.py +++ b/libs/partners/ollama/langchain_ollama/llms.py @@ -1,5 +1,7 @@ """Ollama large language models.""" +from __future__ import annotations + from collections.abc import AsyncIterator, Iterator, Mapping from typing import ( Any, @@ -132,22 +134,22 @@ class OllamaLLM(BaseLLM): """Base url the model is hosted under.""" client_kwargs: Optional[dict] = {} - """Additional kwargs to pass to the httpx clients. + """Additional kwargs to pass to the httpx clients. These arguments are passed to both synchronous and async clients. Use sync_client_kwargs and async_client_kwargs to pass different arguments to synchronous and asynchronous clients. """ async_client_kwargs: Optional[dict] = {} - """Additional kwargs to merge with client_kwargs before passing to the HTTPX + """Additional kwargs to merge with client_kwargs before passing to the HTTPX AsyncClient. - + For a full list of the params, see the `HTTPX documentation `__. """ sync_client_kwargs: Optional[dict] = {} """Additional kwargs to merge with client_kwargs before passing to the HTTPX Client. - + For a full list of the params, see the `HTTPX documentation `__. """ @@ -168,7 +170,8 @@ class OllamaLLM(BaseLLM): **kwargs: Any, ) -> dict[str, Any]: if self.stop is not None and stop is not None: - raise ValueError("`stop` found in both the input and default params.") + msg = "`stop` found in both the input and default params." + raise ValueError(msg) if self.stop is not None: stop = self.stop @@ -193,7 +196,7 @@ class OllamaLLM(BaseLLM): }, ) - params = { + return { "prompt": prompt, "stream": kwargs.pop("stream", True), "model": kwargs.pop("model", self.model), @@ -204,8 +207,6 @@ class OllamaLLM(BaseLLM): **kwargs, } - return params - @property def _llm_type(self) -> str: """Return type of LLM.""" @@ -267,14 +268,14 @@ class OllamaLLM(BaseLLM): prompt: str, stop: Optional[list[str]] = None, run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - verbose: bool = False, + verbose: bool = False, # noqa: FBT001, FBT002 **kwargs: Any, ) -> GenerationChunk: final_chunk = None async for stream_resp in self._acreate_generate_stream(prompt, stop, **kwargs): if not isinstance(stream_resp, str): chunk = GenerationChunk( - text=stream_resp["response"] if "response" in stream_resp else "", + text=stream_resp.get("response", ""), generation_info=( dict(stream_resp) if stream_resp.get("done") is True else None ), @@ -290,7 +291,8 @@ class OllamaLLM(BaseLLM): verbose=verbose, ) if final_chunk is None: - raise ValueError("No data received from Ollama stream.") + msg = "No data received from Ollama stream." + raise ValueError(msg) return final_chunk @@ -299,14 +301,14 @@ class OllamaLLM(BaseLLM): prompt: str, stop: Optional[list[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, - verbose: bool = False, + verbose: bool = False, # noqa: FBT001, FBT002 **kwargs: Any, ) -> GenerationChunk: final_chunk = None for stream_resp in self._create_generate_stream(prompt, stop, **kwargs): if not isinstance(stream_resp, str): chunk = GenerationChunk( - text=stream_resp["response"] if "response" in stream_resp else "", + text=stream_resp.get("response", ""), generation_info=( dict(stream_resp) if stream_resp.get("done") is True else None ), @@ -322,7 +324,8 @@ class OllamaLLM(BaseLLM): verbose=verbose, ) if final_chunk is None: - raise ValueError("No data received from Ollama stream.") + msg = "No data received from Ollama stream." + raise ValueError(msg) return final_chunk diff --git a/libs/partners/ollama/pyproject.toml b/libs/partners/ollama/pyproject.toml index 7be57841516..f801b420260 100644 --- a/libs/partners/ollama/pyproject.toml +++ b/libs/partners/ollama/pyproject.toml @@ -48,15 +48,62 @@ target-version = "py39" [tool.ruff.lint] select = [ - "E", # pycodestyle - "F", # pyflakes - "I", # isort - "T201", # print - "D", # pydocstyle - "UP", # pyupgrade - "S", # flake8-bandit + "A", # flake8-builtins + "B", # flake8-bugbear + "ASYNC", # flake8-async + "C4", # flake8-comprehensions + "COM", # flake8-commas + "D", # pydocstyle + "DOC", # pydoclint + "E", # pycodestyle error + "EM", # flake8-errmsg + "F", # pyflakes + "FA", # flake8-future-annotations + "FBT", # flake8-boolean-trap + "FLY", # flake8-flynt + "I", # isort + "ICN", # flake8-import-conventions + "INT", # flake8-gettext + "ISC", # isort-comprehensions + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PERF", # flake8-perf + "PYI", # flake8-pyi + "Q", # flake8-quotes + "RET", # flake8-return + "RSE", # flake8-rst-docstrings + "RUF", # ruff + "S", # flake8-bandit + "SLF", # flake8-self + "SLOT", # flake8-slots + "SIM", # flake8-simplify + "T10", # flake8-debugger + "T20", # flake8-print + "TID", # flake8-tidy-imports + "UP", # pyupgrade + "W", # pycodestyle warning + "YTT", # flake8-2020 ] -ignore = [ "UP007", ] +ignore = [ + "D100", # pydocstyle: Missing docstring in public module + "D101", # pydocstyle: Missing docstring in public class + "D102", # pydocstyle: Missing docstring in public method + "D103", # pydocstyle: Missing docstring in public function + "D104", # pydocstyle: Missing docstring in public package + "D105", # pydocstyle: Missing docstring in magic method + "D107", # pydocstyle: Missing docstring in __init__ + "D203", # Messes with the formatter + "D407", # pydocstyle: Missing-dashed-underline-after-section + "COM812", # Messes with the formatter + "ISC001", # Messes with the formatter + "PERF203", # Rarely useful + "S112", # Rarely useful + "RUF012", # Doesn't play well with Pydantic + "SLF001", # Private member access + "UP007", # pyupgrade: non-pep604-annotation-union + "UP045", # pyupgrade: non-pep604-annotation-optional +] +unfixable = ["B028"] # People should intentionally tune the stacklevel [tool.ruff.lint.pydocstyle] convention = "google" diff --git a/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models.py b/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models.py index 06f8cf3a035..c24a75297f1 100644 --- a/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models.py +++ b/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models.py @@ -1,5 +1,7 @@ """Ollama specific chat model integration tests""" +from __future__ import annotations + from typing import Annotated, Optional import pytest diff --git a/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models_standard.py b/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models_standard.py index c8500683178..d596011bfb4 100644 --- a/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models_standard.py +++ b/libs/partners/ollama/tests/integration_tests/chat_models/test_chat_models_standard.py @@ -21,8 +21,7 @@ def get_current_weather(location: str) -> dict: """Gets the current weather in a given location.""" if "boston" in location.lower(): return {"temperature": "15°F", "conditions": "snow"} - else: - return {"temperature": "unknown", "conditions": "unknown"} + return {"temperature": "unknown", "conditions": "unknown"} class TestChatOllama(ChatModelIntegrationTests): @@ -65,16 +64,15 @@ class TestChatOllama(ChatModelIntegrationTests): if chunk.tool_call_chunks: tool_chunk_found = True - for tc_chunk in chunk.tool_call_chunks: - collected_tool_chunks.append(tc_chunk) + collected_tool_chunks.extend(chunk.tool_call_chunks) if chunk.tool_calls: final_tool_calls.extend(chunk.tool_calls) assert tool_chunk_found, "Tool streaming did not produce any tool_call_chunks." - assert ( - len(final_tool_calls) == 1 - ), f"Expected 1 final tool call, but got {len(final_tool_calls)}" + assert len(final_tool_calls) == 1, ( + f"Expected 1 final tool call, but got {len(final_tool_calls)}" + ) final_tool_call = final_tool_calls[0] assert final_tool_call["name"] == "get_current_weather" @@ -110,16 +108,15 @@ class TestChatOllama(ChatModelIntegrationTests): if chunk.tool_call_chunks: tool_chunk_found = True - for tc_chunk in chunk.tool_call_chunks: - collected_tool_chunks.append(tc_chunk) + collected_tool_chunks.extend(chunk.tool_call_chunks) if chunk.tool_calls: final_tool_calls.extend(chunk.tool_calls) assert tool_chunk_found, "Tool streaming did not produce any tool_call_chunks." - assert ( - len(final_tool_calls) == 1 - ), f"Expected 1 final tool call, but got {len(final_tool_calls)}" + assert len(final_tool_calls) == 1, ( + f"Expected 1 final tool call, but got {len(final_tool_calls)}" + ) final_tool_call = final_tool_calls[0] assert final_tool_call["name"] == "get_current_weather" diff --git a/libs/partners/ollama/tests/integration_tests/test_compile.py b/libs/partners/ollama/tests/integration_tests/test_compile.py index 33ecccdfa0f..f315e45f521 100644 --- a/libs/partners/ollama/tests/integration_tests/test_compile.py +++ b/libs/partners/ollama/tests/integration_tests/test_compile.py @@ -4,4 +4,3 @@ import pytest @pytest.mark.compile def test_placeholder() -> None: """Used for compiling integration tests without running any real tests.""" - pass diff --git a/libs/partners/ollama/uv.lock b/libs/partners/ollama/uv.lock index ff4d4009e0f..a7a0555f325 100644 --- a/libs/partners/ollama/uv.lock +++ b/libs/partners/ollama/uv.lock @@ -305,7 +305,7 @@ wheels = [ [[package]] name = "langchain-core" -version = "0.3.66" +version = "0.3.68" source = { editable = "../../core" } dependencies = [ { name = "jsonpatch" }, @@ -334,7 +334,7 @@ dev = [ { name = "jupyter", specifier = ">=1.0.0,<2.0.0" }, { name = "setuptools", specifier = ">=67.6.1,<68.0.0" }, ] -lint = [{ name = "ruff", specifier = ">=0.11.2,<0.12.0" }] +lint = [{ name = "ruff", specifier = ">=0.12.2,<0.13" }] test = [ { name = "blockbuster", specifier = "~=1.5.18" }, { name = "freezegun", specifier = ">=1.2.2,<2.0.0" }, @@ -403,7 +403,7 @@ requires-dist = [ [package.metadata.requires-dev] codespell = [{ name = "codespell", specifier = ">=2.2.6,<3.0.0" }] dev = [{ name = "langchain-core", editable = "../../core" }] -lint = [{ name = "ruff", specifier = ">=0.1.8,<1.0.0" }] +lint = [{ name = "ruff", specifier = ">=0.12.2,<0.13" }] test = [ { name = "langchain-core", editable = "../../core" }, { name = "langchain-tests", editable = "../../standard-tests" }, @@ -456,7 +456,7 @@ requires-dist = [ [package.metadata.requires-dev] codespell = [{ name = "codespell", specifier = ">=2.2.0,<3.0.0" }] -lint = [{ name = "ruff", specifier = ">=0.9.2,<1.0.0" }] +lint = [{ name = "ruff", specifier = ">=0.12.2,<0.13" }] test = [{ name = "langchain-core", editable = "../../core" }] test-integration = [] typing = [ @@ -1342,26 +1342,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.1.15" +version = "0.12.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/33/7165f88a156be1c2fd13a18b3af6e75bbf82da5b6978cd2128d666accc18/ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e", size = 1971643, upload-time = "2024-01-29T23:06:05.541Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/3d/d9a195676f25d00dbfcf3cf95fdd4c685c497fcfa7e862a44ac5e4e96480/ruff-0.12.2.tar.gz", hash = "sha256:d7b4f55cd6f325cb7621244f19c873c565a08aff5a4ba9c69aa7355f3f7afd3e", size = 4432239, upload-time = "2025-07-03T16:40:19.566Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/2c/fac0658910ea3ea87a23583e58277533154261b73f9460388eb2e6e02e8f/ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df", size = 14357437, upload-time = "2024-01-29T23:05:04.991Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c1/2116927385c761ffb786dfb77654a634ecd7803dee4de3b47b59536374f1/ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f", size = 7329669, upload-time = "2024-01-29T23:05:12.437Z" }, - { url = "https://files.pythonhosted.org/packages/18/d7/2199ecb42cef4d70de0e72ce4ca8878d060e25fe4434cb66f51e26158a2a/ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8", size = 7137343, upload-time = "2024-01-29T23:05:16.159Z" }, - { url = "https://files.pythonhosted.org/packages/bb/e0/8a6f9db2c5b8c7108c7e7347cd6beca805d1b2ae618569c72f2515d11e52/ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807", size = 6563223, upload-time = "2024-01-29T23:05:19.687Z" }, - { url = "https://files.pythonhosted.org/packages/98/fa/2a627747a5a5f7e1d3447704f795fd35d486460838485762cd569ef8eb0e/ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec", size = 7534853, upload-time = "2024-01-29T23:05:23.18Z" }, - { url = "https://files.pythonhosted.org/packages/55/09/c09d0f9b41d1f5e3de117579f2fcdb7063fd76cd92d6614eae1b77ccbccb/ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5", size = 8168826, upload-time = "2024-01-29T23:05:26.544Z" }, - { url = "https://files.pythonhosted.org/packages/72/48/c9dfc2c87dc6b92446d8092c2be25b42ca4fb201cecb2499996ccf483c34/ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e", size = 7942963, upload-time = "2024-01-29T23:05:30.655Z" }, - { url = "https://files.pythonhosted.org/packages/0c/57/dbc885f94450335fcff82301c4b25cf614894e79d9afbd249714e709ab42/ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b", size = 8524998, upload-time = "2024-01-29T23:05:34.503Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/8dea2fc156ae525971fdada8723f78e605dcf89428f5686728438b12f9ef/ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1", size = 7534144, upload-time = "2024-01-29T23:05:38.642Z" }, - { url = "https://files.pythonhosted.org/packages/47/41/96b770475c46590bfd051ca0c5f797b2d45f2638c45f3a9daf1ae55b96d6/ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5", size = 7055002, upload-time = "2024-01-29T23:05:41.955Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ca/4066dbcc3631a4efe1fe695f42f20aca50474d760b3bd8e57d7565d75aa5/ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2", size = 6552130, upload-time = "2024-01-29T23:05:45.487Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/da93f0fc8f2424cf776fcce6daef9291162345179d16faf1401ff2890068/ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852", size = 7214386, upload-time = "2024-01-29T23:05:48.346Z" }, - { url = "https://files.pythonhosted.org/packages/e5/bf/de34ad339e0d1f6faa858cbcf793f3abc168b7aa516dd9227d843b992be8/ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447", size = 7602787, upload-time = "2024-01-29T23:05:51.341Z" }, - { url = "https://files.pythonhosted.org/packages/8d/61/ffdccecb0b39521d7060d6a6bc33c53d7f20d48d3511d6333cb01f26e979/ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f", size = 6670488, upload-time = "2024-01-29T23:05:54.454Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5f/3ba51cc770ed2b2df88efc32bba26759e6ac5c6149319a60913a85230936/ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587", size = 7319395, upload-time = "2024-01-29T23:05:58.135Z" }, - { url = "https://files.pythonhosted.org/packages/c9/bd/c196493563d6bf8fe960f10b83926a3fae3a43a96eac6b263aecb96c61d7/ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360", size = 6998592, upload-time = "2024-01-29T23:06:01.904Z" }, + { url = "https://files.pythonhosted.org/packages/74/b6/2098d0126d2d3318fd5bec3ad40d06c25d377d95749f7a0c5af17129b3b1/ruff-0.12.2-py3-none-linux_armv6l.whl", hash = "sha256:093ea2b221df1d2b8e7ad92fc6ffdca40a2cb10d8564477a987b44fd4008a7be", size = 10369761, upload-time = "2025-07-03T16:39:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/b1/4b/5da0142033dbe155dc598cfb99262d8ee2449d76920ea92c4eeb9547c208/ruff-0.12.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:09e4cf27cc10f96b1708100fa851e0daf21767e9709e1649175355280e0d950e", size = 11155659, upload-time = "2025-07-03T16:39:42.294Z" }, + { url = "https://files.pythonhosted.org/packages/3e/21/967b82550a503d7c5c5c127d11c935344b35e8c521f52915fc858fb3e473/ruff-0.12.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8ae64755b22f4ff85e9c52d1f82644abd0b6b6b6deedceb74bd71f35c24044cc", size = 10537769, upload-time = "2025-07-03T16:39:44.75Z" }, + { url = "https://files.pythonhosted.org/packages/33/91/00cff7102e2ec71a4890fb7ba1803f2cdb122d82787c7d7cf8041fe8cbc1/ruff-0.12.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eb3a6b2db4d6e2c77e682f0b988d4d61aff06860158fdb413118ca133d57922", size = 10717602, upload-time = "2025-07-03T16:39:47.652Z" }, + { url = "https://files.pythonhosted.org/packages/9b/eb/928814daec4e1ba9115858adcda44a637fb9010618721937491e4e2283b8/ruff-0.12.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:73448de992d05517170fc37169cbca857dfeaeaa8c2b9be494d7bcb0d36c8f4b", size = 10198772, upload-time = "2025-07-03T16:39:49.641Z" }, + { url = "https://files.pythonhosted.org/packages/50/fa/f15089bc20c40f4f72334f9145dde55ab2b680e51afb3b55422effbf2fb6/ruff-0.12.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b8b94317cbc2ae4a2771af641739f933934b03555e51515e6e021c64441532d", size = 11845173, upload-time = "2025-07-03T16:39:52.069Z" }, + { url = "https://files.pythonhosted.org/packages/43/9f/1f6f98f39f2b9302acc161a4a2187b1e3a97634fe918a8e731e591841cf4/ruff-0.12.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45fc42c3bf1d30d2008023a0a9a0cfb06bf9835b147f11fe0679f21ae86d34b1", size = 12553002, upload-time = "2025-07-03T16:39:54.551Z" }, + { url = "https://files.pythonhosted.org/packages/d8/70/08991ac46e38ddd231c8f4fd05ef189b1b94be8883e8c0c146a025c20a19/ruff-0.12.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce48f675c394c37e958bf229fb5c1e843e20945a6d962cf3ea20b7a107dcd9f4", size = 12171330, upload-time = "2025-07-03T16:39:57.55Z" }, + { url = "https://files.pythonhosted.org/packages/88/a9/5a55266fec474acfd0a1c73285f19dd22461d95a538f29bba02edd07a5d9/ruff-0.12.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793d8859445ea47591272021a81391350205a4af65a9392401f418a95dfb75c9", size = 11774717, upload-time = "2025-07-03T16:39:59.78Z" }, + { url = "https://files.pythonhosted.org/packages/87/e5/0c270e458fc73c46c0d0f7cf970bb14786e5fdb88c87b5e423a4bd65232b/ruff-0.12.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6932323db80484dda89153da3d8e58164d01d6da86857c79f1961934354992da", size = 11646659, upload-time = "2025-07-03T16:40:01.934Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b6/45ab96070c9752af37f0be364d849ed70e9ccede07675b0ec4e3ef76b63b/ruff-0.12.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6aa7e623a3a11538108f61e859ebf016c4f14a7e6e4eba1980190cacb57714ce", size = 10604012, upload-time = "2025-07-03T16:40:04.363Z" }, + { url = "https://files.pythonhosted.org/packages/86/91/26a6e6a424eb147cc7627eebae095cfa0b4b337a7c1c413c447c9ebb72fd/ruff-0.12.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2a4a20aeed74671b2def096bdf2eac610c7d8ffcbf4fb0e627c06947a1d7078d", size = 10176799, upload-time = "2025-07-03T16:40:06.514Z" }, + { url = "https://files.pythonhosted.org/packages/f5/0c/9f344583465a61c8918a7cda604226e77b2c548daf8ef7c2bfccf2b37200/ruff-0.12.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:71a4c550195612f486c9d1f2b045a600aeba851b298c667807ae933478fcef04", size = 11241507, upload-time = "2025-07-03T16:40:08.708Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b7/99c34ded8fb5f86c0280278fa89a0066c3760edc326e935ce0b1550d315d/ruff-0.12.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4987b8f4ceadf597c927beee65a5eaf994c6e2b631df963f86d8ad1bdea99342", size = 11717609, upload-time = "2025-07-03T16:40:10.836Z" }, + { url = "https://files.pythonhosted.org/packages/51/de/8589fa724590faa057e5a6d171e7f2f6cffe3287406ef40e49c682c07d89/ruff-0.12.2-py3-none-win32.whl", hash = "sha256:369ffb69b70cd55b6c3fc453b9492d98aed98062db9fec828cdfd069555f5f1a", size = 10523823, upload-time = "2025-07-03T16:40:13.203Z" }, + { url = "https://files.pythonhosted.org/packages/94/47/8abf129102ae4c90cba0c2199a1a9b0fa896f6f806238d6f8c14448cc748/ruff-0.12.2-py3-none-win_amd64.whl", hash = "sha256:dca8a3b6d6dc9810ed8f328d406516bf4d660c00caeaef36eb831cf4871b0639", size = 11629831, upload-time = "2025-07-03T16:40:15.478Z" }, + { url = "https://files.pythonhosted.org/packages/e2/1f/72d2946e3cc7456bb837e88000eb3437e55f80db339c840c04015a11115d/ruff-0.12.2-py3-none-win_arm64.whl", hash = "sha256:48d6c6bfb4761df68bc05ae630e24f506755e702d4fb08f08460be778c7ccb12", size = 10735334, upload-time = "2025-07-03T16:40:17.677Z" }, ] [[package]]