From 321ca5b8d736e160e2af63d7ab1fca3e599d7543 Mon Sep 17 00:00:00 2001 From: Jib Date: Thu, 15 Feb 2024 14:30:29 -0500 Subject: [PATCH 01/22] MongoDB Partner Package -- first pass --- libs/partners/mongodb-atlas/.gitignore | 1 + libs/partners/mongodb-atlas/LICENSE | 21 + libs/partners/mongodb-atlas/Makefile | 59 ++ libs/partners/mongodb-atlas/README.md | 1 + libs/partners/mongodb-atlas/docs/chat.ipynb | 97 +++ libs/partners/mongodb-atlas/docs/llms.ipynb | 102 +++ .../mongodb-atlas/docs/provider.ipynb | 50 ++ .../mongodb-atlas/docs/text_embedding.ipynb | 132 +++ .../mongodb-atlas/docs/vectorstores.ipynb | 87 ++ .../langchain_mongodb_atlas/__init__.py | 8 + .../langchain_mongodb_atlas/py.typed | 0 .../langchain_mongodb_atlas/vectorstores.py | 461 ++++++++++ libs/partners/mongodb-atlas/poetry.lock | 815 ++++++++++++++++++ libs/partners/mongodb-atlas/pyproject.toml | 93 ++ .../mongodb-atlas/scripts/check_imports.py | 17 + .../mongodb-atlas/scripts/check_pydantic.sh | 27 + .../mongodb-atlas/scripts/lint_imports.sh | 17 + libs/partners/mongodb-atlas/tests/__init__.py | 0 .../tests/integration_tests/__init__.py | 0 .../integration_tests/test_vectorstores.py | 150 ++++ .../tests/unit_tests/__init__.py | 0 .../tests/unit_tests/test_imports.py | 10 + .../tests/unit_tests/test_vectorstores.py | 6 + 23 files changed, 2154 insertions(+) create mode 100644 libs/partners/mongodb-atlas/.gitignore create mode 100644 libs/partners/mongodb-atlas/LICENSE create mode 100644 libs/partners/mongodb-atlas/Makefile create mode 100644 libs/partners/mongodb-atlas/README.md create mode 100644 libs/partners/mongodb-atlas/docs/chat.ipynb create mode 100644 libs/partners/mongodb-atlas/docs/llms.ipynb create mode 100644 libs/partners/mongodb-atlas/docs/provider.ipynb create mode 100644 libs/partners/mongodb-atlas/docs/text_embedding.ipynb create mode 100644 libs/partners/mongodb-atlas/docs/vectorstores.ipynb create mode 100644 libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py create mode 100644 libs/partners/mongodb-atlas/langchain_mongodb_atlas/py.typed create mode 100644 libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py create mode 100644 libs/partners/mongodb-atlas/poetry.lock create mode 100644 libs/partners/mongodb-atlas/pyproject.toml create mode 100644 libs/partners/mongodb-atlas/scripts/check_imports.py create mode 100755 libs/partners/mongodb-atlas/scripts/check_pydantic.sh create mode 100755 libs/partners/mongodb-atlas/scripts/lint_imports.sh create mode 100644 libs/partners/mongodb-atlas/tests/__init__.py create mode 100644 libs/partners/mongodb-atlas/tests/integration_tests/__init__.py create mode 100644 libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py create mode 100644 libs/partners/mongodb-atlas/tests/unit_tests/__init__.py create mode 100644 libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py create mode 100644 libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py diff --git a/libs/partners/mongodb-atlas/.gitignore b/libs/partners/mongodb-atlas/.gitignore new file mode 100644 index 00000000000000..bee8a64b79a995 --- /dev/null +++ b/libs/partners/mongodb-atlas/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/libs/partners/mongodb-atlas/LICENSE b/libs/partners/mongodb-atlas/LICENSE new file mode 100644 index 00000000000000..426b65090341f3 --- /dev/null +++ b/libs/partners/mongodb-atlas/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 LangChain, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/partners/mongodb-atlas/Makefile b/libs/partners/mongodb-atlas/Makefile new file mode 100644 index 00000000000000..50f03891b363ab --- /dev/null +++ b/libs/partners/mongodb-atlas/Makefile @@ -0,0 +1,59 @@ +.PHONY: all format lint test tests integration_tests docker_tests help extended_tests + +# Default target executed when no arguments are given to make. +all: help + +# Define a variable for the test file path. +TEST_FILE ?= tests/unit_tests/ + +test: + poetry run pytest $(TEST_FILE) + +tests: + poetry run pytest $(TEST_FILE) + + +###################### +# LINTING AND FORMATTING +###################### + +# Define a variable for Python and notebook files. +PYTHON_FILES=. +MYPY_CACHE=.mypy_cache +lint format: PYTHON_FILES=. +lint_diff format_diff: PYTHON_FILES=$(shell git diff --relative=libs/partners/mongodb-atlas --name-only --diff-filter=d master | grep -E '\.py$$|\.ipynb$$') +lint_package: PYTHON_FILES=langchain_mongodb_atlas +lint_tests: PYTHON_FILES=tests +lint_tests: MYPY_CACHE=.mypy_cache_test + +lint lint_diff lint_package lint_tests: + poetry run ruff . + poetry run ruff format $(PYTHON_FILES) --diff + poetry run ruff --select I $(PYTHON_FILES) + mkdir $(MYPY_CACHE); poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) + +format format_diff: + poetry run ruff format $(PYTHON_FILES) + poetry run ruff --select I --fix $(PYTHON_FILES) + +spell_check: + poetry run codespell --toml pyproject.toml + +spell_fix: + poetry run codespell --toml pyproject.toml -w + +check_imports: $(shell find langchain_mongodb_atlas -name '*.py') + poetry run python ./scripts/check_imports.py $^ + +###################### +# HELP +###################### + +help: + @echo '----' + @echo 'check_imports - check imports' + @echo 'format - run code formatters' + @echo 'lint - run linters' + @echo 'test - run unit tests' + @echo 'tests - run unit tests' + @echo 'test TEST_FILE= - run all tests in file' diff --git a/libs/partners/mongodb-atlas/README.md b/libs/partners/mongodb-atlas/README.md new file mode 100644 index 00000000000000..1090f6f0b4bd5c --- /dev/null +++ b/libs/partners/mongodb-atlas/README.md @@ -0,0 +1 @@ +# langchain-mongodb-atlas diff --git a/libs/partners/mongodb-atlas/docs/chat.ipynb b/libs/partners/mongodb-atlas/docs/chat.ipynb new file mode 100644 index 00000000000000..6d600004a27ff0 --- /dev/null +++ b/libs/partners/mongodb-atlas/docs/chat.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "afaf8039", + "metadata": {}, + "source": [ + "---\n", + "sidebar_label: MongoDBAtlas\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "e49f1e0d", + "metadata": {}, + "source": [ + "# ChatMongoDBAtlas\n", + "\n", + "This notebook covers how to get started with MongoDBAtlas chat models.\n", + "\n", + "## Installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c3bef91", + "metadata": {}, + "outputs": [], + "source": [ + "# install package\n", + "!pip install -U langchain-mongodb-atlas" + ] + }, + { + "cell_type": "markdown", + "id": "2b4f3e15", + "metadata": {}, + "source": [ + "## Environment Setup\n", + "\n", + "Make sure to set the following environment variables:\n", + "\n", + "- TODO: fill out relevant environment variables or secrets\n", + "\n", + "## Usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62e0dbc3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from langchain_mongodb_atlas.chat_models import ChatMongoDBAtlas\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "\n", + "chat = ChatMongoDBAtlas()\n", + "\n", + "prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\"system\", \"You are a helpful assistant that translates English to French.\"),\n", + " (\"human\", \"Translate this sentence from English to French. {english_text}.\"),\n", + " ]\n", + ")\n", + "\n", + "chain = prompt | chat\n", + "chain.invoke({\"english_text\": \"Hello, how are you?\"})" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/libs/partners/mongodb-atlas/docs/llms.ipynb b/libs/partners/mongodb-atlas/docs/llms.ipynb new file mode 100644 index 00000000000000..62a9c76eb2d38d --- /dev/null +++ b/libs/partners/mongodb-atlas/docs/llms.ipynb @@ -0,0 +1,102 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "67db2992", + "metadata": {}, + "source": [ + "---\n", + "sidebar_label: MongoDBAtlas\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "9597802c", + "metadata": {}, + "source": [ + "# MongoDBAtlasLLM\n", + "\n", + "This example goes over how to use LangChain to interact with `MongoDBAtlas` models.\n", + "\n", + "## Installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59c710c4", + "metadata": {}, + "outputs": [], + "source": [ + "# install package\n", + "!pip install -U langchain-mongodb-atlas" + ] + }, + { + "cell_type": "markdown", + "id": "0ee90032", + "metadata": {}, + "source": [ + "## Environment Setup\n", + "\n", + "Make sure to set the following environment variables:\n", + "\n", + "- TODO: fill out relevant environment variables or secrets\n", + "\n", + "## Usage" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "035dea0f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from langchain_core.prompts import PromptTemplate\n", + "from langchain_mongodb_atlas.llms import MongoDBAtlasLLM\n", + "\n", + "template = \"\"\"Question: {question}\n", + "\n", + "Answer: Let's think step by step.\"\"\"\n", + "\n", + "prompt = PromptTemplate.from_string(template)\n", + "\n", + "model = MongoDBAtlasLLM()\n", + "\n", + "chain = prompt | model\n", + "\n", + "chain.invoke({\"question\": \"What is LangChain?\"})" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.11.1 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + }, + "vscode": { + "interpreter": { + "hash": "e971737741ff4ec9aff7dc6155a1060a59a8a6d52c757dbbe66bf8ee389494b1" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/libs/partners/mongodb-atlas/docs/provider.ipynb b/libs/partners/mongodb-atlas/docs/provider.ipynb new file mode 100644 index 00000000000000..a47868d2793fe6 --- /dev/null +++ b/libs/partners/mongodb-atlas/docs/provider.ipynb @@ -0,0 +1,50 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MongoDBAtlas\n", + "\n", + "MongoDBAtlas is a platform that offers..." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "y8ku6X96sebl" + }, + "outputs": [], + "source": [ + "from langchain_mongodb_atlas.chat_models import MongoDBAtlasChat\n", + "from langchain_mongodb_atlas.llms import MongoDBAtlasLLM\n", + "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/libs/partners/mongodb-atlas/docs/text_embedding.ipynb b/libs/partners/mongodb-atlas/docs/text_embedding.ipynb new file mode 100644 index 00000000000000..83557caaa0e049 --- /dev/null +++ b/libs/partners/mongodb-atlas/docs/text_embedding.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "afaf8039", + "metadata": {}, + "source": [ + "---\n", + "sidebar_label: MongoDBAtlas\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "e49f1e0d", + "metadata": {}, + "source": [ + "# MongoDBAtlasEmbeddings\n", + "\n", + "This notebook covers how to get started with MongoDBAtlas embedding models.\n", + "\n", + "## Installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c3bef91", + "metadata": {}, + "outputs": [], + "source": [ + "# install package\n", + "!pip install -U langchain-mongodb-atlas" + ] + }, + { + "cell_type": "markdown", + "id": "2b4f3e15", + "metadata": {}, + "source": [ + "## Environment Setup\n", + "\n", + "Make sure to set the following environment variables:\n", + "\n", + "- TODO: fill out relevant environment variables or secrets\n", + "\n", + "## Usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62e0dbc3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from langchain_mongodb_atlas.embeddings import MongoDBAtlasEmbeddings\n", + "\n", + "embeddings = MongoDBAtlasEmbeddings()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12fcfb4b", + "metadata": {}, + "outputs": [], + "source": [ + "embeddings.embed_query(\"My query to look up\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f2e6104", + "metadata": {}, + "outputs": [], + "source": [ + "embeddings.embed_documents(\n", + " [\"This is a content of the document\", \"This is another document\"]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46739f68", + "metadata": {}, + "outputs": [], + "source": [ + "# async embed query\n", + "await embeddings.aembed_query(\"My query to look up\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e48632ea", + "metadata": {}, + "outputs": [], + "source": [ + "# async embed documents\n", + "await embeddings.aembed_documents(\n", + " [\"This is a content of the document\", \"This is another document\"]\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/libs/partners/mongodb-atlas/docs/vectorstores.ipynb b/libs/partners/mongodb-atlas/docs/vectorstores.ipynb new file mode 100644 index 00000000000000..ff2a1e58d65554 --- /dev/null +++ b/libs/partners/mongodb-atlas/docs/vectorstores.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "1957f5cb", + "metadata": {}, + "source": [ + "---\n", + "sidebar_label: MongoDBAtlas\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "ef1f0986", + "metadata": {}, + "source": [ + "# MongoDBAtlasVectorStore\n", + "\n", + "This notebook covers how to get started with the MongoDBAtlas vector store.\n", + "\n", + "## Installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d97b55c2", + "metadata": {}, + "outputs": [], + "source": [ + "# install package\n", + "!pip install -U langchain-mongodb-atlas" + ] + }, + { + "cell_type": "markdown", + "id": "36fdc060", + "metadata": {}, + "source": [ + "## Environment Setup\n", + "\n", + "Make sure to set the following environment variables:\n", + "\n", + "- TODO: fill out relevant environment variables or secrets\n", + "- Op\n", + "\n", + "## Usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc37144c-208d-4ab3-9f3a-0407a69fe052", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore\n", + "\n", + "# TODO: switch for preferred way to init and use your vector store\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py new file mode 100644 index 00000000000000..d5e5c4b9dc2cb1 --- /dev/null +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py @@ -0,0 +1,8 @@ +from langchain_mongodb_atlas.vectorstores import ( + MongoDBAtlasVectorStore, +) + + +__all__ = [ + "MongoDBAtlasVectorStore", +] diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/py.typed b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/py.typed new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py new file mode 100644 index 00000000000000..9852e0f9dc71fc --- /dev/null +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py @@ -0,0 +1,461 @@ +from __future__ import annotations + + +import asyncio +from functools import partial + +import logging +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Generator, + Iterable, + List, + Optional, + Tuple, + TypeVar, + Union, +) + +import numpy as np +from langchain_core.documents import Document +from langchain_core.embeddings import Embeddings +from langchain_core.vectorstores import VectorStore + +from langchain_community.vectorstores.utils import maximal_marginal_relevance + +if TYPE_CHECKING: + from pymongo.collection import Collection + +MongoDBDocumentType = TypeVar("MongoDBDocumentType", bound=Dict[str, Any]) +VST = TypeVar("VST", bound=VectorStore) + +logger = logging.getLogger(__name__) + +DEFAULT_INSERT_BATCH_SIZE = 100 + + +class MongoDBAtlasVectorStore(VectorStore): + """`MongoDB Atlas Vector Search` vector store. + + To use, you should have both: + - the ``pymongo`` python package installed + - a connection string associated with a MongoDB Atlas Cluster having deployed an + Atlas Search index + + Example: + .. code-block:: python + + from langchain_community.vectorstores import MongoDBAtlasVectorStore + from langchain_community.embeddings.openai import OpenAIEmbeddings + from pymongo import MongoClient + + mongo_client = MongoClient("") + collection = mongo_client[""][""] + embeddings = OpenAIEmbeddings() + vectorstore = MongoDBAtlasVectorStore(collection, embeddings) + """ + + def __init__( + self, + collection: Collection[MongoDBDocumentType], + embedding: Embeddings, + *, + index_name: str = "default", + text_key: str = "text", + embedding_key: str = "embedding", + relevance_score_fn: str = "cosine", + ): + """ + Args: + collection: MongoDB collection to add the texts to. + embedding: Text embedding model to use. + text_key: MongoDB field that will contain the text for each + document. + embedding_key: MongoDB field that will contain the embedding for + each document. + index_name: Name of the Atlas Search index. + relevance_score_fn: The similarity score used for the index. + Currently supported: Euclidean, cosine, and dot product. + """ + self._collection = collection + self._embedding = embedding + self._index_name = index_name + self._text_key = text_key + self._embedding_key = embedding_key + self._relevance_score_fn = relevance_score_fn + + @property + def embeddings(self) -> Embeddings: + return self._embedding + + def _select_relevance_score_fn(self) -> Callable[[float], float]: + if self._relevance_score_fn == "euclidean": + return self._euclidean_relevance_score_fn + elif self._relevance_score_fn == "dotProduct": + return self._max_inner_product_relevance_score_fn + elif self._relevance_score_fn == "cosine": + return self._cosine_relevance_score_fn + else: + raise NotImplementedError( + f"No relevance score function for ${self._relevance_score_fn}" + ) + + @classmethod + def from_connection_string( + cls, + connection_string: str, + namespace: str, + embedding: Embeddings, + **kwargs: Any, + ) -> MongoDBAtlasVectorStore: + """Construct a `MongoDB Atlas Vector Search` vector store + from a MongoDB connection URI. + + Args: + connection_string: A valid MongoDB connection URI. + namespace: A valid MongoDB namespace (database and collection). + embedding: The text embedding model to use for the vector store. + + Returns: + A new MongoDBAtlasVectorStore instance. + + """ + try: + from importlib.metadata import version + + from pymongo import MongoClient + from pymongo.driver_info import DriverInfo + except ImportError: + raise ImportError( + "Could not import pymongo, please install it with " + "`pip install pymongo`." + ) + client: MongoClient = MongoClient( + connection_string, + driver=DriverInfo(name="Langchain", version=version("langchain")), + ) + db_name, collection_name = namespace.split(".") + collection = client[db_name][collection_name] + return cls(collection, embedding, **kwargs) + + def add_texts( + self, + texts: Iterable[str], + metadatas: Optional[List[Dict[str, Any]]] = None, + **kwargs: Any, + ) -> List: + """Run more texts through the embeddings and add to the vectorstore. + + Args: + texts: Iterable of strings to add to the vectorstore. + metadatas: Optional list of metadatas associated with the texts. + + Returns: + List of ids from adding the texts into the vectorstore. + """ + batch_size = kwargs.get("batch_size", DEFAULT_INSERT_BATCH_SIZE) + _metadatas: Union[List, Generator] = metadatas or ({} for _ in texts) + texts_batch = [] + metadatas_batch = [] + result_ids = [] + for i, (text, metadata) in enumerate(zip(texts, _metadatas)): + texts_batch.append(text) + metadatas_batch.append(metadata) + if (i + 1) % batch_size == 0: + result_ids.extend(self._insert_texts(texts_batch, metadatas_batch)) + texts_batch = [] + metadatas_batch = [] + if texts_batch: + result_ids.extend(self._insert_texts(texts_batch, metadatas_batch)) + return result_ids + + def _insert_texts(self, texts: List[str], metadatas: List[Dict[str, Any]]) -> List: + if not texts: + return [] + # Embed and create the documents + embeddings = self._embedding.embed_documents(texts) + to_insert = [ + {self._text_key: t, self._embedding_key: embedding, **m} + for t, m, embedding in zip(texts, metadatas, embeddings) + ] + # insert the documents in MongoDB Atlas + insert_result = self._collection.insert_many(to_insert) # type: ignore + return insert_result.inserted_ids + + def _similarity_search_with_score( + self, + embedding: List[float], + k: int = 4, + pre_filter: Optional[Dict] = None, + post_filter_pipeline: Optional[List[Dict]] = None, + ) -> List[Tuple[Document, float]]: + params = { + "queryVector": embedding, + "path": self._embedding_key, + "numCandidates": k * 10, + "limit": k, + "index": self._index_name, + } + if pre_filter: + params["filter"] = pre_filter + query = {"$vectorSearch": params} + + pipeline = [ + query, + {"$set": {"score": {"$meta": "vectorSearchScore"}}}, + ] + if post_filter_pipeline is not None: + pipeline.extend(post_filter_pipeline) + cursor = self._collection.aggregate(pipeline) # type: ignore[arg-type] + docs = [] + for res in cursor: + text = res.pop(self._text_key) + score = res.pop("score") + del res[self._embedding_key] + docs.append((Document(page_content=text, metadata=res), score)) + return docs + + def similarity_search_with_score( + self, + query: str, + k: int = 4, + pre_filter: Optional[Dict] = None, + post_filter_pipeline: Optional[List[Dict]] = None, + ) -> List[Tuple[Document, float]]: + """Return MongoDB documents most similar to the given query and their scores. + + Uses the vectorSearch operator available in MongoDB Atlas Search. + For more: https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/ + + Args: + query: Text to look up documents similar to. + k: (Optional) number of documents to return. Defaults to 4. + pre_filter: (Optional) dictionary of argument(s) to prefilter document + fields on. + post_filter_pipeline: (Optional) Pipeline of MongoDB aggregation stages + following the vectorSearch stage. + + Returns: + List of documents most similar to the query and their scores. + """ + embedding = self._embedding.embed_query(query) + docs = self._similarity_search_with_score( + embedding, + k=k, + pre_filter=pre_filter, + post_filter_pipeline=post_filter_pipeline, + ) + return docs + + def similarity_search( + self, + query: str, + k: int = 4, + pre_filter: Optional[Dict] = None, + post_filter_pipeline: Optional[List[Dict]] = None, + **kwargs: Any, + ) -> List[Document]: + """Return MongoDB documents most similar to the given query. + + Uses the vectorSearch operator available in MongoDB Atlas Search. + For more: https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/ + + Args: + query: Text to look up documents similar to. + k: (Optional) number of documents to return. Defaults to 4. + pre_filter: (Optional) dictionary of argument(s) to prefilter document + fields on. + post_filter_pipeline: (Optional) Pipeline of MongoDB aggregation stages + following the vectorSearch stage. + + Returns: + List of documents most similar to the query and their scores. + """ + additional = kwargs.get("additional") + docs_and_scores = self.similarity_search_with_score( + query, + k=k, + pre_filter=pre_filter, + post_filter_pipeline=post_filter_pipeline, + ) + + if additional and "similarity_score" in additional: + for doc, score in docs_and_scores: + doc.metadata["score"] = score + return [doc for doc, _ in docs_and_scores] + + def max_marginal_relevance_search( + self, + query: str, + k: int = 4, + fetch_k: int = 20, + lambda_mult: float = 0.5, + pre_filter: Optional[Dict] = None, + post_filter_pipeline: Optional[List[Dict]] = None, + **kwargs: Any, + ) -> List[Document]: + """Return documents selected using the maximal marginal relevance. + + Maximal marginal relevance optimizes for similarity to query AND diversity + among selected documents. + + Args: + query: Text to look up documents similar to. + k: (Optional) number of documents to return. Defaults to 4. + fetch_k: (Optional) number of documents to fetch before passing to MMR + algorithm. Defaults to 20. + lambda_mult: Number between 0 and 1 that determines the degree + of diversity among the results with 0 corresponding + to maximum diversity and 1 to minimum diversity. + Defaults to 0.5. + pre_filter: (Optional) dictionary of argument(s) to prefilter on document + fields. + post_filter_pipeline: (Optional) pipeline of MongoDB aggregation stages + following the vectorSearch stage. + Returns: + List of documents selected by maximal marginal relevance. + """ + query_embedding = self._embedding.embed_query(query) + docs = self._similarity_search_with_score( + query_embedding, + k=fetch_k, + pre_filter=pre_filter, + post_filter_pipeline=post_filter_pipeline, + ) + mmr_doc_indexes = maximal_marginal_relevance( + np.array(query_embedding), + [doc.metadata[self._embedding_key] for doc, _ in docs], + k=k, + lambda_mult=lambda_mult, + ) + mmr_docs = [docs[i][0] for i in mmr_doc_indexes] + return mmr_docs + + @classmethod + def from_texts( + cls, + texts: List[str], + embedding: Embeddings, + metadatas: Optional[List[Dict]] = None, + collection: Optional[Collection[MongoDBDocumentType]] = None, + **kwargs: Any, + ) -> MongoDBAtlasVectorStore: + """Construct a `MongoDB Atlas Vector Search` vector store from raw documents. + + This is a user-friendly interface that: + 1. Embeds documents. + 2. Adds the documents to a provided MongoDB Atlas Vector Search index + (Lucene) + + This is intended to be a quick way to get started. + + Example: + .. code-block:: python + from pymongo import MongoClient + + from langchain_community.vectorstores import MongoDBAtlasVectorStore + from langchain_community.embeddings import OpenAIEmbeddings + + mongo_client = MongoClient("") + collection = mongo_client[""][""] + embeddings = OpenAIEmbeddings() + vectorstore = MongoDBAtlasVectorStore.from_texts( + texts, + embeddings, + metadatas=metadatas, + collection=collection + ) + """ + if collection is None: + raise ValueError("Must provide 'collection' named parameter.") + vectorstore = cls(collection, embedding, **kwargs) + vectorstore.add_texts(texts, metadatas=metadatas) + return vectorstore + + async def aadd_texts( + self, + texts: Iterable[str], + metadatas: Optional[List[dict]] = None, + **kwargs: Any, + ) -> List[str]: + return await asyncio.get_running_loop().run_in_executor( + None, partial(self.add_texts, **kwargs), texts, metadatas + ) + + async def adelete( + self, ids: Optional[List[str]] = None, **kwargs: Any + ) -> Optional[bool]: + raise NotImplementedError + + async def asimilarity_search( + self, query: str, k: int = 4, **kwargs: Any + ) -> List[Document]: + # This is a temporary workaround to make the similarity search + # asynchronous. The proper solution is to make the similarity search + # asynchronous in the vector store implementations. + func = partial(self.similarity_search, query, k=k, **kwargs) + return await asyncio.get_event_loop().run_in_executor(None, func) + + async def asimilarity_search_with_score( + self, *args: Any, **kwargs: Any + ) -> List[Tuple[Document, float]]: + # This is a temporary workaround to make the similarity search + # asynchronous. The proper solution is to make the similarity search + # asynchronous in the vector store implementations. + func = partial(self.similarity_search_with_score, *args, **kwargs) + return await asyncio.get_event_loop().run_in_executor(None, func) + + async def asimilarity_search_by_vector( + self, embedding: List[float], k: int = 4, **kwargs: Any + ) -> List[Document]: + # This is a temporary workaround to make the similarity search + # asynchronous. The proper solution is to make the similarity search + # asynchronous in the vector store implementations. + func = partial(self.similarity_search_by_vector, embedding, k=k, **kwargs) + return await asyncio.get_event_loop().run_in_executor(None, func) + + async def amax_marginal_relevance_search( + self, + query: str, + k: int = 4, + fetch_k: int = 20, + lambda_mult: float = 0.5, + **kwargs: Any, + ) -> List[Document]: + # This is a temporary workaround to make the similarity search + # asynchronous. The proper solution is to make the similarity search + # asynchronous in the vector store implementations. + func = partial( + self.max_marginal_relevance_search, + query, + k=k, + fetch_k=fetch_k, + lambda_mult=lambda_mult, + **kwargs, + ) + return await asyncio.get_event_loop().run_in_executor(None, func) + + async def amax_marginal_relevance_search_by_vector( + self, + embedding: List[float], + k: int = 4, + fetch_k: int = 20, + lambda_mult: float = 0.5, + **kwargs: Any, + ) -> List[Document]: + raise NotImplementedError + + @classmethod + async def afrom_texts( + cls: Type[VST], + texts: List[str], + embedding: Embeddings, + metadatas: Optional[List[dict]] = None, + **kwargs: Any, + ) -> VST: + return await asyncio.get_running_loop().run_in_executor( + None, partial(cls.from_texts, **kwargs), texts, embedding, metadatas + ) diff --git a/libs/partners/mongodb-atlas/poetry.lock b/libs/partners/mongodb-atlas/poetry.lock new file mode 100644 index 00000000000000..635e4d7c39afea --- /dev/null +++ b/libs/partners/mongodb-atlas/poetry.lock @@ -0,0 +1,815 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + +[[package]] +name = "anyio" +version = "4.2.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "codespell" +version = "2.2.6" +description = "Codespell" +optional = false +python-versions = ">=3.8" +files = [ + {file = "codespell-2.2.6-py3-none-any.whl", hash = "sha256:9ee9a3e5df0990604013ac2a9f22fa8e57669c827124a2e961fe8a1da4cacc07"}, + {file = "codespell-2.2.6.tar.gz", hash = "sha256:a8c65d8eb3faa03deabab6b3bbe798bea72e1799c7e9e955d57eca4096abcff9"}, +] + +[package.extras] +dev = ["Pygments", "build", "chardet", "pre-commit", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli", "twine"] +hard-encoding-detection = ["chardet"] +toml = ["tomli"] +types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "freezegun" +version = "1.4.0" +description = "Let your Python tests travel through time" +optional = false +python-versions = ">=3.7" +files = [ + {file = "freezegun-1.4.0-py3-none-any.whl", hash = "sha256:55e0fc3c84ebf0a96a5aa23ff8b53d70246479e9a68863f1fcac5a3e52f19dd6"}, + {file = "freezegun-1.4.0.tar.gz", hash = "sha256:10939b0ba0ff5adaecf3b06a5c2f73071d9678e507c5eaedb23c761d56ac774b"}, +] + +[package.dependencies] +python-dateutil = ">=2.7" + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +description = "Apply JSON-Patches (RFC 6902)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, +] + +[package.dependencies] +jsonpointer = ">=1.9" + +[[package]] +name = "jsonpointer" +version = "2.4" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "langchain-core" +version = "0.1.23" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [] +develop = true + +[package.dependencies] +anyio = ">=3,<5" +jsonpatch = "^1.33" +langsmith = "^0.0.87" +packaging = "^23.2" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = "^2" +tenacity = "^8.1.0" + +[package.extras] +extended-testing = ["jinja2 (>=3,<4)"] + +[package.source] +type = "directory" +url = "../../core" + +[[package]] +name = "langsmith" +version = "0.0.87" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, + {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, +] + +[package.dependencies] +pydantic = ">=1,<3" +requests = ">=2,<3" + +[[package]] +name = "mypy" +version = "0.991" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"}, + {file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"}, + {file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"}, + {file = "mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb"}, + {file = "mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305"}, + {file = "mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c"}, + {file = "mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372"}, + {file = "mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f"}, + {file = "mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33"}, + {file = "mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05"}, + {file = "mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad"}, + {file = "mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297"}, + {file = "mypy-0.991-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813"}, + {file = "mypy-0.991-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711"}, + {file = "mypy-0.991-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd"}, + {file = "mypy-0.991-cp37-cp37m-win_amd64.whl", hash = "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef"}, + {file = "mypy-0.991-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a"}, + {file = "mypy-0.991-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93"}, + {file = "mypy-0.991-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf"}, + {file = "mypy-0.991-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135"}, + {file = "mypy-0.991-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70"}, + {file = "mypy-0.991-cp38-cp38-win_amd64.whl", hash = "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243"}, + {file = "mypy-0.991-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d"}, + {file = "mypy-0.991-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5"}, + {file = "mypy-0.991-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3"}, + {file = "mypy-0.991-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648"}, + {file = "mypy-0.991-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476"}, + {file = "mypy-0.991-cp39-cp39-win_amd64.whl", hash = "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461"}, + {file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"}, + {file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"}, +] + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pluggy" +version = "1.4.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pydantic" +version = "2.6.1" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, + {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.16.2" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.16.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, + {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, + {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, + {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, + {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, + {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, + {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, + {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, + {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, + {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, + {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, + {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, + {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, + {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pytest" +version = "7.4.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.1" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-mock" +version = "3.12.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, + {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-watcher" +version = "0.3.5" +description = "Automatically rerun your tests on file modifications" +optional = false +python-versions = ">=3.7.0,<4.0.0" +files = [ + {file = "pytest_watcher-0.3.5-py3-none-any.whl", hash = "sha256:af00ca52c7be22dc34c0fd3d7ffef99057207a73b05dc5161fe3b2fe91f58130"}, + {file = "pytest_watcher-0.3.5.tar.gz", hash = "sha256:8896152460ba2b1a8200c12117c6611008ec96c8b2d811f0a05ab8a82b043ff8"}, +] + +[package.dependencies] +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} +watchdog = ">=2.0.0" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "ruff" +version = "0.1.15" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, + {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, + {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, + {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, + {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "syrupy" +version = "4.6.1" +description = "Pytest Snapshot Test Utility" +optional = false +python-versions = ">=3.8.1,<4" +files = [ + {file = "syrupy-4.6.1-py3-none-any.whl", hash = "sha256:203e52f9cb9fa749cf683f29bd68f02c16c3bc7e7e5fe8f2fc59bdfe488ce133"}, + {file = "syrupy-4.6.1.tar.gz", hash = "sha256:37a835c9ce7857eeef86d62145885e10b3cb9615bc6abeb4ce404b3f18e1bb36"}, +] + +[package.dependencies] +pytest = ">=7.0.0,<9.0.0" + +[[package]] +name = "tenacity" +version = "8.2.3" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, + {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, +] + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "urllib3" +version = "2.2.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "watchdog" +version = "4.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, + {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, + {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, + {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, + {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, + {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, + {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, + {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8.1,<4.0" +content-hash = "958e6227984c6fff9148576313da41494c2f4642968fccf861d524c8208fbfdc" diff --git a/libs/partners/mongodb-atlas/pyproject.toml b/libs/partners/mongodb-atlas/pyproject.toml new file mode 100644 index 00000000000000..f850b10a008d5e --- /dev/null +++ b/libs/partners/mongodb-atlas/pyproject.toml @@ -0,0 +1,93 @@ +[tool.poetry] +name = "langchain-mongodb-atlas" +version = "0.0.1" +description = "An integration package connecting MongoDBAtlas and LangChain" +authors = [] +readme = "README.md" +repository = "https://github.com/langchain-ai/langchain" +license = "MIT" + +[tool.poetry.urls] +"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/partners/mongodb-atlas" + +[tool.poetry.dependencies] +python = ">=3.8.1,<4.0" +langchain-core = ">=0.0.12" + +[tool.poetry.group.test] +optional = true + +[tool.poetry.group.test.dependencies] +pytest = "^7.3.0" +freezegun = "^1.2.2" +pytest-mock = "^3.10.0" +syrupy = "^4.0.2" +pytest-watcher = "^0.3.4" +pytest-asyncio = "^0.21.1" +langchain-core = {path = "../../core", develop = true} + +[tool.poetry.group.codespell] +optional = true + +[tool.poetry.group.codespell.dependencies] +codespell = "^2.2.0" + +[tool.poetry.group.test_integration] +optional = true + +[tool.poetry.group.test_integration.dependencies] + +[tool.poetry.group.lint] +optional = true + +[tool.poetry.group.lint.dependencies] +ruff = "^0.1.5" + +[tool.poetry.group.typing.dependencies] +mypy = "^0.991" +langchain-core = {path = "../../core", develop = true} + +[tool.poetry.group.dev] +optional = true + +[tool.poetry.group.dev.dependencies] +langchain-core = {path = "../../core", develop = true} + +[tool.ruff] +select = [ + "E", # pycodestyle + "F", # pyflakes + "I", # isort +] + +[tool.mypy] +disallow_untyped_defs = "True" + +[tool.coverage.run] +omit = [ + "tests/*", +] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +# --strict-markers will raise errors on unknown marks. +# https://docs.pytest.org/en/7.1.x/how-to/mark.html#raising-errors-on-unknown-marks +# +# https://docs.pytest.org/en/7.1.x/reference/reference.html +# --strict-config any warnings encountered while parsing the `pytest` +# section of the configuration file raise errors. +# +# https://github.com/tophat/syrupy +# --snapshot-warn-unused Prints a warning on unused snapshots rather than fail the test suite. +addopts = "--snapshot-warn-unused --strict-markers --strict-config --durations=5" +# Registering custom markers. +# https://docs.pytest.org/en/7.1.x/example/markers.html#registering-markers +markers = [ + "requires: mark tests as requiring a specific library", + "asyncio: mark tests as requiring asyncio", + "compile: mark placeholder test used to compile integration tests without running them", +] +asyncio_mode = "auto" diff --git a/libs/partners/mongodb-atlas/scripts/check_imports.py b/libs/partners/mongodb-atlas/scripts/check_imports.py new file mode 100644 index 00000000000000..fd21a4975b7f0b --- /dev/null +++ b/libs/partners/mongodb-atlas/scripts/check_imports.py @@ -0,0 +1,17 @@ +import sys +import traceback +from importlib.machinery import SourceFileLoader + +if __name__ == "__main__": + files = sys.argv[1:] + has_failure = False + for file in files: + try: + SourceFileLoader("x", file).load_module() + except Exception: + has_faillure = True + print(file) + traceback.print_exc() + print() + + sys.exit(1 if has_failure else 0) diff --git a/libs/partners/mongodb-atlas/scripts/check_pydantic.sh b/libs/partners/mongodb-atlas/scripts/check_pydantic.sh new file mode 100755 index 00000000000000..06b5bb81ae2361 --- /dev/null +++ b/libs/partners/mongodb-atlas/scripts/check_pydantic.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# +# This script searches for lines starting with "import pydantic" or "from pydantic" +# in tracked files within a Git repository. +# +# Usage: ./scripts/check_pydantic.sh /path/to/repository + +# Check if a path argument is provided +if [ $# -ne 1 ]; then + echo "Usage: $0 /path/to/repository" + exit 1 +fi + +repository_path="$1" + +# Search for lines matching the pattern within the specified repository +result=$(git -C "$repository_path" grep -E '^import pydantic|^from pydantic') + +# Check if any matching lines were found +if [ -n "$result" ]; then + echo "ERROR: The following lines need to be updated:" + echo "$result" + echo "Please replace the code with an import from langchain_core.pydantic_v1." + echo "For example, replace 'from pydantic import BaseModel'" + echo "with 'from langchain_core.pydantic_v1 import BaseModel'" + exit 1 +fi diff --git a/libs/partners/mongodb-atlas/scripts/lint_imports.sh b/libs/partners/mongodb-atlas/scripts/lint_imports.sh new file mode 100755 index 00000000000000..695613c7ba8fd6 --- /dev/null +++ b/libs/partners/mongodb-atlas/scripts/lint_imports.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -eu + +# Initialize a variable to keep track of errors +errors=0 + +# make sure not importing from langchain or langchain_experimental +git --no-pager grep '^from langchain\.' . && errors=$((errors+1)) +git --no-pager grep '^from langchain_experimental\.' . && errors=$((errors+1)) + +# Decide on an exit status based on the errors +if [ "$errors" -gt 0 ]; then + exit 1 +else + exit 0 +fi diff --git a/libs/partners/mongodb-atlas/tests/__init__.py b/libs/partners/mongodb-atlas/tests/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/libs/partners/mongodb-atlas/tests/integration_tests/__init__.py b/libs/partners/mongodb-atlas/tests/integration_tests/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py new file mode 100644 index 00000000000000..e7e63c21dbe00e --- /dev/null +++ b/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py @@ -0,0 +1,150 @@ +"""Test MongoDB Atlas Vector Search functionality.""" + +from __future__ import annotations + +import os +from time import sleep +from typing import Any + +import pytest + +from pymongo import MongoClient +from pymongo.collection import Collection + +from langchain_core.documents import Document +from langchain_core.embeddings import Embeddings +from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore + + +INDEX_NAME = "langchain-test-index" +NAMESPACE = "langchain_test_db.langchain_test_collection" +CONNECTION_STRING = os.environ.get("MONGODB_ATLAS_URI") +DB_NAME, COLLECTION_NAME = NAMESPACE.split(".") + + +def get_collection() -> Collection: + test_client: MongoClient = MongoClient(CONNECTION_STRING) + return test_client[DB_NAME][COLLECTION_NAME] + + +@pytest.fixture() +def collection() -> Collection: + return get_collection() + + +class TestMongoDBAtlasVectorStore: + @classmethod + def setup_class(cls) -> None: + # insure the test collection is empty + collection = get_collection() + assert collection.count_documents({}) == 0 # type: ignore[index] # noqa: E501 + + @classmethod + def teardown_class(cls) -> None: + collection = get_collection() + # delete all the documents in the collection + collection.delete_many({}) # type: ignore[index] + + @pytest.fixture(autouse=True) + def setup(self) -> None: + collection = get_collection() + # delete all the documents in the collection + collection.delete_many({}) # type: ignore[index] + + def test_from_documents( + self, embedding_openai: Embeddings, collection: Any + ) -> None: + """Test end to end construction and search.""" + documents = [ + Document(page_content="Dogs are tough.", metadata={"a": 1}), + Document(page_content="Cats have fluff.", metadata={"b": 1}), + Document(page_content="What is a sandwich?", metadata={"c": 1}), + Document(page_content="That fence is purple.", metadata={"d": 1, "e": 2}), + ] + vectorstore = MongoDBAtlasVectorStore.from_documents( + documents, + embedding_openai, + collection=collection, + index_name=INDEX_NAME, + ) + sleep(1) # waits for mongot to update Lucene's index + output = vectorstore.similarity_search("Sandwich", k=1) + assert output[0].page_content == "What is a sandwich?" + assert output[0].metadata["c"] == 1 + + def test_from_texts(self, embedding_openai: Embeddings, collection: Any) -> None: + texts = [ + "Dogs are tough.", + "Cats have fluff.", + "What is a sandwich?", + "That fence is purple.", + ] + vectorstore = MongoDBAtlasVectorStore.from_texts( + texts, + embedding_openai, + collection=collection, + index_name=INDEX_NAME, + ) + sleep(1) # waits for mongot to update Lucene's index + output = vectorstore.similarity_search("Sandwich", k=1) + assert output[0].page_content == "What is a sandwich?" + + def test_from_texts_with_metadatas( + self, embedding_openai: Embeddings, collection: Any + ) -> None: + texts = [ + "Dogs are tough.", + "Cats have fluff.", + "What is a sandwich?", + "The fence is purple.", + ] + metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] + vectorstore = MongoDBAtlasVectorStore.from_texts( + texts, + embedding_openai, + metadatas=metadatas, + collection=collection, + index_name=INDEX_NAME, + ) + sleep(1) # waits for mongot to update Lucene's index + output = vectorstore.similarity_search("Sandwich", k=1) + assert output[0].page_content == "What is a sandwich?" + assert output[0].metadata["c"] == 1 + + def test_from_texts_with_metadatas_and_pre_filter( + self, embedding_openai: Embeddings, collection: Any + ) -> None: + texts = [ + "Dogs are tough.", + "Cats have fluff.", + "What is a sandwich?", + "The fence is purple.", + ] + metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] + vectorstore = MongoDBAtlasVectorStore.from_texts( + texts, + embedding_openai, + metadatas=metadatas, + collection=collection, + index_name=INDEX_NAME, + ) + sleep(1) # waits for mongot to update Lucene's index + output = vectorstore.similarity_search( + "Sandwich", k=1, pre_filter={"range": {"lte": 0, "path": "c"}} + ) + assert output == [] + + def test_mmr(self, embedding_openai: Embeddings, collection: Any) -> None: + texts = ["foo", "foo", "fou", "foy"] + vectorstore = MongoDBAtlasVectorStore.from_texts( + texts, + embedding_openai, + collection=collection, + index_name=INDEX_NAME, + ) + sleep(1) # waits for mongot to update Lucene's index + query = "foo" + output = vectorstore.max_marginal_relevance_search(query, k=10, lambda_mult=0.1) + assert len(output) == len(texts) + assert output[0].page_content == "foo" + assert output[1].page_content != "foo" diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/__init__.py b/libs/partners/mongodb-atlas/tests/unit_tests/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py new file mode 100644 index 00000000000000..d204cbbd4126ef --- /dev/null +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py @@ -0,0 +1,10 @@ +from langchain_mongodb_atlas import __all__ + +EXPECTED_ALL = [ + "MongoDBAtlasVectorSearch", + "MongoDBAtlasVectorStore", +] + + +def test_all_imports() -> None: + assert sorted(EXPECTED_ALL) == sorted(__all__) diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py new file mode 100644 index 00000000000000..08b57a68d5f89b --- /dev/null +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py @@ -0,0 +1,6 @@ +from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore + + +def test_initialization(): + """Test initialization of vector store class""" + MongoDBAtlasVectorStore() From edeb5554012f5055a23c9c1933c4660c6cc2ee23 Mon Sep 17 00:00:00 2001 From: Jib Date: Fri, 16 Feb 2024 14:17:11 -0500 Subject: [PATCH 02/22] kept the vectorsearch names and kept the mongodbatlasvectorsearch naming scheme --- .../mongodb-atlas/docs/provider.ipynb | 2 +- .../mongodb-atlas/docs/vectorstores.ipynb | 29 ++- .../langchain_mongodb_atlas/__init__.py | 4 +- .../langchain_mongodb_atlas/vectorstores.py | 167 ++++++++++-------- .../integration_tests/test_vectorstores.py | 14 +- .../tests/unit_tests/test_imports.py | 2 +- .../tests/unit_tests/test_vectorstores.py | 4 +- 7 files changed, 123 insertions(+), 99 deletions(-) diff --git a/libs/partners/mongodb-atlas/docs/provider.ipynb b/libs/partners/mongodb-atlas/docs/provider.ipynb index a47868d2793fe6..b3561967605ff2 100644 --- a/libs/partners/mongodb-atlas/docs/provider.ipynb +++ b/libs/partners/mongodb-atlas/docs/provider.ipynb @@ -19,7 +19,7 @@ "source": [ "from langchain_mongodb_atlas.chat_models import MongoDBAtlasChat\n", "from langchain_mongodb_atlas.llms import MongoDBAtlasLLM\n", - "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore" + "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch" ] } ], diff --git a/libs/partners/mongodb-atlas/docs/vectorstores.ipynb b/libs/partners/mongodb-atlas/docs/vectorstores.ipynb index ff2a1e58d65554..dd7c26a3dc3590 100644 --- a/libs/partners/mongodb-atlas/docs/vectorstores.ipynb +++ b/libs/partners/mongodb-atlas/docs/vectorstores.ipynb @@ -15,7 +15,7 @@ "id": "ef1f0986", "metadata": {}, "source": [ - "# MongoDBAtlasVectorStore\n", + "# MongoDBAtlasVectorSearch\n", "\n", "This notebook covers how to get started with the MongoDBAtlas vector store.\n", "\n", @@ -30,7 +30,7 @@ "outputs": [], "source": [ "# install package\n", - "!pip install -U langchain-mongodb-atlas" + "%pip install -U langchain-mongodb-atlas" ] }, { @@ -38,12 +38,17 @@ "id": "36fdc060", "metadata": {}, "source": [ - "## Environment Setup\n", + "# Environment Setup\n", "\n", - "Make sure to set the following environment variables:\n", + "To use, you should have:\n", + "- the ``pymongo`` python package installed\n", + "- a MongoDB Atlas Server that supports [Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#limitations).\n", + " - To understand what \n", + "- a connection string associated with a MongoDB Atlas Cluster having deployed an\n", + " Atlas Search index\n", "\n", - "- TODO: fill out relevant environment variables or secrets\n", - "- Op\n", + "\n", + "It's good practice to have this connection string retrieved as an environment variable to reduce the chance of having the URI appear in git commit history.\n", "\n", "## Usage" ] @@ -57,9 +62,17 @@ }, "outputs": [], "source": [ - "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore\n", + "import os\n", + "\n", + "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch\n", + "from langchain_community.embeddings.openai import OpenAIEmbeddings\n", + "from pymongo import MongoClient\n", + "\n", "\n", - "# TODO: switch for preferred way to init and use your vector store\n" + "mongo_client = MongoClient(os.environ.get(\"YOUR_CONNECTION_STRING\"))\n", + "collection = mongo_client[\"\"][\"\"]\n", + "embeddings = OpenAIEmbeddings()\n", + "vectorstore = MongoDBAtlasVectorSearch(collection, embeddings)\n" ] } ], diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py index d5e5c4b9dc2cb1..fc822693ef046d 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py @@ -1,8 +1,8 @@ from langchain_mongodb_atlas.vectorstores import ( - MongoDBAtlasVectorStore, + MongoDBAtlasVectorSearch, ) __all__ = [ - "MongoDBAtlasVectorStore", + "MongoDBAtlasVectorSearch", ] diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py index 9852e0f9dc71fc..568f2cc6c9947d 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py @@ -1,10 +1,8 @@ from __future__ import annotations -import asyncio -from functools import partial - import logging +from enum import Enum from typing import ( TYPE_CHECKING, Any, @@ -22,6 +20,7 @@ import numpy as np from langchain_core.documents import Document from langchain_core.embeddings import Embeddings +from langchain_core.runnables.config import run_in_executor from langchain_core.vectorstores import VectorStore from langchain_community.vectorstores.utils import maximal_marginal_relevance @@ -34,10 +33,10 @@ logger = logging.getLogger(__name__) -DEFAULT_INSERT_BATCH_SIZE = 100 +DEFAULT_INSERT_BATCH_SIZE = 1000 -class MongoDBAtlasVectorStore(VectorStore): +class MongoDBAtlasVectorSearch(VectorStore): """`MongoDB Atlas Vector Search` vector store. To use, you should have both: @@ -48,14 +47,14 @@ class MongoDBAtlasVectorStore(VectorStore): Example: .. code-block:: python - from langchain_community.vectorstores import MongoDBAtlasVectorStore + from langchain_community.vectorstores import MongoDBAtlasVectorSearch from langchain_community.embeddings.openai import OpenAIEmbeddings from pymongo import MongoClient mongo_client = MongoClient("") collection = mongo_client[""][""] embeddings = OpenAIEmbeddings() - vectorstore = MongoDBAtlasVectorStore(collection, embeddings) + vectorstore = MongoDBAtlasVectorSearch(collection, embeddings) """ def __init__( @@ -74,11 +73,15 @@ def __init__( embedding: Text embedding model to use. text_key: MongoDB field that will contain the text for each document. + defaults to 'text' embedding_key: MongoDB field that will contain the embedding for each document. + defaults to 'embedding' index_name: Name of the Atlas Search index. + defaults to 'default' relevance_score_fn: The similarity score used for the index. - Currently supported: Euclidean, cosine, and dot product. + defaults to 'cosine' + Currently supported: 'euclidean', 'cosine', and 'dotProduct'. """ self._collection = collection self._embedding = embedding @@ -92,12 +95,13 @@ def embeddings(self) -> Embeddings: return self._embedding def _select_relevance_score_fn(self) -> Callable[[float], float]: - if self._relevance_score_fn == "euclidean": - return self._euclidean_relevance_score_fn - elif self._relevance_score_fn == "dotProduct": - return self._max_inner_product_relevance_score_fn - elif self._relevance_score_fn == "cosine": - return self._cosine_relevance_score_fn + scoring: dict[str, Callable] = { + "euclidean": self._euclidean_relevance_score_fn, + "dotProduct": self._max_inner_product_relevance_score_fn, + "cosine": self._cosine_relevance_score_fn, + } + if self._relevance_score_fn in scoring: + return scoring[self._relevance_score_fn] else: raise NotImplementedError( f"No relevance score function for ${self._relevance_score_fn}" @@ -110,7 +114,7 @@ def from_connection_string( namespace: str, embedding: Embeddings, **kwargs: Any, - ) -> MongoDBAtlasVectorStore: + ) -> MongoDBAtlasVectorSearch: """Construct a `MongoDB Atlas Vector Search` vector store from a MongoDB connection URI. @@ -120,7 +124,7 @@ def from_connection_string( embedding: The text embedding model to use for the vector store. Returns: - A new MongoDBAtlasVectorStore instance. + A new MongoDBAtlasVectorSearch instance. """ try: @@ -342,7 +346,7 @@ def from_texts( metadatas: Optional[List[Dict]] = None, collection: Optional[Collection[MongoDBDocumentType]] = None, **kwargs: Any, - ) -> MongoDBAtlasVectorStore: + ) -> MongoDBAtlasVectorSearch: """Construct a `MongoDB Atlas Vector Search` vector store from raw documents. This is a user-friendly interface that: @@ -356,13 +360,13 @@ def from_texts( .. code-block:: python from pymongo import MongoClient - from langchain_community.vectorstores import MongoDBAtlasVectorStore + from langchain_community.vectorstores import MongoDBAtlasVectorSearch from langchain_community.embeddings import OpenAIEmbeddings mongo_client = MongoClient("") collection = mongo_client[""][""] embeddings = OpenAIEmbeddings() - vectorstore = MongoDBAtlasVectorStore.from_texts( + vectorstore = MongoDBAtlasVectorSearch.from_texts( texts, embeddings, metadatas=metadatas, @@ -375,68 +379,78 @@ def from_texts( vectorstore.add_texts(texts, metadatas=metadatas) return vectorstore - async def aadd_texts( - self, - texts: Iterable[str], - metadatas: Optional[List[dict]] = None, - **kwargs: Any, - ) -> List[str]: - return await asyncio.get_running_loop().run_in_executor( - None, partial(self.add_texts, **kwargs), texts, metadatas - ) + def delete(self, ids: Optional[List[str]] = None, **kwargs: Any) -> Optional[bool]: + """Delete by ObjectId or other criteria. + + Args: + ids: List of ids to delete. + **kwargs: Other keyword arguments that subclasses might use. + + Returns: + Optional[bool]: True if deletion is successful, + False otherwise, None if not implemented. + """ + search_params = {self._text_key: {}} + if ids: + search_params["$in"] = ids + + return self._collection.delete_many({**search_params, **kwargs}) async def adelete( self, ids: Optional[List[str]] = None, **kwargs: Any ) -> Optional[bool]: - raise NotImplementedError + """Delete by vector ID or other criteria. - async def asimilarity_search( - self, query: str, k: int = 4, **kwargs: Any - ) -> List[Document]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial(self.similarity_search, query, k=k, **kwargs) - return await asyncio.get_event_loop().run_in_executor(None, func) - - async def asimilarity_search_with_score( - self, *args: Any, **kwargs: Any - ) -> List[Tuple[Document, float]]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial(self.similarity_search_with_score, *args, **kwargs) - return await asyncio.get_event_loop().run_in_executor(None, func) - - async def asimilarity_search_by_vector( - self, embedding: List[float], k: int = 4, **kwargs: Any - ) -> List[Document]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial(self.similarity_search_by_vector, embedding, k=k, **kwargs) - return await asyncio.get_event_loop().run_in_executor(None, func) + Args: + ids: List of ids to delete. + **kwargs: Other keyword arguments that subclasses might use. + + Returns: + Optional[bool]: True if deletion is successful, + False otherwise, None if not implemented. + """ + return await run_in_executor(None, self.delete, ids=ids, **kwargs) - async def amax_marginal_relevance_search( + async def max_marginal_relevance_search_by_vector( self, - query: str, + embedding: List[float], k: int = 4, fetch_k: int = 20, lambda_mult: float = 0.5, + pre_filter: Optional[Dict] = None, + post_filter_pipeline: Optional[List[Dict]] = None, **kwargs: Any, ) -> List[Document]: - # This is a temporary workaround to make the similarity search - # asynchronous. The proper solution is to make the similarity search - # asynchronous in the vector store implementations. - func = partial( - self.max_marginal_relevance_search, - query, + """Return docs selected using the maximal marginal relevance. + + Maximal marginal relevance optimizes for similarity to query AND diversity + among selected documents. + + Args: + embedding: Embedding to look up documents similar to. + k: Number of Documents to return. Defaults to 4. + fetch_k: Number of Documents to fetch to pass to MMR algorithm. + lambda_mult: Number between 0 and 1 that determines the degree + of diversity among the results with 0 corresponding + to maximum diversity and 1 to minimum diversity. + Defaults to 0.5. + Returns: + List of Documents selected by maximal marginal relevance. + """ + docs = self._similarity_search_with_score( + embedding, + k=fetch_k, + pre_filter=pre_filter, + post_filter_pipeline=post_filter_pipeline, + ) + mmr_doc_indexes = maximal_marginal_relevance( + np.array(embedding), + [doc.metadata[self._embedding_key] for doc, _ in docs], k=k, - fetch_k=fetch_k, lambda_mult=lambda_mult, - **kwargs, ) - return await asyncio.get_event_loop().run_in_executor(None, func) + mmr_docs = [docs[i][0] for i in mmr_doc_indexes] + return mmr_docs async def amax_marginal_relevance_search_by_vector( self, @@ -446,16 +460,13 @@ async def amax_marginal_relevance_search_by_vector( lambda_mult: float = 0.5, **kwargs: Any, ) -> List[Document]: - raise NotImplementedError - - @classmethod - async def afrom_texts( - cls: Type[VST], - texts: List[str], - embedding: Embeddings, - metadatas: Optional[List[dict]] = None, - **kwargs: Any, - ) -> VST: - return await asyncio.get_running_loop().run_in_executor( - None, partial(cls.from_texts, **kwargs), texts, embedding, metadatas + """Return docs selected using the maximal marginal relevance.""" + return await run_in_executor( + None, + self.max_marginal_relevance_search_by_vector, + embedding, + k=k, + fetch_k=fetch_k, + lambda_mult=lambda_mult, + **kwargs, ) diff --git a/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py index e7e63c21dbe00e..eedf6a9b4939bd 100644 --- a/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py +++ b/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py @@ -13,7 +13,7 @@ from langchain_core.documents import Document from langchain_core.embeddings import Embeddings -from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore +from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch INDEX_NAME = "langchain-test-index" @@ -32,7 +32,7 @@ def collection() -> Collection: return get_collection() -class TestMongoDBAtlasVectorStore: +class TestMongoDBAtlasVectorSearch: @classmethod def setup_class(cls) -> None: # insure the test collection is empty @@ -61,7 +61,7 @@ def test_from_documents( Document(page_content="What is a sandwich?", metadata={"c": 1}), Document(page_content="That fence is purple.", metadata={"d": 1, "e": 2}), ] - vectorstore = MongoDBAtlasVectorStore.from_documents( + vectorstore = MongoDBAtlasVectorSearch.from_documents( documents, embedding_openai, collection=collection, @@ -79,7 +79,7 @@ def test_from_texts(self, embedding_openai: Embeddings, collection: Any) -> None "What is a sandwich?", "That fence is purple.", ] - vectorstore = MongoDBAtlasVectorStore.from_texts( + vectorstore = MongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, collection=collection, @@ -99,7 +99,7 @@ def test_from_texts_with_metadatas( "The fence is purple.", ] metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] - vectorstore = MongoDBAtlasVectorStore.from_texts( + vectorstore = MongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, metadatas=metadatas, @@ -121,7 +121,7 @@ def test_from_texts_with_metadatas_and_pre_filter( "The fence is purple.", ] metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] - vectorstore = MongoDBAtlasVectorStore.from_texts( + vectorstore = MongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, metadatas=metadatas, @@ -136,7 +136,7 @@ def test_from_texts_with_metadatas_and_pre_filter( def test_mmr(self, embedding_openai: Embeddings, collection: Any) -> None: texts = ["foo", "foo", "fou", "foy"] - vectorstore = MongoDBAtlasVectorStore.from_texts( + vectorstore = MongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, collection=collection, diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py index d204cbbd4126ef..bcbc01dc6f4cda 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py @@ -2,7 +2,7 @@ EXPECTED_ALL = [ "MongoDBAtlasVectorSearch", - "MongoDBAtlasVectorStore", + "MongoDBAtlasVectorSearch", ] diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py index 08b57a68d5f89b..5ebef57e2d23a3 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py @@ -1,6 +1,6 @@ -from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorStore +from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch def test_initialization(): """Test initialization of vector store class""" - MongoDBAtlasVectorStore() + MongoDBAtlasVectorSearch() From 005266333d7f5ed441bee8dad410bd652a1d88ca Mon Sep 17 00:00:00 2001 From: Jib Date: Fri, 16 Feb 2024 14:34:34 -0500 Subject: [PATCH 03/22] remove docs section --- libs/partners/mongodb-atlas/docs/chat.ipynb | 97 ------------- libs/partners/mongodb-atlas/docs/llms.ipynb | 102 -------------- .../mongodb-atlas/docs/provider.ipynb | 50 ------- .../mongodb-atlas/docs/text_embedding.ipynb | 132 ------------------ .../mongodb-atlas/docs/vectorstores.ipynb | 100 ------------- 5 files changed, 481 deletions(-) delete mode 100644 libs/partners/mongodb-atlas/docs/chat.ipynb delete mode 100644 libs/partners/mongodb-atlas/docs/llms.ipynb delete mode 100644 libs/partners/mongodb-atlas/docs/provider.ipynb delete mode 100644 libs/partners/mongodb-atlas/docs/text_embedding.ipynb delete mode 100644 libs/partners/mongodb-atlas/docs/vectorstores.ipynb diff --git a/libs/partners/mongodb-atlas/docs/chat.ipynb b/libs/partners/mongodb-atlas/docs/chat.ipynb deleted file mode 100644 index 6d600004a27ff0..00000000000000 --- a/libs/partners/mongodb-atlas/docs/chat.ipynb +++ /dev/null @@ -1,97 +0,0 @@ -{ - "cells": [ - { - "cell_type": "raw", - "id": "afaf8039", - "metadata": {}, - "source": [ - "---\n", - "sidebar_label: MongoDBAtlas\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "e49f1e0d", - "metadata": {}, - "source": [ - "# ChatMongoDBAtlas\n", - "\n", - "This notebook covers how to get started with MongoDBAtlas chat models.\n", - "\n", - "## Installation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4c3bef91", - "metadata": {}, - "outputs": [], - "source": [ - "# install package\n", - "!pip install -U langchain-mongodb-atlas" - ] - }, - { - "cell_type": "markdown", - "id": "2b4f3e15", - "metadata": {}, - "source": [ - "## Environment Setup\n", - "\n", - "Make sure to set the following environment variables:\n", - "\n", - "- TODO: fill out relevant environment variables or secrets\n", - "\n", - "## Usage" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62e0dbc3", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from langchain_mongodb_atlas.chat_models import ChatMongoDBAtlas\n", - "from langchain_core.prompts import ChatPromptTemplate\n", - "\n", - "chat = ChatMongoDBAtlas()\n", - "\n", - "prompt = ChatPromptTemplate.from_messages(\n", - " [\n", - " (\"system\", \"You are a helpful assistant that translates English to French.\"),\n", - " (\"human\", \"Translate this sentence from English to French. {english_text}.\"),\n", - " ]\n", - ")\n", - "\n", - "chain = prompt | chat\n", - "chain.invoke({\"english_text\": \"Hello, how are you?\"})" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/libs/partners/mongodb-atlas/docs/llms.ipynb b/libs/partners/mongodb-atlas/docs/llms.ipynb deleted file mode 100644 index 62a9c76eb2d38d..00000000000000 --- a/libs/partners/mongodb-atlas/docs/llms.ipynb +++ /dev/null @@ -1,102 +0,0 @@ -{ - "cells": [ - { - "cell_type": "raw", - "id": "67db2992", - "metadata": {}, - "source": [ - "---\n", - "sidebar_label: MongoDBAtlas\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "9597802c", - "metadata": {}, - "source": [ - "# MongoDBAtlasLLM\n", - "\n", - "This example goes over how to use LangChain to interact with `MongoDBAtlas` models.\n", - "\n", - "## Installation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59c710c4", - "metadata": {}, - "outputs": [], - "source": [ - "# install package\n", - "!pip install -U langchain-mongodb-atlas" - ] - }, - { - "cell_type": "markdown", - "id": "0ee90032", - "metadata": {}, - "source": [ - "## Environment Setup\n", - "\n", - "Make sure to set the following environment variables:\n", - "\n", - "- TODO: fill out relevant environment variables or secrets\n", - "\n", - "## Usage" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "035dea0f", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from langchain_core.prompts import PromptTemplate\n", - "from langchain_mongodb_atlas.llms import MongoDBAtlasLLM\n", - "\n", - "template = \"\"\"Question: {question}\n", - "\n", - "Answer: Let's think step by step.\"\"\"\n", - "\n", - "prompt = PromptTemplate.from_string(template)\n", - "\n", - "model = MongoDBAtlasLLM()\n", - "\n", - "chain = prompt | model\n", - "\n", - "chain.invoke({\"question\": \"What is LangChain?\"})" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.11.1 64-bit", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" - }, - "vscode": { - "interpreter": { - "hash": "e971737741ff4ec9aff7dc6155a1060a59a8a6d52c757dbbe66bf8ee389494b1" - } - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/libs/partners/mongodb-atlas/docs/provider.ipynb b/libs/partners/mongodb-atlas/docs/provider.ipynb deleted file mode 100644 index b3561967605ff2..00000000000000 --- a/libs/partners/mongodb-atlas/docs/provider.ipynb +++ /dev/null @@ -1,50 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# MongoDBAtlas\n", - "\n", - "MongoDBAtlas is a platform that offers..." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "id": "y8ku6X96sebl" - }, - "outputs": [], - "source": [ - "from langchain_mongodb_atlas.chat_models import MongoDBAtlasChat\n", - "from langchain_mongodb_atlas.llms import MongoDBAtlasLLM\n", - "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch" - ] - } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.11" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/libs/partners/mongodb-atlas/docs/text_embedding.ipynb b/libs/partners/mongodb-atlas/docs/text_embedding.ipynb deleted file mode 100644 index 83557caaa0e049..00000000000000 --- a/libs/partners/mongodb-atlas/docs/text_embedding.ipynb +++ /dev/null @@ -1,132 +0,0 @@ -{ - "cells": [ - { - "cell_type": "raw", - "id": "afaf8039", - "metadata": {}, - "source": [ - "---\n", - "sidebar_label: MongoDBAtlas\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "e49f1e0d", - "metadata": {}, - "source": [ - "# MongoDBAtlasEmbeddings\n", - "\n", - "This notebook covers how to get started with MongoDBAtlas embedding models.\n", - "\n", - "## Installation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4c3bef91", - "metadata": {}, - "outputs": [], - "source": [ - "# install package\n", - "!pip install -U langchain-mongodb-atlas" - ] - }, - { - "cell_type": "markdown", - "id": "2b4f3e15", - "metadata": {}, - "source": [ - "## Environment Setup\n", - "\n", - "Make sure to set the following environment variables:\n", - "\n", - "- TODO: fill out relevant environment variables or secrets\n", - "\n", - "## Usage" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62e0dbc3", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from langchain_mongodb_atlas.embeddings import MongoDBAtlasEmbeddings\n", - "\n", - "embeddings = MongoDBAtlasEmbeddings()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12fcfb4b", - "metadata": {}, - "outputs": [], - "source": [ - "embeddings.embed_query(\"My query to look up\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1f2e6104", - "metadata": {}, - "outputs": [], - "source": [ - "embeddings.embed_documents(\n", - " [\"This is a content of the document\", \"This is another document\"]\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "46739f68", - "metadata": {}, - "outputs": [], - "source": [ - "# async embed query\n", - "await embeddings.aembed_query(\"My query to look up\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e48632ea", - "metadata": {}, - "outputs": [], - "source": [ - "# async embed documents\n", - "await embeddings.aembed_documents(\n", - " [\"This is a content of the document\", \"This is another document\"]\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/libs/partners/mongodb-atlas/docs/vectorstores.ipynb b/libs/partners/mongodb-atlas/docs/vectorstores.ipynb deleted file mode 100644 index dd7c26a3dc3590..00000000000000 --- a/libs/partners/mongodb-atlas/docs/vectorstores.ipynb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "cells": [ - { - "cell_type": "raw", - "id": "1957f5cb", - "metadata": {}, - "source": [ - "---\n", - "sidebar_label: MongoDBAtlas\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "ef1f0986", - "metadata": {}, - "source": [ - "# MongoDBAtlasVectorSearch\n", - "\n", - "This notebook covers how to get started with the MongoDBAtlas vector store.\n", - "\n", - "## Installation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d97b55c2", - "metadata": {}, - "outputs": [], - "source": [ - "# install package\n", - "%pip install -U langchain-mongodb-atlas" - ] - }, - { - "cell_type": "markdown", - "id": "36fdc060", - "metadata": {}, - "source": [ - "# Environment Setup\n", - "\n", - "To use, you should have:\n", - "- the ``pymongo`` python package installed\n", - "- a MongoDB Atlas Server that supports [Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#limitations).\n", - " - To understand what \n", - "- a connection string associated with a MongoDB Atlas Cluster having deployed an\n", - " Atlas Search index\n", - "\n", - "\n", - "It's good practice to have this connection string retrieved as an environment variable to reduce the chance of having the URI appear in git commit history.\n", - "\n", - "## Usage" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dc37144c-208d-4ab3-9f3a-0407a69fe052", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "import os\n", - "\n", - "from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch\n", - "from langchain_community.embeddings.openai import OpenAIEmbeddings\n", - "from pymongo import MongoClient\n", - "\n", - "\n", - "mongo_client = MongoClient(os.environ.get(\"YOUR_CONNECTION_STRING\"))\n", - "collection = mongo_client[\"\"][\"\"]\n", - "embeddings = OpenAIEmbeddings()\n", - "vectorstore = MongoDBAtlasVectorSearch(collection, embeddings)\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 05d46e7af42bd8246894922e92c51056f2050006 Mon Sep 17 00:00:00 2001 From: Jib Date: Fri, 16 Feb 2024 14:46:04 -0500 Subject: [PATCH 04/22] make format --- .../mongodb-atlas/langchain_mongodb_atlas/__init__.py | 1 - .../mongodb-atlas/langchain_mongodb_atlas/vectorstores.py | 4 +--- .../tests/integration_tests/test_vectorstores.py | 6 ++---- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py index fc822693ef046d..7f2a0425a111db 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py @@ -2,7 +2,6 @@ MongoDBAtlasVectorSearch, ) - __all__ = [ "MongoDBAtlasVectorSearch", ] diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py index 568f2cc6c9947d..f022bf665d52c3 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py @@ -1,6 +1,5 @@ from __future__ import annotations - import logging from enum import Enum from typing import ( @@ -18,13 +17,12 @@ ) import numpy as np +from langchain_community.vectorstores.utils import maximal_marginal_relevance from langchain_core.documents import Document from langchain_core.embeddings import Embeddings from langchain_core.runnables.config import run_in_executor from langchain_core.vectorstores import VectorStore -from langchain_community.vectorstores.utils import maximal_marginal_relevance - if TYPE_CHECKING: from pymongo.collection import Collection diff --git a/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py index eedf6a9b4939bd..96c2d80d3badf3 100644 --- a/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py +++ b/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py @@ -7,15 +7,13 @@ from typing import Any import pytest - +from langchain_core.documents import Document +from langchain_core.embeddings import Embeddings from pymongo import MongoClient from pymongo.collection import Collection -from langchain_core.documents import Document -from langchain_core.embeddings import Embeddings from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch - INDEX_NAME = "langchain-test-index" NAMESPACE = "langchain_test_db.langchain_test_collection" CONNECTION_STRING = os.environ.get("MONGODB_ATLAS_URI") From 4e751d99f19840b195282ce7277bfea7a7b5ec6e Mon Sep 17 00:00:00 2001 From: Jib Date: Fri, 16 Feb 2024 15:41:37 -0500 Subject: [PATCH 05/22] make format && make lint --- .../langchain_mongodb_atlas/vectorstores.py | 15 ++++++----- .../tests/unit_tests/test_vectorstores.py | 26 +++++++++++++++++-- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py index f022bf665d52c3..601b319ea5518a 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -from enum import Enum from typing import ( TYPE_CHECKING, Any, @@ -388,11 +387,11 @@ def delete(self, ids: Optional[List[str]] = None, **kwargs: Any) -> Optional[boo Optional[bool]: True if deletion is successful, False otherwise, None if not implemented. """ - search_params = {self._text_key: {}} + search_params: dict[str, Any] = {} if ids: - search_params["$in"] = ids + search_params[self._text_key]["$in"] = ids - return self._collection.delete_many({**search_params, **kwargs}) + return self._collection.delete_many({**search_params, **kwargs}).acknowledged async def adelete( self, ids: Optional[List[str]] = None, **kwargs: Any @@ -409,7 +408,7 @@ async def adelete( """ return await run_in_executor(None, self.delete, ids=ids, **kwargs) - async def max_marginal_relevance_search_by_vector( + def max_marginal_relevance_search_by_vector( self, embedding: List[float], k: int = 4, @@ -418,7 +417,7 @@ async def max_marginal_relevance_search_by_vector( pre_filter: Optional[Dict] = None, post_filter_pipeline: Optional[List[Dict]] = None, **kwargs: Any, - ) -> List[Document]: + ) -> List[Document]: # type: ignore """Return docs selected using the maximal marginal relevance. Maximal marginal relevance optimizes for similarity to query AND diversity @@ -432,6 +431,10 @@ async def max_marginal_relevance_search_by_vector( of diversity among the results with 0 corresponding to maximum diversity and 1 to minimum diversity. Defaults to 0.5. + pre_filter: (Optional) dictionary of argument(s) to prefilter on document + fields. + post_filter_pipeline: (Optional) pipeline of MongoDB aggregation stages + following the vectorSearch stage. Returns: List of Documents selected by maximal marginal relevance. """ diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py index 5ebef57e2d23a3..2bd25166cde40d 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py @@ -1,6 +1,28 @@ +import os + +import pytest +from langchain_core.embeddings import Embeddings +from pymongo import MongoClient +from pymongo.collection import Collection + from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch +INDEX_NAME = "langchain-test-index" +NAMESPACE = "langchain_test_db.langchain_test_collection" +CONNECTION_STRING = os.environ.get("MONGODB_ATLAS_URI") +DB_NAME, COLLECTION_NAME = NAMESPACE.split(".") + + +def get_collection() -> Collection: + test_client: MongoClient = MongoClient(CONNECTION_STRING) + return test_client[DB_NAME][COLLECTION_NAME] + + +@pytest.fixture() +def collection() -> Collection: + return get_collection() + -def test_initialization(): +def test_initialization(collection: Collection, embedding_openai: Embeddings) -> None: """Test initialization of vector store class""" - MongoDBAtlasVectorSearch() + MongoDBAtlasVectorSearch(collection, embedding_openai) From ba82b0f48cb0309c5a73b0eb4be9b962d738bf67 Mon Sep 17 00:00:00 2001 From: Jib Date: Tue, 20 Feb 2024 11:05:34 -0500 Subject: [PATCH 06/22] added some more unit tests; removed duplicate import test statement --- .../tests/unit_tests/test_imports.py | 1 - .../tests/unit_tests/test_vectorstores.py | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py index bcbc01dc6f4cda..1ef962601cf75a 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py @@ -2,7 +2,6 @@ EXPECTED_ALL = [ "MongoDBAtlasVectorSearch", - "MongoDBAtlasVectorSearch", ] diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py index 2bd25166cde40d..1f35855b9d1787 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py @@ -25,4 +25,18 @@ def collection() -> Collection: def test_initialization(collection: Collection, embedding_openai: Embeddings) -> None: """Test initialization of vector store class""" - MongoDBAtlasVectorSearch(collection, embedding_openai) + assert MongoDBAtlasVectorSearch(collection, embedding_openai) + + +def test_init_from_connection_string(embedding_openai: Embeddings) -> None: + """Test initialization of vector store class""" + assert MongoDBAtlasVectorSearch.from_connection_string( + CONNECTION_STRING, NAMESPACE, embedding_openai + ) + + +def test_init_from_texts(collection: Collection, embedding_openai: Embeddings) -> None: + """Test from_texts operation on an empty list""" + assert MongoDBAtlasVectorSearch.from_texts( + [], embedding_openai, collection=collection + ) From 0921e472cf2d5d122441b455041e7e3138188dbb Mon Sep 17 00:00:00 2001 From: Jib Date: Tue, 20 Feb 2024 13:49:31 -0500 Subject: [PATCH 07/22] deprecate langchain_community implementation --- .../langchain_community/vectorstores/mongodb_atlas.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/community/langchain_community/vectorstores/mongodb_atlas.py b/libs/community/langchain_community/vectorstores/mongodb_atlas.py index 2e18f4280fa8be..ea776e59c64c9a 100644 --- a/libs/community/langchain_community/vectorstores/mongodb_atlas.py +++ b/libs/community/langchain_community/vectorstores/mongodb_atlas.py @@ -19,6 +19,7 @@ from langchain_core.documents import Document from langchain_core.embeddings import Embeddings from langchain_core.vectorstores import VectorStore +from langchain_core._api.deprecation import deprecated from langchain_community.vectorstores.utils import maximal_marginal_relevance @@ -32,6 +33,11 @@ DEFAULT_INSERT_BATCH_SIZE = 100 +@deprecated( + since="0.1.8", + removal="0.2.0", + alternative_import="langchain_mongodb_atlas.MongoDBAtlasVectorSearch", +) class MongoDBAtlasVectorSearch(VectorStore): """`MongoDB Atlas Vector Search` vector store. From 40ee1acaf4fb4140a2021ff5871aa2b8c864fc27 Mon Sep 17 00:00:00 2001 From: Jib Date: Wed, 21 Feb 2024 14:53:00 -0500 Subject: [PATCH 08/22] updated the README.md to include usage instructions; 'beefed up' unit tests with mocks --- libs/partners/mongodb-atlas/README.md | 39 +++ .../langchain_mongodb_atlas/vectorstores.py | 1 - .../tests/unit_tests/test_vectorstores.py | 240 +++++++++++++++++- 3 files changed, 265 insertions(+), 15 deletions(-) diff --git a/libs/partners/mongodb-atlas/README.md b/libs/partners/mongodb-atlas/README.md index 1090f6f0b4bd5c..676ceb4dd00e3b 100644 --- a/libs/partners/mongodb-atlas/README.md +++ b/libs/partners/mongodb-atlas/README.md @@ -1 +1,40 @@ # langchain-mongodb-atlas + +# Installation +``` +pip install -U langchain-mongodb-atlas +``` + +# Usage +- See [integrations doc](../../../docs/docs/integrations/vectorstores/mongodb_atlas.ipynb) for more in-depth usage instructions. +- See [Getting Started with the LangChain Integration](https://www.mongodb.com/docs/atlas/atlas-vector-search/ai-integrations/langchain/#get-started-with-the-langchain-integration) for a walkthrough on using your first LangChain implementation with MongoDB Atlas. + +## Using MongoDBAtlasVectorSearch +```python +from langchain_community.vectorstores import MongoDBAtlasVectorSearch + +# Pull MongoDB Atlas URI from environment variables +MONGODB_ATLAS_CLUSTER_URI = os.environ.get("MONGODB_ATLAS_CLUSTER_URI") + +DB_NAME = "langchain_db" +COLLECTION_NAME = "test" +ATLAS_VECTOR_SEARCH_INDEX_NAME = "index_name" +MONGODB_COLLECTION = client[DB_NAME][COLLECITON_NAME] + +# Create the vector search via `from_connection_string` +vector_search = MongoDBAtlasVectorSearch.from_connection_string( + MONGODB_ATLAS_CLUSTER_URI, + DB_NAME + "." + COLLECTION_NAME, + OpenAIEmbeddings(disallowed_special=()), + index_name=ATLAS_VECTOR_SEARCH_INDEX_NAME, +) + +# initialize MongoDB python client +client = MongoClient(MONGODB_ATLAS_CLUSTER_URI) +# Create the vector search via instantiation +vector_search_2 = MongoDBAtlasVectorSearch( + collection=MONGODB_COLLECTION, + embeddings=OpenAIEmbeddings(disallowed_special=()), + index_name=ATLAS_VECTOR_SEARCH_INDEX_NAME, +) +``` \ No newline at end of file diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py index 601b319ea5518a..cab2e849e70e62 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py @@ -215,7 +215,6 @@ def _similarity_search_with_score( for res in cursor: text = res.pop(self._text_key) score = res.pop("score") - del res[self._embedding_key] docs.append((Document(page_content=text, metadata=res), score)) return docs diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py index 1f35855b9d1787..05ca5a1a050429 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py @@ -1,38 +1,104 @@ -import os +import uuid +from copy import deepcopy +from typing import Any, List, Optional import pytest +from langchain_core.documents import Document from langchain_core.embeddings import Embeddings -from pymongo import MongoClient from pymongo.collection import Collection +from pymongo.results import DeleteResult, InsertManyResult from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch INDEX_NAME = "langchain-test-index" NAMESPACE = "langchain_test_db.langchain_test_collection" -CONNECTION_STRING = os.environ.get("MONGODB_ATLAS_URI") DB_NAME, COLLECTION_NAME = NAMESPACE.split(".") -def get_collection() -> Collection: - test_client: MongoClient = MongoClient(CONNECTION_STRING) - return test_client[DB_NAME][COLLECTION_NAME] +class ConsistentFakeEmbeddings(Embeddings): + """Fake embeddings functionality for testing.""" + + def __init__(self, dimensionality: int = 10) -> None: + self.known_texts: List[str] = [] + self.dimensionality = dimensionality + + def embed_documents(self, texts: List[str]) -> List[List[float]]: + """Return consistent embeddings for each text seen so far.""" + out_vectors = [] + for text in texts: + if text not in self.known_texts: + self.known_texts.append(text) + vector = [float(1.0)] * (self.dimensionality - 1) + [ + float(self.known_texts.index(text)) + ] + out_vectors.append(vector) + return out_vectors + + def embed_query(self, text: str) -> List[float]: + """Return consistent embeddings for the text, if seen before, or a constant + one if the text is unknown.""" + return self.embed_documents([text])[0] + + async def aembed_documents(self, texts: List[str]) -> List[List[float]]: + return self.embed_documents(texts) + + async def aembed_query(self, text: str) -> List[float]: + return self.embed_query(text) + + +class MockCollection(Collection): + """Mocked Mongo Collection""" + + _aggregate_result: list[Any] + _insert_result: Optional[InsertManyResult] + _data: list[Any] + + def __init__(self) -> None: + self._data = [] + self._aggregate_result = [] + self._insert_result = None + + def delete_many(self, *args, **kwargs) -> DeleteResult: # type: ignore + old_len = len(self._data) + self._data = [] + return DeleteResult({"n": old_len}, acknowledged=True) + + def insert_many(self, to_insert: list[Any], *args, **kwargs) -> InsertManyResult: # type: ignore + mongodb_inserts = [ + {"_id": str(uuid.uuid4()), "score": 1, **insert} for insert in to_insert + ] + self._data.extend(mongodb_inserts) + return self._insert_result or InsertManyResult( + [k["_id"] for k in mongodb_inserts], acknowledged=True + ) + + def aggregate(self, *args, **kwargs) -> list[Any]: # type: ignore + return deepcopy(self._aggregate_result) + + def count_documents(self, *args, **kwargs) -> int: # type: ignore + return len(self._data) + + def __repr__(self) -> str: + return "FakeCollection" + + +def get_collection() -> MockCollection: + return MockCollection() @pytest.fixture() -def collection() -> Collection: +def collection() -> MockCollection: return get_collection() -def test_initialization(collection: Collection, embedding_openai: Embeddings) -> None: - """Test initialization of vector store class""" - assert MongoDBAtlasVectorSearch(collection, embedding_openai) +@pytest.fixture() +def embedding_openai() -> Embeddings: + return ConsistentFakeEmbeddings() -def test_init_from_connection_string(embedding_openai: Embeddings) -> None: +def test_initialization(collection: Collection, embedding_openai: Embeddings) -> None: """Test initialization of vector store class""" - assert MongoDBAtlasVectorSearch.from_connection_string( - CONNECTION_STRING, NAMESPACE, embedding_openai - ) + assert MongoDBAtlasVectorSearch(collection, embedding_openai) def test_init_from_texts(collection: Collection, embedding_openai: Embeddings) -> None: @@ -40,3 +106,149 @@ def test_init_from_texts(collection: Collection, embedding_openai: Embeddings) - assert MongoDBAtlasVectorSearch.from_texts( [], embedding_openai, collection=collection ) + + +class TestMongoDBAtlasVectorSearch: + @classmethod + def setup_class(cls) -> None: + # ensure the test collection is empty + collection = get_collection() + assert collection.count_documents({}) == 0 # type: ignore[index] # noqa: E501 + + @classmethod + def teardown_class(cls) -> None: + collection = get_collection() + # delete all the documents in the collection + collection.delete_many({}) # type: ignore[index] + + @pytest.fixture(autouse=True) + def setup(self) -> None: + collection = get_collection() + # delete all the documents in the collection + collection.delete_many({}) # type: ignore[index] + + def _validate_search( + self, + vectorstore: MongoDBAtlasVectorSearch, + collection: MockCollection, + search_term: str = "sandwich", + page_content: str = "What is a sandwich?", + metadata: Optional[Any] = 1, + ) -> None: + collection._aggregate_result = list( + filter( + lambda x: search_term.lower() in x[vectorstore._text_key].lower(), + collection._data, + ) + ) + output = vectorstore.similarity_search("", k=1) + assert output[0].page_content == page_content + assert output[0].metadata.get("c") == metadata + + def test_from_documents( + self, embedding_openai: Embeddings, collection: MockCollection + ) -> None: + """Test end to end construction and search.""" + documents = [ + Document(page_content="Dogs are tough.", metadata={"a": 1}), + Document(page_content="Cats have fluff.", metadata={"b": 1}), + Document(page_content="What is a sandwich?", metadata={"c": 1}), + Document(page_content="That fence is purple.", metadata={"d": 1, "e": 2}), + ] + vectorstore = MongoDBAtlasVectorSearch.from_documents( + documents, + embedding_openai, + collection=collection, + index_name=INDEX_NAME, + ) + self._validate_search( + vectorstore, collection, metadata=documents[2].metadata["c"] + ) + + def test_from_texts( + self, embedding_openai: Embeddings, collection: MockCollection + ) -> None: + texts = [ + "Dogs are tough.", + "Cats have fluff.", + "What is a sandwich?", + "That fence is purple.", + ] + vectorstore = MongoDBAtlasVectorSearch.from_texts( + texts, + embedding_openai, + collection=collection, + index_name=INDEX_NAME, + ) + self._validate_search(vectorstore, collection, metadata=None) + + def test_from_texts_with_metadatas( + self, embedding_openai: Embeddings, collection: MockCollection + ) -> None: + texts = [ + "Dogs are tough.", + "Cats have fluff.", + "What is a sandwich?", + "The fence is purple.", + ] + metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] + vectorstore = MongoDBAtlasVectorSearch.from_texts( + texts, + embedding_openai, + metadatas=metadatas, + collection=collection, + index_name=INDEX_NAME, + ) + self._validate_search(vectorstore, collection, metadata=metadatas[2]["c"]) + + def test_from_texts_with_metadatas_and_pre_filter( + self, embedding_openai: Embeddings, collection: MockCollection + ) -> None: + texts = [ + "Dogs are tough.", + "Cats have fluff.", + "What is a sandwich?", + "The fence is purple.", + ] + metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] + vectorstore = MongoDBAtlasVectorSearch.from_texts( + texts, + embedding_openai, + metadatas=metadatas, + collection=collection, + index_name=INDEX_NAME, + ) + collection._aggregate_result = list( + filter( + lambda x: "sandwich" in x[vectorstore._text_key].lower() + and x.get("c") < 0, + collection._data, + ) + ) + output = vectorstore.similarity_search( + "Sandwich", k=1, pre_filter={"range": {"lte": 0, "path": "c"}} + ) + assert output == [] + + def test_mmr( + self, embedding_openai: Embeddings, collection: MockCollection + ) -> None: + texts = ["foo", "foo", "fou", "foy"] + vectorstore = MongoDBAtlasVectorSearch.from_texts( + texts, + embedding_openai, + collection=collection, + index_name=INDEX_NAME, + ) + query = "foo" + self._validate_search( + vectorstore, + collection, + search_term=query[0:2], + page_content=query, + metadata=None, + ) + output = vectorstore.max_marginal_relevance_search(query, k=10, lambda_mult=0.1) + assert len(output) == len(texts) + assert output[0].page_content == "foo" + assert output[1].page_content != "foo" From e0c81e1cb0ede673a69aae6434e17e34868c3bcc Mon Sep 17 00:00:00 2001 From: Jib Date: Wed, 21 Feb 2024 14:57:56 -0500 Subject: [PATCH 09/22] set batch sizing back to 100 --- .../mongodb-atlas/langchain_mongodb_atlas/vectorstores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py index cab2e849e70e62..ec791737fe2829 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py +++ b/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py @@ -30,7 +30,7 @@ logger = logging.getLogger(__name__) -DEFAULT_INSERT_BATCH_SIZE = 1000 +DEFAULT_INSERT_BATCH_SIZE = 100 class MongoDBAtlasVectorSearch(VectorStore): From bde5a3c3035f038c5cd0a61acda40ed763e898f6 Mon Sep 17 00:00:00 2001 From: Jib Date: Fri, 23 Feb 2024 09:38:34 -0500 Subject: [PATCH 10/22] Update libs/partners/mongodb-atlas/README.md Co-authored-by: Steven Silvester --- libs/partners/mongodb-atlas/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/partners/mongodb-atlas/README.md b/libs/partners/mongodb-atlas/README.md index 676ceb4dd00e3b..15d06dff6fc9f9 100644 --- a/libs/partners/mongodb-atlas/README.md +++ b/libs/partners/mongodb-atlas/README.md @@ -29,7 +29,7 @@ vector_search = MongoDBAtlasVectorSearch.from_connection_string( index_name=ATLAS_VECTOR_SEARCH_INDEX_NAME, ) -# initialize MongoDB python client +# Initialize MongoDB python client client = MongoClient(MONGODB_ATLAS_CLUSTER_URI) # Create the vector search via instantiation vector_search_2 = MongoDBAtlasVectorSearch( From b156250f91d8673a12df1ba40f2e76b36d076f9d Mon Sep 17 00:00:00 2001 From: Jib Date: Wed, 28 Feb 2024 11:11:50 -0500 Subject: [PATCH 11/22] rename mongodb-atlas -> mongodb; update dependencies --- .../{mongodb-atlas => mongodb}/.gitignore | 0 .../{mongodb-atlas => mongodb}/LICENSE | 0 .../{mongodb-atlas => mongodb}/Makefile | 6 +- .../{mongodb-atlas => mongodb}/README.md | 8 +- .../langchain_mongodb}/__init__.py | 2 +- .../langchain_mongodb}/py.typed | 0 .../mongodb/langchain_mongodb/utils.py | 87 +++++++++++++++++++ .../langchain_mongodb}/vectorstores.py | 19 ++-- .../{mongodb-atlas => mongodb}/poetry.lock | 0 .../{mongodb-atlas => mongodb}/pyproject.toml | 10 ++- .../scripts/check_imports.py | 0 .../scripts/check_pydantic.sh | 0 .../scripts/lint_imports.sh | 0 .../tests/__init__.py | 0 .../tests/integration_tests/__init__.py | 0 .../integration_tests/test_vectorstores.py | 2 +- .../tests/unit_tests/__init__.py | 0 .../tests/unit_tests/test_imports.py | 2 +- .../tests/unit_tests/test_vectorstores.py | 2 +- 19 files changed, 109 insertions(+), 29 deletions(-) rename libs/partners/{mongodb-atlas => mongodb}/.gitignore (100%) rename libs/partners/{mongodb-atlas => mongodb}/LICENSE (100%) rename libs/partners/{mongodb-atlas => mongodb}/Makefile (88%) rename libs/partners/{mongodb-atlas => mongodb}/README.md (86%) rename libs/partners/{mongodb-atlas/langchain_mongodb_atlas => mongodb/langchain_mongodb}/__init__.py (60%) rename libs/partners/{mongodb-atlas/langchain_mongodb_atlas => mongodb/langchain_mongodb}/py.typed (100%) create mode 100644 libs/partners/mongodb/langchain_mongodb/utils.py rename libs/partners/{mongodb-atlas/langchain_mongodb_atlas => mongodb/langchain_mongodb}/vectorstores.py (97%) rename libs/partners/{mongodb-atlas => mongodb}/poetry.lock (100%) rename libs/partners/{mongodb-atlas => mongodb}/pyproject.toml (92%) rename libs/partners/{mongodb-atlas => mongodb}/scripts/check_imports.py (100%) rename libs/partners/{mongodb-atlas => mongodb}/scripts/check_pydantic.sh (100%) rename libs/partners/{mongodb-atlas => mongodb}/scripts/lint_imports.sh (100%) rename libs/partners/{mongodb-atlas => mongodb}/tests/__init__.py (100%) rename libs/partners/{mongodb-atlas => mongodb}/tests/integration_tests/__init__.py (100%) rename libs/partners/{mongodb-atlas => mongodb}/tests/integration_tests/test_vectorstores.py (98%) rename libs/partners/{mongodb-atlas => mongodb}/tests/unit_tests/__init__.py (100%) rename libs/partners/{mongodb-atlas => mongodb}/tests/unit_tests/test_imports.py (75%) rename libs/partners/{mongodb-atlas => mongodb}/tests/unit_tests/test_vectorstores.py (99%) diff --git a/libs/partners/mongodb-atlas/.gitignore b/libs/partners/mongodb/.gitignore similarity index 100% rename from libs/partners/mongodb-atlas/.gitignore rename to libs/partners/mongodb/.gitignore diff --git a/libs/partners/mongodb-atlas/LICENSE b/libs/partners/mongodb/LICENSE similarity index 100% rename from libs/partners/mongodb-atlas/LICENSE rename to libs/partners/mongodb/LICENSE diff --git a/libs/partners/mongodb-atlas/Makefile b/libs/partners/mongodb/Makefile similarity index 88% rename from libs/partners/mongodb-atlas/Makefile rename to libs/partners/mongodb/Makefile index 50f03891b363ab..c65db99a407217 100644 --- a/libs/partners/mongodb-atlas/Makefile +++ b/libs/partners/mongodb/Makefile @@ -21,8 +21,8 @@ tests: PYTHON_FILES=. MYPY_CACHE=.mypy_cache lint format: PYTHON_FILES=. -lint_diff format_diff: PYTHON_FILES=$(shell git diff --relative=libs/partners/mongodb-atlas --name-only --diff-filter=d master | grep -E '\.py$$|\.ipynb$$') -lint_package: PYTHON_FILES=langchain_mongodb_atlas +lint_diff format_diff: PYTHON_FILES=$(shell git diff --relative=libs/partners/mongodb --name-only --diff-filter=d master | grep -E '\.py$$|\.ipynb$$') +lint_package: PYTHON_FILES=langchain_mongodb lint_tests: PYTHON_FILES=tests lint_tests: MYPY_CACHE=.mypy_cache_test @@ -42,7 +42,7 @@ spell_check: spell_fix: poetry run codespell --toml pyproject.toml -w -check_imports: $(shell find langchain_mongodb_atlas -name '*.py') +check_imports: $(shell find langchain_mongodb -name '*.py') poetry run python ./scripts/check_imports.py $^ ###################### diff --git a/libs/partners/mongodb-atlas/README.md b/libs/partners/mongodb/README.md similarity index 86% rename from libs/partners/mongodb-atlas/README.md rename to libs/partners/mongodb/README.md index 15d06dff6fc9f9..7c6373380b93db 100644 --- a/libs/partners/mongodb-atlas/README.md +++ b/libs/partners/mongodb/README.md @@ -1,17 +1,17 @@ -# langchain-mongodb-atlas +# langchain-mongodb # Installation ``` -pip install -U langchain-mongodb-atlas +pip install -U langchain-mongodb ``` # Usage -- See [integrations doc](../../../docs/docs/integrations/vectorstores/mongodb_atlas.ipynb) for more in-depth usage instructions. +- See [integrations doc](../../../docs/docs/integrations/vectorstores/mongodb.ipynb) for more in-depth usage instructions. - See [Getting Started with the LangChain Integration](https://www.mongodb.com/docs/atlas/atlas-vector-search/ai-integrations/langchain/#get-started-with-the-langchain-integration) for a walkthrough on using your first LangChain implementation with MongoDB Atlas. ## Using MongoDBAtlasVectorSearch ```python -from langchain_community.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch # Pull MongoDB Atlas URI from environment variables MONGODB_ATLAS_CLUSTER_URI = os.environ.get("MONGODB_ATLAS_CLUSTER_URI") diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py b/libs/partners/mongodb/langchain_mongodb/__init__.py similarity index 60% rename from libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py rename to libs/partners/mongodb/langchain_mongodb/__init__.py index 7f2a0425a111db..75c1cdc8cbcc7c 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/__init__.py +++ b/libs/partners/mongodb/langchain_mongodb/__init__.py @@ -1,4 +1,4 @@ -from langchain_mongodb_atlas.vectorstores import ( +from langchain_mongodb.vectorstores import ( MongoDBAtlasVectorSearch, ) diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/py.typed b/libs/partners/mongodb/langchain_mongodb/py.typed similarity index 100% rename from libs/partners/mongodb-atlas/langchain_mongodb_atlas/py.typed rename to libs/partners/mongodb/langchain_mongodb/py.typed diff --git a/libs/partners/mongodb/langchain_mongodb/utils.py b/libs/partners/mongodb/langchain_mongodb/utils.py new file mode 100644 index 00000000000000..feb34ad1c23d61 --- /dev/null +++ b/libs/partners/mongodb/langchain_mongodb/utils.py @@ -0,0 +1,87 @@ +""" +Tools for the Maximal Marginal Relevance (MMR) reranking. +Duplicated from langchain_community to avoid cross-dependencies. + +Functions "maximal_marginal_relevance" and "cosine_similarity" +are duplicated in this utility respectively from modules: + - "libs/community/langchain_community/vectorstores/utils.py" + - "libs/community/langchain_community/utils/math.py" +""" + +import logging +from typing import List, Union + +import numpy as np + +logger = logging.getLogger(__name__) + +Matrix = Union[List[List[float]], List[np.ndarray], np.ndarray] + + +def cosine_similarity(X: Matrix, Y: Matrix) -> np.ndarray: + """Row-wise cosine similarity between two equal-width matrices.""" + if len(X) == 0 or len(Y) == 0: + return np.array([]) + + X = np.array(X) + Y = np.array(Y) + if X.shape[1] != Y.shape[1]: + raise ValueError( + f"Number of columns in X and Y must be the same. X has shape {X.shape} " + f"and Y has shape {Y.shape}." + ) + try: + import simsimd as simd # type: ignore + + X = np.array(X, dtype=np.float32) + Y = np.array(Y, dtype=np.float32) + Z = 1 - simd.cdist(X, Y, metric="cosine") + if isinstance(Z, float): + return np.array([Z]) + return Z + except ImportError: + logger.info( + "Unable to import simsimd, defaulting to NumPy implementation. If you want " + "to use simsimd please install with `pip install simsimd`." + ) + X_norm = np.linalg.norm(X, axis=1) + Y_norm = np.linalg.norm(Y, axis=1) + # Ignore divide by zero errors run time warnings as those are handled below. + with np.errstate(divide="ignore", invalid="ignore"): + similarity = np.dot(X, Y.T) / np.outer(X_norm, Y_norm) + similarity[np.isnan(similarity) | np.isinf(similarity)] = 0.0 + return similarity + + +def maximal_marginal_relevance( + query_embedding: np.ndarray, + embedding_list: list, + lambda_mult: float = 0.5, + k: int = 4, +) -> List[int]: + """Calculate maximal marginal relevance.""" + if min(k, len(embedding_list)) <= 0: + return [] + if query_embedding.ndim == 1: + query_embedding = np.expand_dims(query_embedding, axis=0) + similarity_to_query = cosine_similarity(query_embedding, embedding_list)[0] + most_similar = int(np.argmax(similarity_to_query)) + idxs = [most_similar] + selected = np.array([embedding_list[most_similar]]) + while len(idxs) < min(k, len(embedding_list)): + best_score = -np.inf + idx_to_add = -1 + similarity_to_selected = cosine_similarity(embedding_list, selected) + for i, query_score in enumerate(similarity_to_query): + if i in idxs: + continue + redundant_score = max(similarity_to_selected[i]) + equation_score = ( + lambda_mult * query_score - (1 - lambda_mult) * redundant_score + ) + if equation_score > best_score: + best_score = equation_score + idx_to_add = i + idxs.append(idx_to_add) + selected = np.append(selected, [embedding_list[idx_to_add]], axis=0) + return idxs diff --git a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py b/libs/partners/mongodb/langchain_mongodb/vectorstores.py similarity index 97% rename from libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py rename to libs/partners/mongodb/langchain_mongodb/vectorstores.py index ec791737fe2829..afec8230713f0a 100644 --- a/libs/partners/mongodb-atlas/langchain_mongodb_atlas/vectorstores.py +++ b/libs/partners/mongodb/langchain_mongodb/vectorstores.py @@ -1,8 +1,8 @@ from __future__ import annotations import logging +from importlib.metadata import version from typing import ( - TYPE_CHECKING, Any, Callable, Dict, @@ -16,14 +16,15 @@ ) import numpy as np -from langchain_community.vectorstores.utils import maximal_marginal_relevance from langchain_core.documents import Document from langchain_core.embeddings import Embeddings from langchain_core.runnables.config import run_in_executor from langchain_core.vectorstores import VectorStore +from pymongo import MongoClient +from pymongo.collection import Collection +from pymongo.driver_info import DriverInfo -if TYPE_CHECKING: - from pymongo.collection import Collection +from langchain_mongodb.utils import maximal_marginal_relevance MongoDBDocumentType = TypeVar("MongoDBDocumentType", bound=Dict[str, Any]) VST = TypeVar("VST", bound=VectorStore) @@ -124,16 +125,6 @@ def from_connection_string( A new MongoDBAtlasVectorSearch instance. """ - try: - from importlib.metadata import version - - from pymongo import MongoClient - from pymongo.driver_info import DriverInfo - except ImportError: - raise ImportError( - "Could not import pymongo, please install it with " - "`pip install pymongo`." - ) client: MongoClient = MongoClient( connection_string, driver=DriverInfo(name="Langchain", version=version("langchain")), diff --git a/libs/partners/mongodb-atlas/poetry.lock b/libs/partners/mongodb/poetry.lock similarity index 100% rename from libs/partners/mongodb-atlas/poetry.lock rename to libs/partners/mongodb/poetry.lock diff --git a/libs/partners/mongodb-atlas/pyproject.toml b/libs/partners/mongodb/pyproject.toml similarity index 92% rename from libs/partners/mongodb-atlas/pyproject.toml rename to libs/partners/mongodb/pyproject.toml index f850b10a008d5e..7967fd641ba4d1 100644 --- a/libs/partners/mongodb-atlas/pyproject.toml +++ b/libs/partners/mongodb/pyproject.toml @@ -1,18 +1,20 @@ [tool.poetry] -name = "langchain-mongodb-atlas" +name = "langchain-mongodb" version = "0.0.1" -description = "An integration package connecting MongoDBAtlas and LangChain" +description = "An integration package connecting MongoDB and LangChain" authors = [] readme = "README.md" repository = "https://github.com/langchain-ai/langchain" license = "MIT" [tool.poetry.urls] -"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/partners/mongodb-atlas" +"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/partners/mongodb" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" -langchain-core = ">=0.0.12" +pymongo = ">=4.6.1,<5.0" +langchain-core = "^0.1" +numpy = "^1" [tool.poetry.group.test] optional = true diff --git a/libs/partners/mongodb-atlas/scripts/check_imports.py b/libs/partners/mongodb/scripts/check_imports.py similarity index 100% rename from libs/partners/mongodb-atlas/scripts/check_imports.py rename to libs/partners/mongodb/scripts/check_imports.py diff --git a/libs/partners/mongodb-atlas/scripts/check_pydantic.sh b/libs/partners/mongodb/scripts/check_pydantic.sh similarity index 100% rename from libs/partners/mongodb-atlas/scripts/check_pydantic.sh rename to libs/partners/mongodb/scripts/check_pydantic.sh diff --git a/libs/partners/mongodb-atlas/scripts/lint_imports.sh b/libs/partners/mongodb/scripts/lint_imports.sh similarity index 100% rename from libs/partners/mongodb-atlas/scripts/lint_imports.sh rename to libs/partners/mongodb/scripts/lint_imports.sh diff --git a/libs/partners/mongodb-atlas/tests/__init__.py b/libs/partners/mongodb/tests/__init__.py similarity index 100% rename from libs/partners/mongodb-atlas/tests/__init__.py rename to libs/partners/mongodb/tests/__init__.py diff --git a/libs/partners/mongodb-atlas/tests/integration_tests/__init__.py b/libs/partners/mongodb/tests/integration_tests/__init__.py similarity index 100% rename from libs/partners/mongodb-atlas/tests/integration_tests/__init__.py rename to libs/partners/mongodb/tests/integration_tests/__init__.py diff --git a/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py b/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py similarity index 98% rename from libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py rename to libs/partners/mongodb/tests/integration_tests/test_vectorstores.py index 96c2d80d3badf3..ae369d82722be5 100644 --- a/libs/partners/mongodb-atlas/tests/integration_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py @@ -12,7 +12,7 @@ from pymongo import MongoClient from pymongo.collection import Collection -from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch INDEX_NAME = "langchain-test-index" NAMESPACE = "langchain_test_db.langchain_test_collection" diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/__init__.py b/libs/partners/mongodb/tests/unit_tests/__init__.py similarity index 100% rename from libs/partners/mongodb-atlas/tests/unit_tests/__init__.py rename to libs/partners/mongodb/tests/unit_tests/__init__.py diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py b/libs/partners/mongodb/tests/unit_tests/test_imports.py similarity index 75% rename from libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py rename to libs/partners/mongodb/tests/unit_tests/test_imports.py index 1ef962601cf75a..1a05cf909fe4d9 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_imports.py +++ b/libs/partners/mongodb/tests/unit_tests/test_imports.py @@ -1,4 +1,4 @@ -from langchain_mongodb_atlas import __all__ +from langchain_mongodb import __all__ EXPECTED_ALL = [ "MongoDBAtlasVectorSearch", diff --git a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py similarity index 99% rename from libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py rename to libs/partners/mongodb/tests/unit_tests/test_vectorstores.py index 05ca5a1a050429..c2f68d10393363 100644 --- a/libs/partners/mongodb-atlas/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py @@ -8,7 +8,7 @@ from pymongo.collection import Collection from pymongo.results import DeleteResult, InsertManyResult -from langchain_mongodb_atlas.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch INDEX_NAME = "langchain-test-index" NAMESPACE = "langchain_test_db.langchain_test_collection" From fc368190dba76626a23dd1e287c9c22b7f40ad59 Mon Sep 17 00:00:00 2001 From: Jib Date: Wed, 28 Feb 2024 11:42:09 -0500 Subject: [PATCH 12/22] updaetd poetry.lock --- libs/partners/mongodb/poetry.lock | 232 +++++++++++++++++++++++++++++- 1 file changed, 226 insertions(+), 6 deletions(-) diff --git a/libs/partners/mongodb/poetry.lock b/libs/partners/mongodb/poetry.lock index 635e4d7c39afea..392c73c0afe528 100644 --- a/libs/partners/mongodb/poetry.lock +++ b/libs/partners/mongodb/poetry.lock @@ -174,6 +174,26 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "dnspython" +version = "2.6.1" +description = "DNS toolkit" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, +] + +[package.extras] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=0.9.25)"] +idna = ["idna (>=3.6)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] + [[package]] name = "exceptiongroup" version = "1.2.0" @@ -251,7 +271,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.1.23" +version = "0.1.24" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" @@ -261,7 +281,7 @@ develop = true [package.dependencies] anyio = ">=3,<5" jsonpatch = "^1.33" -langsmith = "^0.0.87" +langsmith = "^0.1.0" packaging = "^23.2" pydantic = ">=1,<3" PyYAML = ">=5.3" @@ -277,16 +297,17 @@ url = "../../core" [[package]] name = "langsmith" -version = "0.0.87" +version = "0.1.10" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, - {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, + {file = "langsmith-0.1.10-py3-none-any.whl", hash = "sha256:2997a80aea60ed235d83502a7ccdc1f62ffb4dd6b3b7dd4218e8fa4de68a6725"}, + {file = "langsmith-0.1.10.tar.gz", hash = "sha256:13e7e8b52e694aa4003370cefbb9e79cce3540c65dbf1517902bf7aa4dbbb653"}, ] [package.dependencies] +orjson = ">=3.9.14,<4.0.0" pydantic = ">=1,<3" requests = ">=2,<3" @@ -351,6 +372,102 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "numpy" +version = "1.24.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "orjson" +version = "3.9.15" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orjson-3.9.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d61f7ce4727a9fa7680cd6f3986b0e2c732639f46a5e0156e550e35258aa313a"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4feeb41882e8aa17634b589533baafdceb387e01e117b1ec65534ec724023d04"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fbbeb3c9b2edb5fd044b2a070f127a0ac456ffd079cb82746fc84af01ef021a4"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b66bcc5670e8a6b78f0313bcb74774c8291f6f8aeef10fe70e910b8040f3ab75"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2973474811db7b35c30248d1129c64fd2bdf40d57d84beed2a9a379a6f57d0ab"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fe41b6f72f52d3da4db524c8653e46243c8c92df826ab5ffaece2dba9cccd58"}, + {file = "orjson-3.9.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4228aace81781cc9d05a3ec3a6d2673a1ad0d8725b4e915f1089803e9efd2b99"}, + {file = "orjson-3.9.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f7b65bfaf69493c73423ce9db66cfe9138b2f9ef62897486417a8fcb0a92bfe"}, + {file = "orjson-3.9.15-cp310-none-win32.whl", hash = "sha256:2d99e3c4c13a7b0fb3792cc04c2829c9db07838fb6973e578b85c1745e7d0ce7"}, + {file = "orjson-3.9.15-cp310-none-win_amd64.whl", hash = "sha256:b725da33e6e58e4a5d27958568484aa766e825e93aa20c26c91168be58e08cbb"}, + {file = "orjson-3.9.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c8e8fe01e435005d4421f183038fc70ca85d2c1e490f51fb972db92af6e047c2"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87f1097acb569dde17f246faa268759a71a2cb8c96dd392cd25c668b104cad2f"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff0f9913d82e1d1fadbd976424c316fbc4d9c525c81d047bbdd16bd27dd98cfc"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8055ec598605b0077e29652ccfe9372247474375e0e3f5775c91d9434e12d6b1"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6768a327ea1ba44c9114dba5fdda4a214bdb70129065cd0807eb5f010bfcbb5"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12365576039b1a5a47df01aadb353b68223da413e2e7f98c02403061aad34bde"}, + {file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:71c6b009d431b3839d7c14c3af86788b3cfac41e969e3e1c22f8a6ea13139404"}, + {file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e18668f1bd39e69b7fed19fa7cd1cd110a121ec25439328b5c89934e6d30d357"}, + {file = "orjson-3.9.15-cp311-none-win32.whl", hash = "sha256:62482873e0289cf7313461009bf62ac8b2e54bc6f00c6fabcde785709231a5d7"}, + {file = "orjson-3.9.15-cp311-none-win_amd64.whl", hash = "sha256:b3d336ed75d17c7b1af233a6561cf421dee41d9204aa3cfcc6c9c65cd5bb69a8"}, + {file = "orjson-3.9.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:82425dd5c7bd3adfe4e94c78e27e2fa02971750c2b7ffba648b0f5d5cc016a73"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c51378d4a8255b2e7c1e5cc430644f0939539deddfa77f6fac7b56a9784160a"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6ae4e06be04dc00618247c4ae3f7c3e561d5bc19ab6941427f6d3722a0875ef7"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcef128f970bb63ecf9a65f7beafd9b55e3aaf0efc271a4154050fc15cdb386e"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b72758f3ffc36ca566ba98a8e7f4f373b6c17c646ff8ad9b21ad10c29186f00d"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c57bc7b946cf2efa67ac55766e41764b66d40cbd9489041e637c1304400494"}, + {file = "orjson-3.9.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:946c3a1ef25338e78107fba746f299f926db408d34553b4754e90a7de1d44068"}, + {file = "orjson-3.9.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2f256d03957075fcb5923410058982aea85455d035607486ccb847f095442bda"}, + {file = "orjson-3.9.15-cp312-none-win_amd64.whl", hash = "sha256:5bb399e1b49db120653a31463b4a7b27cf2fbfe60469546baf681d1b39f4edf2"}, + {file = "orjson-3.9.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b17f0f14a9c0ba55ff6279a922d1932e24b13fc218a3e968ecdbf791b3682b25"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f6cbd8e6e446fb7e4ed5bac4661a29e43f38aeecbf60c4b900b825a353276a1"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76bc6356d07c1d9f4b782813094d0caf1703b729d876ab6a676f3aaa9a47e37c"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdfa97090e2d6f73dced247a2f2d8004ac6449df6568f30e7fa1a045767c69a6"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7413070a3e927e4207d00bd65f42d1b780fb0d32d7b1d951f6dc6ade318e1b5a"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cf1596680ac1f01839dba32d496136bdd5d8ffb858c280fa82bbfeb173bdd40"}, + {file = "orjson-3.9.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:809d653c155e2cc4fd39ad69c08fdff7f4016c355ae4b88905219d3579e31eb7"}, + {file = "orjson-3.9.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:920fa5a0c5175ab14b9c78f6f820b75804fb4984423ee4c4f1e6d748f8b22bc1"}, + {file = "orjson-3.9.15-cp38-none-win32.whl", hash = "sha256:2b5c0f532905e60cf22a511120e3719b85d9c25d0e1c2a8abb20c4dede3b05a5"}, + {file = "orjson-3.9.15-cp38-none-win_amd64.whl", hash = "sha256:67384f588f7f8daf040114337d34a5188346e3fae6c38b6a19a2fe8c663a2f9b"}, + {file = "orjson-3.9.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6fc2fe4647927070df3d93f561d7e588a38865ea0040027662e3e541d592811e"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34cbcd216e7af5270f2ffa63a963346845eb71e174ea530867b7443892d77180"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f541587f5c558abd93cb0de491ce99a9ef8d1ae29dd6ab4dbb5a13281ae04cbd"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92255879280ef9c3c0bcb327c5a1b8ed694c290d61a6a532458264f887f052cb"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:05a1f57fb601c426635fcae9ddbe90dfc1ed42245eb4c75e4960440cac667262"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ede0bde16cc6e9b96633df1631fbcd66491d1063667f260a4f2386a098393790"}, + {file = "orjson-3.9.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e88b97ef13910e5f87bcbc4dd7979a7de9ba8702b54d3204ac587e83639c0c2b"}, + {file = "orjson-3.9.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57d5d8cf9c27f7ef6bc56a5925c7fbc76b61288ab674eb352c26ac780caa5b10"}, + {file = "orjson-3.9.15-cp39-none-win32.whl", hash = "sha256:001f4eb0ecd8e9ebd295722d0cbedf0748680fb9998d3993abaed2f40587257a"}, + {file = "orjson-3.9.15-cp39-none-win_amd64.whl", hash = "sha256:ea0b183a5fe6b2b45f3b854b0d19c4e932d6f5934ae1f723b07cf9560edd4ec7"}, + {file = "orjson-3.9.15.tar.gz", hash = "sha256:95cae920959d772f30ab36d3b25f83bb0f3be671e986c72ce22f8fa700dae061"}, +] + [[package]] name = "packaging" version = "23.2" @@ -487,6 +604,109 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pymongo" +version = "4.6.2" +description = "Python driver for MongoDB " +optional = false +python-versions = ">=3.7" +files = [ + {file = "pymongo-4.6.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7640d176ee5b0afec76a1bda3684995cb731b2af7fcfd7c7ef8dc271c5d689af"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux1_i686.whl", hash = "sha256:4e2129ec8f72806751b621470ac5d26aaa18fae4194796621508fa0e6068278a"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:c43205e85cbcbdf03cff62ad8f50426dd9d20134a915cfb626d805bab89a1844"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:91ddf95cedca12f115fbc5f442b841e81197d85aa3cc30b82aee3635a5208af2"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:0fbdbf2fba1b4f5f1522e9f11e21c306e095b59a83340a69e908f8ed9b450070"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:097791d5a8d44e2444e0c8c4d6e14570ac11e22bcb833808885a5db081c3dc2a"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:e0b208ebec3b47ee78a5c836e2e885e8c1e10f8ffd101aaec3d63997a4bdcd04"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1849fd6f1917b4dc5dbf744b2f18e41e0538d08dd8e9ba9efa811c5149d665a3"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa0bbbfbd1f8ebbd5facaa10f9f333b20027b240af012748555148943616fdf3"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4522ad69a4ab0e1b46a8367d62ad3865b8cd54cf77518c157631dac1fdc97584"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397949a9cc85e4a1452f80b7f7f2175d557237177120954eff00bf79553e89d3"}, + {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d511db310f43222bc58d811037b176b4b88dc2b4617478c5ef01fea404f8601"}, + {file = "pymongo-4.6.2-cp310-cp310-win32.whl", hash = "sha256:991e406db5da4d89fb220a94d8caaf974ffe14ce6b095957bae9273c609784a0"}, + {file = "pymongo-4.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:94637941fe343000f728e28d3fe04f1f52aec6376b67b85583026ff8dab2a0e0"}, + {file = "pymongo-4.6.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:84593447a5c5fe7a59ba86b72c2c89d813fbac71c07757acdf162fbfd5d005b9"}, + {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aebddb2ec2128d5fc2fe3aee6319afef8697e0374f8a1fcca3449d6f625e7b4"}, + {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f706c1a644ed33eaea91df0a8fb687ce572b53eeb4ff9b89270cb0247e5d0e1"}, + {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18c422e6b08fa370ed9d8670c67e78d01f50d6517cec4522aa8627014dfa38b6"}, + {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d002ae456a15b1d790a78bb84f87af21af1cb716a63efb2c446ab6bcbbc48ca"}, + {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f86ba0c781b497a3c9c886765d7b6402a0e3ae079dd517365044c89cd7abb06"}, + {file = "pymongo-4.6.2-cp311-cp311-win32.whl", hash = "sha256:ac20dd0c7b42555837c86f5ea46505f35af20a08b9cf5770cd1834288d8bd1b4"}, + {file = "pymongo-4.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:e78af59fd0eb262c2a5f7c7d7e3b95e8596a75480d31087ca5f02f2d4c6acd19"}, + {file = "pymongo-4.6.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6125f73503407792c8b3f80165f8ab88a4e448d7d9234c762681a4d0b446fcb4"}, + {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba052446a14bd714ec83ca4e77d0d97904f33cd046d7bb60712a6be25eb31dbb"}, + {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b65433c90e07dc252b4a55dfd885ca0df94b1cf77c5b8709953ec1983aadc03"}, + {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2160d9c8cd20ce1f76a893f0daf7c0d38af093f36f1b5c9f3dcf3e08f7142814"}, + {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f251f287e6d42daa3654b686ce1fcb6d74bf13b3907c3ae25954978c70f2cd4"}, + {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7d227a60b00925dd3aeae4675575af89c661a8e89a1f7d1677e57eba4a3693c"}, + {file = "pymongo-4.6.2-cp312-cp312-win32.whl", hash = "sha256:311794ef3ccae374aaef95792c36b0e5c06e8d5cf04a1bdb1b2bf14619ac881f"}, + {file = "pymongo-4.6.2-cp312-cp312-win_amd64.whl", hash = "sha256:f673b64a0884edcc56073bda0b363428dc1bf4eb1b5e7d0b689f7ec6173edad6"}, + {file = "pymongo-4.6.2-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:fe010154dfa9e428bd2fb3e9325eff2216ab20a69ccbd6b5cac6785ca2989161"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1f5f4cd2969197e25b67e24d5b8aa2452d381861d2791d06c493eaa0b9c9fcfe"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c9519c9d341983f3a1bd19628fecb1d72a48d8666cf344549879f2e63f54463b"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c68bf4a399e37798f1b5aa4f6c02886188ef465f4ac0b305a607b7579413e366"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:a509db602462eb736666989739215b4b7d8f4bb8ac31d0bffd4be9eae96c63ef"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:362a5adf6f3f938a8ff220a4c4aaa93e84ef932a409abecd837c617d17a5990f"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:ee30a9d4c27a88042d0636aca0275788af09cc237ae365cd6ebb34524bddb9cc"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:477914e13501bb1d4608339ee5bb618be056d2d0e7267727623516cfa902e652"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd343ca44982d480f1e39372c48e8e263fc6f32e9af2be456298f146a3db715"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3797e0a628534e07a36544d2bfa69e251a578c6d013e975e9e3ed2ac41f2d95"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97d81d357e1a2a248b3494d52ebc8bf15d223ee89d59ee63becc434e07438a24"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed694c0d1977cb54281cb808bc2b247c17fb64b678a6352d3b77eb678ebe1bd9"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ceaaff4b812ae368cf9774989dea81b9bbb71e5bed666feca6a9f3087c03e49"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7dd63f7c2b3727541f7f37d0fb78d9942eb12a866180fbeb898714420aad74e2"}, + {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e571434633f99a81e081738721bb38e697345281ed2f79c2f290f809ba3fbb2f"}, + {file = "pymongo-4.6.2-cp37-cp37m-win32.whl", hash = "sha256:3e9f6e2f3da0a6af854a3e959a6962b5f8b43bbb8113cd0bff0421c5059b3106"}, + {file = "pymongo-4.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3a5280f496297537301e78bde250c96fadf4945e7b2c397d8bb8921861dd236d"}, + {file = "pymongo-4.6.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:5f6bcd2d012d82d25191a911a239fd05a8a72e8c5a7d81d056c0f3520cad14d1"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4fa30494601a6271a8b416554bd7cde7b2a848230f0ec03e3f08d84565b4bf8c"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bea62f03a50f363265a7a651b4e2a4429b4f138c1864b2d83d4bf6f9851994be"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b2d445f1cf147331947cc35ec10342f898329f29dd1947a3f8aeaf7e0e6878d1"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:5db133d6ec7a4f7fc7e2bd098e4df23d7ad949f7be47b27b515c9fb9301c61e4"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:9eec7140cf7513aa770ea51505d312000c7416626a828de24318fdcc9ac3214c"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:5379ca6fd325387a34cda440aec2bd031b5ef0b0aa2e23b4981945cff1dab84c"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:579508536113dbd4c56e4738955a18847e8a6c41bf3c0b4ab18b51d81a6b7be8"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3bae553ca39ed52db099d76acd5e8566096064dc7614c34c9359bb239ec4081"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0257e0eebb50f242ca28a92ef195889a6ad03dcdde5bf1c7ab9f38b7e810801"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbafe3a1df21eeadb003c38fc02c1abf567648b6477ec50c4a3c042dca205371"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaecfafb407feb6f562c7f2f5b91f22bfacba6dd739116b1912788cff7124c4a"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e942945e9112075a84d2e2d6e0d0c98833cdcdfe48eb8952b917f996025c7ffa"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f7b98f8d2cf3eeebde738d080ae9b4276d7250912d9751046a9ac1efc9b1ce2"}, + {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8110b78fc4b37dced85081d56795ecbee6a7937966e918e05e33a3900e8ea07d"}, + {file = "pymongo-4.6.2-cp38-cp38-win32.whl", hash = "sha256:df813f0c2c02281720ccce225edf39dc37855bf72cdfde6f789a1d1cf32ffb4b"}, + {file = "pymongo-4.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:64ec3e2dcab9af61bdbfcb1dd863c70d1b0c220b8e8ac11df8b57f80ee0402b3"}, + {file = "pymongo-4.6.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bff601fbfcecd2166d9a2b70777c2985cb9689e2befb3278d91f7f93a0456cae"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f1febca6f79e91feafc572906871805bd9c271b6a2d98a8bb5499b6ace0befed"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d788cb5cc947d78934be26eef1623c78cec3729dc93a30c23f049b361aa6d835"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5c2f258489de12a65b81e1b803a531ee8cf633fa416ae84de65cd5f82d2ceb37"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:fb24abcd50501b25d33a074c1790a1389b6460d2509e4b240d03fd2e5c79f463"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:4d982c6db1da7cf3018183891883660ad085de97f21490d314385373f775915b"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:b2dd8c874927a27995f64a3b44c890e8a944c98dec1ba79eab50e07f1e3f801b"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:4993593de44c741d1e9f230f221fe623179f500765f9855936e4ff6f33571bad"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:658f6c028edaeb02761ebcaca8d44d519c22594b2a51dcbc9bd2432aa93319e3"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68109c13176749fbbbbbdb94dd4a58dcc604db6ea43ee300b2602154aebdd55f"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:707d28a822b918acf941cff590affaddb42a5d640614d71367c8956623a80cbc"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f251db26c239aec2a4d57fbe869e0a27b7f6b5384ec6bf54aeb4a6a5e7408234"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57c05f2e310701fc17ae358caafd99b1830014e316f0242d13ab6c01db0ab1c2"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b575fbe6396bbf21e4d0e5fd2e3cdb656dc90c930b6c5532192e9a89814f72d"}, + {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca5877754f3fa6e4fe5aacf5c404575f04c2d9efc8d22ed39576ed9098d555c8"}, + {file = "pymongo-4.6.2-cp39-cp39-win32.whl", hash = "sha256:8caa73fb19070008e851a589b744aaa38edd1366e2487284c61158c77fdf72af"}, + {file = "pymongo-4.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:3e03c732cb64b96849310e1d8688fb70d75e2571385485bf2f1e7ad1d309fa53"}, + {file = "pymongo-4.6.2.tar.gz", hash = "sha256:ab7d01ac832a1663dad592ccbd92bb0f0775bc8f98a1923c5e1a7d7fead495af"}, +] + +[package.dependencies] +dnspython = ">=1.16.0,<3.0.0" + +[package.extras] +aws = ["pymongo-auth-aws (<2.0.0)"] +encryption = ["certifi", "pymongo[aws]", "pymongocrypt (>=1.6.0,<2.0.0)"] +gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] +ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] +snappy = ["python-snappy"] +test = ["pytest (>=7)"] +zstd = ["zstandard"] + [[package]] name = "pytest" version = "7.4.4" @@ -812,4 +1032,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "958e6227984c6fff9148576313da41494c2f4642968fccf861d524c8208fbfdc" +content-hash = "98977c577bce6fbadf6ade1f1bef569e4cf6ae6a822a245cbeeb0173dcf08ac5" From dbdc50fd47de35745e8f6439ed6b36b1d4d3a8f5 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 28 Feb 2024 13:48:59 -0800 Subject: [PATCH 13/22] format --- .../community/langchain_community/vectorstores/mongodb_atlas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/community/langchain_community/vectorstores/mongodb_atlas.py b/libs/community/langchain_community/vectorstores/mongodb_atlas.py index ea776e59c64c9a..c7487632b60ba5 100644 --- a/libs/community/langchain_community/vectorstores/mongodb_atlas.py +++ b/libs/community/langchain_community/vectorstores/mongodb_atlas.py @@ -16,10 +16,10 @@ ) import numpy as np +from langchain_core._api.deprecation import deprecated from langchain_core.documents import Document from langchain_core.embeddings import Embeddings from langchain_core.vectorstores import VectorStore -from langchain_core._api.deprecation import deprecated from langchain_community.vectorstores.utils import maximal_marginal_relevance From fcb04e1a19921ee92b9ae1b899728f5d945ff83f Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 28 Feb 2024 13:50:10 -0800 Subject: [PATCH 14/22] deprecation version --- .../langchain_community/vectorstores/mongodb_atlas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/community/langchain_community/vectorstores/mongodb_atlas.py b/libs/community/langchain_community/vectorstores/mongodb_atlas.py index c7487632b60ba5..ab15d0a7fcd708 100644 --- a/libs/community/langchain_community/vectorstores/mongodb_atlas.py +++ b/libs/community/langchain_community/vectorstores/mongodb_atlas.py @@ -34,9 +34,9 @@ @deprecated( - since="0.1.8", + since="0.0.25", removal="0.2.0", - alternative_import="langchain_mongodb_atlas.MongoDBAtlasVectorSearch", + alternative_import="langchain_mongodb.MongoDBAtlasVectorSearch", ) class MongoDBAtlasVectorSearch(VectorStore): """`MongoDB Atlas Vector Search` vector store. From 027bcb8ecfb5641cd57d79075f9ac4d74e52fdc6 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 28 Feb 2024 13:52:17 -0800 Subject: [PATCH 15/22] x --- libs/partners/mongodb/LICENSE | 2 +- libs/partners/mongodb/Makefile | 6 +- libs/partners/mongodb/poetry.lock | 195 ++++++++++++++------------- libs/partners/mongodb/pyproject.toml | 20 ++- 4 files changed, 110 insertions(+), 113 deletions(-) diff --git a/libs/partners/mongodb/LICENSE b/libs/partners/mongodb/LICENSE index 426b65090341f3..fc0602feecdd67 100644 --- a/libs/partners/mongodb/LICENSE +++ b/libs/partners/mongodb/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 LangChain, Inc. +Copyright (c) 2024 LangChain, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/libs/partners/mongodb/Makefile b/libs/partners/mongodb/Makefile index c65db99a407217..46132d3fdf016e 100644 --- a/libs/partners/mongodb/Makefile +++ b/libs/partners/mongodb/Makefile @@ -5,11 +5,9 @@ all: help # Define a variable for the test file path. TEST_FILE ?= tests/unit_tests/ +integration_test integration_tests: TEST_FILE=tests/integration_tests/ -test: - poetry run pytest $(TEST_FILE) - -tests: +test tests integration_test integration_tests: poetry run pytest $(TEST_FILE) diff --git a/libs/partners/mongodb/poetry.lock b/libs/partners/mongodb/poetry.lock index 392c73c0afe528..3c9ea16d70358f 100644 --- a/libs/partners/mongodb/poetry.lock +++ b/libs/partners/mongodb/poetry.lock @@ -16,13 +16,13 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} [[package]] name = "anyio" -version = "4.2.0" +version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, ] [package.dependencies] @@ -271,7 +271,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.1.24" +version = "0.1.27" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" @@ -496,18 +496,18 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.6.1" +version = "2.6.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, - {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, + {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, + {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.16.2" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -515,90 +515,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.2" +version = "2.16.3" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, - {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, - {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, - {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, - {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, - {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, - {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, - {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, - {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, - {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, - {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, - {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, - {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, - {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, ] [package.dependencies] @@ -818,6 +818,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -912,13 +913,13 @@ files = [ [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] [[package]] @@ -962,24 +963,24 @@ files = [ [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.10.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] [[package]] name = "urllib3" -version = "2.2.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] diff --git a/libs/partners/mongodb/pyproject.toml b/libs/partners/mongodb/pyproject.toml index 7967fd641ba4d1..f9325f3def156f 100644 --- a/libs/partners/mongodb/pyproject.toml +++ b/libs/partners/mongodb/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-mongodb" -version = "0.0.1" +version = "0.1.0" description = "An integration package connecting MongoDB and LangChain" authors = [] readme = "README.md" @@ -22,11 +22,11 @@ optional = true [tool.poetry.group.test.dependencies] pytest = "^7.3.0" freezegun = "^1.2.2" -pytest-mock = "^3.10.0" +pytest-mock = "^3.10.0" syrupy = "^4.0.2" pytest-watcher = "^0.3.4" pytest-asyncio = "^0.21.1" -langchain-core = {path = "../../core", develop = true} +langchain-core = { path = "../../core", develop = true } [tool.poetry.group.codespell] optional = true @@ -47,28 +47,26 @@ ruff = "^0.1.5" [tool.poetry.group.typing.dependencies] mypy = "^0.991" -langchain-core = {path = "../../core", develop = true} +langchain-core = { path = "../../core", develop = true } [tool.poetry.group.dev] optional = true [tool.poetry.group.dev.dependencies] -langchain-core = {path = "../../core", develop = true} +langchain-core = { path = "../../core", develop = true } [tool.ruff] select = [ - "E", # pycodestyle - "F", # pyflakes - "I", # isort + "E", # pycodestyle + "F", # pyflakes + "I", # isort ] [tool.mypy] disallow_untyped_defs = "True" [tool.coverage.run] -omit = [ - "tests/*", -] +omit = ["tests/*"] [build-system] requires = ["poetry-core>=1.0.0"] From 68c9d56e3537e92d5157c6610001ab9af21dd1e7 Mon Sep 17 00:00:00 2001 From: Jib Date: Wed, 28 Feb 2024 17:05:01 -0500 Subject: [PATCH 16/22] fix typing in vectorstores tests and return test_compile placeholder --- .../mongodb/tests/integration_tests/test_compile.py | 7 +++++++ .../partners/mongodb/tests/unit_tests/test_vectorstores.py | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 libs/partners/mongodb/tests/integration_tests/test_compile.py diff --git a/libs/partners/mongodb/tests/integration_tests/test_compile.py b/libs/partners/mongodb/tests/integration_tests/test_compile.py new file mode 100644 index 00000000000000..33ecccdfa0fbda --- /dev/null +++ b/libs/partners/mongodb/tests/integration_tests/test_compile.py @@ -0,0 +1,7 @@ +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/mongodb/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py index c2f68d10393363..733325728d03c1 100644 --- a/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py @@ -49,9 +49,9 @@ async def aembed_query(self, text: str) -> List[float]: class MockCollection(Collection): """Mocked Mongo Collection""" - _aggregate_result: list[Any] + _aggregate_result: List[Any] _insert_result: Optional[InsertManyResult] - _data: list[Any] + _data: List[Any] def __init__(self) -> None: self._data = [] From 837eec136f4f75abcbe33149b345699c395eb3c3 Mon Sep 17 00:00:00 2001 From: Jib Date: Wed, 28 Feb 2024 17:12:22 -0500 Subject: [PATCH 17/22] rename documentation to import langchain_mongodb rather than langchain_community --- docs/docs/integrations/providers/mongodb_atlas.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/integrations/providers/mongodb_atlas.mdx b/docs/docs/integrations/providers/mongodb_atlas.mdx index 9c5b792c43ce63..238b125b6454b0 100644 --- a/docs/docs/integrations/providers/mongodb_atlas.mdx +++ b/docs/docs/integrations/providers/mongodb_atlas.mdx @@ -8,10 +8,10 @@ See [detail configuration instructions](/docs/integrations/vectorstores/mongodb_atlas). -We need to install `pymongo` python package. +We need to install `langchain_mongodb` python package. ```bash -pip install pymongo +pip install langchain_mongodb ``` ## Vector Store @@ -19,6 +19,6 @@ pip install pymongo See a [usage example](/docs/integrations/vectorstores/mongodb_atlas). ```python -from langchain_community.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch ``` From 5fb1c141881851d427953ab9722a4346a44c08b9 Mon Sep 17 00:00:00 2001 From: Jib Date: Thu, 29 Feb 2024 11:03:57 -0500 Subject: [PATCH 18/22] fix integration_test validity checks & consolidate embedder --- .../integration_tests/test_vectorstores.py | 56 +++++++++++++------ .../tests/unit_tests/test_vectorstores.py | 32 +---------- libs/partners/mongodb/tests/utils.py | 36 ++++++++++++ 3 files changed, 76 insertions(+), 48 deletions(-) create mode 100644 libs/partners/mongodb/tests/utils.py diff --git a/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py b/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py index ae369d82722be5..173198fa96d113 100644 --- a/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py @@ -4,7 +4,7 @@ import os from time import sleep -from typing import Any +from typing import Any, Dict, List import pytest from langchain_core.documents import Document @@ -13,11 +13,26 @@ from pymongo.collection import Collection from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch +from tests.utils import ConsistentFakeEmbeddings INDEX_NAME = "langchain-test-index" NAMESPACE = "langchain_test_db.langchain_test_collection" CONNECTION_STRING = os.environ.get("MONGODB_ATLAS_URI") DB_NAME, COLLECTION_NAME = NAMESPACE.split(".") +DIMENSIONS = 1536 +TIMEOUT = 10.0 +INTERVAL = 0.5 + + +class PatchedMongoDBAtlasVectorSearch(MongoDBAtlasVectorSearch): + def _insert_texts(self, texts: List[str], metadatas: List[Dict[str, Any]]) -> List: + """Patched insert_texts that waits for data to be indexed before returning""" + ids = super()._insert_texts(texts, metadatas) + timeout = TIMEOUT + while len(ids) != self.similarity_search("sandwich") and timeout >= 0: + sleep(INTERVAL) + timeout -= INTERVAL + return ids def get_collection() -> Collection: @@ -49,6 +64,10 @@ def setup(self) -> None: # delete all the documents in the collection collection.delete_many({}) # type: ignore[index] + @pytest.fixture + def embedding_openai(self) -> Embeddings: + return ConsistentFakeEmbeddings(DIMENSIONS) + def test_from_documents( self, embedding_openai: Embeddings, collection: Any ) -> None: @@ -59,16 +78,17 @@ def test_from_documents( Document(page_content="What is a sandwich?", metadata={"c": 1}), Document(page_content="That fence is purple.", metadata={"d": 1, "e": 2}), ] - vectorstore = MongoDBAtlasVectorSearch.from_documents( + vectorstore = PatchedMongoDBAtlasVectorSearch.from_documents( documents, embedding_openai, collection=collection, index_name=INDEX_NAME, ) - sleep(1) # waits for mongot to update Lucene's index + # sleep(5) # waits for mongot to update Lucene's index output = vectorstore.similarity_search("Sandwich", k=1) - assert output[0].page_content == "What is a sandwich?" - assert output[0].metadata["c"] == 1 + assert len(output) == 1 + # Check for the presence of the metadata key + assert any([key.page_content == output[0].page_content for key in documents]) def test_from_texts(self, embedding_openai: Embeddings, collection: Any) -> None: texts = [ @@ -77,15 +97,15 @@ def test_from_texts(self, embedding_openai: Embeddings, collection: Any) -> None "What is a sandwich?", "That fence is purple.", ] - vectorstore = MongoDBAtlasVectorSearch.from_texts( + vectorstore = PatchedMongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, collection=collection, index_name=INDEX_NAME, ) - sleep(1) # waits for mongot to update Lucene's index + # sleep(5) # waits for mongot to update Lucene's index output = vectorstore.similarity_search("Sandwich", k=1) - assert output[0].page_content == "What is a sandwich?" + assert len(output) == 1 def test_from_texts_with_metadatas( self, embedding_openai: Embeddings, collection: Any @@ -97,17 +117,19 @@ def test_from_texts_with_metadatas( "The fence is purple.", ] metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] - vectorstore = MongoDBAtlasVectorSearch.from_texts( + metakeys = ["a", "b", "c", "d", "e"] + vectorstore = PatchedMongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, metadatas=metadatas, collection=collection, index_name=INDEX_NAME, ) - sleep(1) # waits for mongot to update Lucene's index + # sleep(5) # waits for mongot to update Lucene's index output = vectorstore.similarity_search("Sandwich", k=1) - assert output[0].page_content == "What is a sandwich?" - assert output[0].metadata["c"] == 1 + assert len(output) == 1 + # Check for the presence of the metadata key + assert any([key in output[0].metadata for key in metakeys]) def test_from_texts_with_metadatas_and_pre_filter( self, embedding_openai: Embeddings, collection: Any @@ -119,28 +141,28 @@ def test_from_texts_with_metadatas_and_pre_filter( "The fence is purple.", ] metadatas = [{"a": 1}, {"b": 1}, {"c": 1}, {"d": 1, "e": 2}] - vectorstore = MongoDBAtlasVectorSearch.from_texts( + vectorstore = PatchedMongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, metadatas=metadatas, collection=collection, index_name=INDEX_NAME, ) - sleep(1) # waits for mongot to update Lucene's index + # sleep(5) # waits for mongot to update Lucene's index output = vectorstore.similarity_search( - "Sandwich", k=1, pre_filter={"range": {"lte": 0, "path": "c"}} + "Sandwich", k=1, pre_filter={"c": {"$lte": 0}} ) assert output == [] def test_mmr(self, embedding_openai: Embeddings, collection: Any) -> None: texts = ["foo", "foo", "fou", "foy"] - vectorstore = MongoDBAtlasVectorSearch.from_texts( + vectorstore = PatchedMongoDBAtlasVectorSearch.from_texts( texts, embedding_openai, collection=collection, index_name=INDEX_NAME, ) - sleep(1) # waits for mongot to update Lucene's index + # sleep(5) # waits for mongot to update Lucene's index query = "foo" output = vectorstore.max_marginal_relevance_search(query, k=10, lambda_mult=0.1) assert len(output) == len(texts) diff --git a/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py index 733325728d03c1..3f5ab63dde039e 100644 --- a/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py @@ -9,43 +9,13 @@ from pymongo.results import DeleteResult, InsertManyResult from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch +from tests.utils import ConsistentFakeEmbeddings INDEX_NAME = "langchain-test-index" NAMESPACE = "langchain_test_db.langchain_test_collection" DB_NAME, COLLECTION_NAME = NAMESPACE.split(".") -class ConsistentFakeEmbeddings(Embeddings): - """Fake embeddings functionality for testing.""" - - def __init__(self, dimensionality: int = 10) -> None: - self.known_texts: List[str] = [] - self.dimensionality = dimensionality - - def embed_documents(self, texts: List[str]) -> List[List[float]]: - """Return consistent embeddings for each text seen so far.""" - out_vectors = [] - for text in texts: - if text not in self.known_texts: - self.known_texts.append(text) - vector = [float(1.0)] * (self.dimensionality - 1) + [ - float(self.known_texts.index(text)) - ] - out_vectors.append(vector) - return out_vectors - - def embed_query(self, text: str) -> List[float]: - """Return consistent embeddings for the text, if seen before, or a constant - one if the text is unknown.""" - return self.embed_documents([text])[0] - - async def aembed_documents(self, texts: List[str]) -> List[List[float]]: - return self.embed_documents(texts) - - async def aembed_query(self, text: str) -> List[float]: - return self.embed_query(text) - - class MockCollection(Collection): """Mocked Mongo Collection""" diff --git a/libs/partners/mongodb/tests/utils.py b/libs/partners/mongodb/tests/utils.py new file mode 100644 index 00000000000000..9e19605952970e --- /dev/null +++ b/libs/partners/mongodb/tests/utils.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +from typing import List + +from langchain_core.embeddings import Embeddings + + +class ConsistentFakeEmbeddings(Embeddings): + """Fake embeddings functionality for testing.""" + + def __init__(self, dimensionality: int = 10) -> None: + self.known_texts: List[str] = [] + self.dimensionality = dimensionality + + def embed_documents(self, texts: List[str]) -> List[List[float]]: + """Return consistent embeddings for each text seen so far.""" + out_vectors = [] + for text in texts: + if text not in self.known_texts: + self.known_texts.append(text) + vector = [float(1.0)] * (self.dimensionality - 1) + [ + float(self.known_texts.index(text)) + ] + out_vectors.append(vector) + return out_vectors + + def embed_query(self, text: str) -> List[float]: + """Return consistent embeddings for the text, if seen before, or a constant + one if the text is unknown.""" + return self.embed_documents([text])[0] + + async def aembed_documents(self, texts: List[str]) -> List[List[float]]: + return self.embed_documents(texts) + + async def aembed_query(self, text: str) -> List[float]: + return self.embed_query(text) From a86924096208f055b619e791432ee8c9724a9a2b Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 29 Feb 2024 14:53:26 -0800 Subject: [PATCH 19/22] test --- libs/partners/mongodb/tests/unit_tests/test_vectorstores.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py index 3f5ab63dde039e..9e84acbd354287 100644 --- a/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py @@ -33,7 +33,7 @@ def delete_many(self, *args, **kwargs) -> DeleteResult: # type: ignore self._data = [] return DeleteResult({"n": old_len}, acknowledged=True) - def insert_many(self, to_insert: list[Any], *args, **kwargs) -> InsertManyResult: # type: ignore + def insert_many(self, to_insert: List[Any], *args, **kwargs) -> InsertManyResult: # type: ignore mongodb_inserts = [ {"_id": str(uuid.uuid4()), "score": 1, **insert} for insert in to_insert ] @@ -42,7 +42,7 @@ def insert_many(self, to_insert: list[Any], *args, **kwargs) -> InsertManyResult [k["_id"] for k in mongodb_inserts], acknowledged=True ) - def aggregate(self, *args, **kwargs) -> list[Any]: # type: ignore + def aggregate(self, *args, **kwargs) -> List[Any]: # type: ignore return deepcopy(self._aggregate_result) def count_documents(self, *args, **kwargs) -> int: # type: ignore From a74c952f3a8678fc5e04ad95a1313a33b03a304d Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 29 Feb 2024 14:56:51 -0800 Subject: [PATCH 20/22] doc nit --- docs/docs/integrations/providers/mongodb_atlas.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/integrations/providers/mongodb_atlas.mdx b/docs/docs/integrations/providers/mongodb_atlas.mdx index 238b125b6454b0..41e2f473075655 100644 --- a/docs/docs/integrations/providers/mongodb_atlas.mdx +++ b/docs/docs/integrations/providers/mongodb_atlas.mdx @@ -8,10 +8,10 @@ See [detail configuration instructions](/docs/integrations/vectorstores/mongodb_atlas). -We need to install `langchain_mongodb` python package. +We need to install `langchain-mongodb` python package. ```bash -pip install langchain_mongodb +pip install langchain-mongodb ``` ## Vector Store From 0f2ea8286288337987a256f9ae6970db50af347f Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 29 Feb 2024 14:57:04 -0800 Subject: [PATCH 21/22] x --- docs/docs/integrations/providers/mongodb_atlas.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/integrations/providers/mongodb_atlas.mdx b/docs/docs/integrations/providers/mongodb_atlas.mdx index 41e2f473075655..3d83c8f52b6993 100644 --- a/docs/docs/integrations/providers/mongodb_atlas.mdx +++ b/docs/docs/integrations/providers/mongodb_atlas.mdx @@ -19,6 +19,6 @@ pip install langchain-mongodb See a [usage example](/docs/integrations/vectorstores/mongodb_atlas). ```python -from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb import MongoDBAtlasVectorSearch ``` From cf5b5d40191bf11b9d1d76089b518cd88eb9f4b7 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Thu, 29 Feb 2024 14:58:03 -0800 Subject: [PATCH 22/22] x --- libs/partners/mongodb/README.md | 2 +- .../mongodb/tests/integration_tests/test_vectorstores.py | 2 +- libs/partners/mongodb/tests/unit_tests/test_vectorstores.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/partners/mongodb/README.md b/libs/partners/mongodb/README.md index 7c6373380b93db..ca420328a28ae2 100644 --- a/libs/partners/mongodb/README.md +++ b/libs/partners/mongodb/README.md @@ -11,7 +11,7 @@ pip install -U langchain-mongodb ## Using MongoDBAtlasVectorSearch ```python -from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb import MongoDBAtlasVectorSearch # Pull MongoDB Atlas URI from environment variables MONGODB_ATLAS_CLUSTER_URI = os.environ.get("MONGODB_ATLAS_CLUSTER_URI") diff --git a/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py b/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py index 173198fa96d113..d95c99ca23524c 100644 --- a/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/integration_tests/test_vectorstores.py @@ -12,7 +12,7 @@ from pymongo import MongoClient from pymongo.collection import Collection -from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb import MongoDBAtlasVectorSearch from tests.utils import ConsistentFakeEmbeddings INDEX_NAME = "langchain-test-index" diff --git a/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py index 9e84acbd354287..0d631249b2da9f 100644 --- a/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py +++ b/libs/partners/mongodb/tests/unit_tests/test_vectorstores.py @@ -8,7 +8,7 @@ from pymongo.collection import Collection from pymongo.results import DeleteResult, InsertManyResult -from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch +from langchain_mongodb import MongoDBAtlasVectorSearch from tests.utils import ConsistentFakeEmbeddings INDEX_NAME = "langchain-test-index"