diff --git a/Makefile b/Makefile
index 22fd9e69..e5e902e9 100644
--- a/Makefile
+++ b/Makefile
@@ -27,11 +27,12 @@ lint_diff format_diff: PYTHON_FILES=$(shell git diff --relative=. --name-only --
lint lint_diff:
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff
+ [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check $(PYTHON_FILES) --diff
[ "$(PYTHON_FILES)" = "" ] || poetry run mypy $(PYTHON_FILES)
format format_diff:
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES)
- [ "$(PYTHON_FILES)" = "" ] || poetry run ruff --fix $(PYTHON_FILES)
+ [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check --fix $(PYTHON_FILES)
spell_check:
poetry run codespell --toml pyproject.toml
diff --git a/README.md b/README.md
index 06c0a0f6..69b7f441 100644
--- a/README.md
+++ b/README.md
@@ -9,13 +9,13 @@
The `langchain-postgres` package implementations of core LangChain abstractions using `Postgres`.
-The package is released under the MIT license.
+The package is released under the MIT license.
Feel free to use the abstraction as provided or else modify them / extend them as appropriate for your own application.
## Requirements
-The package currently only supports the [psycogp3](https://www.psycopg.org/psycopg3/) driver.
+The package supports the [asyncpg](https://github.com/MagicStack/asyncpg) and [psycogp3](https://www.psycopg.org/psycopg3/) drivers.
## Installation
@@ -23,22 +23,68 @@ The package currently only supports the [psycogp3](https://www.psycopg.org/psyco
pip install -U langchain-postgres
```
-## Change Log
+## Usage
-0.0.6:
-- Remove langgraph as a dependency as it was causing dependency conflicts.
-- Base interface for checkpointer changed in langgraph, so existing implementation would've broken regardless.
+### Vectorstore
-## Usage
+> [!WARNING]
+> In v0.0.14+, `PGVector` is deprecated. Please migrate to `PGVectorStore`
+> Version 0.0.14+ has not been released yet, but you can test version of the vectorstore on the main branch. Until official release do not use in production.
+> for improved performance and manageability.
+> See the [migration guide](https://github.com/langchain-ai/langchain-postgres/blob/main/examples/migrate_pgvector_to_pgvectorstore.md) for details on how to migrate from `PGVector` to `PGVectorStore`.
+
+For a detailed example on `PGVectorStore` see [here](https://github.com/langchain-ai/langchain-postgres/blob/main/examples/pg_vectorstore.ipynb).
+
+```python
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from langchain_postgres import PGEngine, PGVectorStore
+
+# Replace the connection string with your own Postgres connection string
+CONNECTION_STRING = "postgresql+psycopg3://langchain:langchain@localhost:6024/langchain"
+engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+
+# Replace the vector size with your own vector size
+VECTOR_SIZE = 768
+embedding = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+TABLE_NAME = "my_doc_collection"
+
+engine.init_vectorstore_table(
+ table_name=TABLE_NAME,
+ vector_size=VECTOR_SIZE,
+)
+
+store = PGVectorStore.create_sync(
+ engine=engine,
+ table_name=TABLE_NAME,
+ embedding_service=embedding,
+)
+
+docs = [
+ Document(page_content="Apples and oranges"),
+ Document(page_content="Cars and airplanes"),
+ Document(page_content="Train")
+]
+
+store.add_documents(docs)
+
+query = "I'd like a fruit."
+docs = store.similarity_search(query)
+print(docs)
+```
+
+> [!TIP]
+> All synchronous functions have corresponding asynchronous functions
### ChatMessageHistory
-The chat message history abstraction helps to persist chat message history
+The chat message history abstraction helps to persist chat message history
in a postgres table.
PostgresChatMessageHistory is parameterized using a `table_name` and a `session_id`.
-The `table_name` is the name of the table in the database where
+The `table_name` is the name of the table in the database where
the chat messages will be stored.
The `session_id` is a unique identifier for the chat session. It can be assigned
@@ -79,7 +125,21 @@ chat_history.add_messages([
print(chat_history.messages)
```
+## Google Cloud Integrations
-### Vectorstore
+[Google Cloud](https://python.langchain.com/docs/integrations/providers/google/) provides Vector Store, Chat Message History, and Data Loader integrations for [AlloyDB](https://cloud.google.com/alloydb) and [Cloud SQL](https://cloud.google.com/sql) for PostgreSQL databases via the following PyPi packages:
+
+* [`langchain-google-alloydb-pg`](https://github.com/googleapis/langchain-google-alloydb-pg-python)
+
+* [`langchain-google-cloud-sql-pg`](https://github.com/googleapis/langchain-google-cloud-sql-pg-python)
+
+Using the Google Cloud integrations provides the following benefits:
+
+- **Enhanced Security**: Securely connect to Google Cloud databases utilizing IAM for authorization and database authentication without needing to manage SSL certificates, configure firewall rules, or enable authorized networks.
+- **Simplified and Secure Connections:** Connect to Google Cloud databases effortlessly using the instance name instead of complex connection strings. The integrations creates a secure connection pool that can be easily shared across your application using the `engine` object.
+
+| Vector Store | Metadata filtering | Async support | Schema Flexibility | Improved metadata handling | Hybrid Search |
+|--------------------------|--------------------|----------------|--------------------|----------------------------|---------------|
+| Google AlloyDB | ✓ | ✓ | ✓ | ✓ | ✗ |
+| Google Cloud SQL Postgres| ✓ | ✓ | ✓ | ✓ | ✗ |
-See example for the [PGVector vectorstore here](https://github.com/langchain-ai/langchain-postgres/blob/main/examples/vectorstore.ipynb)
diff --git a/docker-compose.yml b/docker-compose.yml
index 6eabf2aa..b68bbbea 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,31 +1,9 @@
-# Use to test langchain-postgres
-version: "3"
name: langchain-postgres
services:
- postgres:
- image: postgres:16
- environment:
- POSTGRES_DB: langchain
- POSTGRES_USER: langchain
- POSTGRES_PASSWORD: langchain
- ports:
- - "6023:5432"
- command: |
- postgres -c log_statement=all
- healthcheck:
- test:
- [
- "CMD-SHELL",
- "psql postgresql://langchain:langchain@localhost/langchain --command 'SELECT 1;' || exit 1",
- ]
- interval: 5s
- retries: 60
- volumes:
- - postgres_data:/var/lib/postgresql/data
pgvector:
# postgres with the pgvector extension
- image: ankane/pgvector
+ image: pgvector/pgvector:pg16
environment:
POSTGRES_DB: langchain
POSTGRES_USER: langchain
@@ -43,8 +21,7 @@ services:
interval: 5s
retries: 60
volumes:
- - postgres_data_pgvector:/var/lib/postgresql/data
+ - postgres_data_pgvector_16:/var/lib/postgresql/data
volumes:
- postgres_data:
- postgres_data_pgvector:
+ postgres_data_pgvector_16:
diff --git a/examples/migrate_pgvector_to_pgvectorstore.md b/examples/migrate_pgvector_to_pgvectorstore.md
new file mode 100644
index 00000000..fab415a4
--- /dev/null
+++ b/examples/migrate_pgvector_to_pgvectorstore.md
@@ -0,0 +1,174 @@
+# Migrate a `PGVector` vector store to `PGVectorStore`
+
+This guide shows how to migrate from the [`PGVector`](https://github.com/langchain-ai/langchain-postgres/blob/main/langchain_postgres/vectorstores.py) vector store class to the [`PGVectorStore`](https://github.com/langchain-ai/langchain-postgres/blob/main/langchain_postgres/vectorstore.py) class.
+
+## Why migrate?
+
+This guide explains how to migrate your vector data from a PGVector-style database (two tables) to an PGVectoStore-style database (one table per collection) for improved performance and manageability.
+
+Migrating to the PGVectorStore interface provides the following benefits:
+
+- **Simplified management**: A single table contains data corresponding to a single collection, making it easier to query, update, and maintain.
+- **Improved metadata handling**: It stores metadata in columns instead of JSON, resulting in significant performance improvements.
+- **Schema flexibility**: The interface allows users to add tables into any database schema.
+- **Improved performance**: The single-table schema can lead to faster query execution, especially for large collections.
+- **Clear separation**: Clearly separate table and extension creation, allowing for distinct permissions and streamlined workflows.
+- **Secure Connections:** The PGVectorStore interface creates a secure connection pool that can be easily shared across your application using the `engine` object.
+
+## Migration process
+
+> **_NOTE:_** The langchain-core library is installed to use the Fake embeddings service. To use a different embedding service, you'll need to install the appropriate library for your chosen provider. Choose embeddings services from [LangChain's Embedding models](https://python.langchain.com/v0.2/docs/integrations/text_embedding/).
+
+While you can use the existing PGVector database, we **strongly recommend** migrating your data to the PGVectorStore-style schema to take full advantage of the performance benefits.
+
+### (Recommended) Data migration
+
+1. **Create a PG engine.**
+
+ ```python
+ from langchain_postgres import PGEngine
+
+ # Replace these variable values
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ ```
+
+ > **_NOTE:_** All sync methods have corresponding async methods.
+
+2. **Create a new table to migrate existing data.**
+
+ ```python
+ # Vertex AI embeddings uses a vector size of 768.
+ # Adjust this according to your embeddings service.
+ VECTOR_SIZE = 768
+
+ engine.init_vectorstore_table(
+ table_name="destination_table",
+ vector_size=VECTOR_SIZE,
+ )
+ ```
+
+ **(Optional) Customize your table.**
+
+ When creating your vectorstore table, you have the flexibility to define custom metadata and ID columns. This is particularly useful for:
+
+ - **Filtering**: Metadata columns allow you to easily filter your data within the vectorstore. For example, you might store the document source, date, or author as metadata for efficient retrieval.
+ - **Non-UUID Identifiers**: By default, the id_column uses UUIDs. If you need to use a different type of ID (e.g., an integer or string), you can define a custom id_column.
+
+ ```python
+ metadata_columns = [
+ Column(f"col_0_{collection_name}", "VARCHAR"),
+ Column(f"col_1_{collection_name}", "VARCHAR"),
+ ]
+ engine.init_vectorstore_table(
+ table_name="destination_table",
+ vector_size=VECTOR_SIZE,
+ metadata_columns=metadata_columns,
+ id_column=Column("langchain_id", "VARCHAR"),
+ )
+ ```
+
+3. **Create a vector store object to interact with the new data.**
+
+ > **_NOTE:_** The `FakeEmbeddings` embedding service is only used to initialise a vector store object, not to generate any embeddings. The embeddings are copied directly from the PGVector table.
+
+ ```python
+ from langchain_postgres import PGVectorStore
+ from langchain_core.embeddings import FakeEmbeddings
+
+ destination_vector_store = PGVectorStore.create_sync(
+ engine,
+ embedding_service=FakeEmbeddings(size=VECTOR_SIZE),
+ table_name="destination_table",
+ )
+ ```
+
+ If you have any customisations on the metadata or the id columns, add them to the vector store as follows:
+
+ ```python
+ from langchain_postgres import PGVectorStore
+ from langchain_core.embeddings import FakeEmbeddings
+
+ destination_vector_store = PGVectorStore.create_sync(
+ engine,
+ embedding_service=FakeEmbeddings(size=VECTOR_SIZE),
+ table_name="destination_table",
+ metadata_columns=[col.name for col in metadata_columns],
+ id_column="langchain_id",
+ )
+ ```
+
+4. **Migrate the data to the new table.**
+
+ ```python
+ from langchain_postgres.utils.pgvector_migrator import amigrate_pgvector_collection
+
+ migrate_pgvector_collection(
+ engine,
+ # Set collection name here
+ collection_name="collection_name",
+ vector_store=destination_vector_store,
+ # This deletes data from the original table upon migration. You can choose to turn it off.
+ delete_pg_collection=True,
+ )
+ ```
+
+ The data will only be deleted from the original table once all of it has been successfully copied to the destination table.
+
+> **TIP:** If you would like to migrate multiple collections, you can use the `alist_pgvector_collection_names` method to get the names of all collections, allowing you to iterate through them.
+>
+> ```python
+> from langchain_postgres.utils.pgvector_migrator import alist_pgvector_collection_names
+>
+> all_collection_names = list_pgvector_collection_names(engine)
+> print(all_collection_names)
+> ```
+
+### (Not Recommended) Use PGVectorStore interface on PGVector databases
+
+If you choose not to migrate your data, you can still use the PGVectorStore interface with your existing PGVector database. However, you won't benefit from the performance improvements of the PGVectorStore-style schema.
+
+1. **Create an PGVectorStore engine.**
+
+ ```python
+ from langchain_postgres import PGEngine
+
+ # Replace these variable values
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ ```
+
+ > **_NOTE:_** All sync methods have corresponding async methods.
+
+2. **Create a vector store object to interact with the data.**
+
+ Use the embeddings service used by your database. See [langchain docs](https://python.langchain.com/docs/integrations/text_embedding/) for reference.
+
+ ```python
+ from langchain_postgres import PGVectorStore
+ from langchain_core.embeddings import FakeEmbeddings
+
+ vector_store = PGVectorStore.create_sync(
+ engine=engine,
+ table_name="langchain_pg_embedding",
+ embedding_service=FakeEmbeddings(size=VECTOR_SIZE),
+ content_column="document",
+ metadata_json_column="cmetadata",
+ metadata_columns=["collection_id"],
+ id_column="id",
+ )
+ ```
+
+3. **Perform similarity search.**
+
+ Filter by collection id:
+
+ ```python
+ vector_store.similarity_search("query", k=5, filter=f"collection_id='{uuid}'")
+ ```
+
+ Filter by collection id and metadata:
+
+ ```python
+ vector_store.similarity_search(
+ "query", k=5, filter=f"collection_id='{uuid}' and cmetadata->>'col_name' = 'value'"
+ )
+ ```
\ No newline at end of file
diff --git a/examples/pg_vectorstore.ipynb b/examples/pg_vectorstore.ipynb
new file mode 100644
index 00000000..4d25d410
--- /dev/null
+++ b/examples/pg_vectorstore.ipynb
@@ -0,0 +1,692 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# PGVectorStore & PGEngine\n",
+ "\n",
+ "This is an implementation of a LangChain vectorstore using `postgres` as the backend.\n",
+ "\n",
+ "This notebook goes over how to use `PGVectorStore` to store vector embeddings."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IR54BmgvdHT_"
+ },
+ "source": [
+ "### 🦜🔗 Library Installation\n",
+ "Install the integration library, `langchain-postgres`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 1000
+ },
+ "id": "0ZITIDE160OD",
+ "outputId": "e184bc0d-6541-4e0a-82d2-1e216db00a2d"
+ },
+ "outputs": [],
+ "source": [
+ "%pip install --upgrade --quiet langchain-postgres\n",
+ "# This tutorial also requires the following dependencies\n",
+ "%pip install --upgrade --quiet langchain-core langchain-cohere SQLAlchemy"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f8f2830ee9ca1e01",
+ "metadata": {
+ "id": "f8f2830ee9ca1e01"
+ },
+ "source": [
+ "## Basic Usage"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This package requires a PostgreSQL database with the `pgvector` extension.\n",
+ "\n",
+ "You can run the following command to spin up a container for a `pgvector` enabled Postgres instance:\n",
+ "\n",
+ "```shell\n",
+ "docker run --name pgvector-container -e POSTGRES_USER=langchain -e POSTGRES_PASSWORD=langchain -e POSTGRES_DB=langchain -p 6024:5432 -d pgvector/pgvector:pg16\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "OMvzMWRrR6n7",
+ "metadata": {
+ "id": "OMvzMWRrR6n7"
+ },
+ "source": [
+ "### Set the postgres connection url\n",
+ "\n",
+ "`PGVectorStore` can be used with the `asyncpg` and `psycopg3` drivers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "irl7eMFnSPZr",
+ "metadata": {
+ "id": "irl7eMFnSPZr"
+ },
+ "outputs": [],
+ "source": [
+ "# @title Set your values or use the defaults to connect to Docker { display-mode: \"form\" }\n",
+ "POSTGRES_USER = \"langchain\" # @param {type: \"string\"}\n",
+ "POSTGRES_PASSWORD = \"langchain\" # @param {type: \"string\"}\n",
+ "POSTGRES_HOST = \"localhost\" # @param {type: \"string\"}\n",
+ "POSTGRES_PORT = \"6024\" # @param {type: \"string\"}\n",
+ "POSTGRES_DB = \"langchain\" # @param {type: \"string\"}\n",
+ "TABLE_NAME = \"vectorstore\" # @param {type: \"string\"}\n",
+ "VECTOR_SIZE = 1024 # @param {type: \"int\"}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "QuQigs4UoFQ2",
+ "metadata": {
+ "id": "QuQigs4UoFQ2"
+ },
+ "source": [
+ "### PGEngine Connection Pool\n",
+ "\n",
+ "One of the requirements and arguments to establish PostgreSQL as a vector store is a `PGEngine` object. The `PGEngine` configures a shared connection pool to your Postgres database. This is an industry best practice to manage number of connections and to reduce latency through cached database connections.\n",
+ "\n",
+ "To create a `PGEngine` using `PGEngine.from_connection_string()` you need to provide:\n",
+ "\n",
+ "1. `url` : Connection string using the `postgresql+asyncpg` driver.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Note:** This tutorial demonstrates the async interface. All async methods have corresponding sync methods."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# See docker command above to launch a Postgres instance with pgvector enabled.\n",
+ "CONNECTION_STRING = (\n",
+ " f\"postgresql+asyncpg://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}\"\n",
+ " f\":{POSTGRES_PORT}/{POSTGRES_DB}\"\n",
+ ")\n",
+ "# To use psycopg3 driver, set your connection string to `postgresql+psycopg://`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langchain_postgres import PGEngine\n",
+ "\n",
+ "pg_engine = PGEngine.from_connection_string(url=CONNECTION_STRING)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To create a `PGEngine` using `PGEngine.from_engine()` you need to provide:\n",
+ "\n",
+ "1. `engine` : An object of `AsyncEngine`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sqlalchemy.ext.asyncio import create_async_engine\n",
+ "\n",
+ "# Create an SQLAlchemy Async Engine\n",
+ "engine = create_async_engine(\n",
+ " CONNECTION_STRING,\n",
+ ")\n",
+ "\n",
+ "pg_engine = PGEngine.from_engine(engine=engine)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "D9Xs2qhm6X56"
+ },
+ "source": [
+ "### Initialize a table\n",
+ "The `PGVectorStore` class requires a database table. The `PGEngine` engine has a helper method `ainit_vectorstore_table()` that can be used to create a table with the proper schema for you."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "id": "avlyHEMn6gzU"
+ },
+ "outputs": [],
+ "source": [
+ "await pg_engine.ainit_vectorstore_table(\n",
+ " table_name=TABLE_NAME,\n",
+ " vector_size=VECTOR_SIZE,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Optional Tip: 💡\n",
+ "You can also specify a schema name by passing `schema_name` wherever you pass `table_name`. Eg:\n",
+ "\n",
+ "```python\n",
+ "SCHEMA_NAME=\"my_schema\"\n",
+ "\n",
+ "await pg_engine.ainit_vectorstore_table(\n",
+ " table_name=TABLE_NAME,\n",
+ " vector_size=768,\n",
+ " schema_name=SCHEMA_NAME, # Default: \"public\"\n",
+ ")\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Create an embedding class instance\n",
+ "\n",
+ "You can use any [LangChain embeddings model](https://python.langchain.com/docs/integrations/text_embedding/)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "Vb2RJocV9_LQ",
+ "outputId": "37f5dc74-2512-47b2-c135-f34c10afdcf4"
+ },
+ "outputs": [],
+ "source": [
+ "from langchain_cohere import CohereEmbeddings\n",
+ "\n",
+ "embedding = CohereEmbeddings(model=\"embed-english-v3.0\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "e1tl0aNx7SWy"
+ },
+ "source": [
+ "### Initialize a default PGVectorStore"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "id": "z-AZyzAQ7bsf"
+ },
+ "outputs": [],
+ "source": [
+ "from langchain_postgres import PGVectorStore\n",
+ "\n",
+ "store = await PGVectorStore.create(\n",
+ " engine=pg_engine,\n",
+ " table_name=TABLE_NAME,\n",
+ " # schema_name=SCHEMA_NAME,\n",
+ " embedding_service=embedding,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Initialize Vector Store with documents\n",
+ "\n",
+ "This is a great way to get started quickly. However, the default method is recommended for most applications to avoid accidentally adding duplicate documents."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langchain_core.documents import Document\n",
+ "import uuid\n",
+ "\n",
+ "docs = [\n",
+ " Document(\n",
+ " page_content=\"Red Apple\",\n",
+ " metadata={\"description\": \"red\", \"content\": \"1\", \"category\": \"fruit\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"Banana Cavendish\",\n",
+ " metadata={\"description\": \"yellow\", \"content\": \"2\", \"category\": \"fruit\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"Orange Navel\",\n",
+ " metadata={\"description\": \"orange\", \"content\": \"3\", \"category\": \"fruit\"},\n",
+ " ),\n",
+ "]\n",
+ "ids = [str(uuid.uuid4()) for i in range(len(docs))]\n",
+ "\n",
+ "store_with_documents = await PGVectorStore.afrom_documents(\n",
+ " documents=docs,\n",
+ " ids=ids,\n",
+ " engine=pg_engine,\n",
+ " table_name=TABLE_NAME,\n",
+ " embedding=embedding,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Add texts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import uuid\n",
+ "\n",
+ "all_texts = [\"Apples and oranges\", \"Cars and airplanes\", \"Pineapple\", \"Train\", \"Banana\"]\n",
+ "metadatas = [{\"len\": len(t)} for t in all_texts]\n",
+ "ids = [str(uuid.uuid4()) for _ in all_texts]\n",
+ "\n",
+ "await store.aadd_texts(all_texts, metadatas=metadatas, ids=ids)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Delete texts"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "await store.adelete([ids[1]])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Search for documents"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "query = \"I'd like a fruit.\"\n",
+ "docs = await store.asimilarity_search(query)\n",
+ "print(docs)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Search for documents by vector"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "query_vector = embedding.embed_query(query)\n",
+ "docs = await store.asimilarity_search_by_vector(query_vector, k=2)\n",
+ "print(docs)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Add a Index\n",
+ "Speed up vector search queries by applying a vector index. Learn more about [vector indexes](https://cloud.google.com/blog/products/databases/faster-similarity-search-performance-with-pgvector-indexes)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langchain_postgres.v2.indexes import IVFFlatIndex\n",
+ "\n",
+ "index = IVFFlatIndex()\n",
+ "await store.aapply_vector_index(index)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Re-index"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "await store.areindex() # Re-index using default index name"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Remove an index"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "await store.adrop_vector_index() # Delete index using default name"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Create a custom Vector Store\n",
+ "A Vector Store can take advantage of relational data to filter similarity searches.\n",
+ "\n",
+ "Create a new table with custom metadata columns.\n",
+ "You can also re-use an existing table which already has custom columns for a Document's id, content, embedding, and/or metadata."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langchain_postgres import Column\n",
+ "\n",
+ "# Set table name\n",
+ "TABLE_NAME = \"vectorstore_custom\"\n",
+ "# SCHEMA_NAME = \"my_schema\"\n",
+ "\n",
+ "await pg_engine.ainit_vectorstore_table(\n",
+ " table_name=TABLE_NAME,\n",
+ " # schema_name=SCHEMA_NAME,\n",
+ " vector_size=VECTOR_SIZE,\n",
+ " metadata_columns=[Column(\"len\", \"INTEGER\")],\n",
+ ")\n",
+ "\n",
+ "\n",
+ "# Initialize PGVectorStore\n",
+ "custom_store = await PGVectorStore.create(\n",
+ " engine=pg_engine,\n",
+ " table_name=TABLE_NAME,\n",
+ " # schema_name=SCHEMA_NAME,\n",
+ " embedding_service=embedding,\n",
+ " metadata_columns=[\"len\"],\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Search for documents with metadata filter"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import uuid\n",
+ "\n",
+ "# Add texts to the Vector Store\n",
+ "all_texts = [\"Apples and oranges\", \"Cars and airplanes\", \"Pineapple\", \"Train\", \"Banana\"]\n",
+ "metadatas = [{\"len\": len(t)} for t in all_texts]\n",
+ "ids = [str(uuid.uuid4()) for _ in all_texts]\n",
+ "await custom_store.aadd_texts(all_texts, metadatas=metadatas, ids=ids)\n",
+ "\n",
+ "# Use string filter on search\n",
+ "docs = await custom_store.asimilarity_search(query, filter=\"len >= 6\")\n",
+ "\n",
+ "print(docs)\n",
+ "\n",
+ "# Use a dictionary filter on search\n",
+ "docs = await custom_store.asimilarity_search(query, filter={\"len\": {\"$gte\": 6}})\n",
+ "\n",
+ "print(docs)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Create a Vector Store using existing table\n",
+ "\n",
+ "A Vector Store can be built up on an existing table.\n",
+ "\n",
+ "Assuming there's a pre-existing table in PG DB: `products`, which stores product details for an eComm venture.\n",
+ "\n",
+ "\n",
+ " Click for Table Schema Details
\n",
+ "\n",
+ " ### SQL query for table creation\n",
+ " ```\n",
+ " CREATE TABLE products (\n",
+ " product_id SERIAL PRIMARY KEY,\n",
+ " name VARCHAR(255) NOT NULL,\n",
+ " description TEXT,\n",
+ " price_usd DECIMAL(10, 2) NOT NULL,\n",
+ " category VARCHAR(255),\n",
+ " quantity INT DEFAULT 0,\n",
+ " sku VARCHAR(255) UNIQUE NOT NULL,\n",
+ " image_url VARCHAR(255),\n",
+ " metadata JSON,\n",
+ " embed vector(768) DEFAULT NULL --> vector dimensions depends on the embedding model\n",
+ " );\n",
+ " ```\n",
+ " ### Insertion of records\n",
+ " ```\n",
+ "INSERT INTO\n",
+ " products (name,\n",
+ " description,\n",
+ " price_usd,\n",
+ " category,\n",
+ " quantity,\n",
+ " sku,\n",
+ " image_url,\n",
+ " METADATA,\n",
+ " embed)\n",
+ "VALUES\n",
+ " ('Laptop', 'High-performance gaming laptop', 1200.00, 'Electronics', 10, 'SKU12345', 'https://example.com/laptop.jpg', '{\"category\" : \"Electronics\", \"name\" : \"Laptop\", \"description\" : \"High-performance gaming laptop\"}', ARRAY[0.028855365,-0.012488421,0.006031946,0.0041402685,0.058347773,0.034766156,0.0033533745,0.02021188,0.022670388,0.049201276,0.029006215,-0.00986186,-0.052214462,-0.012280585,0.023684537,-0.059519604,0.001378169,-0.04670758,0.020753963,0.0013795564,0.013659675,0.013842887,-0.011299884,-0.03746782,-0.024693582,-0.07013125,0.030126512,-0.028513059,-0.045777187,0.020505989,-0.05952914,0.0015648323,-0.050879195,0.006477519,-0.007886009,-0.02629686,-0.0161126,0.0314275,-0.0328995,0.0265609,-0.01530363,-0.019561788,-0.04535006,0.030131247,0.05462397,-0.0122205755,0.009777537,-0.0049046725,0.02023674,-0.064513534,0.041379478,0.006994005,0.045187026,-0.029661352,0.019398877,-0.02221874,-0.017291287,-0.016321573,-0.033429787,-0.009547383,0.031690586,0.009064364,-0.015285908,0.076494075,0.010917006,-0.016593782,-0.018348552,0.017040739,0.05943369,-0.020822933,0.009285482,0.027736548,0.07029796,-0.0644397,-0.037717465,-0.047550958,-0.0054535423,0.047678974,0.060069297,-0.015072207,-0.04320405,-0.0019738402,-0.061910342,-0.034316592,-0.023359261,0.057676528,0.0054635284,0.042063717,0.020484874,0.005591504,-0.008757174,-0.0153757995,0.04932489,-0.04626516,0.0004756786,0.03749645,0.018522505,-0.015642159,-0.00842546,-0.06284679,-0.006150201,-0.061204597,0.0008340049,0.0040505463,0.014210282,-0.009027461,-0.014203488,0.030791085,-0.022282222,0.0011378798,-0.047313087,-0.008226634,-0.03726029,-0.04307269,0.04519085,-0.021895533,0.019570287,0.08584432,-0.003815025,0.021276724,0.027253378,-0.01660856,0.056772888,0.053538952,0.02739156,0.04655151,0.021516826,0.064367436,-0.021094408,0.0149244,-0.009901731,-0.04166729,-0.0032499651,0.022982895,0.063407354,0.04826923,0.056767307,-0.024418632,0.063300684,0.08071309,-0.054988176,0.01652395,-0.014671885,0.000837919,-0.044569198,0.03651631,-0.016364796,0.0053244857,0.051150765,-0.01878448,0.005112729,-0.0011729974,-0.052268386,0.034706745,0.05072015,0.0052968785,0.021704907,0.045661792,0.002976117,-0.02205154,0.037168674,0.002627892,0.018275578,0.032312263,-0.06719407,-0.056915596,-0.019727554,0.0009450171,0.0029568567,0.047435578,0.033826437,-0.009351167,-0.05718618,-0.062166944,-0.005684254,-0.009788955,0.016364967,0.0122847315,-0.016126394,0.012999976,-0.075272575,0.017478324,0.03005914,0.024401167,0.0099941185,-0.043311242,0.032115143,0.0047207233,-0.034337096,0.0054743756,-0.0024234303,0.012045114,0.032277416,-0.019994166,0.012312445,0.021211047,-0.037350595,0.0017910452,0.04450775,0.0054527316,0.03591427,0.029365221,0.0009824947,-0.006488191,0.034008037,0.01649739,0.07955305,-0.035204325,0.0056851353,-0.0086927805,-0.032573096,0.0010878195,-0.061459325,0.027879931,0.015068312,0.032717325,0.03890655,0.01902891,0.016527452,-0.0020142202,0.025338948,-0.0016015576,-0.06429177,-0.0041105347,-0.025726322,0.09078289,-0.03174613,0.015951345,0.009411334,-0.03598392,0.034463316,0.010011217,-0.009883364,-0.008042991,0.040896636,-0.025115138,0.048056312,0.028382989,0.007793395,0.019581616,-0.02584373,0.04317992,0.025689745,0.02035658,-0.05990108,-0.0007803719,-0.06793038,-0.02130707,0.0048890263,0.042799927,-0.009928141,-0.003192067,0.008781545,0.024785394,-0.07565836,-0.043356933,-0.067785084,-0.019649943,-0.024896448,-0.008327102,-0.015189734,-0.0140810255,0.0049958434,-0.015353841,0.020730853,0.028829988,-0.022614283,-0.03751693,0.011577282,0.031927988,-0.024855413,-0.042680055,0.08018929,-0.0021632465,-0.017928878,-0.0030442774,-0.005651566,-0.0010570051,-0.040446285,-0.00189408,0.06388222,0.0024985478,0.004886204,-0.05113467,-0.019480383,0.049765434,0.0077566532,-0.07356923,0.011988718,-0.020965552,-0.04025921,-0.032686763,-0.0053743063,-0.015599607,-0.03576176,0.00907552,-0.044702522,0.038329247,0.046024352,0.02194124,0.01844749,0.004619246,-0.029577129,-0.031205669,0.00896738,0.0115034515,0.013058729,0.01372364,0.03063813,-0.0316296,-0.04826321,-0.049244087,-0.037644744,0.019473651,0.059536345,0.04033204,-0.06602803,0.050612085,-0.027031716,0.04213856,-0.015262794,0.07257449,0.044631373,-0.0151061565,0.012033797,0.0009732858,-0.014827035,0.046652585,-0.042083394,-0.0436095,-0.035586536,0.026696088,-0.004066648,0.06954644,-0.029623765,-0.020358749,-0.04957031,0.01740737,-0.017026579,0.011162373,0.0487351,-0.031720005,-0.050231773,-0.089686565,-0.014156863,-0.02636994,0.015916161,-0.025308851,0.02081637,-0.02257452,0.021604244,0.10139386,-0.03208752,-0.008580313,-0.008898747,-0.06853021,0.04102758,0.041922912,0.047566738,-0.0341902,-0.07725792,0.005653997,0.00021225312,-0.0104829185,0.001749244,0.011929626,0.078264005,0.036519475,-0.0073295147,0.021337496,-0.008336836,-0.035804152,0.010720447,0.007127837,-0.053885818,-0.009795316,-0.05424524,-0.003111704,0.019710006,-0.012413589,0.02320744,0.024137065,0.023079542,0.0030920266,0.013961592,0.0040291087,0.020265838,0.041183334,-0.0029272675,-0.018539282,-0.011489972,0.017938145,0.025854694,0.033188265,-0.042004097,-0.0106819095,-0.045249976,-0.06986475,0.030204961,-0.032193515,-0.00095170306,-0.0107111735,-0.017970158,-0.02740307,-0.06307846,-0.031544626,0.004178074,0.016592229,-0.032037992,-0.030618787,0.008946463,0.03110429,0.0207187,-0.016861247,-0.08070464,-0.03067543,0.067448415,-0.041909873,-0.0048193526,0.018761802,0.020243261,0.024184326,0.002299031,-0.014152546,-0.035749547,-0.0071563246,0.050069712,-0.027215304,0.049641047,0.02778935,0.070745096,0.023794815,0.0029510225,0.0069351746,-0.034430653,-0.085317925,-0.036851004,0.023848707,0.035138704,-0.017030267,0.041982725,0.014077844,0.012787886,-0.029716792,-0.024732213,-0.059604853,0.024058796,-0.027469097,0.02969232,-0.06889772,-0.034953564,-0.0678685,0.02039748,-0.073483475,-0.04067064,-0.023628144,0.052601792,0.10005532,0.0027910264,-0.00044562414,0.025615653,0.008896907,-0.016369712,-0.030180404,0.026393086,-0.02041892,0.0072918,-0.018448602,0.020845268,0.006290655,-0.010850651,-0.035378493,-0.01083432,0.012116494,-0.045438327,0.05191333,-0.082797736,0.042320468,0.039703712,0.00923727,0.03598509,-0.064069025,0.049349498,0.007205401,-0.0079013845,0.015407162,-0.049755134,-0.0335355,-0.033252683,0.025886077,-0.043650113,-0.021745201,-0.046847582,-0.02873071,-0.01435186,0.01642749,-0.030346846,0.00564007,0.0074587157,0.027222605,-0.024691164,0.007528186,-0.04551536,-0.011026097,0.091698915,-0.062147886,0.0013525741,-0.0065618614,-0.030818032,0.024246406,-0.010786434,0.006758053,-0.016815495,0.071824,0.022536254,-0.026362726,-0.066206455,0.011966612,0.06430261,0.021586932,0.032340884,-0.015460002,-0.0963993,-0.0041012894,0.026189657,-0.101343565,0.038662393,0.07043264,-0.0373032,0.0038455573,-0.017408002,0.12948644,-0.056175977,0.02693295,-0.033682294,-0.032874268,0.0016187532,0.023056049,0.06884863,0.04350595,0.02135146,-0.059129357,-0.0055416543,0.0098204445,-0.008596177,-0.04332969,-0.012624592,-0.09298762,0.041691724,-0.014171953,0.004045705,0.009756654,0.059401184,-0.02852561,0.006892971,-0.019445946,-0.013781522,-0.03458903,-0.001079532,-0.008455719,-0.025446072,-0.03641567,-0.034449898,0.004487285,0.07899037,0.031314176,-0.031828023,0.031026838,0.034468375,0.0166286,0.032397788,0.02265452,0.07575427,0.015329588,0.05969185,-0.049144097,-0.043501142,0.031721197,-0.03434621,0.04558533,-0.00039121095,0.00093291467,0.033810064,0.0131731015,-0.0161992,0.039637238,0.0018543458,-0.041811496,-0.01406263,-0.020126836,-0.011859638,0.029031854,0.018889664,0.015262868,-0.03756649,-0.024570176,0.02538295,0.0038968727,-0.06393701,0.00093783275,-0.05943941,-0.062095385,0.08169533,-0.026443593,0.045758378,-0.026765708,-0.023990292,-0.028646782,0.0013627055,0.0022589415,0.009424216,-0.004252787,0.01159273,-0.0393901,-0.02593045,-0.04785985,0.023880653,0.012857186,-0.028907716,-0.05117687,-0.017512657,-0.035777926,0.01183514,0.025101895,0.089760125,-0.009716518,0.012040118,-0.023447596,0.057904292,0.03486462,-0.014875794,0.05191007,0.002385196,0.016686346,-0.052348964,-0.029286617,0.023832947,-0.02915365,0.007727999,-0.012708917,-0.055755604,-0.0073897606,0.032306697,0.02891973,-0.029123511,0.08987496,0.049180396,-0.08122004,-0.029804248,0.03262262,-0.06680825,0.016717656,0.0038353673,0.021287518,0.0018424556,-0.0041867862,-0.0011719886,-0.044280436,0.02019424,-0.052992586,-0.05063449,0.039644204,-0.0494374,-0.033791043,-0.0041454337,-0.032513123,-0.073564336,-0.04585872,0.0023792102,0.027335508,-0.06999816,0.04888005,0.026423248,0.021874929,0.010904174,0.060097646,-0.034017522,0.05548881,-0.024519302,0.049890403,-0.015645353,-0.060680103,0.017045638,0.019808227,0.025153033,0.0040058065,0.053807795,0.034485374,-0.053428553,-0.0034872151,0.033813756,-0.03047597,0.007858348,0.024711734,0.060215656,0.008143574,-0.0070263194,0.0048007956,0.015641727,0.052094024,-0.049206913,0.016296484,-0.0059813466,0.040864628,0.013278136,-0.012139221,-0.04106141,0.0144868875,0.0013842004,0.021345256,0.04826021,-0.06929805,-0.021199407,0.00090551435,0.009481861,-0.0017141728,0.028452767,-0.019797614,0.038415838,0.056153923,-0.014074272,-0.00823969,-0.00050664565,-0.07698735,-0.025168924,0.057516575,-0.07501726,0.037316702,-0.02765656,-0.011325112,0.058868058,-0.010426108,-0.013318932,-0.0016809561,-0.062076304,0.027063645,-0.020674324,0.06843111,0.018448142,-0.04226709,-0.015164476,-0.008888517,0.040828817,0.048462827,0.00942803,-0.019631634,0.020950766,-0.0003345382,-0.030098192,0.022870619,-0.0017267349,-0.009055838,-0.012781693,0.07583533,0.045031916,-0.02076535,-0.07310905,-0.011597339,-0.00062336307,0.005723161,-0.018269768,0.020560576,0.023111053,-0.00881239,0.0052197427,0.022200806,0.013797317,0.019722437]::vector(768)),\n",
+ " ('Smartphone', 'Latest model with high-resolution camera', 800.00, 'Electronics', 15, 'SKU12346', 'https://example.com/smartphone.jpg', '{\"category\" : \"Electronics\", \"name\" : \"Smartphone\", \"description\" : \"Latest model with high-resolution camera\"}', ARRAY[0.031757303,-0.030950155,-0.058881454,-0.05073203,0.053704526,-0.01064694,0.030361004,0.0036670829,-0.014013894,0.022840602,0.06545107,0.0108244,0.009321064,-0.0236112,0.0098358095,-0.038861487,-0.011348891,-0.011887714,0.011245335,-0.018139482,0.03049321,-0.030338986,-0.001923893,0.011787388,-0.01825618,-0.050398953,0.0036137043,-0.04487695,-0.021582587,0.023590472,-0.051335085,0.08021365,-0.06793676,-0.00514603,0.024418706,-0.054447155,-0.050472837,0.010439093,-0.017847419,0.07124281,0.004419413,-0.028902968,-0.062286377,-0.02737251,0.048311986,-0.029160773,0.0059961462,0.0344943,0.037635062,-0.081315145,0.025175434,-0.0050063017,0.023545247,-0.015210805,-0.035123624,-0.020403884,0.014771475,0.015879042,0.0029214756,0.011768866,0.004276383,-0.009031657,-0.050000243,0.059927624,-0.03906005,-0.027238877,-0.04796615,0.03084268,0.07360646,-0.028875567,0.027232852,0.015592421,0.07156161,-0.059652634,-0.04831314,-0.049740285,-0.017305655,0.10253246,0.016519215,-0.0021727297,-0.0063062175,-0.0015423468,-0.03617129,-0.03982753,-0.059866134,0.082323685,-0.01662162,-0.0048025097,0.011876321,0.08410362,-0.006159452,-0.0008565244,0.04274695,-0.08079417,0.04427687,0.04110836,0.04812812,-0.053979542,-0.004387368,-0.04829328,-0.022975856,-0.015012431,-0.0056774826,-0.03936704,0.023132714,-0.007810687,-0.011018049,0.031620245,-0.02713872,0.0018347959,-0.024968592,0.02253628,-0.00809666,-0.0076680584,0.06435103,-0.020083368,-0.0049473317,0.07430767,0.01915259,0.040656384,0.00998682,-0.014684721,0.026354978,0.032759093,0.037668057,-0.009659323,0.006720873,0.063525185,0.03982695,0.04567435,-0.02619304,-0.030550981,-0.014520635,0.0010599799,0.034034356,0.06294083,0.07422565,0.01973267,0.05249243,0.010003681,-0.034319345,-0.023254821,0.0019625498,0.033209592,-0.015176091,0.056498263,0.0041291295,-0.046049923,0.054690883,-0.021583585,-0.019928787,-0.010311507,-0.03155074,0.038876258,0.055084117,0.0006716143,-0.005959439,0.02702423,-0.0041947966,0.015374709,0.057063535,0.028639654,0.069971144,0.019529812,-0.026227735,-0.083985895,-0.0041349265,0.009833876,-0.015811538,0.016993256,-0.010458223,0.040068664,0.009195164,-0.03924835,-0.007896623,-0.06261605,0.015779363,-0.018634042,-0.0013783163,0.016493134,-0.041971806,-0.039205268,0.020863583,-0.00169911,0.026609324,-0.07237093,0.07898098,-0.008871385,0.017599586,0.018514562,-0.01763139,0.00015460308,-0.03443664,0.026305566,0.0019577034,0.049758997,-0.014016935,0.01580608,-0.005885855,-0.014773614,0.008331391,0.011858725,0.047954902,0.016360788,0.040261615,-0.014324732,0.062151354,-0.037888777,0.02075746,0.039549813,-0.077434056,0.00096539775,-0.044017132,-0.012209571,0.034755055,-0.020098051,0.008095624,0.031291816,0.04792529,-0.008659437,0.01759492,0.009537845,-0.05313831,-0.010890252,-0.03342564,0.061369378,-0.031681072,-0.053262327,8.374469e-05,-0.027414132,-0.013404388,0.033906803,0.025408141,-0.035230264,0.030235829,-0.0014981066,0.023731904,0.029274339,0.047021322,0.025153603,-0.050763946,0.042003185,0.028869675,0.023947056,-0.045773767,-0.029348088,-0.04498305,0.03974547,0.021556387,0.032411546,-0.028107764,-0.01917967,0.020117322,0.035401057,-0.087708965,0.028180089,-0.07627729,0.010020432,-0.055026818,0.013467507,0.05156387,0.030606749,-0.012557438,0.0075980667,-0.049580842,0.025251655,0.011958476,-0.05784425,-0.00688397,-0.026897762,-0.0073929257,-0.082809925,0.0707716,0.0044888635,-0.023634167,0.00959699,0.027249858,0.009045479,-0.008601681,0.007323367,0.014609572,0.007073427,0.0055342577,-0.047172364,-0.023501316,-0.03593993,-0.022744065,-0.031178312,0.007601522,0.01038201,-0.040641543,-0.02084411,-0.04739785,0.0016813428,-0.022378212,-0.024991153,-0.019224035,0.033300195,0.04363394,-0.0072962623,0.0044990415,0.00530943,-0.0061862995,-0.1226422,-0.0048183375,-0.010383665,-0.043834127,-0.010673082,0.00016926302,0.026351877,-0.03451933,-0.017912712,-0.06287377,-0.00329357,0.056648213,-0.005951308,-0.017310314,0.06057505,0.00529039,0.04522765,0.009986563,0.09290384,0.0046436884,-0.027085476,-0.0051616537,0.014926508,-0.027059292,0.07819409,0.0018491915,-0.034066174,-0.04200668,0.017987153,-0.054097146,0.0263208,-0.030290576,0.012135319,-0.053635724,0.0040904377,-0.06391213,-0.012962556,0.039401833,0.029892938,-0.010509396,-0.09667328,-0.004525119,-0.0660734,0.005074788,-0.0043580704,0.048569698,-0.029491736,-0.00813117,0.099913284,-0.02152916,-0.0046480033,-0.004279434,-0.022350302,0.07403285,2.6268553e-05,0.024700351,-0.070556544,-0.046257928,0.047623277,0.013440511,0.022684522,0.0105078975,0.029062217,0.036317576,0.012476447,-0.025555858,0.0043436335,0.006260482,-0.030046312,0.012665346,-0.060015686,-0.042867333,-0.043334395,-0.09350731,-0.015882127,-0.023036648,0.0035012013,0.019168707,-0.029792963,0.014690395,-0.03232301,0.04318316,-0.023454774,0.024906443,0.033632547,0.026205529,0.021056164,-0.014863617,0.03884084,0.019737227,0.0643725,-0.015622061,0.010209574,-0.042415053,-0.041623153,0.020822845,-0.020490937,-0.0542278,-0.0033205135,-0.041752372,-0.069488324,-0.016277319,-0.0044792043,-0.02016524,-0.03959827,-0.032634977,-0.0039365673,-0.0132405395,0.0067148125,0.075648956,-0.05606617,-0.06265819,-0.019359354,0.05813966,-0.01447109,-0.010593954,-0.00086784246,0.00957173,0.02843471,0.00845407,0.024766237,-0.017594881,-0.02089351,-0.023622723,-0.033868976,0.01189866,0.04348284,0.017560178,0.0044504236,0.0201572,-0.010445271,0.016996963,-0.063251264,0.036506347,0.014985517,-0.004923813,-0.019643096,0.004065921,-0.03441569,0.02174584,-0.022037273,-0.105745554,-0.017520802,0.024135107,-0.056571614,0.065653384,-0.11961944,-0.019004421,-0.048515763,-0.018267322,-0.02178645,-0.00048087785,-0.042244278,0.041203473,0.039137937,-0.028382456,0.0027469762,-0.035103243,-0.008536376,-0.022003518,0.013834031,0.04035347,-0.05127768,-0.021083988,-0.019288905,0.030957388,0.03837377,-0.0003459004,-0.043197013,0.059090964,0.03584024,-0.009635979,0.049144205,-0.113005035,0.012198436,0.0030250824,-0.0005766731,0.010016404,-0.004630926,0.036304604,0.030682925,-0.028248072,0.0053004674,-0.028463472,-0.045950726,-0.016214147,0.02234844,-0.024365503,0.0045087263,0.0015641076,-0.046219032,0.019860927,0.011021814,-0.024108216,-0.048900776,0.012885111,-0.0022583513,-0.030102832,-0.016490621,0.024889058,-0.0009473834,0.015075038,-0.040798195,-0.005642347,-0.0029682147,-0.050329093,0.0009567131,0.007919075,0.01719906,-0.018685095,-0.016243592,0.010302834,4.1979074e-06,-0.042400364,0.055864133,0.033395868,-0.017874744,0.0013070442,-0.05331383,-0.10789571,0.0074728676,0.03525642,-0.07436872,0.04979144,0.046753135,0.0027637088,0.014162893,-0.026069263,0.06226656,-0.056384422,0.008216318,-0.02018645,-0.007397228,0.0074180462,0.035483476,-0.01882623,-0.02706421,0.04596009,-0.013163229,-0.021003753,0.037058793,0.052453898,0.013129776,0.015402059,-0.048313417,0.023352273,0.009391176,-0.044023603,-0.0107533,0.054881006,-0.019277383,0.02055352,-0.030710667,-0.02347742,0.0092705265,-0.047558293,-0.024285497,-0.03519891,-0.0038767713,-0.005330039,-0.026968258,0.06881978,0.06537581,-0.023353418,0.01331013,0.045053896,0.032502707,0.065926,0.0009946732,0.051750924,0.005718337,-0.0038732293,-0.029579317,-0.06977859,-0.0048092776,-0.025378013,0.023722455,0.032475006,-0.031788938,-0.00917764,0.0056064464,-0.016738426,0.021969007,0.012666437,-0.046921335,-0.02513667,-0.028311022,-0.009224157,0.05264038,-0.026426777,0.02599612,-0.018745475,-0.015264339,-0.013577108,0.0011754846,0.020499794,0.01423578,-0.015937831,-0.034813095,0.06295408,-0.033208452,0.041733917,0.0022288205,-0.0036853347,-0.015074669,-0.00813031,-0.004992453,0.010502773,0.017247686,0.03162546,-0.006212466,-0.06321386,0.022924462,0.03354761,-0.02742972,-0.018287206,-0.05058406,-0.02762529,0.014693771,-0.009422438,-0.0113650765,0.04500726,-0.009418481,0.023177318,-0.0394831,0.07899207,0.010970399,0.01519068,0.060208563,-0.014248415,-0.027108915,-0.055970594,-0.05615517,0.00082430604,-0.02946103,0.012972071,-0.034580585,-0.092063755,0.023562009,0.09187191,0.03979375,-0.048233856,0.0891921,0.0054705814,-0.07132956,-0.03294508,0.015985591,-0.06979576,-0.008607954,0.03748406,0.018775256,-0.00055046624,-0.0018972756,0.010640039,-0.039262787,0.045647603,-0.052634962,-0.04485457,0.059673585,0.005487001,0.005677175,-0.040526956,-0.0023886457,-0.051557075,-0.026969707,-0.020169057,0.020184118,-0.06750348,0.014797761,0.043389246,0.022667736,0.012956063,0.056346934,0.038232267,0.02334661,-0.002965094,0.053386245,-0.016282998,-0.08433834,-0.005240998,0.020763554,0.0041468525,0.011248255,0.013354228,0.0062226793,0.01238483,-0.042322755,0.017076539,-0.024617095,-0.03331688,-0.001430632,0.05623171,0.0073584137,0.013339925,-0.0041607106,0.015201854,0.029444456,-0.039367896,0.032675862,0.016636375,0.04101005,0.0073330533,0.03937178,-0.01699229,0.026922127,-0.00465699,0.014691186,0.07985071,-0.045738634,-0.040622048,0.040370528,-0.0070402357,-0.048223954,0.048428483,-0.013764062,0.02645368,0.030109879,-0.01834218,-0.0045400057,0.036011115,-0.010352046,-0.068165384,0.037795525,-0.036501475,0.020713413,-1.2293508e-05,-0.00038850267,0.073334076,0.01821627,0.003559663,0.017506005,-0.02564981,0.039007656,-0.026543219,0.018282859,-0.038226757,-0.04996024,0.01010447,-0.012900636,-0.020180488,0.042488355,0.0135185765,-0.0083626835,-0.019743606,0.025633369,0.035687257,-0.053833067,-0.053783447,0.007418253,-0.04581871,0.032362275,0.050387084,-0.010103674,-0.051880397,0.010476682,0.015898407,0.04970622,-0.04664034,0.036457486,-0.017625386,-0.0058598807,-0.011529857,0.018154921,0.013366902,0.0021690137]::vector(768)),\n",
+ " ('Coffee Maker', 'Brews coffee in under 5 minutes', 99.99, 'Kitchen Appliances', 20, 'SKU12347', 'https://example.com/coffeemaker.jpg', '{\"category\" : \"Kitchen Appliances\", \"name\" : \"Coffee Maker\", \"description\" : \"Brews coffee in under 5 minutes\"}', ARRAY[0.025002815,-0.052869678,-0.010500825,-0.024296444,0.049798742,0.043427017,-0.01307104,0.0077243242,0.022190414,0.037746448,0.029453197,-0.009484218,0.0028156517,-0.03531512,-0.012121426,0.0091221025,0.025652027,-0.009445565,-0.02820549,-0.04105274,-0.0010839493,0.015024874,0.053036522,-0.018628811,0.014746092,-0.049109433,0.026801802,-0.0070828577,-0.02369395,0.010975214,-0.03531074,0.04859645,-0.004710616,-0.018579654,-0.0076328423,-0.030808363,-0.012824788,0.03848257,0.014652247,0.058704656,0.00325119,-0.007205416,-0.04686223,-0.028575234,0.02045449,-0.008556303,-0.009746742,0.018289749,0.00093424425,-0.046003163,0.0039943205,-0.023993168,0.05866197,0.008093339,-0.00565744,-0.008198263,-0.001283407,-0.0007927462,-0.018114842,-0.008134085,-0.00014443924,0.021404255,-0.014830747,0.050932012,-0.032427747,-0.027500387,-0.020814912,0.025367612,0.061494272,-0.028271751,-0.002093295,-0.005629965,0.054627255,-0.062579386,-0.01051155,-0.06421958,-0.012094066,0.06576773,0.05998704,0.10272862,-0.021875817,-0.062225047,0.022178214,0.010618126,-0.05723891,0.040955715,-0.038523626,0.021909224,0.018677043,0.056335997,-0.01599579,0.015702266,0.025712736,-0.024550503,0.041618552,0.031751215,-0.0013378685,-0.042116627,-0.033073347,-0.011056941,0.022297822,-0.052519917,-0.06455736,0.030026494,0.04122688,0.0435459,-0.021909805,0.025392938,-0.05491582,0.022167888,-0.06104317,0.021199005,0.021531114,0.0003258208,0.051008765,-0.0056826724,0.0019850046,0.08186525,0.014742098,0.01913513,-0.026228607,-0.023587128,0.041640177,0.016765678,0.028365733,0.057187237,0.011515794,0.0734812,0.048084594,-0.0028821004,0.00025123838,-0.010272774,0.025670059,-0.049766205,0.0862307,0.07104121,0.008422137,0.026603732,0.06897059,-0.0013259795,-0.003537648,-0.016978277,-0.03289158,0.019160148,-0.030429484,0.03210423,-0.0025404708,-0.052619252,0.0020272017,-0.014941184,0.0026864705,0.012819193,-0.043763664,0.057997666,0.043563023,0.03174006,-0.04444913,0.0060016355,-0.029776296,-0.017748147,0.036185395,-0.0014833601,-0.017309692,0.04368944,0.020283954,-0.0160715,0.03019354,0.02680017,0.013467745,0.010598811,-0.009857402,0.0035379697,-0.04074403,-0.015414817,0.016311716,-0.0669727,0.0034562463,-0.024640094,-0.023524309,0.0028607736,-0.06249814,-0.058054965,-0.007223816,0.012088017,0.029124737,-0.030978883,0.07969112,-0.05076358,0.015344627,-0.00898595,-0.0097088795,-0.019155432,-0.035673082,0.027780814,0.006400352,0.055502266,-0.046420977,0.03919276,0.040964182,-0.024075434,-0.014520242,0.07941375,0.023109328,0.030869437,0.06598536,0.00059927267,0.076354064,-0.048273984,0.0025508753,0.0066330666,-0.070879966,0.03704847,-0.0650441,0.01176703,0.033744898,0.0400285,0.024317512,0.028281165,-0.008897873,-0.029537052,-0.0047060223,0.026686963,-0.07052627,0.023556747,-0.056385886,0.0714133,0.007949809,0.011887155,0.0029032454,-0.015065537,0.011513513,0.050219424,0.010533179,-0.009971522,0.03655571,-0.0066924663,-0.012303563,0.016773308,0.013691093,0.025839401,-0.044451136,0.049260832,0.05713467,0.013278825,-0.022100078,-0.0017930771,-0.016181005,0.0217466,-0.02600776,0.046996534,-0.022629611,-0.023503313,0.0074507482,0.0134722935,-0.04945182,0.022608835,-0.026130896,-0.01177188,-0.027667308,0.026118958,0.0025001818,0.021639917,-0.015105975,0.02968347,-0.043928802,0.03762012,0.019912925,-0.004347233,-0.006596504,0.016333994,-0.025137693,-0.01686705,0.04786869,0.034643404,0.011117003,-0.011134983,-0.0074818125,-0.006335571,0.022040822,-0.006491301,0.0054816976,0.038022403,0.016072717,-0.06609374,-0.03203102,-0.059326455,-0.04408214,-0.03787348,0.014894112,-0.02038928,-0.044823527,-0.015866352,-0.047105137,0.002020473,-0.04468357,0.018793538,-0.029475007,0.06967502,0.04684481,0.048074055,-0.0010090554,-0.0027273456,0.047790546,-0.030050496,0.023022242,-0.028264726,0.03571066,-0.0164874,-0.019399788,0.0076415916,-0.0060172956,-0.010469042,-0.045296766,-0.0071801674,0.032818798,0.034934863,-0.0737483,0.0327411,-0.006032433,0.05928009,-0.00927453,0.07627373,0.0050010816,-0.048511107,-0.0037969523,-0.007150538,-0.010152546,0.025746513,-0.02757783,-0.049112115,-0.029450508,0.037618097,-0.04765299,0.021502782,0.04031621,-0.021789404,-0.03477437,-0.0029428764,-0.04645585,0.015724704,0.0061205924,0.027327916,-0.016831782,-0.07413835,-0.009106179,-0.005994898,0.0015746661,-0.0066348854,0.08860898,0.026653405,-0.010490873,0.01737892,-0.036203787,0.0019658727,-0.05349199,-0.031604912,0.059320047,-0.0035595773,-0.013159466,-0.043662973,-0.000936755,0.037883844,1.1725969e-05,0.008455511,0.028007427,0.026448535,0.03587197,0.034501214,-0.020195212,-0.036874935,0.008322776,-0.038275808,0.014955824,-0.066956565,-0.03433901,-0.043297864,-0.07503335,-0.037108134,0.032691672,-0.05912909,0.023559488,-0.023238983,0.0012042256,0.0074822125,0.0058873207,-0.021845229,0.0054280413,0.05752058,-0.026954507,0.026175871,0.012301664,0.06307251,0.07353519,0.011740042,-0.012562488,-0.025707787,0.011014364,-0.064245604,-0.018075097,-0.04286179,-0.06992585,-0.031043975,-0.0022823277,-0.05855018,0.015864456,0.00024379989,0.0070141326,-0.00035948,-0.023150876,-0.063177474,0.008194795,0.023019124,0.014603101,-0.06850171,-0.07586402,-0.029384725,0.09732399,-0.023403296,0.00983274,0.00043465907,-0.037277438,0.060318034,-0.010698135,-0.0012939094,-0.015873678,-0.006272459,0.0014064384,-0.041425075,-0.021238888,0.021737115,0.030599548,0.043125883,0.01929081,-0.0011234619,-0.031159677,-0.05745639,0.0146679375,0.046521254,-0.01835481,-0.033141162,0.00036415283,-0.06466151,0.043580752,0.011921412,-0.07292401,-0.047980927,0.02159395,-0.023352068,0.0425091,-0.09635663,0.0060955146,-0.06484201,-0.029811602,-0.026076958,-0.014945281,-0.04334233,-0.00242451,0.047840517,-0.02103297,-0.0191666,-0.0074735563,1.0544848e-05,-0.028074,-0.037163526,0.030064873,-0.02934737,0.050285384,-0.023986174,0.025914317,0.10199452,-0.021887174,-0.0066847154,-0.023618985,0.03283886,0.045797225,0.047762897,-0.07030183,0.026901271,0.008702326,0.017019885,0.033345792,-0.03833666,0.031567782,-0.013102635,-0.009532979,0.025451964,-0.021708276,-0.023218581,-0.07980661,0.03028782,-0.021675726,0.03096571,-0.018742265,-0.04427001,0.009433704,0.03455316,-0.035231985,0.04002238,0.012793141,0.025124295,-0.04512409,-0.06486318,0.019942157,-0.030111039,-0.0069209165,0.0015545462,0.028818183,0.0014206765,-0.032698274,0.008883163,0.058960456,-0.00906729,0.0298577,-0.0070162034,-0.014469902,-0.0032146918,-0.04448409,0.03293327,0.040138587,0.01842061,0.0055912337,-0.03388838,-0.071546026,0.02821449,0.033089,-0.04839594,0.016159212,0.08211776,-0.08987595,0.036964364,-0.051373526,0.1035708,-0.053108595,-0.01896186,0.01644011,-0.012502358,0.008263514,0.04065409,-0.015298684,0.0011162056,0.04276282,0.0027434586,0.0324373,0.03511016,0.02446925,0.002442109,0.049384676,-0.05747281,-0.0020478321,-0.03639974,0.011938583,-0.031114291,0.03284646,-0.03238849,0.08670559,-0.07415254,-0.036738325,-0.025126172,-0.045095183,-0.015307702,-0.06554373,-0.05546525,0.005472855,-0.006981692,0.04587679,0.111925036,0.013912294,0.014268016,0.058842134,-0.011192024,0.034922387,0.012045642,0.008008024,-0.014226386,0.06913233,-0.04700873,-0.06164794,-0.0024386728,0.043209903,0.051432677,-0.017323477,0.013788927,0.012737198,0.06472892,-0.070449375,0.005222667,0.050599333,0.0015403829,0.015714316,-0.008632714,0.014941663,0.06433311,-0.021354778,-0.0071928906,-0.028242689,0.018915592,0.021451298,0.0063637616,0.0019523413,-0.017883593,0.028570741,-0.016318232,0.053636383,-0.028484613,-0.006531752,0.022900375,0.023723338,-0.024363475,-0.015181002,0.024642847,-0.002409233,-0.0001194501,0.013567875,-0.046026736,-0.016705032,-0.013025837,0.020370122,-0.027258568,-0.04735096,0.011894463,0.0019317217,-0.0031460563,0.040866848,0.00464604,0.03964947,0.027275842,-0.0030081465,-0.008669969,0.0462421,0.010375526,-0.024637504,0.08480695,-0.02768799,-0.005021901,-0.009944692,0.015040328,-0.0051919715,-0.043738216,0.054622557,-0.0116185825,-0.044851393,-0.01769878,0.06967592,-0.026938388,0.0030814619,0.07516173,-0.022243993,-0.09390373,-0.056307606,0.011178256,-0.058882743,0.016906237,0.010931337,0.011277608,-0.03310829,0.008875099,-0.017342865,-0.049926963,-0.0021014255,-0.019715691,-0.024091842,0.029629463,-0.06452303,0.009643791,-0.025999011,-0.017722748,-0.09347366,-0.019748896,-0.011190205,-0.0044534663,-0.04336357,-0.01312215,0.056558847,-0.022783643,0.0004763564,0.04152026,-0.03813543,0.0038315274,0.021157283,-0.007934057,0.0004752217,-0.057082873,-0.011285772,-0.014152046,0.03181829,0.033805694,0.04453719,-0.02024123,-0.0038247174,-0.0262423,0.007036252,-0.012817323,-0.025822328,0.06599188,0.067939,-0.022174655,-0.022773167,9.6714546e-05,-0.017627345,0.08549309,-0.06266334,-0.00575442,-0.011873023,-0.07250961,0.0056728884,0.017012162,-0.025071641,0.022021066,0.030550413,-0.010627088,0.050028834,-0.01721913,-0.050976366,-0.024867795,0.011782799,-0.075504154,-0.004392594,-0.01807583,0.031157117,0.030725744,-0.014750008,0.005684259,0.047403537,-0.08811708,0.007985649,0.043377616,-0.037903026,0.029741386,-0.0011720062,-0.010578729,0.051289707,-0.024345556,0.017949736,0.02636295,-0.059689533,0.06373776,-0.049072567,0.013506145,-0.040476285,-0.02940512,-0.023568999,-0.00035632766,0.056101788,0.061561547,0.03079068,-0.02166795,0.009211557,0.0030255727,-0.0036865661,0.023821775,0.0015869564,0.0064414316,-0.057368714,0.061502002,0.023947174,0.0046180966,-0.05202509,0.002360597,0.03557417,0.036739,-0.03005605,0.047780115,0.025282156,0.034349978,0.034781702,0.0276351,-0.040908,0.081558466]::vector(768)),\n",
+ " ('Bluetooth Headphones', 'Noise cancelling, over the ear headphones', 250.00, 'Accessories', 5, 'SKU12348', 'https://example.com/headphones.jpg', '{\"category\" : \"Accessories\", \"name\" : \"Bluetooth Headphones\", \"description\" : \"Noise cancelling, over the ear headphones\"}', ARRAY[0.022783848,-0.057248034,-0.047374193,-0.04242414,0.049324054,0.0077371066,0.017048897,0.00500827,0.008471851,0.010170231,0.054357704,0.018568166,-0.024179503,0.026519066,0.026404649,-0.06330503,0.014405935,-0.015520485,0.0052459002,-0.0398403,0.0026082278,-0.026374431,0.020055598,-0.009738811,0.013321584,-0.033184614,0.034118295,-0.0011876881,-0.04513898,0.04878162,-0.0725106,0.018109042,-0.075869314,-0.023766529,0.015067321,-0.019572936,0.024169574,-0.01577634,-0.048197363,0.049358875,-0.030935159,-0.0363981,-0.04534119,-0.044748895,-0.004167742,-0.02121328,-0.052715167,0.0006209187,0.036595955,-0.085123576,0.052309636,-0.01926014,0.00049565616,-0.0057477825,0.010993081,-0.06675727,0.0037074706,-0.033420403,-0.052601676,0.023439946,-0.01880516,-0.009576131,-0.0114066675,0.10504714,0.00022831495,0.029810086,-0.0044366047,0.043377023,0.06093195,-0.004545408,0.013371212,-0.029174658,0.06625106,-0.0077476054,-0.0163617,-0.056035727,-0.024698364,0.06076837,0.020102862,0.038081013,-0.018504761,-0.027918378,0.03942784,0.004596525,-0.057653908,0.034515597,0.010063118,0.04525672,0.023651283,0.03596632,-0.0378574,-0.013078957,0.021554954,-0.0606351,-0.007272484,0.044470455,-0.015513987,-0.018171282,-0.014020262,-0.040379126,-0.032836802,-0.055859733,-0.05644243,-0.001610613,-0.05527219,-0.00052593346,-0.00546389,0.02911079,-0.0037673921,0.036246333,-0.057133533,0.043779045,-0.0028422247,-0.044305976,0.05993566,-0.005543668,-0.0015800337,0.07515586,-0.00020748413,0.03876171,0.026035579,0.012980581,0.056657698,0.020252425,0.029382393,0.011205804,0.039896134,0.04349186,0.08402962,-0.0031059172,-0.022395832,-0.023471512,0.029480197,0.0038065156,0.07106566,0.07560159,0.019708911,0.0063190344,0.06826459,0.05426478,-0.016353253,-0.016603524,0.035430502,0.01285351,-0.044608854,0.06445639,0.027575186,-0.020047447,0.07155171,-0.024042875,0.007684551,-0.057774883,-0.05863421,0.04027459,0.034241315,0.029786138,-0.011771758,-0.008067332,0.005154275,0.017256541,0.012795448,0.0361206,0.046198364,0.007581977,-0.0643159,-0.032997373,0.025989803,0.039828006,0.00950064,0.043332074,0.016609278,0.034839373,-0.022875424,-0.028605282,-0.017703732,-0.06238004,0.010994231,-0.0007306017,-0.034711856,-0.0440203,-0.025970237,-0.04595589,0.030582627,0.0073314123,-0.017986864,-0.055571377,0.082270294,-0.018736921,-0.0012149982,-0.0060279733,0.0044796504,0.025173035,-0.037219252,0.00027956237,-0.010430433,0.02825617,-0.046855696,0.018841878,0.0435598,0.005803966,0.0019149927,0.092197396,0.022937872,-0.0033373323,0.072473325,-0.014439769,0.047117453,-0.08000118,-0.012863106,0.0260884,-0.04135028,0.0070068296,-0.07510927,0.03672727,0.033531025,0.042364623,-0.019229556,0.0048453975,0.031276144,0.014006409,0.016036421,-0.017694592,-0.036794797,0.014908425,0.030831292,0.03190712,-0.022060342,0.041704472,0.017002491,-0.06408182,0.03923344,-0.02587273,-0.017719302,-0.025430005,0.06814103,-0.009046621,0.033220492,-0.033640996,-0.02523642,0.048086986,-0.035158273,0.048114188,0.043751266,0.01995209,-0.0295469,-0.020247698,-0.053099316,0.032099206,-0.045260355,0.0326798,-0.0043251985,-0.052964494,0.07017924,-0.0037189184,-0.03395965,0.040903587,-0.060891,-0.010537573,-0.030650055,-0.029651405,0.013975478,0.007255845,-0.010439494,-0.011794211,-0.05466926,0.024609366,-0.017408509,-0.05243266,-0.020957882,0.037831362,0.0216147,-0.035116594,0.03829302,-0.016048789,-0.035066966,-0.013764898,0.00042713518,0.030633073,-0.008326726,-0.015224956,0.012373721,0.0844943,0.0245434,-0.046264216,-0.011655971,-0.013199105,-0.05529712,0.006216126,0.038966317,0.04622981,-0.039118554,-0.044550307,-0.009771392,-0.006652356,-0.023040479,0.010476257,-0.004093151,0.008969803,0.010324751,-0.022387082,0.023577597,0.019100022,0.008391375,-0.07391311,-0.02210422,0.021720598,-0.0109519595,-0.0820701,0.022086475,-0.003670014,0.0019491176,-0.053155318,-0.022906458,0.0148452455,0.015515676,0.019605495,-0.02868708,-0.01828674,-0.0005499542,0.06639364,-0.01821442,0.09175476,-0.0016622626,-0.059729476,-0.019477114,0.025505545,-0.034742665,0.028956799,-0.019135797,-0.016046764,-0.03779796,0.06325585,-0.04046284,-0.0065921973,-0.0019740656,0.053527426,-0.06304376,-0.035805233,-0.04792203,-0.0012729234,0.048093352,0.007456611,-0.058022104,-0.07442454,0.012629627,-0.027595298,0.0021199721,-0.027464667,0.02698153,0.00060683774,0.044545636,0.06083593,-0.0031620082,-0.025901018,-0.034706157,0.013555886,0.042545,0.056980383,0.009854132,-0.06190446,-0.034308147,0.0043845526,0.017239122,-0.031214224,-0.010807414,0.026710719,0.022394834,-0.009421089,-0.04236166,0.022885358,0.01318956,-0.019174583,-0.0026612883,0.010784672,-0.010333064,-0.043234736,-0.054500565,-0.027753199,-0.022639737,-0.03062474,0.008183766,-0.017117208,0.03024305,-0.03615811,-0.01150264,-0.03863528,0.04852956,0.024548976,-0.012997513,-0.0041008275,0.03406041,-0.0070994645,0.072934166,0.02805505,-0.030694276,-0.035828616,-0.017640414,-0.03957751,0.06840472,0.0046152286,-0.020437988,-0.025648775,-0.083415866,-0.04167123,-0.035016168,-0.015291769,0.009293348,0.04628708,-0.014721913,-0.0033228637,0.04403616,0.061276685,0.037830554,-0.041214965,-0.084479295,-0.0012414041,0.030978376,-0.017235488,0.04445431,0.05231969,-0.0008037167,0.045372415,0.02067265,0.024952972,-0.033815585,-0.03739797,0.034983158,-0.016312862,0.017926387,-0.02016297,-0.019343764,0.017820694,-0.011671569,0.02410841,-0.042012513,-0.03900872,0.032663334,0.011938514,-0.029834026,0.047740217,-0.0058686035,-0.046729274,0.05985927,0.007610642,-0.060446266,-0.04216537,0.017497085,-0.06986214,0.076023735,-0.10476386,-0.020937927,-0.073560745,-0.014322972,-0.048601817,-0.0056885225,-0.03637434,0.04715089,0.054749545,0.014689732,0.006048463,0.046543427,-0.017363597,-0.03678888,-0.08802858,0.063708976,0.021423126,0.04030153,-0.036243204,0.036450744,0.024569608,0.016401349,-0.022465378,-0.0034262848,0.060547307,-0.014745138,-0.020591581,-0.0054737274,-0.0074623367,0.06138278,-0.016604895,0.0032445828,0.009028142,0.002864045,0.001341044,-0.03825005,0.03237135,-0.009647875,-0.0470159,-0.024240978,0.017859152,0.010279892,-0.014414872,-0.017152937,0.020384172,0.008366546,-0.003495199,-0.024638942,-0.031768326,0.06240018,-0.0067493794,-0.04322142,-0.0030645356,-0.0027114467,-0.0072583677,0.06152745,-0.05525731,0.01201016,0.034348775,-0.032004267,0.027236925,0.05926736,-0.010569189,-0.023563573,0.0018119658,0.04231199,0.01966649,-0.014960187,0.029649874,0.01606933,0.0033748902,0.021692606,0.00794783,-0.113133654,0.012736659,0.03742399,-0.010987754,0.02547777,0.026347551,-0.09020402,0.009588993,-0.043276373,0.106708415,-0.049185734,0.007007848,0.030148245,-0.026434064,-0.017702276,0.0007948643,0.026716268,0.013030543,0.013651695,-0.019745413,-0.0087912055,0.0046337135,0.038207695,0.0059329793,0.016351476,-0.069271706,-0.006662047,0.028512167,0.0038343759,-0.00027066944,0.042824432,-0.038911343,0.012483791,-0.06324616,-0.0023198558,-0.0028892683,-0.043326154,-0.035926916,-0.006348816,-0.025913015,-0.015930604,0.040185526,0.044628017,0.039083507,0.009474702,0.017115341,0.05052131,-0.01357451,0.020331299,0.038159154,0.0349774,0.015846666,0.022699736,-0.022343196,-0.056707054,-0.0010885954,0.020071063,-0.000391925,0.06397024,-0.024627347,-0.005184313,0.05034518,0.009061781,0.034097236,-0.007981921,-0.03801412,-0.0028578758,0.013567372,-0.008190868,0.033633735,-0.053976685,-0.025468381,-0.044378527,0.032747604,0.036202736,0.038062613,0.014995585,0.0036792904,-0.01603846,-0.047275733,0.066113465,0.0045884387,0.08915791,-0.0068142917,-0.0064188805,-0.060516927,-0.016080644,0.041549493,-0.008397882,-0.0071816393,0.0064753946,-0.0017467311,-0.019128935,0.0164788,0.022168875,0.011003241,-0.026863558,-0.05437178,-0.032724023,-0.0042122444,0.010392475,0.0042387135,0.04948556,-0.013747793,0.051330764,-0.0050607547,0.054571416,0.025556272,-0.00022029632,0.047628347,0.01427685,-0.020254403,-0.03590239,0.011610469,0.041846078,-0.02470694,-0.013697807,-0.021193847,-0.04341633,-0.0041078446,0.053439837,-0.021625757,-0.037942924,0.07774385,0.005912317,-0.0929516,-0.025328774,0.025199909,-0.041145753,0.017296704,-0.0050417483,0.012186051,0.0024183579,-0.025558045,-0.0051468383,-0.07548276,0.028603543,-0.04549798,0.007635448,0.010916566,-0.029269122,0.01546215,-0.024502348,-0.021702306,-0.025917016,-0.016031386,-0.0012059321,0.031981774,-0.056502126,0.025166377,0.04160211,-0.020680273,0.010293909,0.029529357,-0.01568588,0.026115898,-0.01032236,0.02089118,-0.01709118,-0.0597839,-0.029326,0.045068808,0.00761455,0.034416553,0.022160128,-0.025166225,-0.04248117,-0.029465536,0.027829373,0.006342403,-0.05032602,0.040032476,0.07705231,-0.01583979,-0.0049204687,-0.0140532,0.022657644,0.05293866,-0.009608256,-0.005003684,-0.02478457,0.029608795,-0.022698086,0.003895031,-0.0039730286,0.023749523,0.07514458,-0.036099195,0.04289709,-0.02329434,-0.06419562,0.037709154,0.0004289863,-0.02686404,0.0032855049,-0.030955583,0.018836787,0.033646755,0.022193655,-0.028475504,0.00394302,-0.05765806,-0.062945105,0.024937302,-0.06828151,0.016094193,-0.036405172,-0.016450962,0.04907368,-0.05975235,-0.04858766,0.07675482,-0.06289323,0.052024625,0.018600732,0.038572676,-0.0011811757,-0.07612922,0.03844793,-0.015206284,0.05163554,0.046980042,0.023522004,0.00037627618,0.011324654,-0.028600419,6.0430884e-05,0.00431597,-0.023766082,-0.015001608,-0.018692184,0.08730754,0.032889076,-0.018612336,-0.019428827,-0.002722986,-0.020110032,0.04016962,-0.043657966,0.044247244,0.019661218,0.042629678,0.016911589,0.038489193,-0.0036892071,0.015036206]::vector(768)),\n",
+ " ('Backpack', 'Waterproof backpack with laptop compartment', 59.99, 'Accessories', 30, 'SKU12349', 'https://example.com/backpack.jpg', '{\"category\" : \"Accessories\", \"name\" : \"Backpack\", \"description\" : \"Waterproof backpack with laptop compartment\"}', ARRAY[-0.0028279827,-0.02903348,-0.02541054,-0.025740657,0.06572692,-0.01105207,-0.018005589,0.014476618,0.0039552255,0.04976717,0.034852527,0.018194634,-0.010718678,0.012003344,-0.008418802,-0.026018273,0.029329967,-0.016163627,0.009272989,-0.03639675,0.011046671,-0.008078595,0.023365447,-0.0033083789,0.020028763,-0.025491415,0.033595297,-0.0116388025,-0.057485484,0.06268812,-0.05302806,0.033510745,-0.06083909,-0.03115934,-0.014793818,-0.028653687,-0.011399838,0.03950949,-0.03437827,-0.001663737,-0.01088612,-0.01894241,-0.055767413,-0.0044360803,0.043946534,0.012161133,0.03891473,0.001239441,0.009908146,-0.07272227,0.055397917,0.003453955,0.016562339,-0.041937787,0.05197343,-0.026436094,-0.025229415,-0.034988422,-0.02628748,0.022921052,0.013600747,-0.0020118777,-0.033795673,0.06700571,0.016018055,-0.024256106,-0.02621731,0.045516666,0.05339654,0.0040287147,-0.03260985,0.0014520925,0.064204894,-0.07453437,-0.05054596,-0.042698923,-0.010596,0.013536595,0.0057951836,0.02499754,-0.008574824,-0.0074555897,-0.03567392,-0.016175417,-0.048651025,0.051804803,0.032162882,0.015001442,-0.015329716,0.028219966,-0.031235777,-0.011996138,0.001956758,-0.057833184,-0.022306677,0.031238675,-0.006414606,-0.06930158,-0.017475452,-0.027142663,0.020731354,-0.02221535,0.031049741,0.02081393,-0.022421336,0.0264318,-0.009509332,0.03522677,-0.004379289,0.011600757,-0.022017384,0.010730822,-0.010784208,-0.032706123,0.011207074,-0.023580823,0.013793131,0.05083659,0.047280807,0.048402432,0.05347524,-0.01837716,0.005956893,0.038448945,0.056967188,0.0107236095,0.03256511,0.06276655,0.04472847,0.04416061,-0.010116117,-0.048367113,0.029135885,0.010681488,0.036315914,0.056885246,0.03745567,-0.045721106,0.060501557,0.07454113,-0.018330548,-0.0113306865,-0.011580698,0.020741342,0.020118712,0.08663372,-0.009871896,0.0153012,0.05436686,-0.032210644,-0.029824084,0.023739373,-0.024163425,0.025129095,-0.016016128,0.04870382,0.013377057,0.012678613,0.011070294,-0.0072714896,0.042209458,0.029714484,0.042831365,0.032464053,-0.047759824,-0.032160178,-0.014084912,0.016434442,0.009782443,0.0013573115,-0.015243139,0.007621731,-0.037185922,-0.054615762,-0.008570435,-0.00029953485,-0.012346052,0.00016998274,-0.03163527,-0.0139267165,-0.07079747,-0.007061694,0.020720486,0.0025725542,0.019498186,-0.03700232,0.10145702,-0.004775887,-0.042089477,-0.023965659,-0.04021527,-0.0004672301,0.007410538,-0.0024715534,0.013863051,0.02261263,-0.027591249,0.020157337,0.012993745,-0.0067202765,-0.029478177,0.052134037,0.020799996,0.014809602,0.06626069,0.0069596902,0.063764,-0.04220143,-0.0040134583,0.007221788,0.014255095,0.059271786,-0.04741277,0.014235989,0.067689635,-0.005667792,0.03801926,0.0117749525,0.025480399,0.011015113,0.0037910545,0.00022392142,-0.044315543,0.010447604,0.010668871,0.0779741,-0.08010141,0.04994428,0.0024064495,-0.04755275,-0.0114773,0.014421721,-0.028229935,-0.06231835,0.05197635,-0.00798093,-0.0025467642,0.010583627,-0.017485484,0.048588324,-0.0008222008,0.033517472,0.007129084,0.0010124474,-0.05219366,0.017978905,-0.01833836,0.019664295,-0.008339645,0.013213594,8.404173e-05,-0.058585837,0.06634499,-0.032446846,-0.066239364,0.0011773852,-0.07504017,0.026009388,-0.026110237,-0.00089784985,0.004558591,-0.027107328,0.017480537,-0.0062587988,-0.008309775,0.024417007,0.022020336,-0.025295774,0.0089702625,0.026482984,0.008462929,-0.043885507,0.023143305,-0.012536918,-0.025114551,-0.030675266,-0.030063663,-0.004634334,-0.0024470752,-0.03869859,0.015594325,0.0131572345,0.0029243943,-0.046118148,-0.03834942,-0.022946607,-0.0071579637,-0.042097863,-0.01229437,0.024193348,-0.03535916,-0.05725744,-0.014191351,-0.034702625,-0.03553529,-0.0063754944,0.0024684118,0.042859882,0.013016258,-0.02985961,-0.0020391515,0.030625137,0.016144354,-0.049042817,0.024231678,-0.025589447,-0.05898161,-0.023193993,0.031626217,-0.028190944,0.017940147,-0.049932066,-0.04810013,0.047244985,0.1082508,0.001041191,-0.057233974,-0.006368648,-0.06945289,0.048442855,-0.021192377,0.10568124,0.053165488,-0.0084766345,0.031292096,-0.009400329,-0.042162478,0.06982496,-0.014560452,-0.0073914286,-0.048956916,0.030368945,0.022202695,-0.0050742053,-0.012722453,-0.011377622,-0.051865157,-0.0070718606,-0.01745792,-0.02462795,0.030636197,0.030104883,-0.04482826,-0.11079195,-0.024324121,-0.002861835,-0.014245193,-0.020608244,0.03153579,-0.009367316,0.014898636,0.033479474,-0.015162162,0.01307384,-0.052216247,-0.025208864,0.014302212,0.023454865,0.030064361,-0.00028293114,-0.05237653,0.02271106,0.0057998034,0.021696828,0.0065965196,0.061783127,0.052609395,0.018527359,-0.012383652,0.036548115,6.0759903e-05,-0.027102679,0.0020538126,-0.026467739,-0.00931995,-0.056754645,-0.059189495,0.022508893,-0.037084196,0.008752761,0.011397571,-0.001640177,0.010061019,0.024978038,0.01750796,0.0017406448,0.0692028,0.042931892,0.008515072,-0.03527143,0.006649334,-0.0015101181,0.09099013,0.0423155,-0.060909722,-0.007118597,-0.0070489836,-0.05583034,0.035233498,-0.008949495,-0.021592604,-0.023997912,-0.030185444,-0.015039309,-0.07469254,-0.05510056,0.029319923,0.01650634,-0.0660325,-0.015404232,0.03715267,0.03294396,0.005133208,-0.071616374,-0.04183193,-0.039515678,0.06556278,-0.006204309,0.018765671,0.0087025305,0.04139539,0.039423864,-0.0096283825,-0.03788884,-0.030308004,0.016888767,0.033892095,-0.0046063373,0.036512673,0.046478424,0.030432703,-0.008351917,0.038958482,0.030963391,-0.0012744869,-0.068324916,0.035514664,0.029101191,0.019952206,-0.035990257,0.05016547,-0.0034300084,0.011099454,-0.01642832,-0.055300374,-0.07178654,0.023697836,-0.02809622,0.054089297,-0.1083301,-0.018408947,-0.075191386,-0.0048826155,-0.042217527,-0.069461025,-0.06703293,0.009000863,0.06276143,-0.0017238993,0.03036515,-0.009982445,0.055421855,-0.027764114,-0.05543302,0.022685751,0.022210898,0.049183954,-0.0047965907,0.055648796,0.011152965,-0.014035957,-0.02337775,-0.01123261,0.052066986,-0.006916061,0.03199984,-0.094863154,0.003547006,0.041498255,0.004490882,0.020994756,-0.07455022,0.036187306,-0.0051827626,-0.017956927,-0.00029976605,-0.044009093,0.0028350798,-0.052361596,0.07876513,-0.06365592,0.0017824164,0.017088404,-0.038679466,-0.008001763,-0.0013830748,-0.025812596,-0.0182766,-8.765931e-05,-0.0072022257,-0.046436142,-0.072371304,0.0057044053,-0.03468649,0.056389496,-0.020051511,0.031401794,0.0026272596,-0.045338016,-0.029466175,0.008883405,0.036455907,-0.012484258,0.0015844881,0.036832172,0.023578366,-0.043958467,0.00577308,0.055652507,-0.036696434,0.002894534,-0.032786682,-0.05258521,-0.006260205,0.030400572,-0.061743345,0.021158593,0.028482735,-0.061397683,-0.015825676,0.01941984,0.075950265,-0.11372872,-0.018362995,-0.010228874,-0.009783626,0.023449693,0.027557475,-0.0023083165,-0.0021188299,0.05987247,-0.00944442,-0.020868102,0.03482851,0.039515875,-0.026193311,0.023197955,-0.07931663,0.005395495,0.013140455,-0.061495673,0.0022219154,0.038023517,-0.05545234,0.020771723,-0.0067305462,-0.03169365,-0.021337083,0.019638145,-0.053754907,-0.035756346,-0.036120877,-0.05413345,-0.0077516357,0.03129875,0.016264724,-0.011121187,0.016678393,0.0678958,-0.014889522,-0.019517552,-0.0059457496,0.018003179,-0.0072531863,0.081852585,-0.030259738,-0.05358454,0.020454926,-0.009424692,0.10091245,-0.012819172,-0.011656013,0.031110896,0.08538375,-0.026021762,0.047623295,0.04384129,-0.05093276,0.014624959,0.026958883,-0.004577614,0.02551685,-0.019736024,0.0063903728,-0.024696782,-0.041850932,0.027209712,0.0050771283,-0.028201208,-0.03125501,-0.001541728,-0.06142714,0.054404832,-0.007287412,0.0626698,0.03180891,-0.015927717,-0.04500077,-0.0022995493,0.0124429,-0.015138294,-0.026622217,0.008842311,-0.010787062,0.0010311591,0.0013770667,0.039663706,-0.02192414,-0.019322718,-0.051264115,-0.011981459,-0.03414706,-0.006800422,-0.028382706,0.043155897,-0.007300542,0.02638807,-0.019196216,0.06930381,0.020622948,0.014042502,0.06754253,-0.043790415,0.015294639,-0.040941276,0.028382495,-0.013607999,-0.040120583,0.008768077,-0.0101868035,-0.060808867,-0.013499631,0.059239235,0.035230562,-0.019976182,0.11870333,0.053272087,-0.08745547,-0.018802922,0.004555603,-0.028306624,0.0020639726,-0.018859716,0.026370116,0.0097041875,-0.0029847843,0.017317675,-0.0533067,0.038994376,-0.03322375,-0.052456018,0.050101582,-0.015041677,-0.03370439,-0.010739062,-0.039727744,-0.045931656,-0.08658831,0.05190126,0.055936754,-0.07664951,0.041408025,0.011245535,-0.012530026,0.024861438,0.016954603,0.017269976,0.06397909,-0.000105038154,0.036761504,0.006065827,-0.02139009,-0.025604198,0.010828613,0.023636553,0.04226646,0.041076142,0.025892248,-0.051934887,0.0029032188,0.040332098,-0.015436589,-0.057878137,0.005353198,0.064739525,-0.006427803,-0.024176747,0.011304507,0.03381613,0.08625095,-0.027353497,-0.039551895,-0.04934357,-0.016709028,0.024133967,0.00441431,-0.048314437,0.040782917,0.026620803,-0.02146332,0.030112874,-0.027528606,-0.016772546,0.005690125,-0.0047134855,-0.036793064,0.04092668,-0.02411072,0.023851473,0.07727627,-0.006492274,-0.0025583038,0.0017014288,-0.0541687,-0.010395329,0.031044465,-0.0536995,0.029957417,-0.040688735,-0.037072316,0.01663893,-0.04231374,-0.030213326,0.0061428403,-0.06634084,0.06036701,0.016658397,0.024410319,-0.03309207,-0.03735754,-0.04359427,-0.013476715,0.00078163255,0.033615876,0.022759296,-0.003551954,0.017715035,-0.0072518513,0.033236742,-0.0070533687,-0.05334901,-0.014660441,0.0025560227,0.03979979,-0.00433087,-0.018232862,-0.017161474,0.008870558,0.021989124,0.078787796,-0.009815632,0.022819351,0.020795409,0.028896132,-0.0061202813,0.012352534,-0.009014175,0.0024110335]::vector(768))\n",
+ " ```\n",
+ " \n",
+ "\n",
+ "Here is how this table mapped to `PGVectorStore`:\n",
+ "\n",
+ "- **`id_column=\"product_id\"`**: ID column uniquely identifies each row in the products table.\n",
+ "\n",
+ "- **`content_column=\"description\"`**: The `description` column contains text descriptions of each product. This text is used by the `embedding_service` to create vectors that go in embedding_column and represent the semantic meaning of each description.\n",
+ "\n",
+ "- **`embedding_column=\"embed\"`**: The `embed` column stores the vectors created from the product descriptions. These vectors are used to find products with similar descriptions.\n",
+ "\n",
+ "- **`metadata_columns=[\"name\", \"category\", \"price_usd\", \"quantity\", \"sku\", \"image_url\"]`**: These columns are treated as metadata for each product. Metadata provides additional information about a product, such as its name, category, price, quantity available, SKU (Stock Keeping Unit), and an image URL. This information is useful for displaying product details in search results or for filtering and categorization.\n",
+ "\n",
+ "- **`metadata_json_column=\"metadata\"`**: The `metadata` column can store any additional information about the products in a flexible JSON format. This allows for storing varied and complex data that doesn't fit into the standard columns.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Set an existing table name\n",
+ "TABLE_NAME = \"products\"\n",
+ "# SCHEMA_NAME = \"my_schema\"\n",
+ "\n",
+ "# Initialize PGVectorStore\n",
+ "custom_store = await PGVectorStore.create(\n",
+ " engine=pg_engine,\n",
+ " table_name=TABLE_NAME,\n",
+ " # schema_name=SCHEMA_NAME,\n",
+ " embedding_service=embedding,\n",
+ " # Connect to existing VectorStore by customizing below column names\n",
+ " id_column=\"product_id\",\n",
+ " content_column=\"description\",\n",
+ " embedding_column=\"embed\",\n",
+ " metadata_columns=[\"name\", \"category\", \"price_usd\", \"quantity\", \"sku\", \"image_url\"],\n",
+ " metadata_json_column=\"metadata\",\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note: \n",
+ "\n",
+ "1. Optional: If the `embed` column is newly created or has different dimensions than supported by embedding model, it is required to one-time add the embeddings for the old records, like this: \n",
+ "\n",
+ " `ALTER TABLE products ADD COLUMN embed vector(768) DEFAULT NULL`\n",
+ "\n",
+ "1. For new records, added via `VectorStore` embeddings are automatically generated."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Search for documents with metadata filter\n",
+ "Since price_usd is one of the metadata_columns, we can use price filter while searching"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import uuid\n",
+ "\n",
+ "docs = await custom_store.asimilarity_search(query, filter=\"price_usd > 100\")\n",
+ "\n",
+ "print(docs)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Search for documents with json filter\n",
+ "Since category is added in json metadata, we can use filter on JSON fields while searching\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "docs = await custom_store.asimilarity_search(\n",
+ " query, filter=\"metadata->>'category' = 'Electronics'\"\n",
+ ")\n",
+ "\n",
+ "print(docs)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Search for documents with dictionary filter\n",
+ "Use a dictionary filter to make your filter DB Agnostic.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "docs = await custom_store.asimilarity_search(query, filter={\"category\": \"Electronics\"})\n",
+ "\n",
+ "print(docs)"
+ ]
+ }
+ ],
+ "metadata": {
+ "colab": {
+ "provenance": [],
+ "toc_visible": true
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.12.8"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/examples/vectorstore.ipynb b/examples/vectorstore.ipynb
index 1ae43b24..ddf99166 100644
--- a/examples/vectorstore.ipynb
+++ b/examples/vectorstore.ipynb
@@ -21,7 +21,7 @@
"\n",
"This code has been ported over from langchain_community. The following changes have been made:\n",
"\n",
- "* langchain_postgres works only with psycopg3. Please update your connnecion strings from `postgresql+psycopg2://...` to `postgresql+psycopg://langchain:langchain@...` (yes, it's the driver name is `psycopg` not `psycopg3`, but it'll use `psycopg3`.\n",
+ "* langchain_postgres works only with psycopg3. Please update your connection strings from `postgresql+psycopg2://...` to `postgresql+psycopg://langchain:langchain@...` (yes, it's the driver name is `psycopg` not `psycopg3`, but it'll use `psycopg3`.\n",
"* The schema of the embedding store and collection have been changed to make add_documents work correctly with user specified ids.\n",
"* One has to pass an explicit connection object now.\n",
"\n",
@@ -68,12 +68,11 @@
"outputs": [],
"source": [
"from langchain_cohere import CohereEmbeddings\n",
- "from langchain_postgres import PGVector\n",
"from langchain_postgres.vectorstores import PGVector\n",
"from langchain_core.documents import Document\n",
"\n",
"# See docker command above to launch a postgres instance with pgvector enabled.\n",
- "connection = \"postgresql+psycopg://langchain:langchain@localhost:6024/langchain\" \n",
+ "connection = \"postgresql+psycopg://langchain:langchain@localhost:6024/langchain\"\n",
"collection_name = \"my_docs\"\n",
"embeddings = CohereEmbeddings()\n",
"\n",
@@ -127,17 +126,47 @@
"outputs": [],
"source": [
"docs = [\n",
- " Document(page_content='there are cats in the pond', metadata={\"id\": 1, \"location\": \"pond\", \"topic\": \"animals\"}),\n",
- " Document(page_content='ducks are also found in the pond', metadata={\"id\": 2, \"location\": \"pond\", \"topic\": \"animals\"}),\n",
- " Document(page_content='fresh apples are available at the market', metadata={\"id\": 3, \"location\": \"market\", \"topic\": \"food\"}),\n",
- " Document(page_content='the market also sells fresh oranges', metadata={\"id\": 4, \"location\": \"market\", \"topic\": \"food\"}),\n",
- " Document(page_content='the new art exhibit is fascinating', metadata={\"id\": 5, \"location\": \"museum\", \"topic\": \"art\"}),\n",
- " Document(page_content='a sculpture exhibit is also at the museum', metadata={\"id\": 6, \"location\": \"museum\", \"topic\": \"art\"}),\n",
- " Document(page_content='a new coffee shop opened on Main Street', metadata={\"id\": 7, \"location\": \"Main Street\", \"topic\": \"food\"}),\n",
- " Document(page_content='the book club meets at the library', metadata={\"id\": 8, \"location\": \"library\", \"topic\": \"reading\"}),\n",
- " Document(page_content='the library hosts a weekly story time for kids', metadata={\"id\": 9, \"location\": \"library\", \"topic\": \"reading\"}),\n",
- " Document(page_content='a cooking class for beginners is offered at the community center', metadata={\"id\": 10, \"location\": \"community center\", \"topic\": \"classes\"})\n",
- "]\n"
+ " Document(\n",
+ " page_content=\"there are cats in the pond\",\n",
+ " metadata={\"id\": 1, \"location\": \"pond\", \"topic\": \"animals\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"ducks are also found in the pond\",\n",
+ " metadata={\"id\": 2, \"location\": \"pond\", \"topic\": \"animals\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"fresh apples are available at the market\",\n",
+ " metadata={\"id\": 3, \"location\": \"market\", \"topic\": \"food\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the market also sells fresh oranges\",\n",
+ " metadata={\"id\": 4, \"location\": \"market\", \"topic\": \"food\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the new art exhibit is fascinating\",\n",
+ " metadata={\"id\": 5, \"location\": \"museum\", \"topic\": \"art\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"a sculpture exhibit is also at the museum\",\n",
+ " metadata={\"id\": 6, \"location\": \"museum\", \"topic\": \"art\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"a new coffee shop opened on Main Street\",\n",
+ " metadata={\"id\": 7, \"location\": \"Main Street\", \"topic\": \"food\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the book club meets at the library\",\n",
+ " metadata={\"id\": 8, \"location\": \"library\", \"topic\": \"reading\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the library hosts a weekly story time for kids\",\n",
+ " metadata={\"id\": 9, \"location\": \"library\", \"topic\": \"reading\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"a cooking class for beginners is offered at the community center\",\n",
+ " metadata={\"id\": 10, \"location\": \"community center\", \"topic\": \"classes\"},\n",
+ " ),\n",
+ "]"
]
},
{
@@ -160,7 +189,7 @@
}
],
"source": [
- "vectorstore.add_documents(docs, ids=[doc.metadata['id'] for doc in docs])"
+ "vectorstore.add_documents(docs, ids=[doc.metadata[\"id\"] for doc in docs])"
]
},
{
@@ -192,7 +221,7 @@
}
],
"source": [
- "vectorstore.similarity_search('kitty', k=10)"
+ "vectorstore.similarity_search(\"kitty\", k=10)"
]
},
{
@@ -213,17 +242,47 @@
"outputs": [],
"source": [
"docs = [\n",
- " Document(page_content='there are cats in the pond', metadata={\"id\": 1, \"location\": \"pond\", \"topic\": \"animals\"}),\n",
- " Document(page_content='ducks are also found in the pond', metadata={\"id\": 2, \"location\": \"pond\", \"topic\": \"animals\"}),\n",
- " Document(page_content='fresh apples are available at the market', metadata={\"id\": 3, \"location\": \"market\", \"topic\": \"food\"}),\n",
- " Document(page_content='the market also sells fresh oranges', metadata={\"id\": 4, \"location\": \"market\", \"topic\": \"food\"}),\n",
- " Document(page_content='the new art exhibit is fascinating', metadata={\"id\": 5, \"location\": \"museum\", \"topic\": \"art\"}),\n",
- " Document(page_content='a sculpture exhibit is also at the museum', metadata={\"id\": 6, \"location\": \"museum\", \"topic\": \"art\"}),\n",
- " Document(page_content='a new coffee shop opened on Main Street', metadata={\"id\": 7, \"location\": \"Main Street\", \"topic\": \"food\"}),\n",
- " Document(page_content='the book club meets at the library', metadata={\"id\": 8, \"location\": \"library\", \"topic\": \"reading\"}),\n",
- " Document(page_content='the library hosts a weekly story time for kids', metadata={\"id\": 9, \"location\": \"library\", \"topic\": \"reading\"}),\n",
- " Document(page_content='a cooking class for beginners is offered at the community center', metadata={\"id\": 10, \"location\": \"community center\", \"topic\": \"classes\"})\n",
- "]\n"
+ " Document(\n",
+ " page_content=\"there are cats in the pond\",\n",
+ " metadata={\"id\": 1, \"location\": \"pond\", \"topic\": \"animals\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"ducks are also found in the pond\",\n",
+ " metadata={\"id\": 2, \"location\": \"pond\", \"topic\": \"animals\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"fresh apples are available at the market\",\n",
+ " metadata={\"id\": 3, \"location\": \"market\", \"topic\": \"food\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the market also sells fresh oranges\",\n",
+ " metadata={\"id\": 4, \"location\": \"market\", \"topic\": \"food\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the new art exhibit is fascinating\",\n",
+ " metadata={\"id\": 5, \"location\": \"museum\", \"topic\": \"art\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"a sculpture exhibit is also at the museum\",\n",
+ " metadata={\"id\": 6, \"location\": \"museum\", \"topic\": \"art\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"a new coffee shop opened on Main Street\",\n",
+ " metadata={\"id\": 7, \"location\": \"Main Street\", \"topic\": \"food\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the book club meets at the library\",\n",
+ " metadata={\"id\": 8, \"location\": \"library\", \"topic\": \"reading\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"the library hosts a weekly story time for kids\",\n",
+ " metadata={\"id\": 9, \"location\": \"library\", \"topic\": \"reading\"},\n",
+ " ),\n",
+ " Document(\n",
+ " page_content=\"a cooking class for beginners is offered at the community center\",\n",
+ " metadata={\"id\": 10, \"location\": \"community center\", \"topic\": \"classes\"},\n",
+ " ),\n",
+ "]"
]
},
{
@@ -276,9 +335,7 @@
}
],
"source": [
- "vectorstore.similarity_search('kitty', k=10, filter={\n",
- " 'id': {'$in': [1, 5, 2, 9]}\n",
- "})"
+ "vectorstore.similarity_search(\"kitty\", k=10, filter={\"id\": {\"$in\": [1, 5, 2, 9]}})"
]
},
{
@@ -310,10 +367,11 @@
}
],
"source": [
- "vectorstore.similarity_search('ducks', k=10, filter={\n",
- " 'id': {'$in': [1, 5, 2, 9]},\n",
- " 'location': {'$in': [\"pond\", \"market\"]}\n",
- "})"
+ "vectorstore.similarity_search(\n",
+ " \"ducks\",\n",
+ " k=10,\n",
+ " filter={\"id\": {\"$in\": [1, 5, 2, 9]}, \"location\": {\"$in\": [\"pond\", \"market\"]}},\n",
+ ")"
]
},
{
@@ -337,12 +395,15 @@
}
],
"source": [
- "vectorstore.similarity_search('ducks', k=10, filter={\n",
- " '$and': [\n",
- " {'id': {'$in': [1, 5, 2, 9]}},\n",
- " {'location': {'$in': [\"pond\", \"market\"]}},\n",
- " ]\n",
- "}\n",
+ "vectorstore.similarity_search(\n",
+ " \"ducks\",\n",
+ " k=10,\n",
+ " filter={\n",
+ " \"$and\": [\n",
+ " {\"id\": {\"$in\": [1, 5, 2, 9]}},\n",
+ " {\"location\": {\"$in\": [\"pond\", \"market\"]}},\n",
+ " ]\n",
+ " },\n",
")"
]
},
@@ -373,9 +434,7 @@
}
],
"source": [
- "vectorstore.similarity_search('bird', k=10, filter={\n",
- " 'location': { \"$ne\": 'pond'}\n",
- "})"
+ "vectorstore.similarity_search(\"bird\", k=10, filter={\"location\": {\"$ne\": \"pond\"}})"
]
}
],
diff --git a/langchain_postgres/__init__.py b/langchain_postgres/__init__.py
index 241c8b89..15a9230f 100644
--- a/langchain_postgres/__init__.py
+++ b/langchain_postgres/__init__.py
@@ -2,6 +2,8 @@
from langchain_postgres.chat_message_histories import PostgresChatMessageHistory
from langchain_postgres.translator import PGVectorTranslator
+from langchain_postgres.v2.engine import Column, ColumnDict, PGEngine
+from langchain_postgres.v2.vectorstores import PGVectorStore
from langchain_postgres.vectorstores import PGVector
try:
@@ -12,7 +14,11 @@
__all__ = [
"__version__",
+ "Column",
+ "ColumnDict",
+ "PGEngine",
"PostgresChatMessageHistory",
"PGVector",
+ "PGVectorStore",
"PGVectorTranslator",
]
diff --git a/langchain_postgres/chat_message_histories.py b/langchain_postgres/chat_message_histories.py
index 85f2aef7..c1ff7cc3 100644
--- a/langchain_postgres/chat_message_histories.py
+++ b/langchain_postgres/chat_message_histories.py
@@ -340,11 +340,17 @@ async def aget_messages(self) -> List[BaseMessage]:
messages = messages_from_dict(items)
return messages
- @property # type: ignore[override]
+ @property
def messages(self) -> List[BaseMessage]:
"""The abstraction required a property."""
return self.get_messages()
+ @messages.setter
+ def messages(self, value: list[BaseMessage]) -> None:
+ """Clear the stored messages and appends a list of messages."""
+ self.clear()
+ self.add_messages(value)
+
def clear(self) -> None:
"""Clear the chat message history for the GIVEN session."""
if self._connection is None:
diff --git a/langchain_postgres/utils/pgvector_migrator.py b/langchain_postgres/utils/pgvector_migrator.py
new file mode 100644
index 00000000..9480d1e2
--- /dev/null
+++ b/langchain_postgres/utils/pgvector_migrator.py
@@ -0,0 +1,321 @@
+import asyncio
+import json
+import warnings
+from typing import Any, AsyncIterator, Iterator, Optional, Sequence, TypeVar
+
+from sqlalchemy import RowMapping, text
+from sqlalchemy.exc import ProgrammingError, SQLAlchemyError
+
+from ..v2.engine import PGEngine
+from ..v2.vectorstores import PGVectorStore
+
+COLLECTIONS_TABLE = "langchain_pg_collection"
+EMBEDDINGS_TABLE = "langchain_pg_embedding"
+
+T = TypeVar("T")
+
+
+async def __aget_collection_uuid(
+ engine: PGEngine,
+ collection_name: str,
+) -> str:
+ """
+ Get the collection uuid for a collection present in PGVector tables.
+
+ Args:
+ engine (PGEngine): The PG engine corresponding to the Database.
+ collection_name (str): The name of the collection to get the uuid for.
+ Returns:
+ The uuid corresponding to the collection.
+ """
+ query = f"SELECT name, uuid FROM {COLLECTIONS_TABLE} WHERE name = :collection_name"
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(
+ text(query), parameters={"collection_name": collection_name}
+ )
+ result_map = result.mappings()
+ result_fetch = result_map.fetchone()
+ if result_fetch is None:
+ raise ValueError(f"Collection, {collection_name} not found.")
+ return result_fetch.uuid
+
+
+async def __aextract_pgvector_collection(
+ engine: PGEngine,
+ collection_name: str,
+ batch_size: int = 1000,
+) -> AsyncIterator[Sequence[RowMapping]]:
+ """
+ Extract all data belonging to a PGVector collection.
+
+ Args:
+ engine (PGEngine): The PG engine corresponding to the Database.
+ collection_name (str): The name of the collection to get the data for.
+ batch_size (int): The batch size for collection extraction.
+ Default: 1000. Optional.
+
+ Yields:
+ The data present in the collection.
+ """
+ try:
+ uuid_task = asyncio.create_task(__aget_collection_uuid(engine, collection_name))
+ query = f"SELECT * FROM {EMBEDDINGS_TABLE} WHERE collection_id = :id"
+ async with engine._pool.connect() as conn:
+ uuid = await uuid_task
+ result_proxy = await conn.execute(text(query), parameters={"id": uuid})
+ while True:
+ rows = result_proxy.fetchmany(size=batch_size)
+ if not rows:
+ break
+ yield [row._mapping for row in rows]
+ except ValueError:
+ raise ValueError(f"Collection, {collection_name} does not exist.")
+ except SQLAlchemyError as e:
+ raise ProgrammingError(
+ statement=f"Failed to extract data from collection '{collection_name}': {e}",
+ params={"id": uuid},
+ orig=e,
+ ) from e
+
+
+async def __concurrent_batch_insert(
+ data_batches: AsyncIterator[Sequence[RowMapping]],
+ vector_store: PGVectorStore,
+ max_concurrency: int = 100,
+) -> None:
+ pending: set[Any] = set()
+ async for batch_data in data_batches:
+ pending.add(
+ asyncio.ensure_future(
+ vector_store.aadd_embeddings(
+ texts=[data.document for data in batch_data],
+ embeddings=[json.loads(data.embedding) for data in batch_data],
+ metadatas=[data.cmetadata for data in batch_data],
+ ids=[data.id for data in batch_data],
+ )
+ )
+ )
+ if len(pending) >= max_concurrency:
+ _, pending = await asyncio.wait(
+ pending, return_when=asyncio.FIRST_COMPLETED
+ )
+ if pending:
+ await asyncio.wait(pending)
+
+
+async def __amigrate_pgvector_collection(
+ engine: PGEngine,
+ collection_name: str,
+ vector_store: PGVectorStore,
+ delete_pg_collection: Optional[bool] = False,
+ insert_batch_size: int = 1000,
+) -> None:
+ """
+ Migrate all data present in a PGVector collection to use separate tables for each collection.
+ The new data format is compatible with the PGVectoreStore interface.
+
+ Args:
+ engine (PGEngine): The PG engine corresponding to the Database.
+ collection_name (str): The collection to migrate.
+ vector_store (PGVectorStore): The PGVectorStore object corresponding to the new collection table.
+ delete_pg_collection (bool): An option to delete the original data upon migration.
+ Default: False. Optional.
+ insert_batch_size (int): Number of rows to insert at once in the table.
+ Default: 1000.
+ """
+ destination_table = vector_store.get_table_name()
+
+ # Get row count in PGVector collection
+ uuid_task = asyncio.create_task(__aget_collection_uuid(engine, collection_name))
+ query = (
+ f"SELECT COUNT(*) FROM {EMBEDDINGS_TABLE} WHERE collection_id=:collection_id"
+ )
+ async with engine._pool.connect() as conn:
+ uuid = await uuid_task
+ result = await conn.execute(text(query), parameters={"collection_id": uuid})
+ result_map = result.mappings()
+ collection_data_len = result_map.fetchone()
+ if collection_data_len is None:
+ warnings.warn(f"Collection, {collection_name} contains no elements.")
+ return
+
+ # Extract data from the collection and batch insert into the new table
+ data_batches = __aextract_pgvector_collection(
+ engine, collection_name, batch_size=insert_batch_size
+ )
+ await __concurrent_batch_insert(data_batches, vector_store, max_concurrency=100)
+
+ # Validate data migration
+ query = f"SELECT COUNT(*) FROM {destination_table}"
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(text(query))
+ result_map = result.mappings()
+ table_size = result_map.fetchone()
+ if not table_size:
+ raise ValueError(f"Table: {destination_table} does not exist.")
+
+ if collection_data_len["count"] != table_size["count"]:
+ raise ValueError(
+ "All data not yet migrated.\n"
+ f"Original row count: {collection_data_len['count']}\n"
+ f"Collection table, {destination_table} row count: {table_size['count']}"
+ )
+ elif delete_pg_collection:
+ # Delete PGVector data
+ query = f"DELETE FROM {EMBEDDINGS_TABLE} WHERE collection_id=:collection_id"
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query), parameters={"collection_id": uuid})
+ await conn.commit()
+
+ query = f"DELETE FROM {COLLECTIONS_TABLE} WHERE name=:collection_name"
+ async with engine._pool.connect() as conn:
+ await conn.execute(
+ text(query), parameters={"collection_name": collection_name}
+ )
+ await conn.commit()
+ print(f"Successfully deleted PGVector collection, {collection_name}")
+
+
+async def __alist_pgvector_collection_names(
+ engine: PGEngine,
+) -> list[str]:
+ """Lists all collection names present in PGVector table."""
+ try:
+ query = f"SELECT name from {COLLECTIONS_TABLE}"
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(text(query))
+ result_map = result.mappings()
+ all_rows = result_map.fetchall()
+ return [row["name"] for row in all_rows]
+ except ProgrammingError as e:
+ raise ValueError(
+ "Please provide the correct collection table name: " + str(e)
+ ) from e
+
+
+async def aextract_pgvector_collection(
+ engine: PGEngine,
+ collection_name: str,
+ batch_size: int = 1000,
+) -> AsyncIterator[Sequence[RowMapping]]:
+ """
+ Extract all data belonging to a PGVector collection.
+
+ Args:
+ engine (PGEngine): The PG engine corresponding to the Database.
+ collection_name (str): The name of the collection to get the data for.
+ batch_size (int): The batch size for collection extraction.
+ Default: 1000. Optional.
+
+ Yields:
+ The data present in the collection.
+ """
+ iterator = __aextract_pgvector_collection(engine, collection_name, batch_size)
+ while True:
+ try:
+ result = await engine._run_as_async(iterator.__anext__())
+ yield result
+ except StopAsyncIteration:
+ break
+
+
+async def alist_pgvector_collection_names(
+ engine: PGEngine,
+) -> list[str]:
+ """Lists all collection names present in PGVector table."""
+ return await engine._run_as_async(__alist_pgvector_collection_names(engine))
+
+
+async def amigrate_pgvector_collection(
+ engine: PGEngine,
+ collection_name: str,
+ vector_store: PGVectorStore,
+ delete_pg_collection: Optional[bool] = False,
+ insert_batch_size: int = 1000,
+) -> None:
+ """
+ Migrate all data present in a PGVector collection to use separate tables for each collection.
+ The new data format is compatible with the PGVectorStore interface.
+
+ Args:
+ engine (PGEngine): The PG engine corresponding to the Database.
+ collection_name (str): The collection to migrate.
+ vector_store (PGVectorStore): The PGVectorStore object corresponding to the new collection table.
+ use_json_metadata (bool): An option to keep the PGVector metadata as json in the new table.
+ Default: False. Optional.
+ delete_pg_collection (bool): An option to delete the original data upon migration.
+ Default: False. Optional.
+ insert_batch_size (int): Number of rows to insert at once in the table.
+ Default: 1000.
+ """
+ await engine._run_as_async(
+ __amigrate_pgvector_collection(
+ engine,
+ collection_name,
+ vector_store,
+ delete_pg_collection,
+ insert_batch_size,
+ )
+ )
+
+
+def extract_pgvector_collection(
+ engine: PGEngine,
+ collection_name: str,
+ batch_size: int = 1000,
+) -> Iterator[Sequence[RowMapping]]:
+ """
+ Extract all data belonging to a PGVector collection.
+
+ Args:
+ engine (PGEngine): The PG engine corresponding to the Database.
+ collection_name (str): The name of the collection to get the data for.
+ batch_size (int): The batch size for collection extraction.
+ Default: 1000. Optional.
+
+ Yields:
+ The data present in the collection.
+ """
+ iterator = __aextract_pgvector_collection(engine, collection_name, batch_size)
+ while True:
+ try:
+ result = engine._run_as_sync(iterator.__anext__())
+ yield result
+ except StopAsyncIteration:
+ break
+
+
+def list_pgvector_collection_names(engine: PGEngine) -> list[str]:
+ """Lists all collection names present in PGVector table."""
+ return engine._run_as_sync(__alist_pgvector_collection_names(engine))
+
+
+def migrate_pgvector_collection(
+ engine: PGEngine,
+ collection_name: str,
+ vector_store: PGVectorStore,
+ delete_pg_collection: Optional[bool] = False,
+ insert_batch_size: int = 1000,
+) -> None:
+ """
+ Migrate all data present in a PGVector collection to use separate tables for each collection.
+ The new data format is compatible with the PGVectorStore interface.
+
+ Args:
+ engine (PGEngine): The PG engine corresponding to the Database.
+ collection_name (str): The collection to migrate.
+ vector_store (PGVectorStore): The PGVectorStore object corresponding to the new collection table.
+ delete_pg_collection (bool): An option to delete the original data upon migration.
+ Default: False. Optional.
+ insert_batch_size (int): Number of rows to insert at once in the table.
+ Default: 1000.
+ """
+ engine._run_as_sync(
+ __amigrate_pgvector_collection(
+ engine,
+ collection_name,
+ vector_store,
+ delete_pg_collection,
+ insert_batch_size,
+ )
+ )
diff --git a/langchain_postgres/v2/__init__.py b/langchain_postgres/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/langchain_postgres/v2/async_vectorstore.py b/langchain_postgres/v2/async_vectorstore.py
new file mode 100644
index 00000000..dde47f40
--- /dev/null
+++ b/langchain_postgres/v2/async_vectorstore.py
@@ -0,0 +1,1268 @@
+# TODO: Remove below import when minimum supported Python version is 3.10
+from __future__ import annotations
+
+import copy
+import json
+import uuid
+from typing import Any, Callable, Iterable, Optional, Sequence
+
+import numpy as np
+from langchain_core.documents import Document
+from langchain_core.embeddings import Embeddings
+from langchain_core.vectorstores import VectorStore, utils
+from sqlalchemy import RowMapping, text
+from sqlalchemy.ext.asyncio import AsyncEngine
+
+from .engine import PGEngine
+from .indexes import (
+ DEFAULT_DISTANCE_STRATEGY,
+ DEFAULT_INDEX_NAME_SUFFIX,
+ BaseIndex,
+ DistanceStrategy,
+ ExactNearestNeighbor,
+ QueryOptions,
+)
+
+COMPARISONS_TO_NATIVE = {
+ "$eq": "=",
+ "$ne": "!=",
+ "$lt": "<",
+ "$lte": "<=",
+ "$gt": ">",
+ "$gte": ">=",
+}
+
+SPECIAL_CASED_OPERATORS = {
+ "$in",
+ "$nin",
+ "$between",
+ "$exists",
+}
+
+TEXT_OPERATORS = {
+ "$like",
+ "$ilike",
+}
+
+LOGICAL_OPERATORS = {"$and", "$or", "$not"}
+
+SUPPORTED_OPERATORS = (
+ set(COMPARISONS_TO_NATIVE)
+ .union(TEXT_OPERATORS)
+ .union(LOGICAL_OPERATORS)
+ .union(SPECIAL_CASED_OPERATORS)
+)
+
+
+class AsyncPGVectorStore(VectorStore):
+ """Postgres Vector Store class"""
+
+ __create_key = object()
+
+ def __init__(
+ self,
+ key: object,
+ engine: AsyncEngine,
+ embedding_service: Embeddings,
+ table_name: str,
+ *,
+ schema_name: str = "public",
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: Optional[str] = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ ):
+ """AsyncPGVectorStore constructor.
+ Args:
+ key (object): Prevent direct constructor usage.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ embedding_service (Embeddings): Text embedding model to use.
+ table_name (str): Name of the existing table or the table to be created.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ content_column (str): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str]): Column(s) that represent a document's metadata.
+ id_column (str): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+
+ Raises:
+ Exception: If called directly by user.
+ """
+ if key != AsyncPGVectorStore.__create_key:
+ raise Exception(
+ "Only create class through 'create' or 'create_sync' methods!"
+ )
+
+ self.engine = engine
+ self.embedding_service = embedding_service
+ self.table_name = table_name
+ self.schema_name = schema_name
+ self.content_column = content_column
+ self.embedding_column = embedding_column
+ self.metadata_columns = metadata_columns if metadata_columns is not None else []
+ self.id_column = id_column
+ self.metadata_json_column = metadata_json_column
+ self.distance_strategy = distance_strategy
+ self.k = k
+ self.fetch_k = fetch_k
+ self.lambda_mult = lambda_mult
+ self.index_query_options = index_query_options
+
+ @classmethod
+ async def create(
+ cls: type[AsyncPGVectorStore],
+ engine: PGEngine,
+ embedding_service: Embeddings,
+ table_name: str,
+ *,
+ schema_name: str = "public",
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: Optional[str] = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ ) -> AsyncPGVectorStore:
+ """Create an AsyncPGVectorStore instance.
+
+ Args:
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ embedding_service (Embeddings): Text embedding model to use.
+ table_name (str): Name of an existing table.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ content_column (str): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str]): Column(s) that represent a document's metadata.
+ ignore_metadata_columns (list[str]): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Returns:
+ AsyncPGVectorStore
+ """
+
+ if metadata_columns is None:
+ metadata_columns = []
+
+ if metadata_columns and ignore_metadata_columns:
+ raise ValueError(
+ "Can not use both metadata_columns and ignore_metadata_columns."
+ )
+ # Get field type information
+ stmt = "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = :table_name AND table_schema = :schema_name"
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(
+ text(stmt),
+ {"table_name": table_name, "schema_name": schema_name},
+ )
+ result_map = result.mappings()
+ results = result_map.fetchall()
+ columns = {}
+ for field in results:
+ columns[field["column_name"]] = field["data_type"]
+
+ # Check columns
+ if id_column not in columns:
+ raise ValueError(f"Id column, {id_column}, does not exist.")
+ if content_column not in columns:
+ raise ValueError(f"Content column, {content_column}, does not exist.")
+ content_type = columns[content_column]
+ if content_type != "text" and "char" not in content_type:
+ raise ValueError(
+ f"Content column, {content_column}, is type, {content_type}. It must be a type of character string."
+ )
+ if embedding_column not in columns:
+ raise ValueError(f"Embedding column, {embedding_column}, does not exist.")
+ if columns[embedding_column] != "USER-DEFINED":
+ raise ValueError(
+ f"Embedding column, {embedding_column}, is not type Vector."
+ )
+
+ metadata_json_column = (
+ None if metadata_json_column not in columns else metadata_json_column
+ )
+
+ # If using metadata_columns check to make sure column exists
+ for column in metadata_columns:
+ if column not in columns:
+ raise ValueError(f"Metadata column, {column}, does not exist.")
+
+ # If using ignore_metadata_columns, filter out known columns and set known metadata columns
+ all_columns = columns
+ if ignore_metadata_columns:
+ for column in ignore_metadata_columns:
+ del all_columns[column]
+
+ del all_columns[id_column]
+ del all_columns[content_column]
+ del all_columns[embedding_column]
+ metadata_columns = [k for k in all_columns.keys()]
+
+ return cls(
+ cls.__create_key,
+ engine._pool,
+ embedding_service,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ id_column=id_column,
+ metadata_json_column=metadata_json_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ )
+
+ @property
+ def embeddings(self) -> Embeddings:
+ return self.embedding_service
+
+ async def aadd_embeddings(
+ self,
+ texts: Iterable[str],
+ embeddings: list[list[float]],
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Add data along with embeddings to the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ if not ids:
+ ids = [str(uuid.uuid4()) for _ in texts]
+ else:
+ # This is done to fill in any missing ids
+ ids = [id if id is not None else str(uuid.uuid4()) for id in ids]
+ if not metadatas:
+ metadatas = [{} for _ in texts]
+
+ # Check for inline embedding capability
+ inline_embed_func = getattr(self.embedding_service, "embed_query_inline", None)
+ can_inline_embed = callable(inline_embed_func)
+ # Insert embeddings
+ for id, content, embedding, metadata in zip(ids, texts, embeddings, metadatas):
+ metadata_col_names = (
+ ", " + ", ".join(f'"{col}"' for col in self.metadata_columns)
+ if len(self.metadata_columns) > 0
+ else ""
+ )
+ insert_stmt = f'INSERT INTO "{self.schema_name}"."{self.table_name}"("{self.id_column}", "{self.content_column}", "{self.embedding_column}"{metadata_col_names}'
+ values = {
+ "id": id,
+ "content": content,
+ "embedding": str([float(dimension) for dimension in embedding]),
+ }
+ values_stmt = "VALUES (:id, :content, :embedding"
+
+ if not embedding and can_inline_embed:
+ values_stmt = f"VALUES (:id, :content, {self.embedding_service.embed_query_inline(content)}" # type: ignore
+
+ # Add metadata
+ extra = copy.deepcopy(metadata)
+ for metadata_column in self.metadata_columns:
+ if metadata_column in metadata:
+ values_stmt += f", :{metadata_column}"
+ values[metadata_column] = metadata[metadata_column]
+ del extra[metadata_column]
+ else:
+ values_stmt += ",null"
+
+ # Add JSON column and/or close statement
+ insert_stmt += (
+ f""", "{self.metadata_json_column}")"""
+ if self.metadata_json_column
+ else ")"
+ )
+ if self.metadata_json_column:
+ values_stmt += ", :extra)"
+ values["extra"] = json.dumps(extra)
+ else:
+ values_stmt += ")"
+
+ upsert_stmt = f' ON CONFLICT ("{self.id_column}") DO UPDATE SET "{self.content_column}" = EXCLUDED."{self.content_column}", "{self.embedding_column}" = EXCLUDED."{self.embedding_column}"'
+
+ if self.metadata_json_column:
+ upsert_stmt += f', "{self.metadata_json_column}" = EXCLUDED."{self.metadata_json_column}"'
+
+ for column in self.metadata_columns:
+ upsert_stmt += f', "{column}" = EXCLUDED."{column}"'
+
+ upsert_stmt += ";"
+
+ query = insert_stmt + values_stmt + upsert_stmt
+ async with self.engine.connect() as conn:
+ await conn.execute(text(query), values)
+ await conn.commit()
+
+ return ids
+
+ async def aadd_texts(
+ self,
+ texts: Iterable[str],
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Embed texts and add to the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ # Check for inline embedding query
+ inline_embed_func = getattr(self.embedding_service, "embed_query_inline", None)
+ if callable(inline_embed_func):
+ embeddings: list[list[float]] = [[] for _ in list(texts)]
+ else:
+ embeddings = await self.embedding_service.aembed_documents(list(texts))
+
+ ids = await self.aadd_embeddings(
+ texts, embeddings, metadatas=metadatas, ids=ids, **kwargs
+ )
+ return ids
+
+ async def aadd_documents(
+ self,
+ documents: list[Document],
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Embed documents and add to the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ texts = [doc.page_content for doc in documents]
+ metadatas = [doc.metadata for doc in documents]
+ if not ids:
+ ids = [doc.id for doc in documents]
+ ids = await self.aadd_texts(texts, metadatas=metadatas, ids=ids, **kwargs)
+ return ids
+
+ async def adelete(
+ self,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> Optional[bool]:
+ """Delete records from the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ if not ids:
+ return False
+
+ placeholders = ", ".join(f":id_{i}" for i in range(len(ids)))
+ param_dict = {f"id_{i}": id for i, id in enumerate(ids)}
+ query = f'DELETE FROM "{self.schema_name}"."{self.table_name}" WHERE {self.id_column} in ({placeholders})'
+ async with self.engine.connect() as conn:
+ await conn.execute(text(query), param_dict)
+ await conn.commit()
+ return True
+
+ @classmethod
+ async def afrom_texts( # type: ignore[override]
+ cls: type[AsyncPGVectorStore],
+ texts: list[str],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ *,
+ schema_name: str = "public",
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ **kwargs: Any,
+ ) -> AsyncPGVectorStore:
+ """Create an AsyncPGVectorStore instance from texts.
+
+ Args:
+ texts (list[str]): Texts to add to the vector store.
+ embedding (Embeddings): Text embedding model to use.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ table_name (str): Name of an existing table.
+ metadatas (Optional[list[dict]]): List of metadatas to add to table records.
+ ids: (Optional[list[str]]): List of IDs to add to table records.
+ content_column (str): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str]): Column(s) that represent a document's metadata.
+ ignore_metadata_columns (list[str]): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+
+ Returns:
+ AsyncPGVectorStore
+ """
+ vs = await cls.create(
+ engine,
+ embedding,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ id_column=id_column,
+ metadata_json_column=metadata_json_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ )
+ await vs.aadd_texts(texts, metadatas=metadatas, ids=ids, **kwargs)
+ return vs
+
+ @classmethod
+ async def afrom_documents( # type: ignore[override]
+ cls: type[AsyncPGVectorStore],
+ documents: list[Document],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ *,
+ schema_name: str = "public",
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ **kwargs: Any,
+ ) -> AsyncPGVectorStore:
+ """Create an AsyncPGVectorStore instance from documents.
+
+ Args:
+ documents (list[Document]): Documents to add to the vector store.
+ embedding (Embeddings): Text embedding model to use.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ table_name (str): Name of an existing table.
+ metadatas (Optional[list[dict]]): List of metadatas to add to table records.
+ ids: (Optional[list[str]]): List of IDs to add to table records.
+ content_column (str): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str]): Column(s) that represent a document's metadata.
+ ignore_metadata_columns (list[str]): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+
+ Returns:
+ AsyncPGVectorStore
+ """
+
+ vs = await cls.create(
+ engine,
+ embedding,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ id_column=id_column,
+ metadata_json_column=metadata_json_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ )
+ texts = [doc.page_content for doc in documents]
+ metadatas = [doc.metadata for doc in documents]
+ await vs.aadd_texts(texts, metadatas=metadatas, ids=ids, **kwargs)
+ return vs
+
+ async def __query_collection(
+ self,
+ embedding: list[float],
+ *,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> Sequence[RowMapping]:
+ """Perform similarity search query on database."""
+ k = k if k else self.k
+ operator = self.distance_strategy.operator
+ search_function = self.distance_strategy.search_function
+
+ columns = self.metadata_columns + [
+ self.id_column,
+ self.content_column,
+ self.embedding_column,
+ ]
+ if self.metadata_json_column:
+ columns.append(self.metadata_json_column)
+
+ column_names = ", ".join(f'"{col}"' for col in columns)
+
+ safe_filter = None
+ filter_dict = None
+ if filter and isinstance(filter, dict):
+ safe_filter, filter_dict = self._create_filter_clause(filter)
+ param_filter = f"WHERE {safe_filter}" if safe_filter else ""
+ inline_embed_func = getattr(self.embedding_service, "embed_query_inline", None)
+ if not embedding and callable(inline_embed_func) and "query" in kwargs:
+ query_embedding = self.embedding_service.embed_query_inline(kwargs["query"]) # type: ignore
+ else:
+ query_embedding = f"{[float(dimension) for dimension in embedding]}"
+ stmt = f"""SELECT {column_names}, {search_function}("{self.embedding_column}", :query_embedding) as distance
+ FROM "{self.schema_name}"."{self.table_name}" {param_filter} ORDER BY "{self.embedding_column}" {operator} :query_embedding LIMIT :k;
+ """
+ param_dict = {"query_embedding": query_embedding, "k": k}
+ if filter_dict:
+ param_dict.update(filter_dict)
+ if self.index_query_options:
+ async with self.engine.connect() as conn:
+ # Set each query option individually
+ for query_option in self.index_query_options.to_parameter():
+ query_options_stmt = f"SET LOCAL {query_option};"
+ await conn.execute(text(query_options_stmt))
+ result = await conn.execute(text(stmt), param_dict)
+ result_map = result.mappings()
+ results = result_map.fetchall()
+ else:
+ async with self.engine.connect() as conn:
+ result = await conn.execute(text(stmt), param_dict)
+ result_map = result.mappings()
+ results = result_map.fetchall()
+ return results
+
+ async def asimilarity_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected by similarity search on query."""
+ inline_embed_func = getattr(self.embedding_service, "embed_query_inline", None)
+ embedding = (
+ []
+ if callable(inline_embed_func)
+ else await self.embedding_service.aembed_query(text=query)
+ )
+ kwargs["query"] = query
+
+ return await self.asimilarity_search_by_vector(
+ embedding=embedding, k=k, filter=filter, **kwargs
+ )
+
+ def _select_relevance_score_fn(self) -> Callable[[float], float]:
+ """Select a relevance function based on distance strategy."""
+ # Calculate distance strategy provided in
+ # vectorstore constructor
+ if self.distance_strategy == DistanceStrategy.COSINE_DISTANCE:
+ return self._cosine_relevance_score_fn
+ if self.distance_strategy == DistanceStrategy.INNER_PRODUCT:
+ return self._max_inner_product_relevance_score_fn
+ elif self.distance_strategy == DistanceStrategy.EUCLIDEAN:
+ return self._euclidean_relevance_score_fn
+
+ async def asimilarity_search_with_score(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected by similarity search on query."""
+ inline_embed_func = getattr(self.embedding_service, "embed_query_inline", None)
+ embedding = (
+ []
+ if callable(inline_embed_func)
+ else await self.embedding_service.aembed_query(text=query)
+ )
+ kwargs["query"] = query
+
+ docs = await self.asimilarity_search_with_score_by_vector(
+ embedding=embedding, k=k, filter=filter, **kwargs
+ )
+ return docs
+
+ async def asimilarity_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected by vector similarity search."""
+ docs_and_scores = await self.asimilarity_search_with_score_by_vector(
+ embedding=embedding, k=k, filter=filter, **kwargs
+ )
+
+ return [doc for doc, _ in docs_and_scores]
+
+ async def asimilarity_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected by vector similarity search."""
+ results = await self.__query_collection(
+ embedding=embedding, k=k, filter=filter, **kwargs
+ )
+
+ documents_with_scores = []
+ for row in results:
+ metadata = (
+ row[self.metadata_json_column]
+ if self.metadata_json_column and row[self.metadata_json_column]
+ else {}
+ )
+ for col in self.metadata_columns:
+ metadata[col] = row[col]
+ documents_with_scores.append(
+ (
+ Document(
+ page_content=row[self.content_column],
+ metadata=metadata,
+ id=str(row[self.id_column]),
+ ),
+ row["distance"],
+ )
+ )
+
+ return documents_with_scores
+
+ async def amax_marginal_relevance_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected using the maximal marginal relevance."""
+ embedding = await self.embedding_service.aembed_query(text=query)
+
+ return await self.amax_marginal_relevance_search_by_vector(
+ embedding=embedding,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ filter=filter,
+ **kwargs,
+ )
+
+ async def amax_marginal_relevance_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected using the maximal marginal relevance."""
+ docs_and_scores = (
+ await self.amax_marginal_relevance_search_with_score_by_vector(
+ embedding,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ filter=filter,
+ **kwargs,
+ )
+ )
+
+ return [result[0] for result in docs_and_scores]
+
+ async def amax_marginal_relevance_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected using the maximal marginal relevance."""
+ results = await self.__query_collection(
+ embedding=embedding, k=fetch_k, filter=filter, **kwargs
+ )
+
+ k = k if k else self.k
+ fetch_k = fetch_k if fetch_k else self.fetch_k
+ lambda_mult = lambda_mult if lambda_mult else self.lambda_mult
+ embedding_list = [json.loads(row[self.embedding_column]) for row in results]
+ mmr_selected = utils.maximal_marginal_relevance(
+ np.array(embedding, dtype=np.float32),
+ embedding_list,
+ k=k,
+ lambda_mult=lambda_mult,
+ )
+
+ documents_with_scores = []
+ for row in results:
+ metadata = (
+ row[self.metadata_json_column]
+ if self.metadata_json_column and row[self.metadata_json_column]
+ else {}
+ )
+ for col in self.metadata_columns:
+ metadata[col] = row[col]
+ documents_with_scores.append(
+ (
+ Document(
+ page_content=row[self.content_column],
+ metadata=metadata,
+ id=str(row[self.id_column]),
+ ),
+ row["distance"],
+ )
+ )
+
+ return [r for i, r in enumerate(documents_with_scores) if i in mmr_selected]
+
+ async def aapply_vector_index(
+ self,
+ index: BaseIndex,
+ name: Optional[str] = None,
+ *,
+ concurrently: bool = False,
+ ) -> None:
+ """Create index in the vector store table."""
+ if isinstance(index, ExactNearestNeighbor):
+ await self.adrop_vector_index()
+ return
+
+ # if extension name is mentioned, create the extension
+ if index.extension_name:
+ async with self.engine.connect() as conn:
+ await conn.execute(
+ text(f"CREATE EXTENSION IF NOT EXISTS {index.extension_name}")
+ )
+ await conn.commit()
+ function = index.get_index_function()
+
+ filter = f"WHERE ({index.partial_indexes})" if index.partial_indexes else ""
+ params = "WITH " + index.index_options()
+ if name is None:
+ if index.name == None:
+ index.name = self.table_name + DEFAULT_INDEX_NAME_SUFFIX
+ name = index.name
+ stmt = f'CREATE INDEX {"CONCURRENTLY" if concurrently else ""} "{name}" ON "{self.schema_name}"."{self.table_name}" USING {index.index_type} ({self.embedding_column} {function}) {params} {filter};'
+ if concurrently:
+ async with self.engine.connect() as conn:
+ autocommit_conn = await conn.execution_options(
+ isolation_level="AUTOCOMMIT"
+ )
+ await autocommit_conn.execute(text(stmt))
+ else:
+ async with self.engine.connect() as conn:
+ await conn.execute(text(stmt))
+ await conn.commit()
+
+ async def areindex(self, index_name: Optional[str] = None) -> None:
+ """Re-index the vector store table."""
+ index_name = index_name or self.table_name + DEFAULT_INDEX_NAME_SUFFIX
+ query = f'REINDEX INDEX "{index_name}";'
+ async with self.engine.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ async def adrop_vector_index(
+ self,
+ index_name: Optional[str] = None,
+ ) -> None:
+ """Drop the vector index."""
+ index_name = index_name or self.table_name + DEFAULT_INDEX_NAME_SUFFIX
+ query = f'DROP INDEX IF EXISTS "{index_name}";'
+ async with self.engine.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ async def is_valid_index(
+ self,
+ index_name: Optional[str] = None,
+ ) -> bool:
+ """Check if index exists in the table."""
+ index_name = index_name or self.table_name + DEFAULT_INDEX_NAME_SUFFIX
+ query = """
+ SELECT tablename, indexname
+ FROM pg_indexes
+ WHERE tablename = :table_name AND schemaname = :schema_name AND indexname = :index_name;
+ """
+ param_dict = {
+ "table_name": self.table_name,
+ "schema_name": self.schema_name,
+ "index_name": index_name,
+ }
+ async with self.engine.connect() as conn:
+ result = await conn.execute(text(query), param_dict)
+ result_map = result.mappings()
+ results = result_map.fetchall()
+ return bool(len(results) == 1)
+
+ async def aget_by_ids(self, ids: Sequence[str]) -> list[Document]:
+ """Get documents by ids."""
+
+ columns = self.metadata_columns + [
+ self.id_column,
+ self.content_column,
+ ]
+ if self.metadata_json_column:
+ columns.append(self.metadata_json_column)
+
+ column_names = ", ".join(f'"{col}"' for col in columns)
+
+ placeholders = ", ".join(f":id_{i}" for i in range(len(ids)))
+ param_dict = {f"id_{i}": id for i, id in enumerate(ids)}
+
+ query = f'SELECT {column_names} FROM "{self.schema_name}"."{self.table_name}" WHERE "{self.id_column}" IN ({placeholders});'
+
+ async with self.engine.connect() as conn:
+ result = await conn.execute(text(query), param_dict)
+ result_map = result.mappings()
+ results = result_map.fetchall()
+
+ documents = []
+ for row in results:
+ metadata = (
+ row[self.metadata_json_column]
+ if self.metadata_json_column and row[self.metadata_json_column]
+ else {}
+ )
+ for col in self.metadata_columns:
+ metadata[col] = row[col]
+ documents.append(
+ (
+ Document(
+ page_content=row[self.content_column],
+ metadata=metadata,
+ id=str(row[self.id_column]),
+ )
+ )
+ )
+
+ return documents
+
+ def _handle_field_filter(
+ self,
+ *,
+ field: str,
+ value: Any,
+ ) -> tuple[str, dict]:
+ """Create a filter for a specific field.
+
+ Args:
+ field: name of field
+ value: value to filter
+ If provided as is then this will be an equality filter
+ If provided as a dictionary then this will be a filter, the key
+ will be the operator and the value will be the value to filter by
+
+ Returns:
+ sql where query as a string
+ """
+ if not isinstance(field, str):
+ raise ValueError(
+ f"field should be a string but got: {type(field)} with value: {field}"
+ )
+
+ if field.startswith("$"):
+ raise ValueError(
+ f"Invalid filter condition. Expected a field but got an operator: "
+ f"{field}"
+ )
+
+ # Allow [a-zA-Z0-9_], disallow $ for now until we support escape characters
+ if not field.isidentifier():
+ raise ValueError(
+ f"Invalid field name: {field}. Expected a valid identifier."
+ )
+
+ if isinstance(value, dict):
+ # This is a filter specification
+ if len(value) != 1:
+ raise ValueError(
+ "Invalid filter condition. Expected a value which "
+ "is a dictionary with a single key that corresponds to an operator "
+ f"but got a dictionary with {len(value)} keys. The first few "
+ f"keys are: {list(value.keys())[:3]}"
+ )
+ operator, filter_value = list(value.items())[0]
+ # Verify that that operator is an operator
+ if operator not in SUPPORTED_OPERATORS:
+ raise ValueError(
+ f"Invalid operator: {operator}. "
+ f"Expected one of {SUPPORTED_OPERATORS}"
+ )
+ else: # Then we assume an equality operator
+ operator = "$eq"
+ filter_value = value
+
+ if operator in COMPARISONS_TO_NATIVE:
+ # Then we implement an equality filter
+ # native is trusted input
+ native = COMPARISONS_TO_NATIVE[operator]
+ id = str(uuid.uuid4()).split("-")[0]
+ return f"{field} {native} :{field}_{id}", {f"{field}_{id}": filter_value}
+ elif operator == "$between":
+ # Use AND with two comparisons
+ low, high = filter_value
+
+ return f"({field} BETWEEN :{field}_low AND :{field}_high)", {
+ f"{field}_low": low,
+ f"{field}_high": high,
+ }
+ elif operator in {"$in", "$nin", "$like", "$ilike"}:
+ # We'll do force coercion to text
+ if operator in {"$in", "$nin"}:
+ for val in filter_value:
+ if not isinstance(val, (str, int, float)):
+ raise NotImplementedError(
+ f"Unsupported type: {type(val)} for value: {val}"
+ )
+
+ if isinstance(val, bool): # b/c bool is an instance of int
+ raise NotImplementedError(
+ f"Unsupported type: {type(val)} for value: {val}"
+ )
+
+ if operator in {"$in"}:
+ return f"{field} = ANY(:{field}_in)", {f"{field}_in": filter_value}
+ elif operator in {"$nin"}:
+ return f"{field} <> ALL (:{field}_nin)", {f"{field}_nin": filter_value}
+ elif operator in {"$like"}:
+ return f"({field} LIKE :{field}_like)", {f"{field}_like": filter_value}
+ elif operator in {"$ilike"}:
+ return f"({field} ILIKE :{field}_ilike)", {
+ f"{field}_ilike": filter_value
+ }
+ else:
+ raise NotImplementedError()
+ elif operator == "$exists":
+ if not isinstance(filter_value, bool):
+ raise ValueError(
+ "Expected a boolean value for $exists "
+ f"operator, but got: {filter_value}"
+ )
+ else:
+ if filter_value:
+ return f"({field} IS NOT NULL)", {}
+ else:
+ return f"({field} IS NULL)", {}
+ else:
+ raise NotImplementedError()
+
+ def _create_filter_clause(self, filters: Any) -> tuple[str, dict]:
+ """Create LangChain filter representation to matching SQL where clauses
+
+ Args:
+ filters: Dictionary of filters to apply to the query.
+
+ Returns:
+ String containing the sql where query.
+ """
+
+ if not isinstance(filters, dict):
+ raise ValueError(
+ f"Invalid type: Expected a dictionary but got type: {type(filters)}"
+ )
+ if len(filters) == 1:
+ # The only operators allowed at the top level are $AND, $OR, and $NOT
+ # First check if an operator or a field
+ key, value = list(filters.items())[0]
+ if key.startswith("$"):
+ # Then it's an operator
+ if key.lower() not in ["$and", "$or", "$not"]:
+ raise ValueError(
+ f"Invalid filter condition. Expected $and, $or or $not "
+ f"but got: {key}"
+ )
+ else:
+ # Then it's a field
+ return self._handle_field_filter(field=key, value=filters[key])
+
+ if key.lower() == "$and" or key.lower() == "$or":
+ if not isinstance(value, list):
+ raise ValueError(
+ f"Expected a list, but got {type(value)} for value: {value}"
+ )
+ op = key[1:].upper() # Extract the operator
+ filter_clause = [self._create_filter_clause(el) for el in value]
+ if len(filter_clause) > 1:
+ all_clauses = [clause[0] for clause in filter_clause]
+ params = {}
+ for clause in filter_clause:
+ params.update(clause[1])
+ return f"({f' {op} '.join(all_clauses)})", params
+ elif len(filter_clause) == 1:
+ return filter_clause[0]
+ else:
+ raise ValueError(
+ "Invalid filter condition. Expected a dictionary "
+ "but got an empty dictionary"
+ )
+ elif key.lower() == "$not":
+ if isinstance(value, list):
+ not_conditions = [
+ self._create_filter_clause(item) for item in value
+ ]
+ all_clauses = [clause[0] for clause in not_conditions]
+ params = {}
+ for clause in not_conditions:
+ params.update(clause[1])
+ not_stmts = [f"NOT {condition}" for condition in all_clauses]
+ return f"({' AND '.join(not_stmts)})", params
+ elif isinstance(value, dict):
+ not_, params = self._create_filter_clause(value)
+ return f"(NOT {not_})", params
+ else:
+ raise ValueError(
+ f"Invalid filter condition. Expected a dictionary "
+ f"or a list but got: {type(value)}"
+ )
+ else:
+ raise ValueError(
+ f"Invalid filter condition. Expected $and, $or or $not "
+ f"but got: {key}"
+ )
+ elif len(filters) > 1:
+ # Then all keys have to be fields (they cannot be operators)
+ for key in filters.keys():
+ if key.startswith("$"):
+ raise ValueError(
+ f"Invalid filter condition. Expected a field but got: {key}"
+ )
+ # These should all be fields and combined using an $and operator
+ and_ = [
+ self._handle_field_filter(field=k, value=v) for k, v in filters.items()
+ ]
+ if len(and_) > 1:
+ all_clauses = [clause[0] for clause in and_]
+ params = {}
+ for clause in and_:
+ params.update(clause[1])
+ return f"({' AND '.join(all_clauses)})", params
+ elif len(and_) == 1:
+ return and_[0]
+ else:
+ raise ValueError(
+ "Invalid filter condition. Expected a dictionary "
+ "but got an empty dictionary"
+ )
+ else:
+ return "", {}
+
+ def get_by_ids(self, ids: Sequence[str]) -> list[Document]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def add_texts(
+ self,
+ texts: Iterable[str],
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def add_documents(
+ self,
+ documents: list[Document],
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def delete(
+ self,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> Optional[bool]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ @classmethod
+ def from_texts( # type: ignore[override]
+ cls: type[AsyncPGVectorStore],
+ texts: list[str],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ **kwargs: Any,
+ ) -> AsyncPGVectorStore:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ @classmethod
+ def from_documents( # type: ignore[override]
+ cls: type[AsyncPGVectorStore],
+ documents: list[Document],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ **kwargs: Any,
+ ) -> AsyncPGVectorStore:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def similarity_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def similarity_search_with_score(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def similarity_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def similarity_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def max_marginal_relevance_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def max_marginal_relevance_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
+
+ def max_marginal_relevance_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ raise NotImplementedError(
+ "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+ )
diff --git a/langchain_postgres/v2/engine.py b/langchain_postgres/v2/engine.py
new file mode 100644
index 00000000..dfd6c3b9
--- /dev/null
+++ b/langchain_postgres/v2/engine.py
@@ -0,0 +1,348 @@
+from __future__ import annotations
+
+import asyncio
+from dataclasses import dataclass
+from threading import Thread
+from typing import Any, Awaitable, Optional, TypedDict, TypeVar, Union
+
+from sqlalchemy import text
+from sqlalchemy.engine import URL
+from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
+
+T = TypeVar("T")
+
+
+class ColumnDict(TypedDict):
+ name: str
+ data_type: str
+ nullable: bool
+
+
+@dataclass
+class Column:
+ name: str
+ data_type: str
+ nullable: bool = True
+
+ def __post_init__(self) -> None:
+ """Check if initialization parameters are valid.
+
+ Raises:
+ ValueError: If Column name is not string.
+ ValueError: If data_type is not type string.
+ """
+
+ if not isinstance(self.name, str):
+ raise ValueError("Column name must be type string")
+ if not isinstance(self.data_type, str):
+ raise ValueError("Column data_type must be type string")
+
+
+class PGEngine:
+ """A class for managing connections to a Postgres database."""
+
+ _default_loop: Optional[asyncio.AbstractEventLoop] = None
+ _default_thread: Optional[Thread] = None
+ __create_key = object()
+
+ def __init__(
+ self,
+ key: object,
+ pool: AsyncEngine,
+ loop: Optional[asyncio.AbstractEventLoop],
+ thread: Optional[Thread],
+ ) -> None:
+ """PGEngine constructor.
+
+ Args:
+ key (object): Prevent direct constructor usage.
+ pool (AsyncEngine): Async engine connection pool.
+ loop (Optional[asyncio.AbstractEventLoop]): Async event loop used to create the engine.
+ thread (Optional[Thread]): Thread used to create the engine async.
+
+ Raises:
+ Exception: If the constructor is called directly by the user.
+ """
+
+ if key != PGEngine.__create_key:
+ raise Exception(
+ "Only create class through 'from_connection_string' or 'from_engine' methods!"
+ )
+ self._pool = pool
+ self._loop = loop
+ self._thread = thread
+
+ @classmethod
+ def from_engine(
+ cls: type[PGEngine],
+ engine: AsyncEngine,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ ) -> PGEngine:
+ """Create an PGEngine instance from an AsyncEngine."""
+ return cls(cls.__create_key, engine, loop, None)
+
+ @classmethod
+ def from_connection_string(
+ cls,
+ url: str | URL,
+ **kwargs: Any,
+ ) -> PGEngine:
+ """Create an PGEngine instance from arguments
+
+ Args:
+ url (Optional[str]): the URL used to connect to a database. Use url or set other arguments.
+
+ Raises:
+ ValueError: If not all database url arguments are specified
+
+ Returns:
+ PGEngine
+ """
+ # Running a loop in a background thread allows us to support
+ # async methods from non-async environments
+ if cls._default_loop is None:
+ cls._default_loop = asyncio.new_event_loop()
+ cls._default_thread = Thread(
+ target=cls._default_loop.run_forever, daemon=True
+ )
+ cls._default_thread.start()
+
+ engine = create_async_engine(url, **kwargs)
+ return cls(cls.__create_key, engine, cls._default_loop, cls._default_thread)
+
+ async def _run_as_async(self, coro: Awaitable[T]) -> T:
+ """Run an async coroutine asynchronously"""
+ # If a loop has not been provided, attempt to run in current thread
+ if not self._loop:
+ return await coro
+ # Otherwise, run in the background thread
+ return await asyncio.wrap_future(
+ asyncio.run_coroutine_threadsafe(coro, self._loop)
+ )
+
+ def _run_as_sync(self, coro: Awaitable[T]) -> T:
+ """Run an async coroutine synchronously"""
+ if not self._loop:
+ raise Exception(
+ "Engine was initialized without a background loop and cannot call sync methods."
+ )
+ return asyncio.run_coroutine_threadsafe(coro, self._loop).result()
+
+ async def close(self) -> None:
+ """Dispose of connection pool"""
+ await self._run_as_async(self._pool.dispose())
+
+ def _escape_postgres_identifier(self, name: str) -> str:
+ return name.replace('"', '""')
+
+ def _validate_column_dict(self, col: ColumnDict) -> None:
+ if not isinstance(col.get("name"), str):
+ raise TypeError("The 'name' field must be a string.")
+ if not isinstance(col.get("data_type"), str):
+ raise TypeError("The 'data_type' field must be a string.")
+ if not isinstance(col.get("nullable"), bool):
+ raise TypeError("The 'nullable' field must be a boolean.")
+
+ async def _ainit_vectorstore_table(
+ self,
+ table_name: str,
+ vector_size: int,
+ *,
+ schema_name: str = "public",
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[Union[Column, ColumnDict]]] = None,
+ metadata_json_column: str = "langchain_metadata",
+ id_column: Union[str, Column, ColumnDict] = "langchain_id",
+ overwrite_existing: bool = False,
+ store_metadata: bool = True,
+ ) -> None:
+ """
+ Create a table for saving of vectors to be used with PGVectorStore.
+
+ Args:
+ table_name (str): The database table name.
+ vector_size (int): Vector size for the embedding model to be used.
+ schema_name (str): The schema name.
+ Default: "public".
+ content_column (str): Name of the column to store document content.
+ Default: "page_content".
+ embedding_column (str) : Name of the column to store vector embeddings.
+ Default: "embedding".
+ metadata_columns (Optional[list[Union[Column, ColumnDict]]]): A list of Columns to create for custom
+ metadata. Default: None. Optional.
+ metadata_json_column (str): The column to store extra metadata in JSON format.
+ Default: "langchain_metadata". Optional.
+ id_column (Union[str, Column, ColumnDict]) : Column to store ids.
+ Default: "langchain_id" column name with data type UUID. Optional.
+ overwrite_existing (bool): Whether to drop existing table. Default: False.
+ store_metadata (bool): Whether to store metadata in the table.
+ Default: True.
+
+ Raises:
+ :class:`DuplicateTableError `: if table already exists.
+ :class:`UndefinedObjectError `: if the data type of the id column is not a postgreSQL data type.
+ """
+
+ schema_name = self._escape_postgres_identifier(schema_name)
+ table_name = self._escape_postgres_identifier(table_name)
+ content_column = self._escape_postgres_identifier(content_column)
+ embedding_column = self._escape_postgres_identifier(embedding_column)
+ if metadata_columns is None:
+ metadata_columns = []
+ else:
+ for col in metadata_columns:
+ if isinstance(col, Column):
+ col.name = self._escape_postgres_identifier(col.name)
+ elif isinstance(col, dict):
+ self._validate_column_dict(col)
+ col["name"] = self._escape_postgres_identifier(col["name"])
+ if isinstance(id_column, str):
+ id_column = self._escape_postgres_identifier(id_column)
+ elif isinstance(id_column, Column):
+ id_column.name = self._escape_postgres_identifier(id_column.name)
+ else:
+ self._validate_column_dict(id_column)
+ id_column["name"] = self._escape_postgres_identifier(id_column["name"])
+
+ async with self._pool.connect() as conn:
+ await conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector"))
+ await conn.commit()
+
+ if overwrite_existing:
+ async with self._pool.connect() as conn:
+ await conn.execute(
+ text(f'DROP TABLE IF EXISTS "{schema_name}"."{table_name}"')
+ )
+ await conn.commit()
+
+ if isinstance(id_column, str):
+ id_data_type = "UUID"
+ id_column_name = id_column
+ elif isinstance(id_column, Column):
+ id_data_type = id_column.data_type
+ id_column_name = id_column.name
+ else:
+ id_data_type = id_column["data_type"]
+ id_column_name = id_column["name"]
+
+ query = f"""CREATE TABLE "{schema_name}"."{table_name}"(
+ "{id_column_name}" {id_data_type} PRIMARY KEY,
+ "{content_column}" TEXT NOT NULL,
+ "{embedding_column}" vector({vector_size}) NOT NULL"""
+ for column in metadata_columns:
+ if isinstance(column, Column):
+ nullable = "NOT NULL" if not column.nullable else ""
+ query += f',\n"{column.name}" {column.data_type} {nullable}'
+ elif isinstance(column, dict):
+ nullable = "NOT NULL" if not column["nullable"] else ""
+ query += f',\n"{column["name"]}" {column["data_type"]} {nullable}'
+ if store_metadata:
+ query += f""",\n"{metadata_json_column}" JSON"""
+ query += "\n);"
+
+ async with self._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ async def ainit_vectorstore_table(
+ self,
+ table_name: str,
+ vector_size: int,
+ *,
+ schema_name: str = "public",
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[Union[Column, ColumnDict]]] = None,
+ metadata_json_column: str = "langchain_metadata",
+ id_column: Union[str, Column, ColumnDict] = "langchain_id",
+ overwrite_existing: bool = False,
+ store_metadata: bool = True,
+ ) -> None:
+ """
+ Create a table for saving of vectors to be used with PGVectorStore.
+
+ Args:
+ table_name (str): The database table name.
+ vector_size (int): Vector size for the embedding model to be used.
+ schema_name (str): The schema name.
+ Default: "public".
+ content_column (str): Name of the column to store document content.
+ Default: "page_content".
+ embedding_column (str) : Name of the column to store vector embeddings.
+ Default: "embedding".
+ metadata_columns (Optional[list[Union[Column, ColumnDict]]]): A list of Columns to create for custom
+ metadata. Default: None. Optional.
+ metadata_json_column (str): The column to store extra metadata in JSON format.
+ Default: "langchain_metadata". Optional.
+ id_column (Union[str, Column, ColumnDict]) : Column to store ids.
+ Default: "langchain_id" column name with data type UUID. Optional.
+ overwrite_existing (bool): Whether to drop existing table. Default: False.
+ store_metadata (bool): Whether to store metadata in the table.
+ Default: True.
+ """
+ await self._run_as_async(
+ self._ainit_vectorstore_table(
+ table_name,
+ vector_size,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ overwrite_existing=overwrite_existing,
+ store_metadata=store_metadata,
+ )
+ )
+
+ def init_vectorstore_table(
+ self,
+ table_name: str,
+ vector_size: int,
+ *,
+ schema_name: str = "public",
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[Union[Column, ColumnDict]]] = None,
+ metadata_json_column: str = "langchain_metadata",
+ id_column: Union[str, Column, ColumnDict] = "langchain_id",
+ overwrite_existing: bool = False,
+ store_metadata: bool = True,
+ ) -> None:
+ """
+ Create a table for saving of vectors to be used with PGVectorStore.
+
+ Args:
+ table_name (str): The database table name.
+ vector_size (int): Vector size for the embedding model to be used.
+ schema_name (str): The schema name.
+ Default: "public".
+ content_column (str): Name of the column to store document content.
+ Default: "page_content".
+ embedding_column (str) : Name of the column to store vector embeddings.
+ Default: "embedding".
+ metadata_columns (Optional[list[Union[Column, ColumnDict]]]): A list of Columns to create for custom
+ metadata. Default: None. Optional.
+ metadata_json_column (str): The column to store extra metadata in JSON format.
+ Default: "langchain_metadata". Optional.
+ id_column (Union[str, Column, ColumnDict]) : Column to store ids.
+ Default: "langchain_id" column name with data type UUID. Optional.
+ overwrite_existing (bool): Whether to drop existing table. Default: False.
+ store_metadata (bool): Whether to store metadata in the table.
+ Default: True.
+ """
+ self._run_as_sync(
+ self._ainit_vectorstore_table(
+ table_name,
+ vector_size,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ overwrite_existing=overwrite_existing,
+ store_metadata=store_metadata,
+ )
+ )
diff --git a/langchain_postgres/v2/indexes.py b/langchain_postgres/v2/indexes.py
new file mode 100644
index 00000000..8dbcc4f7
--- /dev/null
+++ b/langchain_postgres/v2/indexes.py
@@ -0,0 +1,155 @@
+"""Index class to add vector indexes on the PGVectorStore.
+
+Learn more about vector indexes at https://github.com/pgvector/pgvector?tab=readme-ov-file#indexing
+"""
+
+import enum
+import re
+import warnings
+from abc import ABC, abstractmethod
+from dataclasses import dataclass, field
+from typing import Optional
+
+
+@dataclass
+class StrategyMixin:
+ operator: str
+ search_function: str
+ index_function: str
+
+
+class DistanceStrategy(StrategyMixin, enum.Enum):
+ """Enumerator of the Distance strategies."""
+
+ EUCLIDEAN = "<->", "l2_distance", "vector_l2_ops"
+ COSINE_DISTANCE = "<=>", "cosine_distance", "vector_cosine_ops"
+ INNER_PRODUCT = "<#>", "inner_product", "vector_ip_ops"
+
+
+DEFAULT_DISTANCE_STRATEGY: DistanceStrategy = DistanceStrategy.COSINE_DISTANCE
+DEFAULT_INDEX_NAME_SUFFIX: str = "langchainvectorindex"
+
+
+def validate_identifier(identifier: str) -> None:
+ if re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", identifier) is None:
+ raise ValueError(
+ f"Invalid identifier: {identifier}. Identifiers must start with a letter or underscore, and subsequent characters can be letters, digits, or underscores."
+ )
+
+
+@dataclass
+class BaseIndex(ABC):
+ """
+ Abstract base class for defining vector indexes.
+
+ Attributes:
+ name (Optional[str]): A human-readable name for the index. Defaults to None.
+ index_type (str): A string identifying the type of index. Defaults to "base".
+ distance_strategy (DistanceStrategy): The strategy used to calculate distances
+ between vectors in the index. Defaults to DistanceStrategy.COSINE_DISTANCE.
+ partial_indexes (Optional[list[str]]): A list of names of partial indexes. Defaults to None.
+ extension_name (Optional[str]): The name of the extension to be created for the index, if any. Defaults to None.
+ """
+
+ name: Optional[str] = None
+ index_type: str = "base"
+ distance_strategy: DistanceStrategy = field(
+ default_factory=lambda: DistanceStrategy.COSINE_DISTANCE
+ )
+ partial_indexes: Optional[list[str]] = None
+ extension_name: Optional[str] = None
+
+ @abstractmethod
+ def index_options(self) -> str:
+ """Set index query options for vector store initialization."""
+ raise NotImplementedError(
+ "index_options method must be implemented by subclass"
+ )
+
+ def get_index_function(self) -> str:
+ return self.distance_strategy.index_function
+
+ def __post_init__(self) -> None:
+ """Check if initialization parameters are valid.
+
+ Raises:
+ ValueError: extension_name is a valid postgreSQL identifier
+ """
+
+ if self.extension_name:
+ validate_identifier(self.extension_name)
+ if self.index_type:
+ validate_identifier(self.index_type)
+
+
+@dataclass
+class ExactNearestNeighbor(BaseIndex):
+ index_type: str = "exactnearestneighbor"
+
+
+@dataclass
+class QueryOptions(ABC):
+ @abstractmethod
+ def to_parameter(self) -> list[str]:
+ """Convert index attributes to list of configurations."""
+ raise NotImplementedError("to_parameter method must be implemented by subclass")
+
+ @abstractmethod
+ def to_string(self) -> str:
+ """Convert index attributes to string."""
+ raise NotImplementedError("to_string method must be implemented by subclass")
+
+
+@dataclass
+class HNSWIndex(BaseIndex):
+ index_type: str = "hnsw"
+ m: int = 16
+ ef_construction: int = 64
+
+ def index_options(self) -> str:
+ """Set index query options for vector store initialization."""
+ return f"(m = {self.m}, ef_construction = {self.ef_construction})"
+
+
+@dataclass
+class HNSWQueryOptions(QueryOptions):
+ ef_search: int = 40
+
+ def to_parameter(self) -> list[str]:
+ """Convert index attributes to list of configurations."""
+ return [f"hnsw.ef_search = {self.ef_search}"]
+
+ def to_string(self) -> str:
+ """Convert index attributes to string."""
+ warnings.warn(
+ "to_string is deprecated, use to_parameter instead.",
+ DeprecationWarning,
+ )
+ return f"hnsw.ef_search = {self.ef_search}"
+
+
+@dataclass
+class IVFFlatIndex(BaseIndex):
+ index_type: str = "ivfflat"
+ lists: int = 100
+
+ def index_options(self) -> str:
+ """Set index query options for vector store initialization."""
+ return f"(lists = {self.lists})"
+
+
+@dataclass
+class IVFFlatQueryOptions(QueryOptions):
+ probes: int = 1
+
+ def to_parameter(self) -> list[str]:
+ """Convert index attributes to list of configurations."""
+ return [f"ivfflat.probes = {self.probes}"]
+
+ def to_string(self) -> str:
+ """Convert index attributes to string."""
+ warnings.warn(
+ "to_string is deprecated, use to_parameter instead.",
+ DeprecationWarning,
+ )
+ return f"ivfflat.probes = {self.probes}"
diff --git a/langchain_postgres/v2/vectorstores.py b/langchain_postgres/v2/vectorstores.py
new file mode 100644
index 00000000..1dc1be97
--- /dev/null
+++ b/langchain_postgres/v2/vectorstores.py
@@ -0,0 +1,842 @@
+# TODO: Remove below import when minimum supported Python version is 3.10
+from __future__ import annotations
+
+from typing import Any, Callable, Iterable, Optional, Sequence
+
+from langchain_core.documents import Document
+from langchain_core.embeddings import Embeddings
+from langchain_core.vectorstores import VectorStore
+
+from .async_vectorstore import AsyncPGVectorStore
+from .engine import PGEngine
+from .indexes import (
+ DEFAULT_DISTANCE_STRATEGY,
+ BaseIndex,
+ DistanceStrategy,
+ QueryOptions,
+)
+
+
+class PGVectorStore(VectorStore):
+ """Postgres Vector Store class"""
+
+ __create_key = object()
+
+ def __init__(self, key: object, engine: PGEngine, vs: AsyncPGVectorStore):
+ """PGVectorStore constructor.
+ Args:
+ key (object): Prevent direct constructor usage.
+ engine (PGEngine): Connection pool engine for managing connections to Postgres database.
+ vs (AsyncPGVectorStore): The async only VectorStore implementation
+
+
+ Raises:
+ Exception: If called directly by user.
+ """
+ if key != PGVectorStore.__create_key:
+ raise Exception(
+ "Only create class through 'create' or 'create_sync' methods!"
+ )
+
+ self._engine = engine
+ self.__vs = vs
+
+ @classmethod
+ async def create(
+ cls: type[PGVectorStore],
+ engine: PGEngine,
+ embedding_service: Embeddings,
+ table_name: str,
+ schema_name: str = "public",
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: Optional[str] = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ ) -> PGVectorStore:
+ """Create an PGVectorStore instance.
+
+ Args:
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ embedding_service (Embeddings): Text embedding model to use.
+ table_name (str): Name of an existing table.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ content_column (str): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str]): Column(s) that represent a document's metadata.
+ ignore_metadata_columns (list[str]): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Returns:
+ PGVectorStore
+ """
+ coro = AsyncPGVectorStore.create(
+ engine,
+ embedding_service,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ )
+ vs = await engine._run_as_async(coro)
+ return cls(cls.__create_key, engine, vs)
+
+ @classmethod
+ def create_sync(
+ cls,
+ engine: PGEngine,
+ embedding_service: Embeddings,
+ table_name: str,
+ schema_name: str = "public",
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ ) -> PGVectorStore:
+ """Create an PGVectorStore instance.
+
+ Args:
+ key (object): Prevent direct constructor usage.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ embedding_service (Embeddings): Text embedding model to use.
+ table_name (str): Name of an existing table.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ content_column (str, optional): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str, optional): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str], optional): Column(s) that represent a document's metadata. Defaults to None.
+ ignore_metadata_columns (Optional[list[str]]): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str, optional): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str, optional): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy, optional): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int, optional): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int, optional): Number of Documents to fetch to pass to MMR algorithm. Defaults to 20.
+ lambda_mult (float, optional): 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.
+ index_query_options (Optional[QueryOptions], optional): Index query option. Defaults to None.
+
+ Returns:
+ PGVectorStore
+ """
+ coro = AsyncPGVectorStore.create(
+ engine,
+ embedding_service,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ )
+ vs = engine._run_as_sync(coro)
+ return cls(cls.__create_key, engine, vs)
+
+ @property
+ def embeddings(self) -> Embeddings:
+ return self.__vs.embedding_service
+
+ async def aadd_embeddings(
+ self,
+ texts: Iterable[str],
+ embeddings: list[list[float]],
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list[str]] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Add data along with embeddings to the table."""
+ return await self._engine._run_as_async(
+ self.__vs.aadd_embeddings(texts, embeddings, metadatas, ids, **kwargs)
+ )
+
+ async def aadd_texts(
+ self,
+ texts: Iterable[str],
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Embed texts and add to the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ return await self._engine._run_as_async(
+ self.__vs.aadd_texts(texts, metadatas, ids, **kwargs)
+ )
+
+ async def aadd_documents(
+ self,
+ documents: list[Document],
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Embed documents and add to the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ return await self._engine._run_as_async(
+ self.__vs.aadd_documents(documents, ids, **kwargs)
+ )
+
+ def add_embeddings(
+ self,
+ texts: Iterable[str],
+ embeddings: list[list[float]],
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list[str]] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Add data along with embeddings to the table."""
+ return self._engine._run_as_sync(
+ self.__vs.aadd_embeddings(texts, embeddings, metadatas, ids, **kwargs)
+ )
+
+ def add_texts(
+ self,
+ texts: Iterable[str],
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Embed texts and add to the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ return self._engine._run_as_sync(
+ self.__vs.aadd_texts(texts, metadatas, ids, **kwargs)
+ )
+
+ def add_documents(
+ self,
+ documents: list[Document],
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> list[str]:
+ """Embed documents and add to the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ return self._engine._run_as_sync(
+ self.__vs.aadd_documents(documents, ids, **kwargs)
+ )
+
+ async def adelete(
+ self,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> Optional[bool]:
+ """Delete records from the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ return await self._engine._run_as_async(self.__vs.adelete(ids, **kwargs))
+
+ def delete(
+ self,
+ ids: Optional[list] = None,
+ **kwargs: Any,
+ ) -> Optional[bool]:
+ """Delete records from the table.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+ """
+ return self._engine._run_as_sync(self.__vs.adelete(ids, **kwargs))
+
+ @classmethod
+ async def afrom_texts( # type: ignore[override]
+ cls: type[PGVectorStore],
+ texts: list[str],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ schema_name: str = "public",
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ **kwargs: Any,
+ ) -> PGVectorStore:
+ """Create an PGVectorStore instance from texts.
+
+ Args:
+ texts (list[str]): Texts to add to the vector store.
+ embedding (Embeddings): Text embedding model to use.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ table_name (str): Name of an existing table.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ metadatas (Optional[list[dict]], optional): List of metadatas to add to table records. Defaults to None.
+ ids: (Optional[list]): List of IDs to add to table records. Defaults to None.
+ content_column (str, optional): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str, optional): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str], optional): Column(s) that represent a document's metadata. Defaults to an empty list.
+ ignore_metadata_columns (Optional[list[str]], optional): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str, optional): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str, optional): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+
+ Returns:
+ PGVectorStore
+ """
+ vs = await cls.create(
+ engine,
+ embedding,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ )
+ await vs.aadd_texts(texts, metadatas=metadatas, ids=ids)
+ return vs
+
+ @classmethod
+ async def afrom_documents( # type: ignore[override]
+ cls: type[PGVectorStore],
+ documents: list[Document],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ schema_name: str = "public",
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ **kwargs: Any,
+ ) -> PGVectorStore:
+ """Create an PGVectorStore instance from documents.
+
+ Args:
+ documents (list[Document]): Documents to add to the vector store.
+ embedding (Embeddings): Text embedding model to use.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ table_name (str): Name of an existing table.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ ids: (Optional[list]): List of IDs to add to table records. Defaults to None.
+ content_column (str, optional): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str, optional): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str], optional): Column(s) that represent a document's metadata. Defaults to an empty list.
+ ignore_metadata_columns (Optional[list[str]], optional): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str, optional): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str, optional): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+
+ Returns:
+ PGVectorStore
+ """
+
+ vs = await cls.create(
+ engine,
+ embedding,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ )
+ await vs.aadd_documents(documents, ids=ids)
+ return vs
+
+ @classmethod
+ def from_texts( # type: ignore[override]
+ cls: type[PGVectorStore],
+ texts: list[str],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ schema_name: str = "public",
+ metadatas: Optional[list[dict]] = None,
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ **kwargs: Any,
+ ) -> PGVectorStore:
+ """Create an PGVectorStore instance from texts.
+
+ Args:
+ texts (list[str]): Texts to add to the vector store.
+ embedding (Embeddings): Text embedding model to use.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ table_name (str): Name of an existing table.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ metadatas (Optional[list[dict]], optional): List of metadatas to add to table records. Defaults to None.
+ ids: (Optional[list]): List of IDs to add to table records. Defaults to None.
+ content_column (str, optional): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str, optional): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str], optional): Column(s) that represent a document's metadata. Defaults to empty list.
+ ignore_metadata_columns (Optional[list[str]], optional): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str, optional): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str, optional): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+
+ Returns:
+ PGVectorStore
+ """
+ vs = cls.create_sync(
+ engine,
+ embedding,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ **kwargs,
+ )
+ vs.add_texts(texts, metadatas=metadatas, ids=ids)
+ return vs
+
+ @classmethod
+ def from_documents( # type: ignore[override]
+ cls: type[PGVectorStore],
+ documents: list[Document],
+ embedding: Embeddings,
+ engine: PGEngine,
+ table_name: str,
+ schema_name: str = "public",
+ ids: Optional[list] = None,
+ content_column: str = "content",
+ embedding_column: str = "embedding",
+ metadata_columns: Optional[list[str]] = None,
+ ignore_metadata_columns: Optional[list[str]] = None,
+ id_column: str = "langchain_id",
+ metadata_json_column: str = "langchain_metadata",
+ distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,
+ k: int = 4,
+ fetch_k: int = 20,
+ lambda_mult: float = 0.5,
+ index_query_options: Optional[QueryOptions] = None,
+ **kwargs: Any,
+ ) -> PGVectorStore:
+ """Create an PGVectorStore instance from documents.
+
+ Args:
+ documents (list[Document]): Documents to add to the vector store.
+ embedding (Embeddings): Text embedding model to use.
+ engine (PGEngine): Connection pool engine for managing connections to postgres database.
+ table_name (str): Name of an existing table.
+ schema_name (str, optional): Name of the database schema. Defaults to "public".
+ ids: (Optional[list]): List of IDs to add to table records. Defaults to None.
+ content_column (str, optional): Column that represent a Document's page_content. Defaults to "content".
+ embedding_column (str, optional): Column for embedding vectors. The embedding is generated from the document value. Defaults to "embedding".
+ metadata_columns (list[str], optional): Column(s) that represent a document's metadata. Defaults to an empty list.
+ ignore_metadata_columns (Optional[list[str]], optional): Column(s) to ignore in pre-existing tables for a document's metadata. Can not be used with metadata_columns. Defaults to None.
+ id_column (str, optional): Column that represents the Document's id. Defaults to "langchain_id".
+ metadata_json_column (str, optional): Column to store metadata as JSON. Defaults to "langchain_metadata".
+ distance_strategy (DistanceStrategy): Distance strategy to use for vector similarity search. Defaults to COSINE_DISTANCE.
+ k (int): Number of Documents to return from search. Defaults to 4.
+ fetch_k (int): Number of Documents to fetch to pass to MMR algorithm.
+ lambda_mult (float): 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.
+ index_query_options (QueryOptions): Index query option.
+
+ Raises:
+ :class:`InvalidTextRepresentationError `: if the `ids` data type does not match that of the `id_column`.
+
+ Returns:
+ PGVectorStore
+ """
+ vs = cls.create_sync(
+ engine,
+ embedding,
+ table_name,
+ schema_name=schema_name,
+ content_column=content_column,
+ embedding_column=embedding_column,
+ metadata_columns=metadata_columns,
+ ignore_metadata_columns=ignore_metadata_columns,
+ metadata_json_column=metadata_json_column,
+ id_column=id_column,
+ distance_strategy=distance_strategy,
+ k=k,
+ fetch_k=fetch_k,
+ lambda_mult=lambda_mult,
+ index_query_options=index_query_options,
+ **kwargs,
+ )
+ vs.add_documents(documents, ids=ids)
+ return vs
+
+ def similarity_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected by similarity search on query."""
+ return self._engine._run_as_sync(
+ self.__vs.asimilarity_search(query, k, filter, **kwargs)
+ )
+
+ async def asimilarity_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected by similarity search on query."""
+ return await self._engine._run_as_async(
+ self.__vs.asimilarity_search(query, k, filter, **kwargs)
+ )
+
+ # Required for (a)similarity_search_with_relevance_scores
+ def _select_relevance_score_fn(self) -> Callable[[float], float]:
+ """Select a relevance function based on distance strategy."""
+ # Calculate distance strategy provided in vectorstore constructor
+ if self.__vs.distance_strategy == DistanceStrategy.COSINE_DISTANCE:
+ return self._cosine_relevance_score_fn
+ if self.__vs.distance_strategy == DistanceStrategy.INNER_PRODUCT:
+ return self._max_inner_product_relevance_score_fn
+ elif self.__vs.distance_strategy == DistanceStrategy.EUCLIDEAN:
+ return self._euclidean_relevance_score_fn
+
+ async def asimilarity_search_with_score(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected by similarity search on query."""
+ return await self._engine._run_as_async(
+ self.__vs.asimilarity_search_with_score(query, k, filter, **kwargs)
+ )
+
+ async def asimilarity_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected by vector similarity search."""
+ return await self._engine._run_as_async(
+ self.__vs.asimilarity_search_by_vector(embedding, k, filter, **kwargs)
+ )
+
+ async def asimilarity_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected by vector similarity search."""
+ return await self._engine._run_as_async(
+ self.__vs.asimilarity_search_with_score_by_vector(
+ embedding, k, filter, **kwargs
+ )
+ )
+
+ async def amax_marginal_relevance_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected using the maximal marginal relevance."""
+ return await self._engine._run_as_async(
+ self.__vs.amax_marginal_relevance_search(
+ query, k, fetch_k, lambda_mult, filter, **kwargs
+ )
+ )
+
+ async def amax_marginal_relevance_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected using the maximal marginal relevance."""
+ return await self._engine._run_as_async(
+ self.__vs.amax_marginal_relevance_search_by_vector(
+ embedding, k, fetch_k, lambda_mult, filter, **kwargs
+ )
+ )
+
+ async def amax_marginal_relevance_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected using the maximal marginal relevance."""
+ return await self._engine._run_as_async(
+ self.__vs.amax_marginal_relevance_search_with_score_by_vector(
+ embedding, k, fetch_k, lambda_mult, filter, **kwargs
+ )
+ )
+
+ def similarity_search_with_score(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected by similarity search on query."""
+ return self._engine._run_as_sync(
+ self.__vs.asimilarity_search_with_score(query, k, filter, **kwargs)
+ )
+
+ def similarity_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected by vector similarity search."""
+ return self._engine._run_as_sync(
+ self.__vs.asimilarity_search_by_vector(embedding, k, filter, **kwargs)
+ )
+
+ def similarity_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected by similarity search on vector."""
+ return self._engine._run_as_sync(
+ self.__vs.asimilarity_search_with_score_by_vector(
+ embedding, k, filter, **kwargs
+ )
+ )
+
+ def max_marginal_relevance_search(
+ self,
+ query: str,
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected using the maximal marginal relevance."""
+ return self._engine._run_as_sync(
+ self.__vs.amax_marginal_relevance_search(
+ query, k, fetch_k, lambda_mult, filter, **kwargs
+ )
+ )
+
+ def max_marginal_relevance_search_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[Document]:
+ """Return docs selected using the maximal marginal relevance."""
+ return self._engine._run_as_sync(
+ self.__vs.amax_marginal_relevance_search_by_vector(
+ embedding, k, fetch_k, lambda_mult, filter, **kwargs
+ )
+ )
+
+ def max_marginal_relevance_search_with_score_by_vector(
+ self,
+ embedding: list[float],
+ k: Optional[int] = None,
+ fetch_k: Optional[int] = None,
+ lambda_mult: Optional[float] = None,
+ filter: Optional[dict] = None,
+ **kwargs: Any,
+ ) -> list[tuple[Document, float]]:
+ """Return docs and distance scores selected using the maximal marginal relevance."""
+ return self._engine._run_as_sync(
+ self.__vs.amax_marginal_relevance_search_with_score_by_vector(
+ embedding, k, fetch_k, lambda_mult, filter, **kwargs
+ )
+ )
+
+ async def aapply_vector_index(
+ self,
+ index: BaseIndex,
+ name: Optional[str] = None,
+ concurrently: bool = False,
+ ) -> None:
+ """Create an index on the vector store table."""
+ return await self._engine._run_as_async(
+ self.__vs.aapply_vector_index(index, name, concurrently=concurrently)
+ )
+
+ def apply_vector_index(
+ self,
+ index: BaseIndex,
+ name: Optional[str] = None,
+ concurrently: bool = False,
+ ) -> None:
+ """Create an index on the vector store table."""
+ return self._engine._run_as_sync(
+ self.__vs.aapply_vector_index(index, name, concurrently=concurrently)
+ )
+
+ async def areindex(self, index_name: Optional[str] = None) -> None:
+ """Re-index the vector store table."""
+ return await self._engine._run_as_async(self.__vs.areindex(index_name))
+
+ def reindex(self, index_name: Optional[str] = None) -> None:
+ """Re-index the vector store table."""
+ return self._engine._run_as_sync(self.__vs.areindex(index_name))
+
+ async def adrop_vector_index(
+ self,
+ index_name: Optional[str] = None,
+ ) -> None:
+ """Drop the vector index."""
+ return await self._engine._run_as_async(
+ self.__vs.adrop_vector_index(index_name)
+ )
+
+ def drop_vector_index(
+ self,
+ index_name: Optional[str] = None,
+ ) -> None:
+ """Drop the vector index."""
+ return self._engine._run_as_sync(self.__vs.adrop_vector_index(index_name))
+
+ async def ais_valid_index(
+ self,
+ index_name: Optional[str] = None,
+ ) -> bool:
+ """Check if index exists in the table."""
+ return await self._engine._run_as_async(self.__vs.is_valid_index(index_name))
+
+ def is_valid_index(
+ self,
+ index_name: Optional[str] = None,
+ ) -> bool:
+ """Check if index exists in the table."""
+ return self._engine._run_as_sync(self.__vs.is_valid_index(index_name))
+
+ async def aget_by_ids(self, ids: Sequence[str]) -> list[Document]:
+ """Get documents by ids."""
+ return await self._engine._run_as_async(self.__vs.aget_by_ids(ids=ids))
+
+ def get_by_ids(self, ids: Sequence[str]) -> list[Document]:
+ """Get documents by ids."""
+ return self._engine._run_as_sync(self.__vs.aget_by_ids(ids=ids))
+
+ def get_table_name(self) -> str:
+ return self.__vs.table_name
diff --git a/langchain_postgres/vectorstores.py b/langchain_postgres/vectorstores.py
index e1630a18..a3743e4b 100644
--- a/langchain_postgres/vectorstores.py
+++ b/langchain_postgres/vectorstores.py
@@ -5,6 +5,7 @@
import enum
import logging
import uuid
+import warnings
from typing import (
Any,
AsyncGenerator,
@@ -48,6 +49,8 @@
from langchain_postgres._utils import maximal_marginal_relevance
+warnings.simplefilter("once", PendingDeprecationWarning)
+
class DistanceStrategy(str, enum.Enum):
"""Enumerator of the Distance strategies."""
@@ -197,9 +200,7 @@ class EmbeddingStore(Base):
__tablename__ = "langchain_pg_embedding"
- id = sqlalchemy.Column(
- sqlalchemy.String, nullable=True, primary_key=True, index=True, unique=True
- )
+ id = sqlalchemy.Column(sqlalchemy.String, primary_key=True)
collection_id = sqlalchemy.Column(
UUID(as_uuid=True),
@@ -269,7 +270,6 @@ class PGVector(VectorStore):
Instantiate:
.. code-block:: python
- from langchain_postgres import PGVector
from langchain_postgres.vectorstores import PGVector
from langchain_openai import OpenAIEmbeddings
diff --git a/poetry.lock b/poetry.lock
index a648c81d..50ffee86 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
[[package]]
name = "aiofiles"
@@ -6,6 +6,7 @@ version = "22.1.0"
description = "File support for asyncio."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["dev"]
files = [
{file = "aiofiles-22.1.0-py3-none-any.whl", hash = "sha256:1142fa8e80dbae46bb6339573ad4c8c0841358f79c6eb50a493dceca14621bad"},
{file = "aiofiles-22.1.0.tar.gz", hash = "sha256:9107f1ca0b2a5553987a94a3c9959fe5b491fdf731389aa5b7b1bd0733e32de6"},
@@ -17,6 +18,7 @@ version = "0.21.0"
description = "asyncio bridge to the standard sqlite3 module"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "aiosqlite-0.21.0-py3-none-any.whl", hash = "sha256:2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0"},
{file = "aiosqlite-0.21.0.tar.gz", hash = "sha256:131bb8056daa3bc875608c631c678cda73922a2d4ba8aec373b19f18c17e7aa3"},
@@ -35,6 +37,7 @@ version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
+groups = ["main", "test"]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@@ -42,13 +45,14 @@ files = [
[[package]]
name = "anyio"
-version = "4.8.0"
+version = "4.9.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.9"
+groups = ["main", "dev", "test"]
files = [
- {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"},
- {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"},
+ {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"},
+ {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"},
]
[package.dependencies]
@@ -58,8 +62,8 @@ sniffio = ">=1.1"
typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
[package.extras]
-doc = ["Sphinx (>=7.4,<8.0)", "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)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"]
+doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"]
+test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
trio = ["trio (>=0.26.1)"]
[[package]]
@@ -68,6 +72,8 @@ version = "0.1.4"
description = "Disable App Nap on macOS >= 10.9"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
+markers = "platform_system == \"Darwin\""
files = [
{file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"},
{file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"},
@@ -79,6 +85,7 @@ version = "23.1.0"
description = "Argon2 for Python"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"},
{file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"},
@@ -99,6 +106,7 @@ version = "21.2.0"
description = "Low-level CFFI bindings for Argon2"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"},
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"},
@@ -136,6 +144,7 @@ version = "1.3.0"
description = "Better dates & times for Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"},
{file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"},
@@ -155,6 +164,7 @@ version = "3.0.0"
description = "Annotate AST trees with source code positions"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"},
{file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"},
@@ -164,24 +174,105 @@ files = [
astroid = ["astroid (>=2,<4)"]
test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"]
+[[package]]
+name = "async-timeout"
+version = "5.0.1"
+description = "Timeout context manager for asyncio programs"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version < \"3.11.0\""
+files = [
+ {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"},
+ {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
+]
+
+[[package]]
+name = "asyncpg"
+version = "0.30.0"
+description = "An asyncio PostgreSQL driver"
+optional = false
+python-versions = ">=3.8.0"
+groups = ["main"]
+files = [
+ {file = "asyncpg-0.30.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfb4dd5ae0699bad2b233672c8fc5ccbd9ad24b89afded02341786887e37927e"},
+ {file = "asyncpg-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc1f62c792752a49f88b7e6f774c26077091b44caceb1983509edc18a2222ec0"},
+ {file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3152fef2e265c9c24eec4ee3d22b4f4d2703d30614b0b6753e9ed4115c8a146f"},
+ {file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7255812ac85099a0e1ffb81b10dc477b9973345793776b128a23e60148dd1af"},
+ {file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:578445f09f45d1ad7abddbff2a3c7f7c291738fdae0abffbeb737d3fc3ab8b75"},
+ {file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c42f6bb65a277ce4d93f3fba46b91a265631c8df7250592dd4f11f8b0152150f"},
+ {file = "asyncpg-0.30.0-cp310-cp310-win32.whl", hash = "sha256:aa403147d3e07a267ada2ae34dfc9324e67ccc4cdca35261c8c22792ba2b10cf"},
+ {file = "asyncpg-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb622c94db4e13137c4c7f98834185049cc50ee01d8f657ef898b6407c7b9c50"},
+ {file = "asyncpg-0.30.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5e0511ad3dec5f6b4f7a9e063591d407eee66b88c14e2ea636f187da1dcfff6a"},
+ {file = "asyncpg-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:915aeb9f79316b43c3207363af12d0e6fd10776641a7de8a01212afd95bdf0ed"},
+ {file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c198a00cce9506fcd0bf219a799f38ac7a237745e1d27f0e1f66d3707c84a5a"},
+ {file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3326e6d7381799e9735ca2ec9fd7be4d5fef5dcbc3cb555d8a463d8460607956"},
+ {file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:51da377487e249e35bd0859661f6ee2b81db11ad1f4fc036194bc9cb2ead5056"},
+ {file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc6d84136f9c4d24d358f3b02be4b6ba358abd09f80737d1ac7c444f36108454"},
+ {file = "asyncpg-0.30.0-cp311-cp311-win32.whl", hash = "sha256:574156480df14f64c2d76450a3f3aaaf26105869cad3865041156b38459e935d"},
+ {file = "asyncpg-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:3356637f0bd830407b5597317b3cb3571387ae52ddc3bca6233682be88bbbc1f"},
+ {file = "asyncpg-0.30.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c902a60b52e506d38d7e80e0dd5399f657220f24635fee368117b8b5fce1142e"},
+ {file = "asyncpg-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aca1548e43bbb9f0f627a04666fedaca23db0a31a84136ad1f868cb15deb6e3a"},
+ {file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c2a2ef565400234a633da0eafdce27e843836256d40705d83ab7ec42074efb3"},
+ {file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1292b84ee06ac8a2ad8e51c7475aa309245874b61333d97411aab835c4a2f737"},
+ {file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f5712350388d0cd0615caec629ad53c81e506b1abaaf8d14c93f54b35e3595a"},
+ {file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db9891e2d76e6f425746c5d2da01921e9a16b5a71a1c905b13f30e12a257c4af"},
+ {file = "asyncpg-0.30.0-cp312-cp312-win32.whl", hash = "sha256:68d71a1be3d83d0570049cd1654a9bdfe506e794ecc98ad0873304a9f35e411e"},
+ {file = "asyncpg-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a0292c6af5c500523949155ec17b7fe01a00ace33b68a476d6b5059f9630305"},
+ {file = "asyncpg-0.30.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05b185ebb8083c8568ea8a40e896d5f7af4b8554b64d7719c0eaa1eb5a5c3a70"},
+ {file = "asyncpg-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c47806b1a8cbb0a0db896f4cd34d89942effe353a5035c62734ab13b9f938da3"},
+ {file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b6fde867a74e8c76c71e2f64f80c64c0f3163e687f1763cfaf21633ec24ec33"},
+ {file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46973045b567972128a27d40001124fbc821c87a6cade040cfcd4fa8a30bcdc4"},
+ {file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9110df111cabc2ed81aad2f35394a00cadf4f2e0635603db6ebbd0fc896f46a4"},
+ {file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04ff0785ae7eed6cc138e73fc67b8e51d54ee7a3ce9b63666ce55a0bf095f7ba"},
+ {file = "asyncpg-0.30.0-cp313-cp313-win32.whl", hash = "sha256:ae374585f51c2b444510cdf3595b97ece4f233fde739aa14b50e0d64e8a7a590"},
+ {file = "asyncpg-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e"},
+ {file = "asyncpg-0.30.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29ff1fc8b5bf724273782ff8b4f57b0f8220a1b2324184846b39d1ab4122031d"},
+ {file = "asyncpg-0.30.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64e899bce0600871b55368b8483e5e3e7f1860c9482e7f12e0a771e747988168"},
+ {file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b290f4726a887f75dcd1b3006f484252db37602313f806e9ffc4e5996cfe5cb"},
+ {file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f86b0e2cd3f1249d6fe6fd6cfe0cd4538ba994e2d8249c0491925629b9104d0f"},
+ {file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:393af4e3214c8fa4c7b86da6364384c0d1b3298d45803375572f415b6f673f38"},
+ {file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fd4406d09208d5b4a14db9a9dbb311b6d7aeeab57bded7ed2f8ea41aeef39b34"},
+ {file = "asyncpg-0.30.0-cp38-cp38-win32.whl", hash = "sha256:0b448f0150e1c3b96cb0438a0d0aa4871f1472e58de14a3ec320dbb2798fb0d4"},
+ {file = "asyncpg-0.30.0-cp38-cp38-win_amd64.whl", hash = "sha256:f23b836dd90bea21104f69547923a02b167d999ce053f3d502081acea2fba15b"},
+ {file = "asyncpg-0.30.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f4e83f067b35ab5e6371f8a4c93296e0439857b4569850b178a01385e82e9ad"},
+ {file = "asyncpg-0.30.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5df69d55add4efcd25ea2a3b02025b669a285b767bfbf06e356d68dbce4234ff"},
+ {file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3479a0d9a852c7c84e822c073622baca862d1217b10a02dd57ee4a7a081f708"},
+ {file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26683d3b9a62836fad771a18ecf4659a30f348a561279d6227dab96182f46144"},
+ {file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1b982daf2441a0ed314bd10817f1606f1c28b1136abd9e4f11335358c2c631cb"},
+ {file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1c06a3a50d014b303e5f6fc1e5f95eb28d2cee89cf58384b700da621e5d5e547"},
+ {file = "asyncpg-0.30.0-cp39-cp39-win32.whl", hash = "sha256:1b11a555a198b08f5c4baa8f8231c74a366d190755aa4f99aacec5970afe929a"},
+ {file = "asyncpg-0.30.0-cp39-cp39-win_amd64.whl", hash = "sha256:8b684a3c858a83cd876f05958823b68e8d14ec01bb0c0d14a6704c5bf9711773"},
+ {file = "asyncpg-0.30.0.tar.gz", hash = "sha256:c551e9928ab6707602f44811817f82ba3c446e018bfe1d3abecc8ba5f3eac851"},
+]
+
+[package.dependencies]
+async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.11.0\""}
+
+[package.extras]
+docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"]
+gssauth = ["gssapi ; platform_system != \"Windows\"", "sspilib ; platform_system == \"Windows\""]
+test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi ; platform_system == \"Linux\"", "k5test ; platform_system == \"Linux\"", "mypy (>=1.8.0,<1.9.0)", "sspilib ; platform_system == \"Windows\"", "uvloop (>=0.15.3) ; platform_system != \"Windows\" and python_version < \"3.14.0\""]
+
[[package]]
name = "attrs"
-version = "25.1.0"
+version = "25.3.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
- {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"},
- {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"},
+ {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"},
+ {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"},
]
[package.extras]
-benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
-tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
+benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"]
+tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""]
[[package]]
name = "babel"
@@ -189,13 +280,14 @@ version = "2.17.0"
description = "Internationalization utilities"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"},
{file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"},
]
[package.extras]
-dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"]
+dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""]
[[package]]
name = "beautifulsoup4"
@@ -203,6 +295,7 @@ version = "4.13.3"
description = "Screen-scraping library"
optional = false
python-versions = ">=3.7.0"
+groups = ["dev"]
files = [
{file = "beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16"},
{file = "beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b"},
@@ -225,6 +318,7 @@ version = "6.2.0"
description = "An easy safelist-based HTML-sanitizing tool."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"},
{file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"},
@@ -243,6 +337,7 @@ version = "2025.1.31"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev", "test"]
files = [
{file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"},
{file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"},
@@ -254,6 +349,7 @@ version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "test"]
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
@@ -323,6 +419,7 @@ files = [
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
]
+markers = {main = "platform_python_implementation == \"PyPy\"", test = "platform_python_implementation == \"PyPy\""}
[package.dependencies]
pycparser = "*"
@@ -333,6 +430,7 @@ version = "3.4.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev", "test"]
files = [
{file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"},
{file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"},
@@ -434,6 +532,7 @@ version = "2.4.1"
description = "Fix common misspellings in text files"
optional = false
python-versions = ">=3.8"
+groups = ["codespell"]
files = [
{file = "codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425"},
{file = "codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5"},
@@ -442,7 +541,7 @@ files = [
[package.extras]
dev = ["Pygments", "build", "chardet", "pre-commit", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli", "twine"]
hard-encoding-detection = ["chardet"]
-toml = ["tomli"]
+toml = ["tomli ; python_version < \"3.11\""]
types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"]
[[package]]
@@ -451,6 +550,8 @@ 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"
+groups = ["dev", "test"]
+markers = "sys_platform == \"win32\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@@ -462,6 +563,7 @@ version = "0.2.2"
description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"},
{file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"},
@@ -475,125 +577,129 @@ test = ["pytest"]
[[package]]
name = "coverage"
-version = "7.6.10"
+version = "7.8.0"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.9"
-files = [
- {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"},
- {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"},
- {file = "coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a"},
- {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165"},
- {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988"},
- {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5"},
- {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3"},
- {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5"},
- {file = "coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244"},
- {file = "coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e"},
- {file = "coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3"},
- {file = "coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43"},
- {file = "coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132"},
- {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f"},
- {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994"},
- {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99"},
- {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd"},
- {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377"},
- {file = "coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8"},
- {file = "coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609"},
- {file = "coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853"},
- {file = "coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078"},
- {file = "coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0"},
- {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50"},
- {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022"},
- {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b"},
- {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0"},
- {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852"},
- {file = "coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359"},
- {file = "coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247"},
- {file = "coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9"},
- {file = "coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b"},
- {file = "coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690"},
- {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18"},
- {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c"},
- {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd"},
- {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e"},
- {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694"},
- {file = "coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6"},
- {file = "coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e"},
- {file = "coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe"},
- {file = "coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273"},
- {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8"},
- {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098"},
- {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb"},
- {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0"},
- {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf"},
- {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2"},
- {file = "coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312"},
- {file = "coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d"},
- {file = "coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a"},
- {file = "coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27"},
- {file = "coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4"},
- {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f"},
- {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25"},
- {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315"},
- {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90"},
- {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d"},
- {file = "coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18"},
- {file = "coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59"},
- {file = "coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"},
- {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"},
+groups = ["test"]
+files = [
+ {file = "coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe"},
+ {file = "coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28"},
+ {file = "coverage-7.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3"},
+ {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676"},
+ {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d"},
+ {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a"},
+ {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c"},
+ {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f"},
+ {file = "coverage-7.8.0-cp310-cp310-win32.whl", hash = "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f"},
+ {file = "coverage-7.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23"},
+ {file = "coverage-7.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27"},
+ {file = "coverage-7.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea"},
+ {file = "coverage-7.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7"},
+ {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040"},
+ {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543"},
+ {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2"},
+ {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318"},
+ {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9"},
+ {file = "coverage-7.8.0-cp311-cp311-win32.whl", hash = "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c"},
+ {file = "coverage-7.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78"},
+ {file = "coverage-7.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc"},
+ {file = "coverage-7.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6"},
+ {file = "coverage-7.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d"},
+ {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05"},
+ {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a"},
+ {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6"},
+ {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47"},
+ {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe"},
+ {file = "coverage-7.8.0-cp312-cp312-win32.whl", hash = "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545"},
+ {file = "coverage-7.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b"},
+ {file = "coverage-7.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd"},
+ {file = "coverage-7.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00"},
+ {file = "coverage-7.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64"},
+ {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067"},
+ {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008"},
+ {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733"},
+ {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323"},
+ {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3"},
+ {file = "coverage-7.8.0-cp313-cp313-win32.whl", hash = "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d"},
+ {file = "coverage-7.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487"},
+ {file = "coverage-7.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25"},
+ {file = "coverage-7.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42"},
+ {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502"},
+ {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1"},
+ {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4"},
+ {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73"},
+ {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a"},
+ {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883"},
+ {file = "coverage-7.8.0-cp313-cp313t-win32.whl", hash = "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada"},
+ {file = "coverage-7.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257"},
+ {file = "coverage-7.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f"},
+ {file = "coverage-7.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a"},
+ {file = "coverage-7.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82"},
+ {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814"},
+ {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c"},
+ {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd"},
+ {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4"},
+ {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899"},
+ {file = "coverage-7.8.0-cp39-cp39-win32.whl", hash = "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f"},
+ {file = "coverage-7.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3"},
+ {file = "coverage-7.8.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd"},
+ {file = "coverage-7.8.0-py3-none-any.whl", hash = "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7"},
+ {file = "coverage-7.8.0.tar.gz", hash = "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501"},
]
[package.dependencies]
tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
[package.extras]
-toml = ["tomli"]
+toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
[[package]]
name = "debugpy"
-version = "1.8.12"
+version = "1.8.13"
description = "An implementation of the Debug Adapter Protocol for Python"
optional = false
python-versions = ">=3.8"
-files = [
- {file = "debugpy-1.8.12-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:a2ba7ffe58efeae5b8fad1165357edfe01464f9aef25e814e891ec690e7dd82a"},
- {file = "debugpy-1.8.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbbd4149c4fc5e7d508ece083e78c17442ee13b0e69bfa6bd63003e486770f45"},
- {file = "debugpy-1.8.12-cp310-cp310-win32.whl", hash = "sha256:b202f591204023b3ce62ff9a47baa555dc00bb092219abf5caf0e3718ac20e7c"},
- {file = "debugpy-1.8.12-cp310-cp310-win_amd64.whl", hash = "sha256:9649eced17a98ce816756ce50433b2dd85dfa7bc92ceb60579d68c053f98dff9"},
- {file = "debugpy-1.8.12-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:36f4829839ef0afdfdd208bb54f4c3d0eea86106d719811681a8627ae2e53dd5"},
- {file = "debugpy-1.8.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a28ed481d530e3138553be60991d2d61103ce6da254e51547b79549675f539b7"},
- {file = "debugpy-1.8.12-cp311-cp311-win32.whl", hash = "sha256:4ad9a94d8f5c9b954e0e3b137cc64ef3f579d0df3c3698fe9c3734ee397e4abb"},
- {file = "debugpy-1.8.12-cp311-cp311-win_amd64.whl", hash = "sha256:4703575b78dd697b294f8c65588dc86874ed787b7348c65da70cfc885efdf1e1"},
- {file = "debugpy-1.8.12-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:7e94b643b19e8feb5215fa508aee531387494bf668b2eca27fa769ea11d9f498"},
- {file = "debugpy-1.8.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:086b32e233e89a2740c1615c2f775c34ae951508b28b308681dbbb87bba97d06"},
- {file = "debugpy-1.8.12-cp312-cp312-win32.whl", hash = "sha256:2ae5df899732a6051b49ea2632a9ea67f929604fd2b036613a9f12bc3163b92d"},
- {file = "debugpy-1.8.12-cp312-cp312-win_amd64.whl", hash = "sha256:39dfbb6fa09f12fae32639e3286112fc35ae976114f1f3d37375f3130a820969"},
- {file = "debugpy-1.8.12-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:696d8ae4dff4cbd06bf6b10d671e088b66669f110c7c4e18a44c43cf75ce966f"},
- {file = "debugpy-1.8.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:898fba72b81a654e74412a67c7e0a81e89723cfe2a3ea6fcd3feaa3395138ca9"},
- {file = "debugpy-1.8.12-cp313-cp313-win32.whl", hash = "sha256:22a11c493c70413a01ed03f01c3c3a2fc4478fc6ee186e340487b2edcd6f4180"},
- {file = "debugpy-1.8.12-cp313-cp313-win_amd64.whl", hash = "sha256:fdb3c6d342825ea10b90e43d7f20f01535a72b3a1997850c0c3cefa5c27a4a2c"},
- {file = "debugpy-1.8.12-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:b0232cd42506d0c94f9328aaf0d1d0785f90f87ae72d9759df7e5051be039738"},
- {file = "debugpy-1.8.12-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9af40506a59450f1315168d47a970db1a65aaab5df3833ac389d2899a5d63b3f"},
- {file = "debugpy-1.8.12-cp38-cp38-win32.whl", hash = "sha256:5cc45235fefac57f52680902b7d197fb2f3650112379a6fa9aa1b1c1d3ed3f02"},
- {file = "debugpy-1.8.12-cp38-cp38-win_amd64.whl", hash = "sha256:557cc55b51ab2f3371e238804ffc8510b6ef087673303890f57a24195d096e61"},
- {file = "debugpy-1.8.12-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:b5c6c967d02fee30e157ab5227706f965d5c37679c687b1e7bbc5d9e7128bd41"},
- {file = "debugpy-1.8.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a77f422f31f170c4b7e9ca58eae2a6c8e04da54121900651dfa8e66c29901a"},
- {file = "debugpy-1.8.12-cp39-cp39-win32.whl", hash = "sha256:a4042edef80364239f5b7b5764e55fd3ffd40c32cf6753da9bda4ff0ac466018"},
- {file = "debugpy-1.8.12-cp39-cp39-win_amd64.whl", hash = "sha256:f30b03b0f27608a0b26c75f0bb8a880c752c0e0b01090551b9d87c7d783e2069"},
- {file = "debugpy-1.8.12-py2.py3-none-any.whl", hash = "sha256:274b6a2040349b5c9864e475284bce5bb062e63dce368a394b8cc865ae3b00c6"},
- {file = "debugpy-1.8.12.tar.gz", hash = "sha256:646530b04f45c830ceae8e491ca1c9320a2d2f0efea3141487c82130aba70dce"},
+groups = ["dev"]
+files = [
+ {file = "debugpy-1.8.13-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:06859f68e817966723ffe046b896b1bd75c665996a77313370336ee9e1de3e90"},
+ {file = "debugpy-1.8.13-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb56c2db69fb8df3168bc857d7b7d2494fed295dfdbde9a45f27b4b152f37520"},
+ {file = "debugpy-1.8.13-cp310-cp310-win32.whl", hash = "sha256:46abe0b821cad751fc1fb9f860fb2e68d75e2c5d360986d0136cd1db8cad4428"},
+ {file = "debugpy-1.8.13-cp310-cp310-win_amd64.whl", hash = "sha256:dc7b77f5d32674686a5f06955e4b18c0e41fb5a605f5b33cf225790f114cfeec"},
+ {file = "debugpy-1.8.13-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:eee02b2ed52a563126c97bf04194af48f2fe1f68bb522a312b05935798e922ff"},
+ {file = "debugpy-1.8.13-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4caca674206e97c85c034c1efab4483f33971d4e02e73081265ecb612af65377"},
+ {file = "debugpy-1.8.13-cp311-cp311-win32.whl", hash = "sha256:7d9a05efc6973b5aaf076d779cf3a6bbb1199e059a17738a2aa9d27a53bcc888"},
+ {file = "debugpy-1.8.13-cp311-cp311-win_amd64.whl", hash = "sha256:62f9b4a861c256f37e163ada8cf5a81f4c8d5148fc17ee31fb46813bd658cdcc"},
+ {file = "debugpy-1.8.13-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1"},
+ {file = "debugpy-1.8.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522"},
+ {file = "debugpy-1.8.13-cp312-cp312-win32.whl", hash = "sha256:3872ce5453b17837ef47fb9f3edc25085ff998ce63543f45ba7af41e7f7d370f"},
+ {file = "debugpy-1.8.13-cp312-cp312-win_amd64.whl", hash = "sha256:63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea"},
+ {file = "debugpy-1.8.13-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:31abc9618be4edad0b3e3a85277bc9ab51a2d9f708ead0d99ffb5bb750e18503"},
+ {file = "debugpy-1.8.13-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0bd87557f97bced5513a74088af0b84982b6ccb2e254b9312e29e8a5c4270eb"},
+ {file = "debugpy-1.8.13-cp313-cp313-win32.whl", hash = "sha256:5268ae7fdca75f526d04465931cb0bd24577477ff50e8bb03dab90983f4ebd02"},
+ {file = "debugpy-1.8.13-cp313-cp313-win_amd64.whl", hash = "sha256:79ce4ed40966c4c1631d0131606b055a5a2f8e430e3f7bf8fd3744b09943e8e8"},
+ {file = "debugpy-1.8.13-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:acf39a6e98630959763f9669feddee540745dfc45ad28dbc9bd1f9cd60639391"},
+ {file = "debugpy-1.8.13-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:924464d87e7d905eb0d79fb70846558910e906d9ee309b60c4fe597a2e802590"},
+ {file = "debugpy-1.8.13-cp38-cp38-win32.whl", hash = "sha256:3dae443739c6b604802da9f3e09b0f45ddf1cf23c99161f3a1a8039f61a8bb89"},
+ {file = "debugpy-1.8.13-cp38-cp38-win_amd64.whl", hash = "sha256:ed93c3155fc1f888ab2b43626182174e457fc31b7781cd1845629303790b8ad1"},
+ {file = "debugpy-1.8.13-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:6fab771639332bd8ceb769aacf454a30d14d7a964f2012bf9c4e04c60f16e85b"},
+ {file = "debugpy-1.8.13-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32b6857f8263a969ce2ca098f228e5cc0604d277447ec05911a8c46cf3e7e307"},
+ {file = "debugpy-1.8.13-cp39-cp39-win32.whl", hash = "sha256:f14d2c4efa1809da125ca62df41050d9c7cd9cb9e380a2685d1e453c4d450ccb"},
+ {file = "debugpy-1.8.13-cp39-cp39-win_amd64.whl", hash = "sha256:ea869fe405880327497e6945c09365922c79d2a1eed4c3ae04d77ac7ae34b2b5"},
+ {file = "debugpy-1.8.13-py2.py3-none-any.whl", hash = "sha256:d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f"},
+ {file = "debugpy-1.8.13.tar.gz", hash = "sha256:837e7bef95bdefba426ae38b9a94821ebdc5bea55627879cd48165c90b9e50ce"},
]
[[package]]
name = "decorator"
-version = "5.1.1"
+version = "5.2.1"
description = "Decorators for Humans"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.8"
+groups = ["dev"]
files = [
- {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
- {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
+ {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"},
+ {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"},
]
[[package]]
@@ -602,6 +708,7 @@ version = "0.7.1"
description = "XML bomb protection for Python stdlib modules"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+groups = ["dev"]
files = [
{file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"},
{file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"},
@@ -613,6 +720,7 @@ version = "0.4"
description = "Discover and load entry points from installed packages."
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"},
{file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"},
@@ -624,6 +732,8 @@ version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev", "test"]
+markers = "python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@@ -638,13 +748,14 @@ version = "2.2.0"
description = "Get the currently executing AST node of a frame, and other information"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"},
{file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"},
]
[package.extras]
-tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
+tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
[[package]]
name = "fastjsonschema"
@@ -652,6 +763,7 @@ version = "2.21.1"
description = "Fastest Python implementation of JSON schema"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"},
{file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"},
@@ -666,6 +778,7 @@ version = "1.5.1"
description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers"
optional = false
python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4"
+groups = ["dev"]
files = [
{file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"},
{file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"},
@@ -677,6 +790,7 @@ version = "3.1.1"
description = "Lightweight in-process concurrent programming"
optional = false
python-versions = ">=3.7"
+groups = ["main", "test"]
files = [
{file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"},
{file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"},
@@ -763,6 +877,7 @@ version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
optional = false
python-versions = ">=3.7"
+groups = ["main", "test"]
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -774,6 +889,7 @@ version = "1.0.7"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
+groups = ["main", "test"]
files = [
{file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"},
{file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"},
@@ -795,6 +911,7 @@ version = "0.28.1"
description = "The next generation HTTP client."
optional = false
python-versions = ">=3.8"
+groups = ["main", "test"]
files = [
{file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
{file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
@@ -807,7 +924,7 @@ httpcore = "==1.*"
idna = "*"
[package.extras]
-brotli = ["brotli", "brotlicffi"]
+brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""]
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
@@ -819,6 +936,7 @@ version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev", "test"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
@@ -833,6 +951,8 @@ version = "8.6.1"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version < \"3.10\""
files = [
{file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"},
{file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"},
@@ -842,23 +962,24 @@ files = [
zipp = ">=3.20"
[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
perf = ["ipython"]
-test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
+test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
type = ["pytest-mypy"]
[[package]]
name = "iniconfig"
-version = "2.0.0"
+version = "2.1.0"
description = "brain-dead simple config-ini parsing"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
+groups = ["test"]
files = [
- {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
- {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"},
+ {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"},
]
[[package]]
@@ -867,6 +988,7 @@ version = "6.29.5"
description = "IPython Kernel for Jupyter"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"},
{file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"},
@@ -900,6 +1022,8 @@ version = "8.18.1"
description = "IPython: Productive Interactive Computing"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version < \"3.12\""
files = [
{file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"},
{file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"},
@@ -931,23 +1055,74 @@ qtconsole = ["qtconsole"]
test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"]
test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"]
+[[package]]
+name = "ipython"
+version = "9.1.0"
+description = "IPython: Productive Interactive Computing"
+optional = false
+python-versions = ">=3.11"
+groups = ["dev"]
+markers = "python_version >= \"3.12\""
+files = [
+ {file = "ipython-9.1.0-py3-none-any.whl", hash = "sha256:2df07257ec2f84a6b346b8d83100bcf8fa501c6e01ab75cd3799b0bb253b3d2a"},
+ {file = "ipython-9.1.0.tar.gz", hash = "sha256:a47e13a5e05e02f3b8e1e7a0f9db372199fe8c3763532fe7a1e0379e4e135f16"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+decorator = "*"
+ipython-pygments-lexers = "*"
+jedi = ">=0.16"
+matplotlib-inline = "*"
+pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""}
+prompt_toolkit = ">=3.0.41,<3.1.0"
+pygments = ">=2.4.0"
+stack_data = "*"
+traitlets = ">=5.13.0"
+
+[package.extras]
+all = ["ipython[doc,matplotlib,test,test-extra]"]
+black = ["black"]
+doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"]
+matplotlib = ["matplotlib"]
+test = ["packaging", "pytest", "pytest-asyncio (<0.22)", "testpath"]
+test-extra = ["curio", "ipykernel", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbclient", "nbformat", "numpy (>=1.23)", "pandas", "trio"]
+
[[package]]
name = "ipython-genutils"
version = "0.2.0"
description = "Vestigial utilities from IPython"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"},
{file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"},
]
+[[package]]
+name = "ipython-pygments-lexers"
+version = "1.1.1"
+description = "Defines a variety of Pygments lexers for highlighting IPython code."
+optional = false
+python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version >= \"3.12\""
+files = [
+ {file = "ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c"},
+ {file = "ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81"},
+]
+
+[package.dependencies]
+pygments = "*"
+
[[package]]
name = "isoduration"
version = "20.11.0"
description = "Operations with ISO 8601 durations"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"},
{file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"},
@@ -962,6 +1137,7 @@ version = "0.19.2"
description = "An autocompletion tool for Python that can be used for text editors."
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"},
{file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"},
@@ -977,13 +1153,14 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
[[package]]
name = "jinja2"
-version = "3.1.5"
+version = "3.1.6"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
- {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
- {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
+ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"},
+ {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"},
]
[package.dependencies]
@@ -994,17 +1171,18 @@ i18n = ["Babel (>=2.7)"]
[[package]]
name = "json5"
-version = "0.10.0"
+version = "0.12.0"
description = "A Python implementation of the JSON5 data format."
optional = false
python-versions = ">=3.8.0"
+groups = ["dev"]
files = [
- {file = "json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa"},
- {file = "json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559"},
+ {file = "json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db"},
+ {file = "json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a"},
]
[package.extras]
-dev = ["build (==1.2.2.post1)", "coverage (==7.5.3)", "mypy (==1.13.0)", "pip (==24.3.1)", "pylint (==3.2.3)", "ruff (==0.7.3)", "twine (==5.1.1)", "uv (==0.5.1)"]
+dev = ["build (==1.2.2.post1)", "coverage (==7.5.4) ; python_version < \"3.9\"", "coverage (==7.8.0) ; python_version >= \"3.9\"", "mypy (==1.14.1) ; python_version < \"3.9\"", "mypy (==1.15.0) ; python_version >= \"3.9\"", "pip (==25.0.1)", "pylint (==3.2.7) ; python_version < \"3.9\"", "pylint (==3.3.6) ; python_version >= \"3.9\"", "ruff (==0.11.2)", "twine (==6.1.0)", "uv (==0.6.11)"]
[[package]]
name = "jsonpatch"
@@ -1012,6 +1190,7 @@ 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.*"
+groups = ["main", "test"]
files = [
{file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"},
{file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"},
@@ -1026,6 +1205,7 @@ version = "3.0.0"
description = "Identify specific nodes in a JSON document (RFC 6901)"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev", "test"]
files = [
{file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"},
{file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"},
@@ -1037,6 +1217,7 @@ version = "4.23.0"
description = "An implementation of JSON Schema validation for Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"},
{file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"},
@@ -1066,6 +1247,7 @@ version = "2024.10.1"
description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"},
{file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"},
@@ -1080,6 +1262,7 @@ version = "7.4.9"
description = "Jupyter protocol implementation and client libraries"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "jupyter_client-7.4.9-py3-none-any.whl", hash = "sha256:214668aaea208195f4c13d28eb272ba79f945fc0cf3f11c7092c20b2ca1980e7"},
{file = "jupyter_client-7.4.9.tar.gz", hash = "sha256:52be28e04171f07aed8f20e1616a5a552ab9fee9cbbe6c1896ae170c3880d392"},
@@ -1104,6 +1287,7 @@ version = "5.7.2"
description = "Jupyter core package. A base package on which Jupyter projects rely."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"},
{file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"},
@@ -1124,6 +1308,7 @@ version = "0.12.0"
description = "Jupyter Event System library"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb"},
{file = "jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b"},
@@ -1150,6 +1335,7 @@ version = "2.15.0"
description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "jupyter_server-2.15.0-py3-none-any.whl", hash = "sha256:872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3"},
{file = "jupyter_server-2.15.0.tar.gz", hash = "sha256:9d446b8697b4f7337a1b7cdcac40778babdd93ba614b6d68ab1c0c918f1c4084"},
@@ -1186,6 +1372,7 @@ version = "0.9.3"
description = "Jupyter Server extension providing an implementation of the File ID service."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "jupyter_server_fileid-0.9.3-py3-none-any.whl", hash = "sha256:f73c01c19f90005d3fff93607b91b4955ba4e1dccdde9bfe8026646f94053791"},
{file = "jupyter_server_fileid-0.9.3.tar.gz", hash = "sha256:521608bb87f606a8637fcbdce2f3d24a8b3cc89d2eef61751cb40e468d4e54be"},
@@ -1205,6 +1392,7 @@ version = "0.5.3"
description = "A Jupyter Server Extension Providing Terminals."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"},
{file = "jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269"},
@@ -1224,6 +1412,7 @@ version = "0.8.0"
description = "A Jupyter Server Extension Providing Y Documents."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "jupyter_server_ydoc-0.8.0-py3-none-any.whl", hash = "sha256:969a3a1a77ed4e99487d60a74048dc9fa7d3b0dcd32e60885d835bbf7ba7be11"},
{file = "jupyter_server_ydoc-0.8.0.tar.gz", hash = "sha256:a6fe125091792d16c962cc3720c950c2b87fcc8c3ecf0c54c84e9a20b814526c"},
@@ -1243,6 +1432,7 @@ version = "0.2.5"
description = "Document structures for collaborative editing using Ypy"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "jupyter_ydoc-0.2.5-py3-none-any.whl", hash = "sha256:5759170f112c70320a84217dd98d287699076ae65a7f88d458d57940a9f2b882"},
{file = "jupyter_ydoc-0.2.5.tar.gz", hash = "sha256:5a02ca7449f0d875f73e8cb8efdf695dddef15a8e71378b1f4eda6b7c90f5382"},
@@ -1262,6 +1452,7 @@ version = "3.6.8"
description = "JupyterLab computational environment"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "jupyterlab-3.6.8-py3-none-any.whl", hash = "sha256:891284e75158998e23eb7a23ecc4caaf27b365e41adca374109b1305b9f769db"},
{file = "jupyterlab-3.6.8.tar.gz", hash = "sha256:a2477383e23f20009188bd9dac7e6e38dbc54307bc36d716bea6ced450647c97"},
@@ -1291,6 +1482,7 @@ version = "0.3.0"
description = "Pygments theme using JupyterLab CSS variables"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"},
{file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"},
@@ -1302,6 +1494,7 @@ version = "2.27.3"
description = "A set of server components for JupyterLab and JupyterLab like applications."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4"},
{file = "jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4"},
@@ -1324,13 +1517,14 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v
[[package]]
name = "langchain-core"
-version = "0.3.33"
+version = "0.3.51"
description = "Building applications with LLMs through composability"
optional = false
python-versions = "<4.0,>=3.9"
+groups = ["main", "test"]
files = [
- {file = "langchain_core-0.3.33-py3-none-any.whl", hash = "sha256:269706408a2223f863ff1f9616f31903a5712403199d828b50aadbc4c28b553a"},
- {file = "langchain_core-0.3.33.tar.gz", hash = "sha256:b5dd93a4e7f8198d2fc6048723b0bfecf7aaf128b0d268cbac19c34c1579b953"},
+ {file = "langchain_core-0.3.51-py3-none-any.whl", hash = "sha256:4bd71e8acd45362aa428953f2a91d8162318014544a2216e4b769463caf68e13"},
+ {file = "langchain_core-0.3.51.tar.gz", hash = "sha256:db76b9cc331411602cb40ba0469a161febe7a0663fbcaddbc9056046ac2d22f4"},
]
[package.dependencies]
@@ -1351,6 +1545,7 @@ version = "0.3.7"
description = "Standard tests for LangChain implementations"
optional = false
python-versions = "<4.0,>=3.9"
+groups = ["test"]
files = [
{file = "langchain_tests-0.3.7-py3-none-any.whl", hash = "sha256:ebbb15bb4b81a75b15272ecfd8a6b9ff45f015c6edccdcf0a16d1fe461a33c90"},
{file = "langchain_tests-0.3.7.tar.gz", hash = "sha256:28c1edff887de6f50b399345568f54f38797b7fa25d1d01b05e07172717ff7a0"},
@@ -1370,18 +1565,20 @@ syrupy = ">=4,<5"
[[package]]
name = "langsmith"
-version = "0.3.5"
+version = "0.3.26"
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
optional = false
python-versions = "<4.0,>=3.9"
+groups = ["main", "test"]
files = [
- {file = "langsmith-0.3.5-py3-none-any.whl", hash = "sha256:29da924d2e3662dd56f96d179ebc06662b66dd0b2317362ccebe0de1b78750e7"},
- {file = "langsmith-0.3.5.tar.gz", hash = "sha256:d891a205f70ab0b2c26311db6c52486ffc9fc1124238b999619445f6ae900725"},
+ {file = "langsmith-0.3.26-py3-none-any.whl", hash = "sha256:3ae49e49d6f3c980a524d15ac2fd895896e709ecedc83ac150c38e1ead776e1b"},
+ {file = "langsmith-0.3.26.tar.gz", hash = "sha256:3bd5b952a5fc82d69b0e2c030e502ee081a8ccf20468e96fd3d53e1572aef6fc"},
]
[package.dependencies]
httpx = ">=0.23.0,<1"
orjson = {version = ">=3.9.14,<4.0.0", markers = "platform_python_implementation != \"PyPy\""}
+packaging = ">=23.2"
pydantic = [
{version = ">=1,<3", markers = "python_full_version < \"3.12.4\""},
{version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""},
@@ -1392,6 +1589,8 @@ zstandard = ">=0.23.0,<0.24.0"
[package.extras]
langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"]
+openai-agents = ["openai-agents (>=0.0.3,<0.1)"]
+otel = ["opentelemetry-api (>=1.30.0,<2.0.0)", "opentelemetry-exporter-otlp-proto-http (>=1.30.0,<2.0.0)", "opentelemetry-sdk (>=1.30.0,<2.0.0)"]
pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4,<14.0.0)"]
[[package]]
@@ -1400,6 +1599,7 @@ version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
@@ -1470,6 +1670,7 @@ version = "0.1.7"
description = "Inline Matplotlib backend for Jupyter"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"},
{file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"},
@@ -1480,13 +1681,14 @@ traitlets = "*"
[[package]]
name = "mistune"
-version = "3.1.1"
+version = "3.1.3"
description = "A sane and fast Markdown parser with useful plugins and renderers"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
- {file = "mistune-3.1.1-py3-none-any.whl", hash = "sha256:02106ac2aa4f66e769debbfa028509a275069dcffce0dfa578edd7b991ee700a"},
- {file = "mistune-3.1.1.tar.gz", hash = "sha256:e0740d635f515119f7d1feb6f9b192ee60f0cc649f80a8f944f905706a21654c"},
+ {file = "mistune-3.1.3-py3-none-any.whl", hash = "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9"},
+ {file = "mistune-3.1.3.tar.gz", hash = "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0"},
]
[package.dependencies]
@@ -1494,49 +1696,44 @@ typing-extensions = {version = "*", markers = "python_version < \"3.11\""}
[[package]]
name = "mypy"
-version = "1.14.1"
+version = "1.15.0"
description = "Optional static typing for Python"
optional = false
-python-versions = ">=3.8"
-files = [
- {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"},
- {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"},
- {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d"},
- {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b"},
- {file = "mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427"},
- {file = "mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f"},
- {file = "mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c"},
- {file = "mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1"},
- {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8"},
- {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f"},
- {file = "mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1"},
- {file = "mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae"},
- {file = "mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14"},
- {file = "mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9"},
- {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11"},
- {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e"},
- {file = "mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89"},
- {file = "mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b"},
- {file = "mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255"},
- {file = "mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34"},
- {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a"},
- {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9"},
- {file = "mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd"},
- {file = "mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107"},
- {file = "mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31"},
- {file = "mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6"},
- {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319"},
- {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac"},
- {file = "mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b"},
- {file = "mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837"},
- {file = "mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35"},
- {file = "mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc"},
- {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9"},
- {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb"},
- {file = "mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60"},
- {file = "mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c"},
- {file = "mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1"},
- {file = "mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6"},
+python-versions = ">=3.9"
+groups = ["typing"]
+files = [
+ {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"},
+ {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"},
+ {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"},
+ {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"},
+ {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"},
+ {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"},
+ {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"},
+ {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"},
+ {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"},
+ {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"},
+ {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"},
+ {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"},
+ {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"},
+ {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"},
+ {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"},
+ {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"},
+ {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"},
+ {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"},
+ {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"},
+ {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"},
+ {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"},
+ {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"},
+ {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"},
+ {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"},
+ {file = "mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078"},
+ {file = "mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba"},
+ {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5"},
+ {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b"},
+ {file = "mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2"},
+ {file = "mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980"},
+ {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"},
+ {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"},
]
[package.dependencies]
@@ -1557,6 +1754,7 @@ version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
+groups = ["typing"]
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"},
@@ -1568,6 +1766,7 @@ version = "1.2.0"
description = "Jupyter Notebook as a Jupyter Server extension."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "nbclassic-1.2.0-py3-none-any.whl", hash = "sha256:61cc3612dae9d418d6c3577f7c6d8dad1d6a81b68e7a12585483283d5c92ec37"},
{file = "nbclassic-1.2.0.tar.gz", hash = "sha256:736ec50483a54485971db213be9207e34e51fc144c78343625b69917423644ba"},
@@ -1582,7 +1781,7 @@ notebook-shim = ">=0.2.3"
[package.extras]
docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"]
json-logging = ["json-logging"]
-test = ["coverage", "nbval", "pytest", "pytest-cov", "pytest-jupyter", "pytest-playwright", "pytest-tornasync", "requests", "requests-unixsocket", "testpath"]
+test = ["coverage", "nbval", "pytest", "pytest-cov", "pytest-jupyter", "pytest-playwright", "pytest-tornasync", "requests", "requests-unixsocket ; sys_platform != \"win32\"", "testpath"]
[[package]]
name = "nbclient"
@@ -1590,6 +1789,7 @@ version = "0.10.2"
description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor."
optional = false
python-versions = ">=3.9.0"
+groups = ["dev"]
files = [
{file = "nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d"},
{file = "nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193"},
@@ -1612,6 +1812,7 @@ version = "7.16.6"
description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b"},
{file = "nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582"},
@@ -1649,6 +1850,7 @@ version = "5.10.4"
description = "The Jupyter Notebook format"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"},
{file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"},
@@ -1670,6 +1872,7 @@ version = "1.6.0"
description = "Patch asyncio to allow nested event loops"
optional = false
python-versions = ">=3.5"
+groups = ["dev"]
files = [
{file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"},
{file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
@@ -1681,6 +1884,7 @@ version = "6.5.7"
description = "A web-based notebook environment for interactive computing"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "notebook-6.5.7-py3-none-any.whl", hash = "sha256:a6afa9a4ff4d149a0771ff8b8c881a7a73b3835f9add0606696d6e9d98ac1cd0"},
{file = "notebook-6.5.7.tar.gz", hash = "sha256:04eb9011dfac634fbd4442adaf0a8c27cd26beef831fe1d19faf930c327768e4"},
@@ -1707,7 +1911,7 @@ traitlets = ">=4.2.1"
[package.extras]
docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"]
json-logging = ["json-logging"]
-test = ["coverage", "nbval", "pytest", "pytest-cov", "requests", "requests-unixsocket", "selenium (==4.1.5)", "testpath"]
+test = ["coverage", "nbval", "pytest", "pytest-cov", "requests", "requests-unixsocket ; sys_platform != \"win32\"", "selenium (==4.1.5)", "testpath"]
[[package]]
name = "notebook-shim"
@@ -1715,6 +1919,7 @@ version = "0.2.4"
description = "A shim layer for notebook traits and config"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef"},
{file = "notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb"},
@@ -1732,6 +1937,7 @@ version = "1.26.4"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.9"
+groups = ["main", "test"]
files = [
{file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"},
{file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"},
@@ -1771,146 +1977,83 @@ files = [
{file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
]
-[[package]]
-name = "numpy"
-version = "2.0.2"
-description = "Fundamental package for array computing in Python"
-optional = false
-python-versions = ">=3.9"
-files = [
- {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"},
- {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"},
- {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"},
- {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"},
- {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"},
- {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"},
- {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"},
- {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"},
- {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"},
- {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"},
- {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"},
- {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"},
- {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"},
- {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"},
- {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"},
- {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"},
- {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"},
- {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"},
- {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"},
- {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"},
- {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"},
- {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"},
- {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"},
- {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"},
- {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"},
- {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"},
- {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"},
- {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"},
- {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"},
-]
-
[[package]]
name = "orjson"
-version = "3.10.15"
+version = "3.10.16"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
optional = false
-python-versions = ">=3.8"
-files = [
- {file = "orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04"},
- {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8"},
- {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8"},
- {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814"},
- {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164"},
- {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf"},
- {file = "orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061"},
- {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3"},
- {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d"},
- {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182"},
- {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e"},
- {file = "orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab"},
- {file = "orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806"},
- {file = "orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6"},
- {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef"},
- {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334"},
- {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d"},
- {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0"},
- {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13"},
- {file = "orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5"},
- {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b"},
- {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399"},
- {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388"},
- {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c"},
- {file = "orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e"},
- {file = "orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e"},
- {file = "orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a"},
- {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d"},
- {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0"},
- {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4"},
- {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767"},
- {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41"},
- {file = "orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514"},
- {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17"},
- {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b"},
- {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7"},
- {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a"},
- {file = "orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665"},
- {file = "orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa"},
- {file = "orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6"},
- {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a"},
- {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9"},
- {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0"},
- {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307"},
- {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e"},
- {file = "orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7"},
- {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8"},
- {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca"},
- {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561"},
- {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825"},
- {file = "orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890"},
- {file = "orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf"},
- {file = "orjson-3.10.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e8afd6200e12771467a1a44e5ad780614b86abb4b11862ec54861a82d677746"},
- {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9a18c500f19273e9e104cca8c1f0b40a6470bcccfc33afcc088045d0bf5ea6"},
- {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb00b7bfbdf5d34a13180e4805d76b4567025da19a197645ca746fc2fb536586"},
- {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33aedc3d903378e257047fee506f11e0833146ca3e57a1a1fb0ddb789876c1e1"},
- {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd0099ae6aed5eb1fc84c9eb72b95505a3df4267e6962eb93cdd5af03be71c98"},
- {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c864a80a2d467d7786274fce0e4f93ef2a7ca4ff31f7fc5634225aaa4e9e98c"},
- {file = "orjson-3.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c25774c9e88a3e0013d7d1a6c8056926b607a61edd423b50eb5c88fd7f2823ae"},
- {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e78c211d0074e783d824ce7bb85bf459f93a233eb67a5b5003498232ddfb0e8a"},
- {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:43e17289ffdbbac8f39243916c893d2ae41a2ea1a9cbb060a56a4d75286351ae"},
- {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:781d54657063f361e89714293c095f506c533582ee40a426cb6489c48a637b81"},
- {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6875210307d36c94873f553786a808af2788e362bd0cf4c8e66d976791e7b528"},
- {file = "orjson-3.10.15-cp38-cp38-win32.whl", hash = "sha256:305b38b2b8f8083cc3d618927d7f424349afce5975b316d33075ef0f73576b60"},
- {file = "orjson-3.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:5dd9ef1639878cc3efffed349543cbf9372bdbd79f478615a1c633fe4e4180d1"},
- {file = "orjson-3.10.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ffe19f3e8d68111e8644d4f4e267a069ca427926855582ff01fc012496d19969"},
- {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d433bf32a363823863a96561a555227c18a522a8217a6f9400f00ddc70139ae2"},
- {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da03392674f59a95d03fa5fb9fe3a160b0511ad84b7a3914699ea5a1b3a38da2"},
- {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a63bb41559b05360ded9132032239e47983a39b151af1201f07ec9370715c82"},
- {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3766ac4702f8f795ff3fa067968e806b4344af257011858cc3d6d8721588b53f"},
- {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1c73dcc8fadbd7c55802d9aa093b36878d34a3b3222c41052ce6b0fc65f8e8"},
- {file = "orjson-3.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b299383825eafe642cbab34be762ccff9fd3408d72726a6b2a4506d410a71ab3"},
- {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:abc7abecdbf67a173ef1316036ebbf54ce400ef2300b4e26a7b843bd446c2480"},
- {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3614ea508d522a621384c1d6639016a5a2e4f027f3e4a1c93a51867615d28829"},
- {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:295c70f9dc154307777ba30fe29ff15c1bcc9dfc5c48632f37d20a607e9ba85a"},
- {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:63309e3ff924c62404923c80b9e2048c1f74ba4b615e7584584389ada50ed428"},
- {file = "orjson-3.10.15-cp39-cp39-win32.whl", hash = "sha256:a2f708c62d026fb5340788ba94a55c23df4e1869fec74be455e0b2f5363b8507"},
- {file = "orjson-3.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:efcf6c735c3d22ef60c4aa27a5238f1a477df85e9b15f2142f9d669beb2d13fd"},
- {file = "orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e"},
+python-versions = ">=3.9"
+groups = ["main", "test"]
+markers = "platform_python_implementation != \"PyPy\""
+files = [
+ {file = "orjson-3.10.16-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4cb473b8e79154fa778fb56d2d73763d977be3dcc140587e07dbc545bbfc38f8"},
+ {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:622a8e85eeec1948690409a19ca1c7d9fd8ff116f4861d261e6ae2094fe59a00"},
+ {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c682d852d0ce77613993dc967e90e151899fe2d8e71c20e9be164080f468e370"},
+ {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c520ae736acd2e32df193bcff73491e64c936f3e44a2916b548da048a48b46b"},
+ {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:134f87c76bfae00f2094d85cfab261b289b76d78c6da8a7a3b3c09d362fd1e06"},
+ {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b59afde79563e2cf37cfe62ee3b71c063fd5546c8e662d7fcfc2a3d5031a5c4c"},
+ {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113602f8241daaff05d6fad25bd481d54c42d8d72ef4c831bb3ab682a54d9e15"},
+ {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4fc0077d101f8fab4031e6554fc17b4c2ad8fdbc56ee64a727f3c95b379e31da"},
+ {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9c6bf6ff180cd69e93f3f50380224218cfab79953a868ea3908430bcfaf9cb5e"},
+ {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5673eadfa952f95a7cd76418ff189df11b0a9c34b1995dff43a6fdbce5d63bf4"},
+ {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5fe638a423d852b0ae1e1a79895851696cb0d9fa0946fdbfd5da5072d9bb9551"},
+ {file = "orjson-3.10.16-cp310-cp310-win32.whl", hash = "sha256:33af58f479b3c6435ab8f8b57999874b4b40c804c7a36b5cc6b54d8f28e1d3dd"},
+ {file = "orjson-3.10.16-cp310-cp310-win_amd64.whl", hash = "sha256:0338356b3f56d71293c583350af26f053017071836b07e064e92819ecf1aa055"},
+ {file = "orjson-3.10.16-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44fcbe1a1884f8bc9e2e863168b0f84230c3d634afe41c678637d2728ea8e739"},
+ {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78177bf0a9d0192e0b34c3d78bcff7fe21d1b5d84aeb5ebdfe0dbe637b885225"},
+ {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12824073a010a754bb27330cad21d6e9b98374f497f391b8707752b96f72e741"},
+ {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddd41007e56284e9867864aa2f29f3136bb1dd19a49ca43c0b4eda22a579cf53"},
+ {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0877c4d35de639645de83666458ca1f12560d9fa7aa9b25d8bb8f52f61627d14"},
+ {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a09a539e9cc3beead3e7107093b4ac176d015bec64f811afb5965fce077a03c"},
+ {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31b98bc9b40610fec971d9a4d67bb2ed02eec0a8ae35f8ccd2086320c28526ca"},
+ {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0ce243f5a8739f3a18830bc62dc2e05b69a7545bafd3e3249f86668b2bcd8e50"},
+ {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:64792c0025bae049b3074c6abe0cf06f23c8e9f5a445f4bab31dc5ca23dbf9e1"},
+ {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ea53f7e68eec718b8e17e942f7ca56c6bd43562eb19db3f22d90d75e13f0431d"},
+ {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a741ba1a9488c92227711bde8c8c2b63d7d3816883268c808fbeada00400c164"},
+ {file = "orjson-3.10.16-cp311-cp311-win32.whl", hash = "sha256:c7ed2c61bb8226384c3fdf1fb01c51b47b03e3f4536c985078cccc2fd19f1619"},
+ {file = "orjson-3.10.16-cp311-cp311-win_amd64.whl", hash = "sha256:cd67d8b3e0e56222a2e7b7f7da9031e30ecd1fe251c023340b9f12caca85ab60"},
+ {file = "orjson-3.10.16-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6d3444abbfa71ba21bb042caa4b062535b122248259fdb9deea567969140abca"},
+ {file = "orjson-3.10.16-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:30245c08d818fdcaa48b7d5b81499b8cae09acabb216fe61ca619876b128e184"},
+ {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0ba1d0baa71bf7579a4ccdcf503e6f3098ef9542106a0eca82395898c8a500a"},
+ {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb0beefa5ef3af8845f3a69ff2a4aa62529b5acec1cfe5f8a6b4141033fd46ef"},
+ {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6daa0e1c9bf2e030e93c98394de94506f2a4d12e1e9dadd7c53d5e44d0f9628e"},
+ {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9da9019afb21e02410ef600e56666652b73eb3e4d213a0ec919ff391a7dd52aa"},
+ {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:daeb3a1ee17b69981d3aae30c3b4e786b0f8c9e6c71f2b48f1aef934f63f38f4"},
+ {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fed80eaf0e20a31942ae5d0728849862446512769692474be5e6b73123a23b"},
+ {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73390ed838f03764540a7bdc4071fe0123914c2cc02fb6abf35182d5fd1b7a42"},
+ {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a22bba012a0c94ec02a7768953020ab0d3e2b884760f859176343a36c01adf87"},
+ {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5385bbfdbc90ff5b2635b7e6bebf259652db00a92b5e3c45b616df75b9058e88"},
+ {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:02c6279016346e774dd92625d46c6c40db687b8a0d685aadb91e26e46cc33e1e"},
+ {file = "orjson-3.10.16-cp312-cp312-win32.whl", hash = "sha256:7ca55097a11426db80f79378e873a8c51f4dde9ffc22de44850f9696b7eb0e8c"},
+ {file = "orjson-3.10.16-cp312-cp312-win_amd64.whl", hash = "sha256:86d127efdd3f9bf5f04809b70faca1e6836556ea3cc46e662b44dab3fe71f3d6"},
+ {file = "orjson-3.10.16-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:148a97f7de811ba14bc6dbc4a433e0341ffd2cc285065199fb5f6a98013744bd"},
+ {file = "orjson-3.10.16-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1d960c1bf0e734ea36d0adc880076de3846aaec45ffad29b78c7f1b7962516b8"},
+ {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a318cd184d1269f68634464b12871386808dc8b7c27de8565234d25975a7a137"},
+ {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df23f8df3ef9223d1d6748bea63fca55aae7da30a875700809c500a05975522b"},
+ {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b94dda8dd6d1378f1037d7f3f6b21db769ef911c4567cbaa962bb6dc5021cf90"},
+ {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f12970a26666a8775346003fd94347d03ccb98ab8aa063036818381acf5f523e"},
+ {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15a1431a245d856bd56e4d29ea0023eb4d2c8f71efe914beb3dee8ab3f0cd7fb"},
+ {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c83655cfc247f399a222567d146524674a7b217af7ef8289c0ff53cfe8db09f0"},
+ {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fa59ae64cb6ddde8f09bdbf7baf933c4cd05734ad84dcf4e43b887eb24e37652"},
+ {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ca5426e5aacc2e9507d341bc169d8af9c3cbe88f4cd4c1cf2f87e8564730eb56"},
+ {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6fd5da4edf98a400946cd3a195680de56f1e7575109b9acb9493331047157430"},
+ {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:980ecc7a53e567169282a5e0ff078393bac78320d44238da4e246d71a4e0e8f5"},
+ {file = "orjson-3.10.16-cp313-cp313-win32.whl", hash = "sha256:28f79944dd006ac540a6465ebd5f8f45dfdf0948ff998eac7a908275b4c1add6"},
+ {file = "orjson-3.10.16-cp313-cp313-win_amd64.whl", hash = "sha256:fe0a145e96d51971407cb8ba947e63ead2aa915db59d6631a355f5f2150b56b7"},
+ {file = "orjson-3.10.16-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c35b5c1fb5a5d6d2fea825dec5d3d16bea3c06ac744708a8e1ff41d4ba10cdf1"},
+ {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9aac7ecc86218b4b3048c768f227a9452287001d7548500150bb75ee21bf55d"},
+ {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6e19f5102fff36f923b6dfdb3236ec710b649da975ed57c29833cb910c5a73ab"},
+ {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17210490408eb62755a334a6f20ed17c39f27b4f45d89a38cd144cd458eba80b"},
+ {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbbe04451db85916e52a9f720bd89bf41f803cf63b038595674691680cbebd1b"},
+ {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a966eba501a3a1f309f5a6af32ed9eb8f316fa19d9947bac3e6350dc63a6f0a"},
+ {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01e0d22f06c81e6c435723343e1eefc710e0510a35d897856766d475f2a15687"},
+ {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7c1e602d028ee285dbd300fb9820b342b937df64d5a3336e1618b354e95a2569"},
+ {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d230e5020666a6725629df81e210dc11c3eae7d52fe909a7157b3875238484f3"},
+ {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0f8baac07d4555f57d44746a7d80fbe6b2c4fe2ed68136b4abb51cfec512a5e9"},
+ {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:524e48420b90fc66953e91b660b3d05faaf921277d6707e328fde1c218b31250"},
+ {file = "orjson-3.10.16-cp39-cp39-win32.whl", hash = "sha256:a9f614e31423d7292dbca966a53b2d775c64528c7d91424ab2747d8ab8ce5c72"},
+ {file = "orjson-3.10.16-cp39-cp39-win_amd64.whl", hash = "sha256:c338dc2296d1ed0d5c5c27dfb22d00b330555cb706c2e0be1e1c3940a0895905"},
+ {file = "orjson-3.10.16.tar.gz", hash = "sha256:d2aaa5c495e11d17b9b93205f5fa196737ee3202f000aaebf028dc9a73750f10"},
]
[[package]]
@@ -1919,6 +2062,7 @@ version = "7.7.0"
description = "A decorator to automatically detect mismatch when overriding a method."
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49"},
{file = "overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a"},
@@ -1930,6 +2074,7 @@ version = "24.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "test"]
files = [
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
@@ -1941,6 +2086,7 @@ version = "1.5.1"
description = "Utilities for writing pandoc filters in python"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+groups = ["dev"]
files = [
{file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"},
{file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"},
@@ -1952,6 +2098,7 @@ version = "0.8.4"
description = "A Python Parser"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"},
{file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"},
@@ -1967,6 +2114,8 @@ version = "4.9.0"
description = "Pexpect allows easy control of interactive console applications."
optional = false
python-versions = "*"
+groups = ["dev"]
+markers = "python_version < \"3.12\" and sys_platform != \"win32\" or sys_platform != \"win32\" and sys_platform != \"emscripten\""
files = [
{file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"},
{file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
@@ -1981,6 +2130,7 @@ version = "0.3.6"
description = "pgvector support for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "pgvector-0.3.6-py3-none-any.whl", hash = "sha256:f6c269b3c110ccb7496bac87202148ed18f34b390a0189c783e351062400a75a"},
{file = "pgvector-0.3.6.tar.gz", hash = "sha256:31d01690e6ea26cea8a633cde5f0f55f5b246d9c8292d68efdef8c22ec994ade"},
@@ -1991,19 +2141,20 @@ numpy = "*"
[[package]]
name = "platformdirs"
-version = "4.3.6"
+version = "4.3.7"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["dev"]
files = [
- {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
- {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
+ {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"},
+ {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"},
]
[package.extras]
-docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
-test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
-type = ["mypy (>=1.11.2)"]
+docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"]
+type = ["mypy (>=1.14.1)"]
[[package]]
name = "pluggy"
@@ -2011,6 +2162,7 @@ version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
+groups = ["test"]
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
@@ -2026,6 +2178,7 @@ version = "0.21.1"
description = "Python client for the Prometheus monitoring system."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "prometheus_client-0.21.1-py3-none-any.whl", hash = "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301"},
{file = "prometheus_client-0.21.1.tar.gz", hash = "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb"},
@@ -2040,6 +2193,7 @@ version = "3.0.50"
description = "Library for building powerful interactive command lines in Python"
optional = false
python-versions = ">=3.8.0"
+groups = ["dev"]
files = [
{file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"},
{file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"},
@@ -2050,43 +2204,38 @@ wcwidth = "*"
[[package]]
name = "psutil"
-version = "6.1.1"
-description = "Cross-platform lib for process and system monitoring in Python."
+version = "7.0.0"
+description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7."
optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+python-versions = ">=3.6"
+groups = ["dev"]
files = [
- {file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"},
- {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"},
- {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8df0178ba8a9e5bc84fed9cfa61d54601b371fbec5c8eebad27575f1e105c0d4"},
- {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1924e659d6c19c647e763e78670a05dbb7feaf44a0e9c94bf9e14dfc6ba50468"},
- {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:018aeae2af92d943fdf1da6b58665124897cfc94faa2ca92098838f83e1b1bca"},
- {file = "psutil-6.1.1-cp27-none-win32.whl", hash = "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac"},
- {file = "psutil-6.1.1-cp27-none-win_amd64.whl", hash = "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030"},
- {file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"},
- {file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"},
- {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"},
- {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"},
- {file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"},
- {file = "psutil-6.1.1-cp36-cp36m-win32.whl", hash = "sha256:384636b1a64b47814437d1173be1427a7c83681b17a450bfc309a1953e329603"},
- {file = "psutil-6.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8be07491f6ebe1a693f17d4f11e69d0dc1811fa082736500f649f79df7735303"},
- {file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"},
- {file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"},
- {file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"},
-]
-
-[package.extras]
-dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"]
+ {file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"},
+ {file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"},
+ {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91"},
+ {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34"},
+ {file = "psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993"},
+ {file = "psutil-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17"},
+ {file = "psutil-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e"},
+ {file = "psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99"},
+ {file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"},
+ {file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"},
+]
+
+[package.extras]
+dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"]
test = ["pytest", "pytest-xdist", "setuptools"]
[[package]]
name = "psycopg"
-version = "3.2.4"
+version = "3.2.6"
description = "PostgreSQL database adapter for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
- {file = "psycopg-3.2.4-py3-none-any.whl", hash = "sha256:43665368ccd48180744cab26b74332f46b63b7e06e8ce0775547a3533883d381"},
- {file = "psycopg-3.2.4.tar.gz", hash = "sha256:f26f1346d6bf1ef5f5ef1714dd405c67fb365cfd1c6cea07de1792747b167b92"},
+ {file = "psycopg-3.2.6-py3-none-any.whl", hash = "sha256:f3ff5488525890abb0566c429146add66b329e20d6d4835662b920cbbf90ac58"},
+ {file = "psycopg-3.2.6.tar.gz", hash = "sha256:16fa094efa2698f260f2af74f3710f781e4a6f226efe9d1fd0c37f384639ed8a"},
]
[package.dependencies]
@@ -2094,22 +2243,23 @@ typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""}
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras]
-binary = ["psycopg-binary (==3.2.4)"]
-c = ["psycopg-c (==3.2.4)"]
-dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.14)", "pre-commit (>=4.0.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
+binary = ["psycopg-binary (==3.2.6) ; implementation_name != \"pypy\""]
+c = ["psycopg-c (==3.2.6) ; implementation_name != \"pypy\""]
+dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "isort-psycopg", "isort[colors] (>=6.0)", "mypy (>=1.14)", "pre-commit (>=4.0.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"]
pool = ["psycopg-pool"]
test = ["anyio (>=4.0)", "mypy (>=1.14)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
[[package]]
name = "psycopg-pool"
-version = "3.2.4"
+version = "3.2.6"
description = "Connection Pool for Psycopg"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
- {file = "psycopg_pool-3.2.4-py3-none-any.whl", hash = "sha256:f6a22cff0f21f06d72fb2f5cb48c618946777c49385358e0c88d062c59cbd224"},
- {file = "psycopg_pool-3.2.4.tar.gz", hash = "sha256:61774b5bbf23e8d22bedc7504707135aaf744679f8ef9b3fe29942920746a6ed"},
+ {file = "psycopg_pool-3.2.6-py3-none-any.whl", hash = "sha256:5887318a9f6af906d041a0b1dc1c60f8f0dda8340c2572b74e10907b51ed5da7"},
+ {file = "psycopg_pool-3.2.6.tar.gz", hash = "sha256:0f92a7817719517212fbfe2fd58b8c35c1850cdd2a80d36b581ba2085d9148e5"},
]
[package.dependencies]
@@ -2121,6 +2271,8 @@ version = "0.7.0"
description = "Run a subprocess in a pseudo terminal"
optional = false
python-versions = "*"
+groups = ["dev"]
+markers = "sys_platform != \"win32\" and python_version < \"3.12\" or sys_platform != \"win32\" and sys_platform != \"emscripten\" or os_name != \"nt\""
files = [
{file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
@@ -2132,6 +2284,7 @@ version = "0.2.3"
description = "Safely evaluate AST nodes without side effects"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"},
{file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"},
@@ -2146,138 +2299,142 @@ version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "test"]
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
+markers = {main = "platform_python_implementation == \"PyPy\"", test = "platform_python_implementation == \"PyPy\""}
[[package]]
name = "pydantic"
-version = "2.10.6"
+version = "2.11.2"
description = "Data validation using Python type hints"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["main", "test"]
files = [
- {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"},
- {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"},
+ {file = "pydantic-2.11.2-py3-none-any.whl", hash = "sha256:7f17d25846bcdf89b670a86cdfe7b29a9f1c9ca23dee154221c9aa81845cfca7"},
+ {file = "pydantic-2.11.2.tar.gz", hash = "sha256:2138628e050bd7a1e70b91d4bf4a91167f4ad76fdb83209b107c8d84b854917e"},
]
[package.dependencies]
annotated-types = ">=0.6.0"
-pydantic-core = "2.27.2"
+pydantic-core = "2.33.1"
typing-extensions = ">=4.12.2"
+typing-inspection = ">=0.4.0"
[package.extras]
email = ["email-validator (>=2.0.0)"]
-timezone = ["tzdata"]
+timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""]
[[package]]
name = "pydantic-core"
-version = "2.27.2"
+version = "2.33.1"
description = "Core functionality for Pydantic validation and serialization"
optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
- {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
- {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"},
- {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"},
- {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"},
- {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"},
- {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"},
- {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"},
- {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"},
- {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"},
- {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"},
- {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"},
- {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"},
- {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"},
- {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"},
- {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"},
- {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"},
- {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"},
- {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"},
- {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"},
- {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"},
- {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"},
- {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"},
- {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"},
- {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"},
- {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"},
- {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"},
- {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"},
- {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"},
- {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"},
- {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"},
- {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"},
- {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"},
- {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"},
- {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"},
- {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"},
- {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"},
- {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"},
- {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"},
- {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"},
- {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"},
- {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"},
- {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"},
- {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"},
- {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"},
- {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"},
- {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"},
- {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"},
- {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"},
- {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"},
- {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"},
- {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"},
- {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"},
- {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"},
- {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"},
- {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"},
- {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"},
- {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"},
- {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"},
- {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"},
- {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"},
- {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"},
- {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"},
- {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"},
- {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"},
- {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"},
- {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"},
- {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"},
- {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"},
- {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"},
- {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"},
- {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"},
- {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"},
- {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"},
- {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"},
- {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"},
- {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"},
- {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"},
- {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"},
- {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"},
- {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"},
- {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"},
- {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"},
- {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"},
+python-versions = ">=3.9"
+groups = ["main", "test"]
+files = [
+ {file = "pydantic_core-2.33.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3077cfdb6125cc8dab61b155fdd714663e401f0e6883f9632118ec12cf42df26"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ffab8b2908d152e74862d276cf5017c81a2f3719f14e8e3e8d6b83fda863927"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5183e4f6a2d468787243ebcd70cf4098c247e60d73fb7d68d5bc1e1beaa0c4db"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:398a38d323f37714023be1e0285765f0a27243a8b1506b7b7de87b647b517e48"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87d3776f0001b43acebfa86f8c64019c043b55cc5a6a2e313d728b5c95b46969"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c566dd9c5f63d22226409553531f89de0cac55397f2ab8d97d6f06cfce6d947e"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d5f3acc81452c56895e90643a625302bd6be351e7010664151cc55b7b97f89"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3a07fadec2a13274a8d861d3d37c61e97a816beae717efccaa4b36dfcaadcde"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f99aeda58dce827f76963ee87a0ebe75e648c72ff9ba1174a253f6744f518f65"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:902dbc832141aa0ec374f4310f1e4e7febeebc3256f00dc359a9ac3f264a45dc"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fe44d56aa0b00d66640aa84a3cbe80b7a3ccdc6f0b1ca71090696a6d4777c091"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-win32.whl", hash = "sha256:ed3eb16d51257c763539bde21e011092f127a2202692afaeaccb50db55a31383"},
+ {file = "pydantic_core-2.33.1-cp310-cp310-win_amd64.whl", hash = "sha256:694ad99a7f6718c1a498dc170ca430687a39894a60327f548e02a9c7ee4b6504"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e966fc3caaf9f1d96b349b0341c70c8d6573bf1bac7261f7b0ba88f96c56c24"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bfd0adeee563d59c598ceabddf2c92eec77abcb3f4a391b19aa7366170bd9e30"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91815221101ad3c6b507804178a7bb5cb7b2ead9ecd600041669c8d805ebd595"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9fea9c1869bb4742d174a57b4700c6dadea951df8b06de40c2fedb4f02931c2e"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d20eb4861329bb2484c021b9d9a977566ab16d84000a57e28061151c62b349a"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb935c5591573ae3201640579f30128ccc10739b45663f93c06796854405505"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c964fd24e6166420d18fb53996d8c9fd6eac9bf5ae3ec3d03015be4414ce497f"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:681d65e9011f7392db5aa002b7423cc442d6a673c635668c227c6c8d0e5a4f77"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e100c52f7355a48413e2999bfb4e139d2977a904495441b374f3d4fb4a170961"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:048831bd363490be79acdd3232f74a0e9951b11b2b4cc058aeb72b22fdc3abe1"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bdc84017d28459c00db6f918a7272a5190bec3090058334e43a76afb279eac7c"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-win32.whl", hash = "sha256:32cd11c5914d1179df70406427097c7dcde19fddf1418c787540f4b730289896"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-win_amd64.whl", hash = "sha256:2ea62419ba8c397e7da28a9170a16219d310d2cf4970dbc65c32faf20d828c83"},
+ {file = "pydantic_core-2.33.1-cp311-cp311-win_arm64.whl", hash = "sha256:fc903512177361e868bc1f5b80ac8c8a6e05fcdd574a5fb5ffeac5a9982b9e89"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1293d7febb995e9d3ec3ea09caf1a26214eec45b0f29f6074abb004723fc1de8"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99b56acd433386c8f20be5c4000786d1e7ca0523c8eefc995d14d79c7a081498"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35a5ec3fa8c2fe6c53e1b2ccc2454398f95d5393ab398478f53e1afbbeb4d939"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b172f7b9d2f3abc0efd12e3386f7e48b576ef309544ac3a63e5e9cdd2e24585d"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9097b9f17f91eea659b9ec58148c0747ec354a42f7389b9d50701610d86f812e"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc77ec5b7e2118b152b0d886c7514a4653bcb58c6b1d760134a9fab915f777b3"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3d15245b08fa4a84cefc6c9222e6f37c98111c8679fbd94aa145f9a0ae23d"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef99779001d7ac2e2461d8ab55d3373fe7315caefdbecd8ced75304ae5a6fc6b"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fc6bf8869e193855e8d91d91f6bf59699a5cdfaa47a404e278e776dd7f168b39"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:b1caa0bc2741b043db7823843e1bde8aaa58a55a58fda06083b0569f8b45693a"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ec259f62538e8bf364903a7d0d0239447059f9434b284f5536e8402b7dd198db"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-win32.whl", hash = "sha256:e14f369c98a7c15772b9da98987f58e2b509a93235582838bd0d1d8c08b68fda"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-win_amd64.whl", hash = "sha256:1c607801d85e2e123357b3893f82c97a42856192997b95b4d8325deb1cd0c5f4"},
+ {file = "pydantic_core-2.33.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d13f0276806ee722e70a1c93da19748594f19ac4299c7e41237fc791d1861ea"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:70af6a21237b53d1fe7b9325b20e65cbf2f0a848cf77bed492b029139701e66a"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:282b3fe1bbbe5ae35224a0dbd05aed9ccabccd241e8e6b60370484234b456266"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b315e596282bbb5822d0c7ee9d255595bd7506d1cb20c2911a4da0b970187d3"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dfae24cf9921875ca0ca6a8ecb4bb2f13c855794ed0d468d6abbec6e6dcd44a"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dd8ecfde08d8bfadaea669e83c63939af76f4cf5538a72597016edfa3fad516"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f593494876eae852dc98c43c6f260f45abdbfeec9e4324e31a481d948214764"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:948b73114f47fd7016088e5186d13faf5e1b2fe83f5e320e371f035557fd264d"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e11f3864eb516af21b01e25fac915a82e9ddad3bb0fb9e95a246067398b435a4"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:549150be302428b56fdad0c23c2741dcdb5572413776826c965619a25d9c6bde"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:495bc156026efafd9ef2d82372bd38afce78ddd82bf28ef5276c469e57c0c83e"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ec79de2a8680b1a67a07490bddf9636d5c2fab609ba8c57597e855fa5fa4dacd"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-win32.whl", hash = "sha256:ee12a7be1742f81b8a65b36c6921022301d466b82d80315d215c4c691724986f"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-win_amd64.whl", hash = "sha256:ede9b407e39949d2afc46385ce6bd6e11588660c26f80576c11c958e6647bc40"},
+ {file = "pydantic_core-2.33.1-cp313-cp313-win_arm64.whl", hash = "sha256:aa687a23d4b7871a00e03ca96a09cad0f28f443690d300500603bd0adba4b523"},
+ {file = "pydantic_core-2.33.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:401d7b76e1000d0dd5538e6381d28febdcacb097c8d340dde7d7fc6e13e9f95d"},
+ {file = "pydantic_core-2.33.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aeb055a42d734c0255c9e489ac67e75397d59c6fbe60d155851e9782f276a9c"},
+ {file = "pydantic_core-2.33.1-cp313-cp313t-win_amd64.whl", hash = "sha256:338ea9b73e6e109f15ab439e62cb3b78aa752c7fd9536794112e14bee02c8d18"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5ab77f45d33d264de66e1884fca158bc920cb5e27fd0764a72f72f5756ae8bdb"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7aaba1b4b03aaea7bb59e1b5856d734be011d3e6d98f5bcaa98cb30f375f2ad"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fb66263e9ba8fea2aa85e1e5578980d127fb37d7f2e292773e7bc3a38fb0c7b"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f2648b9262607a7fb41d782cc263b48032ff7a03a835581abbf7a3bec62bcf5"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:723c5630c4259400818b4ad096735a829074601805d07f8cafc366d95786d331"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d100e3ae783d2167782391e0c1c7a20a31f55f8015f3293647544df3f9c67824"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177d50460bc976a0369920b6c744d927b0ecb8606fb56858ff542560251b19e5"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3edde68d1a1f9af1273b2fe798997b33f90308fb6d44d8550c89fc6a3647cf6"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a62c3c3ef6a7e2c45f7853b10b5bc4ddefd6ee3cd31024754a1a5842da7d598d"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:c91dbb0ab683fa0cd64a6e81907c8ff41d6497c346890e26b23de7ee55353f96"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f466e8bf0a62dc43e068c12166281c2eca72121dd2adc1040f3aa1e21ef8599"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-win32.whl", hash = "sha256:ab0277cedb698749caada82e5d099dc9fed3f906a30d4c382d1a21725777a1e5"},
+ {file = "pydantic_core-2.33.1-cp39-cp39-win_amd64.whl", hash = "sha256:5773da0ee2d17136b1f1c6fbde543398d452a6ad2a7b54ea1033e2daa739b8d2"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c834f54f8f4640fd7e4b193f80eb25a0602bba9e19b3cd2fc7ffe8199f5ae02"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:049e0de24cf23766f12cc5cc71d8abc07d4a9deb9061b334b62093dedc7cb068"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a28239037b3d6f16916a4c831a5a0eadf856bdd6d2e92c10a0da3a59eadcf3e"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d3da303ab5f378a268fa7d45f37d7d85c3ec19769f28d2cc0c61826a8de21fe"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25626fb37b3c543818c14821afe0fd3830bc327a43953bc88db924b68c5723f1"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3ab2d36e20fbfcce8f02d73c33a8a7362980cff717926bbae030b93ae46b56c7"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:2f9284e11c751b003fd4215ad92d325d92c9cb19ee6729ebd87e3250072cdcde"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:048c01eee07d37cbd066fc512b9d8b5ea88ceeb4e629ab94b3e56965ad655add"},
+ {file = "pydantic_core-2.33.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5ccd429694cf26af7997595d627dd2637e7932214486f55b8a357edaac9dae8c"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3a371dc00282c4b84246509a5ddc808e61b9864aa1eae9ecc92bb1268b82db4a"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f59295ecc75a1788af8ba92f2e8c6eeaa5a94c22fc4d151e8d9638814f85c8fc"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08530b8ac922003033f399128505f513e30ca770527cc8bbacf75a84fcc2c74b"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bae370459da6a5466978c0eacf90690cb57ec9d533f8e63e564ef3822bfa04fe"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e3de2777e3b9f4d603112f78006f4ae0acb936e95f06da6cb1a45fbad6bdb4b5"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a64e81e8cba118e108d7126362ea30e021291b7805d47e4896e52c791be2761"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:52928d8c1b6bda03cc6d811e8923dffc87a2d3c8b3bfd2ce16471c7147a24850"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1b30d92c9412beb5ac6b10a3eb7ef92ccb14e3f2a8d7732e2d739f58b3aa7544"},
+ {file = "pydantic_core-2.33.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f995719707e0e29f0f41a8aa3bcea6e761a36c9136104d3189eafb83f5cec5e5"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7edbc454a29fc6aeae1e1eecba4f07b63b8d76e76a748532233c4c167b4cb9ea"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ad05b683963f69a1d5d2c2bdab1274a31221ca737dbbceaa32bcb67359453cdd"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df6a94bf9452c6da9b5d76ed229a5683d0306ccb91cca8e1eea883189780d568"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7965c13b3967909a09ecc91f21d09cfc4576bf78140b988904e94f130f188396"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3f1fdb790440a34f6ecf7679e1863b825cb5ffde858a9197f851168ed08371e5"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5277aec8d879f8d05168fdd17ae811dd313b8ff894aeeaf7cd34ad28b4d77e33"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8ab581d3530611897d863d1a649fb0644b860286b4718db919bfd51ece41f10b"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0483847fa9ad5e3412265c1bd72aad35235512d9ce9d27d81a56d935ef489672"},
+ {file = "pydantic_core-2.33.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:de9e06abe3cc5ec6a2d5f75bc99b0bdca4f5c719a5b34026f8c57efbdecd2ee3"},
+ {file = "pydantic_core-2.33.1.tar.gz", hash = "sha256:bcc9c6fdb0ced789245b02b7d6603e17d1563064ddcfc36f046b61c0c05dd9df"},
]
[package.dependencies]
@@ -2289,6 +2446,7 @@ version = "2.19.1"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
{file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
@@ -2303,6 +2461,7 @@ version = "7.4.4"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.7"
+groups = ["test"]
files = [
{file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"},
{file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"},
@@ -2325,6 +2484,7 @@ version = "0.23.8"
description = "Pytest support for asyncio"
optional = false
python-versions = ">=3.8"
+groups = ["test"]
files = [
{file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"},
{file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"},
@@ -2343,6 +2503,7 @@ version = "5.0.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.8"
+groups = ["test"]
files = [
{file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
{file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
@@ -2361,6 +2522,7 @@ version = "0.7.0"
description = "Pytest Plugin to disable socket calls during tests"
optional = false
python-versions = ">=3.8,<4.0"
+groups = ["test"]
files = [
{file = "pytest_socket-0.7.0-py3-none-any.whl", hash = "sha256:7e0f4642177d55d317bbd58fc68c6bd9048d6eadb2d46a89307fa9221336ce45"},
{file = "pytest_socket-0.7.0.tar.gz", hash = "sha256:71ab048cbbcb085c15a4423b73b619a8b35d6a307f46f78ea46be51b1b7e11b3"},
@@ -2375,6 +2537,7 @@ version = "2.3.1"
description = "pytest plugin to abort hanging tests"
optional = false
python-versions = ">=3.7"
+groups = ["test"]
files = [
{file = "pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9"},
{file = "pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e"},
@@ -2389,6 +2552,7 @@ version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["dev"]
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
@@ -2399,46 +2563,47 @@ six = ">=1.5"
[[package]]
name = "python-json-logger"
-version = "3.2.1"
+version = "3.3.0"
description = "JSON Log Formatter for the Python Logging Package"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
- {file = "python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090"},
- {file = "python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008"},
+ {file = "python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7"},
+ {file = "python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84"},
]
[package.dependencies]
typing_extensions = {version = "*", markers = "python_version < \"3.10\""}
[package.extras]
-dev = ["backports.zoneinfo", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec", "msgspec-python313-pre", "mypy", "orjson", "pylint", "pytest", "tzdata", "validate-pyproject[all]"]
+dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec ; implementation_name != \"pypy\"", "mypy", "orjson ; implementation_name != \"pypy\"", "pylint", "pytest", "tzdata", "validate-pyproject[all]"]
[[package]]
name = "pywin32"
-version = "308"
+version = "310"
description = "Python for Window Extensions"
optional = false
python-versions = "*"
-files = [
- {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"},
- {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"},
- {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"},
- {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"},
- {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"},
- {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"},
- {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"},
- {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"},
- {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"},
- {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"},
- {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"},
- {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"},
- {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"},
- {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"},
- {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"},
- {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"},
- {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"},
- {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"},
+groups = ["dev"]
+markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""
+files = [
+ {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"},
+ {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"},
+ {file = "pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213"},
+ {file = "pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd"},
+ {file = "pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c"},
+ {file = "pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582"},
+ {file = "pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d"},
+ {file = "pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060"},
+ {file = "pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966"},
+ {file = "pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab"},
+ {file = "pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"},
+ {file = "pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33"},
+ {file = "pywin32-310-cp38-cp38-win32.whl", hash = "sha256:0867beb8addefa2e3979d4084352e4ac6e991ca45373390775f7084cc0209b9c"},
+ {file = "pywin32-310-cp38-cp38-win_amd64.whl", hash = "sha256:30f0a9b3138fb5e07eb4973b7077e1883f558e40c578c6925acc7a94c34eaa36"},
+ {file = "pywin32-310-cp39-cp39-win32.whl", hash = "sha256:851c8d927af0d879221e616ae1f66145253537bbdd321a77e8ef701b443a9a1a"},
+ {file = "pywin32-310-cp39-cp39-win_amd64.whl", hash = "sha256:96867217335559ac619f00ad70e513c0fcf84b8a3af9fc2bba3b59b97da70475"},
]
[[package]]
@@ -2447,6 +2612,8 @@ version = "2.0.15"
description = "Pseudo terminal support for Windows from Python."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "os_name == \"nt\""
files = [
{file = "pywinpty-2.0.15-cp310-cp310-win_amd64.whl", hash = "sha256:8e7f5de756a615a38b96cd86fa3cd65f901ce54ce147a3179c45907fa11b4c4e"},
{file = "pywinpty-2.0.15-cp311-cp311-win_amd64.whl", hash = "sha256:9a6bcec2df2707aaa9d08b86071970ee32c5026e10bcc3cc5f6f391d85baf7ca"},
@@ -2463,6 +2630,7 @@ version = "6.0.2"
description = "YAML parser and emitter for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "test"]
files = [
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
@@ -2521,120 +2689,105 @@ files = [
[[package]]
name = "pyzmq"
-version = "26.2.1"
+version = "26.4.0"
description = "Python bindings for 0MQ"
optional = false
-python-versions = ">=3.7"
-files = [
- {file = "pyzmq-26.2.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:f39d1227e8256d19899d953e6e19ed2ccb689102e6d85e024da5acf410f301eb"},
- {file = "pyzmq-26.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a23948554c692df95daed595fdd3b76b420a4939d7a8a28d6d7dea9711878641"},
- {file = "pyzmq-26.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95f5728b367a042df146cec4340d75359ec6237beebf4a8f5cf74657c65b9257"},
- {file = "pyzmq-26.2.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95f7b01b3f275504011cf4cf21c6b885c8d627ce0867a7e83af1382ebab7b3ff"},
- {file = "pyzmq-26.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a00370a2ef2159c310e662c7c0f2d030f437f35f478bb8b2f70abd07e26b24"},
- {file = "pyzmq-26.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8531ed35dfd1dd2af95f5d02afd6545e8650eedbf8c3d244a554cf47d8924459"},
- {file = "pyzmq-26.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cdb69710e462a38e6039cf17259d328f86383a06c20482cc154327968712273c"},
- {file = "pyzmq-26.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e7eeaef81530d0b74ad0d29eec9997f1c9230c2f27242b8d17e0ee67662c8f6e"},
- {file = "pyzmq-26.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:361edfa350e3be1f987e592e834594422338d7174364763b7d3de5b0995b16f3"},
- {file = "pyzmq-26.2.1-cp310-cp310-win32.whl", hash = "sha256:637536c07d2fb6a354988b2dd1d00d02eb5dd443f4bbee021ba30881af1c28aa"},
- {file = "pyzmq-26.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:45fad32448fd214fbe60030aa92f97e64a7140b624290834cc9b27b3a11f9473"},
- {file = "pyzmq-26.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:d9da0289d8201c8a29fd158aaa0dfe2f2e14a181fd45e2dc1fbf969a62c1d594"},
- {file = "pyzmq-26.2.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:c059883840e634a21c5b31d9b9a0e2b48f991b94d60a811092bc37992715146a"},
- {file = "pyzmq-26.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed038a921df836d2f538e509a59cb638df3e70ca0fcd70d0bf389dfcdf784d2a"},
- {file = "pyzmq-26.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9027a7fcf690f1a3635dc9e55e38a0d6602dbbc0548935d08d46d2e7ec91f454"},
- {file = "pyzmq-26.2.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d75fcb00a1537f8b0c0bb05322bc7e35966148ffc3e0362f0369e44a4a1de99"},
- {file = "pyzmq-26.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0019cc804ac667fb8c8eaecdb66e6d4a68acf2e155d5c7d6381a5645bd93ae4"},
- {file = "pyzmq-26.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f19dae58b616ac56b96f2e2290f2d18730a898a171f447f491cc059b073ca1fa"},
- {file = "pyzmq-26.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f5eeeb82feec1fc5cbafa5ee9022e87ffdb3a8c48afa035b356fcd20fc7f533f"},
- {file = "pyzmq-26.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:000760e374d6f9d1a3478a42ed0c98604de68c9e94507e5452951e598ebecfba"},
- {file = "pyzmq-26.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:817fcd3344d2a0b28622722b98500ae9c8bfee0f825b8450932ff19c0b15bebd"},
- {file = "pyzmq-26.2.1-cp311-cp311-win32.whl", hash = "sha256:88812b3b257f80444a986b3596e5ea5c4d4ed4276d2b85c153a6fbc5ca457ae7"},
- {file = "pyzmq-26.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:ef29630fde6022471d287c15c0a2484aba188adbfb978702624ba7a54ddfa6c1"},
- {file = "pyzmq-26.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:f32718ee37c07932cc336096dc7403525301fd626349b6eff8470fe0f996d8d7"},
- {file = "pyzmq-26.2.1-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:a6549ecb0041dafa55b5932dcbb6c68293e0bd5980b5b99f5ebb05f9a3b8a8f3"},
- {file = "pyzmq-26.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0250c94561f388db51fd0213cdccbd0b9ef50fd3c57ce1ac937bf3034d92d72e"},
- {file = "pyzmq-26.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36ee4297d9e4b34b5dc1dd7ab5d5ea2cbba8511517ef44104d2915a917a56dc8"},
- {file = "pyzmq-26.2.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2a9cb17fd83b7a3a3009901aca828feaf20aa2451a8a487b035455a86549c09"},
- {file = "pyzmq-26.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:786dd8a81b969c2081b31b17b326d3a499ddd1856e06d6d79ad41011a25148da"},
- {file = "pyzmq-26.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:2d88ba221a07fc2c5581565f1d0fe8038c15711ae79b80d9462e080a1ac30435"},
- {file = "pyzmq-26.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c84c1297ff9f1cd2440da4d57237cb74be21fdfe7d01a10810acba04e79371a"},
- {file = "pyzmq-26.2.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:46d4ebafc27081a7f73a0f151d0c38d4291656aa134344ec1f3d0199ebfbb6d4"},
- {file = "pyzmq-26.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:91e2bfb8e9a29f709d51b208dd5f441dc98eb412c8fe75c24ea464734ccdb48e"},
- {file = "pyzmq-26.2.1-cp312-cp312-win32.whl", hash = "sha256:4a98898fdce380c51cc3e38ebc9aa33ae1e078193f4dc641c047f88b8c690c9a"},
- {file = "pyzmq-26.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:a0741edbd0adfe5f30bba6c5223b78c131b5aa4a00a223d631e5ef36e26e6d13"},
- {file = "pyzmq-26.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:e5e33b1491555843ba98d5209439500556ef55b6ab635f3a01148545498355e5"},
- {file = "pyzmq-26.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:099b56ef464bc355b14381f13355542e452619abb4c1e57a534b15a106bf8e23"},
- {file = "pyzmq-26.2.1-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:651726f37fcbce9f8dd2a6dab0f024807929780621890a4dc0c75432636871be"},
- {file = "pyzmq-26.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57dd4d91b38fa4348e237a9388b4423b24ce9c1695bbd4ba5a3eada491e09399"},
- {file = "pyzmq-26.2.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d51a7bfe01a48e1064131f3416a5439872c533d756396be2b39e3977b41430f9"},
- {file = "pyzmq-26.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7154d228502e18f30f150b7ce94f0789d6b689f75261b623f0fdc1eec642aab"},
- {file = "pyzmq-26.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:f1f31661a80cc46aba381bed475a9135b213ba23ca7ff6797251af31510920ce"},
- {file = "pyzmq-26.2.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:290c96f479504439b6129a94cefd67a174b68ace8a8e3f551b2239a64cfa131a"},
- {file = "pyzmq-26.2.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f2c307fbe86e18ab3c885b7e01de942145f539165c3360e2af0f094dd440acd9"},
- {file = "pyzmq-26.2.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:b314268e716487bfb86fcd6f84ebbe3e5bec5fac75fdf42bc7d90fdb33f618ad"},
- {file = "pyzmq-26.2.1-cp313-cp313-win32.whl", hash = "sha256:edb550616f567cd5603b53bb52a5f842c0171b78852e6fc7e392b02c2a1504bb"},
- {file = "pyzmq-26.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:100a826a029c8ef3d77a1d4c97cbd6e867057b5806a7276f2bac1179f893d3bf"},
- {file = "pyzmq-26.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:6991ee6c43e0480deb1b45d0c7c2bac124a6540cba7db4c36345e8e092da47ce"},
- {file = "pyzmq-26.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:25e720dba5b3a3bb2ad0ad5d33440babd1b03438a7a5220511d0c8fa677e102e"},
- {file = "pyzmq-26.2.1-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:9ec6abfb701437142ce9544bd6a236addaf803a32628d2260eb3dbd9a60e2891"},
- {file = "pyzmq-26.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e1eb9d2bfdf5b4e21165b553a81b2c3bd5be06eeddcc4e08e9692156d21f1f6"},
- {file = "pyzmq-26.2.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90dc731d8e3e91bcd456aa7407d2eba7ac6f7860e89f3766baabb521f2c1de4a"},
- {file = "pyzmq-26.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6a93d684278ad865fc0b9e89fe33f6ea72d36da0e842143891278ff7fd89c3"},
- {file = "pyzmq-26.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:c1bb37849e2294d519117dd99b613c5177934e5c04a5bb05dd573fa42026567e"},
- {file = "pyzmq-26.2.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:632a09c6d8af17b678d84df442e9c3ad8e4949c109e48a72f805b22506c4afa7"},
- {file = "pyzmq-26.2.1-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:fc409c18884eaf9ddde516d53af4f2db64a8bc7d81b1a0c274b8aa4e929958e8"},
- {file = "pyzmq-26.2.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:17f88622b848805d3f6427ce1ad5a2aa3cf61f12a97e684dab2979802024d460"},
- {file = "pyzmq-26.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3ef584f13820d2629326fe20cc04069c21c5557d84c26e277cfa6235e523b10f"},
- {file = "pyzmq-26.2.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:160194d1034902937359c26ccfa4e276abffc94937e73add99d9471e9f555dd6"},
- {file = "pyzmq-26.2.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:574b285150afdbf0a0424dddf7ef9a0d183988eb8d22feacb7160f7515e032cb"},
- {file = "pyzmq-26.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44dba28c34ce527cf687156c81f82bf1e51f047838d5964f6840fd87dfecf9fe"},
- {file = "pyzmq-26.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9fbdb90b85c7624c304f72ec7854659a3bd901e1c0ffb2363163779181edeb68"},
- {file = "pyzmq-26.2.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a7ad34a2921e8f76716dc7205c9bf46a53817e22b9eec2e8a3e08ee4f4a72468"},
- {file = "pyzmq-26.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:866c12b7c90dd3a86983df7855c6f12f9407c8684db6aa3890fc8027462bda82"},
- {file = "pyzmq-26.2.1-cp37-cp37m-win32.whl", hash = "sha256:eeb37f65350d5c5870517f02f8bbb2ac0fbec7b416c0f4875219fef305a89a45"},
- {file = "pyzmq-26.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4eb3197f694dfb0ee6af29ef14a35f30ae94ff67c02076eef8125e2d98963cd0"},
- {file = "pyzmq-26.2.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:36d4e7307db7c847fe37413f333027d31c11d5e6b3bacbb5022661ac635942ba"},
- {file = "pyzmq-26.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1c6ae0e95d0a4b0cfe30f648a18e764352d5415279bdf34424decb33e79935b8"},
- {file = "pyzmq-26.2.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5b4fc44f5360784cc02392f14235049665caaf7c0fe0b04d313e763d3338e463"},
- {file = "pyzmq-26.2.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:51431f6b2750eb9b9d2b2952d3cc9b15d0215e1b8f37b7a3239744d9b487325d"},
- {file = "pyzmq-26.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdbc78ae2065042de48a65f1421b8af6b76a0386bb487b41955818c3c1ce7bed"},
- {file = "pyzmq-26.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d14f50d61a89b0925e4d97a0beba6053eb98c426c5815d949a43544f05a0c7ec"},
- {file = "pyzmq-26.2.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:004837cb958988c75d8042f5dac19a881f3d9b3b75b2f574055e22573745f841"},
- {file = "pyzmq-26.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0b2007f28ce1b8acebdf4812c1aab997a22e57d6a73b5f318b708ef9bcabbe95"},
- {file = "pyzmq-26.2.1-cp38-cp38-win32.whl", hash = "sha256:269c14904da971cb5f013100d1aaedb27c0a246728c341d5d61ddd03f463f2f3"},
- {file = "pyzmq-26.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:31fff709fef3b991cfe7189d2cfe0c413a1d0e82800a182cfa0c2e3668cd450f"},
- {file = "pyzmq-26.2.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:a4bffcadfd40660f26d1b3315a6029fd4f8f5bf31a74160b151f5c577b2dc81b"},
- {file = "pyzmq-26.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e76ad4729c2f1cf74b6eb1bdd05f6aba6175999340bd51e6caee49a435a13bf5"},
- {file = "pyzmq-26.2.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8b0f5bab40a16e708e78a0c6ee2425d27e1a5d8135c7a203b4e977cee37eb4aa"},
- {file = "pyzmq-26.2.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e8e47050412f0ad3a9b2287779758073cbf10e460d9f345002d4779e43bb0136"},
- {file = "pyzmq-26.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f18ce33f422d119b13c1363ed4cce245b342b2c5cbbb76753eabf6aa6f69c7d"},
- {file = "pyzmq-26.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ceb0d78b7ef106708a7e2c2914afe68efffc0051dc6a731b0dbacd8b4aee6d68"},
- {file = "pyzmq-26.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ebdd96bd637fd426d60e86a29ec14b8c1ab64b8d972f6a020baf08a30d1cf46"},
- {file = "pyzmq-26.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:03719e424150c6395b9513f53a5faadcc1ce4b92abdf68987f55900462ac7eec"},
- {file = "pyzmq-26.2.1-cp39-cp39-win32.whl", hash = "sha256:ef5479fac31df4b304e96400fc67ff08231873ee3537544aa08c30f9d22fce38"},
- {file = "pyzmq-26.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:f92a002462154c176dac63a8f1f6582ab56eb394ef4914d65a9417f5d9fde218"},
- {file = "pyzmq-26.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:1fd4b3efc6f62199886440d5e27dd3ccbcb98dfddf330e7396f1ff421bfbb3c2"},
- {file = "pyzmq-26.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:380816d298aed32b1a97b4973a4865ef3be402a2e760204509b52b6de79d755d"},
- {file = "pyzmq-26.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97cbb368fd0debdbeb6ba5966aa28e9a1ae3396c7386d15569a6ca4be4572b99"},
- {file = "pyzmq-26.2.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf7b5942c6b0dafcc2823ddd9154f419147e24f8df5b41ca8ea40a6db90615c"},
- {file = "pyzmq-26.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fe6e28a8856aea808715f7a4fc11f682b9d29cac5d6262dd8fe4f98edc12d53"},
- {file = "pyzmq-26.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bd8fdee945b877aa3bffc6a5a8816deb048dab0544f9df3731ecd0e54d8c84c9"},
- {file = "pyzmq-26.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ee7152f32c88e0e1b5b17beb9f0e2b14454235795ef68c0c120b6d3d23d12833"},
- {file = "pyzmq-26.2.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:baa1da72aecf6a490b51fba7a51f1ce298a1e0e86d0daef8265c8f8f9848eb77"},
- {file = "pyzmq-26.2.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:49135bb327fca159262d8fd14aa1f4a919fe071b04ed08db4c7c37d2f0647162"},
- {file = "pyzmq-26.2.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8bacc1a10c150d58e8a9ee2b2037a70f8d903107e0f0b6e079bf494f2d09c091"},
- {file = "pyzmq-26.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:09dac387ce62d69bec3f06d51610ca1d660e7849eb45f68e38e7f5cf1f49cbcb"},
- {file = "pyzmq-26.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:70b3a46ecd9296e725ccafc17d732bfc3cdab850b54bd913f843a0a54dfb2c04"},
- {file = "pyzmq-26.2.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:59660e15c797a3b7a571c39f8e0b62a1f385f98ae277dfe95ca7eaf05b5a0f12"},
- {file = "pyzmq-26.2.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0f50db737d688e96ad2a083ad2b453e22865e7e19c7f17d17df416e91ddf67eb"},
- {file = "pyzmq-26.2.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a003200b6cd64e89b5725ff7e284a93ab24fd54bbac8b4fa46b1ed57be693c27"},
- {file = "pyzmq-26.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f9ba5def063243793dec6603ad1392f735255cbc7202a3a484c14f99ec290705"},
- {file = "pyzmq-26.2.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1238c2448c58b9c8d6565579393148414a42488a5f916b3f322742e561f6ae0d"},
- {file = "pyzmq-26.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eddb3784aed95d07065bcf94d07e8c04024fdb6b2386f08c197dfe6b3528fda"},
- {file = "pyzmq-26.2.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0f19c2097fffb1d5b07893d75c9ee693e9cbc809235cf3f2267f0ef6b015f24"},
- {file = "pyzmq-26.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0995fd3530f2e89d6b69a2202e340bbada3191014352af978fa795cb7a446331"},
- {file = "pyzmq-26.2.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7c6160fe513654e65665332740f63de29ce0d165e053c0c14a161fa60dd0da01"},
- {file = "pyzmq-26.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8ec8e3aea6146b761d6c57fcf8f81fcb19f187afecc19bf1701a48db9617a217"},
- {file = "pyzmq-26.2.1.tar.gz", hash = "sha256:17d72a74e5e9ff3829deb72897a175333d3ef5b5413948cae3cf7ebf0b02ecca"},
+python-versions = ">=3.8"
+groups = ["dev"]
+files = [
+ {file = "pyzmq-26.4.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:0329bdf83e170ac133f44a233fc651f6ed66ef8e66693b5af7d54f45d1ef5918"},
+ {file = "pyzmq-26.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:398a825d2dea96227cf6460ce0a174cf7657d6f6827807d4d1ae9d0f9ae64315"},
+ {file = "pyzmq-26.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d52d62edc96787f5c1dfa6c6ccff9b581cfae5a70d94ec4c8da157656c73b5b"},
+ {file = "pyzmq-26.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1410c3a3705db68d11eb2424d75894d41cff2f64d948ffe245dd97a9debfebf4"},
+ {file = "pyzmq-26.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7dacb06a9c83b007cc01e8e5277f94c95c453c5851aac5e83efe93e72226353f"},
+ {file = "pyzmq-26.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6bab961c8c9b3a4dc94d26e9b2cdf84de9918931d01d6ff38c721a83ab3c0ef5"},
+ {file = "pyzmq-26.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7a5c09413b924d96af2aa8b57e76b9b0058284d60e2fc3730ce0f979031d162a"},
+ {file = "pyzmq-26.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d489ac234d38e57f458fdbd12a996bfe990ac028feaf6f3c1e81ff766513d3b"},
+ {file = "pyzmq-26.4.0-cp310-cp310-win32.whl", hash = "sha256:dea1c8db78fb1b4b7dc9f8e213d0af3fc8ecd2c51a1d5a3ca1cde1bda034a980"},
+ {file = "pyzmq-26.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:fa59e1f5a224b5e04dc6c101d7186058efa68288c2d714aa12d27603ae93318b"},
+ {file = "pyzmq-26.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:a651fe2f447672f4a815e22e74630b6b1ec3a1ab670c95e5e5e28dcd4e69bbb5"},
+ {file = "pyzmq-26.4.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:bfcf82644c9b45ddd7cd2a041f3ff8dce4a0904429b74d73a439e8cab1bd9e54"},
+ {file = "pyzmq-26.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9bcae3979b2654d5289d3490742378b2f3ce804b0b5fd42036074e2bf35b030"},
+ {file = "pyzmq-26.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccdff8ac4246b6fb60dcf3982dfaeeff5dd04f36051fe0632748fc0aa0679c01"},
+ {file = "pyzmq-26.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4550af385b442dc2d55ab7717837812799d3674cb12f9a3aa897611839c18e9e"},
+ {file = "pyzmq-26.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f7ffe9db1187a253fca95191854b3fda24696f086e8789d1d449308a34b88"},
+ {file = "pyzmq-26.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3709c9ff7ba61589b7372923fd82b99a81932b592a5c7f1a24147c91da9a68d6"},
+ {file = "pyzmq-26.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f8f3c30fb2d26ae5ce36b59768ba60fb72507ea9efc72f8f69fa088450cff1df"},
+ {file = "pyzmq-26.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:382a4a48c8080e273427fc692037e3f7d2851959ffe40864f2db32646eeb3cef"},
+ {file = "pyzmq-26.4.0-cp311-cp311-win32.whl", hash = "sha256:d56aad0517d4c09e3b4f15adebba8f6372c5102c27742a5bdbfc74a7dceb8fca"},
+ {file = "pyzmq-26.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:963977ac8baed7058c1e126014f3fe58b3773f45c78cce7af5c26c09b6823896"},
+ {file = "pyzmq-26.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0c8e8cadc81e44cc5088fcd53b9b3b4ce9344815f6c4a03aec653509296fae3"},
+ {file = "pyzmq-26.4.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:5227cb8da4b6f68acfd48d20c588197fd67745c278827d5238c707daf579227b"},
+ {file = "pyzmq-26.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1c07a7fa7f7ba86554a2b1bef198c9fed570c08ee062fd2fd6a4dcacd45f905"},
+ {file = "pyzmq-26.4.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae775fa83f52f52de73183f7ef5395186f7105d5ed65b1ae65ba27cb1260de2b"},
+ {file = "pyzmq-26.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66c760d0226ebd52f1e6b644a9e839b5db1e107a23f2fcd46ec0569a4fdd4e63"},
+ {file = "pyzmq-26.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ef8c6ecc1d520debc147173eaa3765d53f06cd8dbe7bd377064cdbc53ab456f5"},
+ {file = "pyzmq-26.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3150ef4084e163dec29ae667b10d96aad309b668fac6810c9e8c27cf543d6e0b"},
+ {file = "pyzmq-26.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4448c9e55bf8329fa1dcedd32f661bf611214fa70c8e02fee4347bc589d39a84"},
+ {file = "pyzmq-26.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e07dde3647afb084d985310d067a3efa6efad0621ee10826f2cb2f9a31b89d2f"},
+ {file = "pyzmq-26.4.0-cp312-cp312-win32.whl", hash = "sha256:ba034a32ecf9af72adfa5ee383ad0fd4f4e38cdb62b13624278ef768fe5b5b44"},
+ {file = "pyzmq-26.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:056a97aab4064f526ecb32f4343917a4022a5d9efb6b9df990ff72e1879e40be"},
+ {file = "pyzmq-26.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f23c750e485ce1eb639dbd576d27d168595908aa2d60b149e2d9e34c9df40e0"},
+ {file = "pyzmq-26.4.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:c43fac689880f5174d6fc864857d1247fe5cfa22b09ed058a344ca92bf5301e3"},
+ {file = "pyzmq-26.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:902aca7eba477657c5fb81c808318460328758e8367ecdd1964b6330c73cae43"},
+ {file = "pyzmq-26.4.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e48a830bfd152fe17fbdeaf99ac5271aa4122521bf0d275b6b24e52ef35eb6"},
+ {file = "pyzmq-26.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31be2b6de98c824c06f5574331f805707c667dc8f60cb18580b7de078479891e"},
+ {file = "pyzmq-26.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6332452034be001bbf3206ac59c0d2a7713de5f25bb38b06519fc6967b7cf771"},
+ {file = "pyzmq-26.4.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:da8c0f5dd352136853e6a09b1b986ee5278dfddfebd30515e16eae425c872b30"},
+ {file = "pyzmq-26.4.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f4ccc1a0a2c9806dda2a2dd118a3b7b681e448f3bb354056cad44a65169f6d86"},
+ {file = "pyzmq-26.4.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1c0b5fceadbab461578daf8d1dcc918ebe7ddd2952f748cf30c7cf2de5d51101"},
+ {file = "pyzmq-26.4.0-cp313-cp313-win32.whl", hash = "sha256:28e2b0ff5ba4b3dd11062d905682bad33385cfa3cc03e81abd7f0822263e6637"},
+ {file = "pyzmq-26.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b"},
+ {file = "pyzmq-26.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:1edb0385c7f025045d6e0f759d4d3afe43c17a3d898914ec6582e6f464203c08"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:93a29e882b2ba1db86ba5dd5e88e18e0ac6b627026c5cfbec9983422011b82d4"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45684f276f57110bb89e4300c00f1233ca631f08f5f42528a5c408a79efc4a"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f72073e75260cb301aad4258ad6150fa7f57c719b3f498cb91e31df16784d89b"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be37e24b13026cfedd233bcbbccd8c0bcd2fdd186216094d095f60076201538d"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:237b283044934d26f1eeff4075f751b05d2f3ed42a257fc44386d00df6a270cf"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:b30f862f6768b17040929a68432c8a8be77780317f45a353cb17e423127d250c"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:c80fcd3504232f13617c6ab501124d373e4895424e65de8b72042333316f64a8"},
+ {file = "pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:26a2a7451606b87f67cdeca2c2789d86f605da08b4bd616b1a9981605ca3a364"},
+ {file = "pyzmq-26.4.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:831cc53bf6068d46d942af52fa8b0b9d128fb39bcf1f80d468dc9a3ae1da5bfb"},
+ {file = "pyzmq-26.4.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:51d18be6193c25bd229524cfac21e39887c8d5e0217b1857998dfbef57c070a4"},
+ {file = "pyzmq-26.4.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:445c97854204119ae2232503585ebb4fa7517142f71092cb129e5ee547957a1f"},
+ {file = "pyzmq-26.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:807b8f4ad3e6084412c0f3df0613269f552110fa6fb91743e3e306223dbf11a6"},
+ {file = "pyzmq-26.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c01d109dd675ac47fa15c0a79d256878d898f90bc10589f808b62d021d2e653c"},
+ {file = "pyzmq-26.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0a294026e28679a8dd64c922e59411cb586dad307661b4d8a5c49e7bbca37621"},
+ {file = "pyzmq-26.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:22c8dd677274af8dfb1efd05006d6f68fb2f054b17066e308ae20cb3f61028cf"},
+ {file = "pyzmq-26.4.0-cp38-cp38-win32.whl", hash = "sha256:14fc678b696bc42c14e2d7f86ac4e97889d5e6b94d366ebcb637a768d2ad01af"},
+ {file = "pyzmq-26.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1ef0a536662bbbdc8525f7e2ef19e74123ec9c4578e0582ecd41aedc414a169"},
+ {file = "pyzmq-26.4.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:a88643de8abd000ce99ca72056a1a2ae15881ee365ecb24dd1d9111e43d57842"},
+ {file = "pyzmq-26.4.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a744ce209ecb557406fb928f3c8c55ce79b16c3eeb682da38ef5059a9af0848"},
+ {file = "pyzmq-26.4.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9434540f333332224ecb02ee6278b6c6f11ea1266b48526e73c903119b2f420f"},
+ {file = "pyzmq-26.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6c6f0a23e55cd38d27d4c89add963294ea091ebcb104d7fdab0f093bc5abb1c"},
+ {file = "pyzmq-26.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6145df55dc2309f6ef72d70576dcd5aabb0fd373311613fe85a5e547c722b780"},
+ {file = "pyzmq-26.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2ea81823840ef8c56e5d2f9918e4d571236294fea4d1842b302aebffb9e40997"},
+ {file = "pyzmq-26.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc2abc385dc37835445abe206524fbc0c9e3fce87631dfaa90918a1ba8f425eb"},
+ {file = "pyzmq-26.4.0-cp39-cp39-win32.whl", hash = "sha256:41a2508fe7bed4c76b4cf55aacfb8733926f59d440d9ae2b81ee8220633b4d12"},
+ {file = "pyzmq-26.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:d4000e8255d6cbce38982e5622ebb90823f3409b7ffe8aeae4337ef7d6d2612a"},
+ {file = "pyzmq-26.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f6919d9c120488246bdc2a2f96662fa80d67b35bd6d66218f457e722b3ff64"},
+ {file = "pyzmq-26.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:98d948288ce893a2edc5ec3c438fe8de2daa5bbbd6e2e865ec5f966e237084ba"},
+ {file = "pyzmq-26.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9f34f5c9e0203ece706a1003f1492a56c06c0632d86cb77bcfe77b56aacf27b"},
+ {file = "pyzmq-26.4.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80c9b48aef586ff8b698359ce22f9508937c799cc1d2c9c2f7c95996f2300c94"},
+ {file = "pyzmq-26.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3f2a5b74009fd50b53b26f65daff23e9853e79aa86e0aa08a53a7628d92d44a"},
+ {file = "pyzmq-26.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:61c5f93d7622d84cb3092d7f6398ffc77654c346545313a3737e266fc11a3beb"},
+ {file = "pyzmq-26.4.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4478b14cb54a805088299c25a79f27eaf530564a7a4f72bf432a040042b554eb"},
+ {file = "pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a28ac29c60e4ba84b5f58605ace8ad495414a724fe7aceb7cf06cd0598d04e1"},
+ {file = "pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43b03c1ceea27c6520124f4fb2ba9c647409b9abdf9a62388117148a90419494"},
+ {file = "pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7731abd23a782851426d4e37deb2057bf9410848a4459b5ede4fe89342e687a9"},
+ {file = "pyzmq-26.4.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a222ad02fbe80166b0526c038776e8042cd4e5f0dec1489a006a1df47e9040e0"},
+ {file = "pyzmq-26.4.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:91c3ffaea475ec8bb1a32d77ebc441dcdd13cd3c4c284a6672b92a0f5ade1917"},
+ {file = "pyzmq-26.4.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d9a78a52668bf5c9e7b0da36aa5760a9fc3680144e1445d68e98df78a25082ed"},
+ {file = "pyzmq-26.4.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b70cab356ff8c860118b89dc86cd910c73ce2127eb986dada4fbac399ef644cf"},
+ {file = "pyzmq-26.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acae207d4387780838192326b32d373bb286da0b299e733860e96f80728eb0af"},
+ {file = "pyzmq-26.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f928eafd15794aa4be75463d537348b35503c1e014c5b663f206504ec1a90fe4"},
+ {file = "pyzmq-26.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:552b0d2e39987733e1e9e948a0ced6ff75e0ea39ab1a1db2fc36eb60fd8760db"},
+ {file = "pyzmq-26.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd670a8aa843f2ee637039bbd412e0d7294a5e588e1ecc9ad98b0cdc050259a4"},
+ {file = "pyzmq-26.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d367b7b775a0e1e54a59a2ba3ed4d5e0a31566af97cc9154e34262777dab95ed"},
+ {file = "pyzmq-26.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112af16c406e4a93df2caef49f884f4c2bb2b558b0b5577ef0b2465d15c1abc"},
+ {file = "pyzmq-26.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c76c298683f82669cab0b6da59071f55238c039738297c69f187a542c6d40099"},
+ {file = "pyzmq-26.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:49b6ca2e625b46f499fb081aaf7819a177f41eeb555acb05758aa97f4f95d147"},
+ {file = "pyzmq-26.4.0.tar.gz", hash = "sha256:4bd13f85f80962f91a651a7356fe0472791a5f7a92f227822b5acf44795c626d"},
]
[package.dependencies]
@@ -2646,6 +2799,7 @@ version = "0.36.2"
description = "JSON Referencing + Python"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"},
{file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"},
@@ -2662,6 +2816,7 @@ version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "test"]
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@@ -2683,6 +2838,7 @@ version = "1.0.0"
description = "A utility belt for advanced users of python-requests"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+groups = ["main", "test"]
files = [
{file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"},
{file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"},
@@ -2697,6 +2853,7 @@ version = "0.1.4"
description = "A pure python RFC3339 validator"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+groups = ["dev"]
files = [
{file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"},
{file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"},
@@ -2711,6 +2868,7 @@ version = "0.1.1"
description = "Pure python rfc3986 validator"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+groups = ["dev"]
files = [
{file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"},
{file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"},
@@ -2718,114 +2876,126 @@ files = [
[[package]]
name = "rpds-py"
-version = "0.22.3"
+version = "0.24.0"
description = "Python bindings to Rust's persistent data structures (rpds)"
optional = false
python-versions = ">=3.9"
-files = [
- {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"},
- {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"},
- {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"},
- {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"},
- {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"},
- {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"},
- {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"},
- {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"},
- {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"},
- {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"},
- {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"},
- {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"},
- {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"},
- {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"},
- {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"},
- {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"},
- {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"},
- {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"},
- {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"},
- {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"},
- {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"},
- {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"},
- {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"},
- {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"},
- {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"},
- {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"},
- {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"},
- {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"},
- {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"},
- {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"},
- {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"},
- {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"},
- {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"},
- {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"},
- {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"},
- {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"},
- {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"},
- {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"},
- {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"},
- {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"},
- {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"},
- {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"},
- {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"},
- {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"},
- {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"},
- {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"},
- {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"},
- {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"},
- {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"},
- {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"},
- {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"},
- {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"},
- {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"},
- {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"},
- {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"},
- {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"},
- {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"},
- {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"},
- {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"},
- {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"},
- {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"},
- {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"},
- {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"},
- {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"},
- {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"},
- {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"},
- {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"},
- {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"},
- {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"},
- {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"},
- {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"},
- {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"},
- {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"},
- {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"},
- {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"},
- {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"},
- {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"},
- {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"},
- {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"},
- {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"},
- {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"},
+groups = ["dev"]
+files = [
+ {file = "rpds_py-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724"},
+ {file = "rpds_py-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b"},
+ {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727"},
+ {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964"},
+ {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5"},
+ {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664"},
+ {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc"},
+ {file = "rpds_py-0.24.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0"},
+ {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f"},
+ {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f"},
+ {file = "rpds_py-0.24.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875"},
+ {file = "rpds_py-0.24.0-cp310-cp310-win32.whl", hash = "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07"},
+ {file = "rpds_py-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052"},
+ {file = "rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef"},
+ {file = "rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97"},
+ {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e"},
+ {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d"},
+ {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586"},
+ {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4"},
+ {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae"},
+ {file = "rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc"},
+ {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c"},
+ {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c"},
+ {file = "rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718"},
+ {file = "rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a"},
+ {file = "rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6"},
+ {file = "rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205"},
+ {file = "rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7"},
+ {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9"},
+ {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e"},
+ {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda"},
+ {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e"},
+ {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029"},
+ {file = "rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9"},
+ {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7"},
+ {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91"},
+ {file = "rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56"},
+ {file = "rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30"},
+ {file = "rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034"},
+ {file = "rpds_py-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c"},
+ {file = "rpds_py-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c"},
+ {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240"},
+ {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8"},
+ {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8"},
+ {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b"},
+ {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d"},
+ {file = "rpds_py-0.24.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7"},
+ {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad"},
+ {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120"},
+ {file = "rpds_py-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9"},
+ {file = "rpds_py-0.24.0-cp313-cp313-win32.whl", hash = "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143"},
+ {file = "rpds_py-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-win32.whl", hash = "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba"},
+ {file = "rpds_py-0.24.0-cp313-cp313t-win_amd64.whl", hash = "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350"},
+ {file = "rpds_py-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d"},
+ {file = "rpds_py-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e"},
+ {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65"},
+ {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b"},
+ {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791"},
+ {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9"},
+ {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c"},
+ {file = "rpds_py-0.24.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58"},
+ {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124"},
+ {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149"},
+ {file = "rpds_py-0.24.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45"},
+ {file = "rpds_py-0.24.0-cp39-cp39-win32.whl", hash = "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103"},
+ {file = "rpds_py-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc"},
+ {file = "rpds_py-0.24.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25"},
+ {file = "rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796"},
+ {file = "rpds_py-0.24.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f"},
+ {file = "rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e"},
]
[[package]]
@@ -2834,6 +3004,7 @@ version = "0.1.15"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
+groups = ["lint"]
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"},
@@ -2860,15 +3031,16 @@ version = "1.8.3"
description = "Send file to trash natively under Mac OS X, Windows and Linux"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+groups = ["dev"]
files = [
{file = "Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9"},
{file = "Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf"},
]
[package.extras]
-nativelib = ["pyobjc-framework-Cocoa", "pywin32"]
-objc = ["pyobjc-framework-Cocoa"]
-win32 = ["pywin32"]
+nativelib = ["pyobjc-framework-Cocoa ; sys_platform == \"darwin\"", "pywin32 ; sys_platform == \"win32\""]
+objc = ["pyobjc-framework-Cocoa ; sys_platform == \"darwin\""]
+win32 = ["pywin32 ; sys_platform == \"win32\""]
[[package]]
name = "six"
@@ -2876,6 +3048,7 @@ version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["dev"]
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
@@ -2887,6 +3060,7 @@ version = "1.3.1"
description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev", "test"]
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@@ -2898,6 +3072,7 @@ version = "2.6"
description = "A modern CSS selector implementation for Beautiful Soup."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"},
{file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"},
@@ -2905,80 +3080,81 @@ files = [
[[package]]
name = "sqlalchemy"
-version = "2.0.37"
+version = "2.0.40"
description = "Database Abstraction Library"
optional = false
python-versions = ">=3.7"
-files = [
- {file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da36c3b0e891808a7542c5c89f224520b9a16c7f5e4d6a1156955605e54aef0e"},
- {file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e7402ff96e2b073a98ef6d6142796426d705addd27b9d26c3b32dbaa06d7d069"},
- {file = "SQLAlchemy-2.0.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f5d254a22394847245f411a2956976401e84da4288aa70cbcd5190744062c1"},
- {file = "SQLAlchemy-2.0.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41296bbcaa55ef5fdd32389a35c710133b097f7b2609d8218c0eabded43a1d84"},
- {file = "SQLAlchemy-2.0.37-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bedee60385c1c0411378cbd4dc486362f5ee88deceea50002772912d798bb00f"},
- {file = "SQLAlchemy-2.0.37-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6c67415258f9f3c69867ec02fea1bf6508153709ecbd731a982442a590f2b7e4"},
- {file = "SQLAlchemy-2.0.37-cp310-cp310-win32.whl", hash = "sha256:650dcb70739957a492ad8acff65d099a9586b9b8920e3507ca61ec3ce650bb72"},
- {file = "SQLAlchemy-2.0.37-cp310-cp310-win_amd64.whl", hash = "sha256:93d1543cd8359040c02b6614421c8e10cd7a788c40047dbc507ed46c29ae5636"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:78361be6dc9073ed17ab380985d1e45e48a642313ab68ab6afa2457354ff692c"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b661b49d0cb0ab311a189b31e25576b7ac3e20783beb1e1817d72d9d02508bf5"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d57bafbab289e147d064ffbd5cca2d7b1394b63417c0636cea1f2e93d16eb9e8"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fa2c0913f02341d25fb858e4fb2031e6b0813494cca1ba07d417674128ce11b"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9df21b8d9e5c136ea6cde1c50d2b1c29a2b5ff2b1d610165c23ff250e0704087"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db18ff6b8c0f1917f8b20f8eca35c28bbccb9f83afa94743e03d40203ed83de9"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-win32.whl", hash = "sha256:46954173612617a99a64aee103bcd3f078901b9a8dcfc6ae80cbf34ba23df989"},
- {file = "SQLAlchemy-2.0.37-cp311-cp311-win_amd64.whl", hash = "sha256:7b7e772dc4bc507fdec4ee20182f15bd60d2a84f1e087a8accf5b5b7a0dcf2ba"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2952748ecd67ed3b56773c185e85fc084f6bdcdec10e5032a7c25a6bc7d682ef"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3151822aa1db0eb5afd65ccfafebe0ef5cda3a7701a279c8d0bf17781a793bb4"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaa8039b6d20137a4e02603aba37d12cd2dde7887500b8855356682fc33933f4"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cdba1f73b64530c47b27118b7053b8447e6d6f3c8104e3ac59f3d40c33aa9fd"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1b2690456528a87234a75d1a1644cdb330a6926f455403c8e4f6cad6921f9098"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf5ae8a9dcf657fd72144a7fd01f243236ea39e7344e579a121c4205aedf07bb"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-win32.whl", hash = "sha256:ea308cec940905ba008291d93619d92edaf83232ec85fbd514dcb329f3192761"},
- {file = "SQLAlchemy-2.0.37-cp312-cp312-win_amd64.whl", hash = "sha256:635d8a21577341dfe4f7fa59ec394b346da12420b86624a69e466d446de16aff"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8c4096727193762e72ce9437e2a86a110cf081241919ce3fab8e89c02f6b6658"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e4fb5ac86d8fe8151966814f6720996430462e633d225497566b3996966b9bdb"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e56a139bfe136a22c438478a86f8204c1eb5eed36f4e15c4224e4b9db01cb3e4"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f95fc8e3f34b5f6b3effb49d10ac97c569ec8e32f985612d9b25dd12d0d2e94"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c505edd429abdfe3643fa3b2e83efb3445a34a9dc49d5f692dd087be966020e0"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:12b0f1ec623cccf058cf21cb544f0e74656618165b083d78145cafde156ea7b6"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-win32.whl", hash = "sha256:293f9ade06b2e68dd03cfb14d49202fac47b7bb94bffcff174568c951fbc7af2"},
- {file = "SQLAlchemy-2.0.37-cp313-cp313-win_amd64.whl", hash = "sha256:d70f53a0646cc418ca4853da57cf3ddddbccb8c98406791f24426f2dd77fd0e2"},
- {file = "SQLAlchemy-2.0.37-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:44f569d0b1eb82301b92b72085583277316e7367e038d97c3a1a899d9a05e342"},
- {file = "SQLAlchemy-2.0.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2eae3423e538c10d93ae3e87788c6a84658c3ed6db62e6a61bb9495b0ad16bb"},
- {file = "SQLAlchemy-2.0.37-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfff7be361048244c3aa0f60b5e63221c5e0f0e509f4e47b8910e22b57d10ae7"},
- {file = "SQLAlchemy-2.0.37-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:5bc3339db84c5fb9130ac0e2f20347ee77b5dd2596ba327ce0d399752f4fce39"},
- {file = "SQLAlchemy-2.0.37-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:84b9f23b0fa98a6a4b99d73989350a94e4a4ec476b9a7dfe9b79ba5939f5e80b"},
- {file = "SQLAlchemy-2.0.37-cp37-cp37m-win32.whl", hash = "sha256:51bc9cfef83e0ac84f86bf2b10eaccb27c5a3e66a1212bef676f5bee6ef33ebb"},
- {file = "SQLAlchemy-2.0.37-cp37-cp37m-win_amd64.whl", hash = "sha256:8e47f1af09444f87c67b4f1bb6231e12ba6d4d9f03050d7fc88df6d075231a49"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6b788f14c5bb91db7f468dcf76f8b64423660a05e57fe277d3f4fad7b9dcb7ce"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521ef85c04c33009166777c77e76c8a676e2d8528dc83a57836b63ca9c69dcd1"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75311559f5c9881a9808eadbeb20ed8d8ba3f7225bef3afed2000c2a9f4d49b9"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cce918ada64c956b62ca2c2af59b125767097ec1dca89650a6221e887521bfd7"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9d087663b7e1feabea8c578d6887d59bb00388158e8bff3a76be11aa3f748ca2"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cf95a60b36997dad99692314c4713f141b61c5b0b4cc5c3426faad570b31ca01"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-win32.whl", hash = "sha256:d75ead7dd4d255068ea0f21492ee67937bd7c90964c8f3c2bea83c7b7f81b95f"},
- {file = "SQLAlchemy-2.0.37-cp38-cp38-win_amd64.whl", hash = "sha256:74bbd1d0a9bacf34266a7907d43260c8d65d31d691bb2356f41b17c2dca5b1d0"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:648ec5acf95ad59255452ef759054f2176849662af4521db6cb245263ae4aa33"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:35bd2df269de082065d4b23ae08502a47255832cc3f17619a5cea92ce478b02b"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f581d365af9373a738c49e0c51e8b18e08d8a6b1b15cc556773bcd8a192fa8b"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82df02816c14f8dc9f4d74aea4cb84a92f4b0620235daa76dde002409a3fbb5a"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94b564e38b344d3e67d2e224f0aec6ba09a77e4582ced41e7bfd0f757d926ec9"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:955a2a765aa1bd81aafa69ffda179d4fe3e2a3ad462a736ae5b6f387f78bfeb8"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-win32.whl", hash = "sha256:03f0528c53ca0b67094c4764523c1451ea15959bbf0a8a8a3096900014db0278"},
- {file = "SQLAlchemy-2.0.37-cp39-cp39-win_amd64.whl", hash = "sha256:4b12885dc85a2ab2b7d00995bac6d967bffa8594123b02ed21e8eb2205a7584b"},
- {file = "SQLAlchemy-2.0.37-py3-none-any.whl", hash = "sha256:a8998bf9f8658bd3839cbc44ddbe982955641863da0c1efe5b00c1ab4f5c16b1"},
- {file = "sqlalchemy-2.0.37.tar.gz", hash = "sha256:12b28d99a9c14eaf4055810df1001557176716de0167b91026e648e65229bffb"},
-]
-
-[package.dependencies]
-greenlet = {version = "!=0.4.17", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
+groups = ["main"]
+files = [
+ {file = "SQLAlchemy-2.0.40-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ae9597cab738e7cc823f04a704fb754a9249f0b6695a6aeb63b74055cd417a96"},
+ {file = "SQLAlchemy-2.0.40-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37a5c21ab099a83d669ebb251fddf8f5cee4d75ea40a5a1653d9c43d60e20867"},
+ {file = "SQLAlchemy-2.0.40-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bece9527f5a98466d67fb5d34dc560c4da964240d8b09024bb21c1246545e04e"},
+ {file = "SQLAlchemy-2.0.40-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:8bb131ffd2165fae48162c7bbd0d97c84ab961deea9b8bab16366543deeab625"},
+ {file = "SQLAlchemy-2.0.40-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:9408fd453d5f8990405cc9def9af46bfbe3183e6110401b407c2d073c3388f47"},
+ {file = "SQLAlchemy-2.0.40-cp37-cp37m-win32.whl", hash = "sha256:00a494ea6f42a44c326477b5bee4e0fc75f6a80c01570a32b57e89cf0fbef85a"},
+ {file = "SQLAlchemy-2.0.40-cp37-cp37m-win_amd64.whl", hash = "sha256:c7b927155112ac858357ccf9d255dd8c044fd9ad2dc6ce4c4149527c901fa4c3"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f1ea21bef99c703f44444ad29c2c1b6bd55d202750b6de8e06a955380f4725d7"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:afe63b208153f3a7a2d1a5b9df452b0673082588933e54e7c8aac457cf35e758"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8aae085ea549a1eddbc9298b113cffb75e514eadbb542133dd2b99b5fb3b6af"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ea9181284754d37db15156eb7be09c86e16e50fbe77610e9e7bee09291771a1"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5434223b795be5c5ef8244e5ac98056e290d3a99bdcc539b916e282b160dda00"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15d08d5ef1b779af6a0909b97be6c1fd4298057504eb6461be88bd1696cb438e"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-win32.whl", hash = "sha256:cd2f75598ae70bcfca9117d9e51a3b06fe29edd972fdd7fd57cc97b4dbf3b08a"},
+ {file = "sqlalchemy-2.0.40-cp310-cp310-win_amd64.whl", hash = "sha256:2cbafc8d39ff1abdfdda96435f38fab141892dc759a2165947d1a8fffa7ef596"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f6bacab7514de6146a1976bc56e1545bee247242fab030b89e5f70336fc0003e"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5654d1ac34e922b6c5711631f2da497d3a7bffd6f9f87ac23b35feea56098011"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35904d63412db21088739510216e9349e335f142ce4a04b69e2528020ee19ed4"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7a80ed86d6aaacb8160a1caef6680d4ddd03c944d985aecee940d168c411d1"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:519624685a51525ddaa7d8ba8265a1540442a2ec71476f0e75241eb8263d6f51"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2ee5f9999a5b0e9689bed96e60ee53c3384f1a05c2dd8068cc2e8361b0df5b7a"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-win32.whl", hash = "sha256:c0cae71e20e3c02c52f6b9e9722bca70e4a90a466d59477822739dc31ac18b4b"},
+ {file = "sqlalchemy-2.0.40-cp311-cp311-win_amd64.whl", hash = "sha256:574aea2c54d8f1dd1699449f332c7d9b71c339e04ae50163a3eb5ce4c4325ee4"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9d3b31d0a1c44b74d3ae27a3de422dfccd2b8f0b75e51ecb2faa2bf65ab1ba0d"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:37f7a0f506cf78c80450ed1e816978643d3969f99c4ac6b01104a6fe95c5490a"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bb933a650323e476a2e4fbef8997a10d0003d4da996aad3fd7873e962fdde4d"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6959738971b4745eea16f818a2cd086fb35081383b078272c35ece2b07012716"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:110179728e442dae85dd39591beb74072ae4ad55a44eda2acc6ec98ead80d5f2"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8040680eaacdce4d635f12c55c714f3d4c7f57da2bc47a01229d115bd319191"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-win32.whl", hash = "sha256:650490653b110905c10adac69408380688cefc1f536a137d0d69aca1069dc1d1"},
+ {file = "sqlalchemy-2.0.40-cp312-cp312-win_amd64.whl", hash = "sha256:2be94d75ee06548d2fc591a3513422b873490efb124048f50556369a834853b0"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:915866fd50dd868fdcc18d61d8258db1bf9ed7fbd6dfec960ba43365952f3b01"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a4c5a2905a9ccdc67a8963e24abd2f7afcd4348829412483695c59e0af9a705"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55028d7a3ebdf7ace492fab9895cbc5270153f75442a0472d8516e03159ab364"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cfedff6878b0e0d1d0a50666a817ecd85051d12d56b43d9d425455e608b5ba0"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bb19e30fdae77d357ce92192a3504579abe48a66877f476880238a962e5b96db"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:16d325ea898f74b26ffcd1cf8c593b0beed8714f0317df2bed0d8d1de05a8f26"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-win32.whl", hash = "sha256:a669cbe5be3c63f75bcbee0b266779706f1a54bcb1000f302685b87d1b8c1500"},
+ {file = "sqlalchemy-2.0.40-cp313-cp313-win_amd64.whl", hash = "sha256:641ee2e0834812d657862f3a7de95e0048bdcb6c55496f39c6fa3d435f6ac6ad"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:50f5885bbed261fc97e2e66c5156244f9704083a674b8d17f24c72217d29baf5"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cf0e99cdb600eabcd1d65cdba0d3c91418fee21c4aa1d28db47d095b1064a7d8"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe147fcd85aaed53ce90645c91ed5fca0cc88a797314c70dfd9d35925bd5d106"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf7cee56bd552385c1ee39af360772fbfc2f43be005c78d1140204ad6148438"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4aeb939bcac234b88e2d25d5381655e8353fe06b4e50b1c55ecffe56951d18c2"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c268b5100cfeaa222c40f55e169d484efa1384b44bf9ca415eae6d556f02cb08"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-win32.whl", hash = "sha256:46628ebcec4f23a1584fb52f2abe12ddb00f3bb3b7b337618b80fc1b51177aff"},
+ {file = "sqlalchemy-2.0.40-cp38-cp38-win_amd64.whl", hash = "sha256:7e0505719939e52a7b0c65d20e84a6044eb3712bb6f239c6b1db77ba8e173a37"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c884de19528e0fcd9dc34ee94c810581dd6e74aef75437ff17e696c2bfefae3e"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1abb387710283fc5983d8a1209d9696a4eae9db8d7ac94b402981fe2fe2e39ad"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cfa124eda500ba4b0d3afc3e91ea27ed4754e727c7f025f293a22f512bcd4c9"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b6b28d303b9d57c17a5164eb1fd2d5119bb6ff4413d5894e74873280483eeb5"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b5a5bbe29c10c5bfd63893747a1bf6f8049df607638c786252cb9243b86b6706"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f0fda83e113bb0fb27dc003685f32a5dcb99c9c4f41f4fa0838ac35265c23b5c"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-win32.whl", hash = "sha256:957f8d85d5e834397ef78a6109550aeb0d27a53b5032f7a57f2451e1adc37e98"},
+ {file = "sqlalchemy-2.0.40-cp39-cp39-win_amd64.whl", hash = "sha256:1ffdf9c91428e59744f8e6f98190516f8e1d05eec90e936eb08b257332c5e870"},
+ {file = "sqlalchemy-2.0.40-py3-none-any.whl", hash = "sha256:32587e2e1e359276957e6fe5dad089758bc042a971a8a09ae8ecf7a8fe23d07a"},
+ {file = "sqlalchemy-2.0.40.tar.gz", hash = "sha256:d827099289c64589418ebbcaead0145cd19f4e3e8a93919a0100247af245fa00"},
+]
+
+[package.dependencies]
+greenlet = {version = ">=1", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
typing-extensions = ">=4.6.0"
[package.extras]
-aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
-aioodbc = ["aioodbc", "greenlet (!=0.4.17)"]
-aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
-asyncio = ["greenlet (!=0.4.17)"]
-asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"]
+aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"]
+aioodbc = ["aioodbc", "greenlet (>=1)"]
+aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"]
+asyncio = ["greenlet (>=1)"]
+asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"]
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"]
mssql = ["pyodbc"]
mssql-pymssql = ["pymssql"]
@@ -2989,7 +3165,7 @@ mysql-connector = ["mysql-connector-python"]
oracle = ["cx_oracle (>=8)"]
oracle-oracledb = ["oracledb (>=1.0.1)"]
postgresql = ["psycopg2 (>=2.7)"]
-postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
+postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"]
postgresql-pg8000 = ["pg8000 (>=1.29.1)"]
postgresql-psycopg = ["psycopg (>=3.0.7)"]
postgresql-psycopg2binary = ["psycopg2-binary"]
@@ -3004,6 +3180,7 @@ version = "0.6.3"
description = "Extract data from python stack frames and tracebacks for informative displays"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"},
{file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"},
@@ -3019,13 +3196,14 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
[[package]]
name = "syrupy"
-version = "4.8.1"
+version = "4.9.1"
description = "Pytest Snapshot Test Utility"
optional = false
python-versions = ">=3.8.1"
+groups = ["test"]
files = [
- {file = "syrupy-4.8.1-py3-none-any.whl", hash = "sha256:274f97cbaf44175f5e478a2f3a53559d31f41c66c6bf28131695f94ac893ea00"},
- {file = "syrupy-4.8.1.tar.gz", hash = "sha256:8da8c0311e6d92de0b15767768c6ab98982b7b4a4c67083c08fbac3fbad4d44c"},
+ {file = "syrupy-4.9.1-py3-none-any.whl", hash = "sha256:b94cc12ed0e5e75b448255430af642516842a2374a46936dd2650cfb6dd20eda"},
+ {file = "syrupy-4.9.1.tar.gz", hash = "sha256:b7d0fcadad80a7d2f6c4c71917918e8ebe2483e8c703dfc8d49cdbb01081f9a4"},
]
[package.dependencies]
@@ -3033,13 +3211,14 @@ pytest = ">=7.0.0,<9.0.0"
[[package]]
name = "tenacity"
-version = "9.0.0"
+version = "9.1.2"
description = "Retry code until it succeeds"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["main", "test"]
files = [
- {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"},
- {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"},
+ {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"},
+ {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"},
]
[package.extras]
@@ -3052,6 +3231,7 @@ version = "0.18.1"
description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"},
{file = "terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e"},
@@ -3073,6 +3253,7 @@ version = "1.4.0"
description = "A tiny CSS parser"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"},
{file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"},
@@ -3091,6 +3272,7 @@ version = "2.2.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
+groups = ["dev", "test", "typing"]
files = [
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
@@ -3125,6 +3307,7 @@ files = [
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
]
+markers = {dev = "python_version < \"3.11\"", test = "python_full_version <= \"3.11.0a6\"", typing = "python_version < \"3.11\""}
[[package]]
name = "tornado"
@@ -3132,6 +3315,7 @@ version = "6.4.2"
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"},
{file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"},
@@ -3152,6 +3336,7 @@ version = "5.14.3"
description = "Traitlets Python configuration system"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"},
{file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"},
@@ -3167,6 +3352,7 @@ version = "2.9.0.20241206"
description = "Typing stubs for python-dateutil"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"},
{file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"},
@@ -3174,24 +3360,42 @@ files = [
[[package]]
name = "typing-extensions"
-version = "4.12.2"
+version = "4.13.1"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "test", "typing"]
+files = [
+ {file = "typing_extensions-4.13.1-py3-none-any.whl", hash = "sha256:4b6cf02909eb5495cfbc3f6e8fd49217e6cc7944e145cdda8caa3734777f9e69"},
+ {file = "typing_extensions-4.13.1.tar.gz", hash = "sha256:98795af00fb9640edec5b8e31fc647597b4691f099ad75f469a2616be1a76dff"},
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.0"
+description = "Runtime typing introspection tools"
+optional = false
+python-versions = ">=3.9"
+groups = ["main", "test"]
files = [
- {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
- {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
+ {file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"},
+ {file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"},
]
+[package.dependencies]
+typing-extensions = ">=4.12.0"
+
[[package]]
name = "tzdata"
-version = "2025.1"
+version = "2025.2"
description = "Provider of IANA time zone data"
optional = false
python-versions = ">=2"
+groups = ["main"]
+markers = "sys_platform == \"win32\""
files = [
- {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"},
- {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"},
+ {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"},
+ {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"},
]
[[package]]
@@ -3200,6 +3404,7 @@ version = "1.3.0"
description = "RFC 6570 URI Template Processor"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"},
{file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"},
@@ -3214,13 +3419,14 @@ version = "2.3.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.9"
+groups = ["main", "dev", "test"]
files = [
{file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"},
{file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"},
]
[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
+brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
@@ -3231,6 +3437,7 @@ version = "0.2.13"
description = "Measures the displayed width of unicode strings in a terminal"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
{file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
@@ -3242,6 +3449,7 @@ version = "24.11.1"
description = "A library for working with the color formats defined by HTML and CSS."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9"},
{file = "webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6"},
@@ -3253,6 +3461,7 @@ version = "0.5.1"
description = "Character encoding aliases for legacy web content"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
{file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
@@ -3264,6 +3473,7 @@ version = "1.8.0"
description = "WebSocket client for Python with low level API options"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"},
{file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"},
@@ -3280,6 +3490,7 @@ version = "0.6.2"
description = "Python bindings for the Y-CRDT built from yrs (Rust)"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "y_py-0.6.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:c26bada6cd109095139237a46f50fc4308f861f0d304bc9e70acbc6c4503d158"},
{file = "y_py-0.6.2-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bae1b1ad8d2b8cf938a60313f8f7461de609621c5dcae491b6e54975f76f83c5"},
@@ -3363,6 +3574,7 @@ version = "0.8.4"
description = "WebSocket connector for Ypy"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "ypy_websocket-0.8.4-py3-none-any.whl", hash = "sha256:b1ba0dfcc9762f0ca168d2378062d3ca1299d39076b0f145d961359121042be5"},
{file = "ypy_websocket-0.8.4.tar.gz", hash = "sha256:43a001473f5c8abcf182f603049cf305cbc855ad8deaa9dfa0f3b5a7cea9d0ff"},
@@ -3382,17 +3594,19 @@ version = "3.21.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version < \"3.10\""
files = [
{file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"},
{file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"},
]
[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
-test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
+test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
type = ["pytest-mypy"]
[[package]]
@@ -3401,6 +3615,7 @@ version = "0.23.0"
description = "Zstandard bindings for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main", "test"]
files = [
{file = "zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9"},
{file = "zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880"},
@@ -3508,6 +3723,6 @@ cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\
cffi = ["cffi (>=1.11)"]
[metadata]
-lock-version = "2.0"
+lock-version = "2.1"
python-versions = "^3.9"
-content-hash = "a9a2c1b3ebd06e93ff340bed08e0c69886694c51bbf2c07033c170b1b77878bb"
+content-hash = "612ce8eb161f2a215258e4798f6adb1d9bc7ed6e9f60d505fbb4aac99a46ec9f"
diff --git a/pyproject.toml b/pyproject.toml
index cc25b797..8e499e5e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "langchain-postgres"
-version = "0.0.13"
+version = "0.0.14"
description = "An integration package connecting Postgres and LangChain"
authors = []
readme = "README.md"
@@ -16,8 +16,9 @@ langchain-core = ">=0.2.13,<0.4.0"
psycopg = "^3"
psycopg-pool = "^3.2.1"
sqlalchemy = "^2"
-pgvector = "<0.4"
-numpy = ">=1.21"
+pgvector = ">=0.2.5,<0.4"
+numpy = "^1.21"
+asyncpg = "^0.30.0"
[tool.poetry.group.docs.dependencies]
diff --git a/tests/unit_tests/fake_embeddings.py b/tests/unit_tests/fake_embeddings.py
index 81fd2aa5..376695f8 100644
--- a/tests/unit_tests/fake_embeddings.py
+++ b/tests/unit_tests/fake_embeddings.py
@@ -1,4 +1,5 @@
"""Copied from community."""
+
from typing import List
from langchain_core.embeddings import Embeddings
diff --git a/tests/unit_tests/fixtures/filtering_test_cases.py b/tests/unit_tests/fixtures/filtering_test_cases.py
index 181e8ba1..28ffca3c 100644
--- a/tests/unit_tests/fixtures/filtering_test_cases.py
+++ b/tests/unit_tests/fixtures/filtering_test_cases.py
@@ -1,4 +1,5 @@
"""Module needs to move to a stasndalone package."""
+
from langchain_core.documents import Document
metadatas = [
diff --git a/tests/unit_tests/fixtures/metadata_filtering_data.py b/tests/unit_tests/fixtures/metadata_filtering_data.py
new file mode 100644
index 00000000..446263d5
--- /dev/null
+++ b/tests/unit_tests/fixtures/metadata_filtering_data.py
@@ -0,0 +1,249 @@
+METADATAS = [
+ {
+ "name": "Wireless Headphones",
+ "code": "WH001",
+ "price": 149.99,
+ "is_available": True,
+ "release_date": "2023-10-26",
+ "tags": ["audio", "wireless", "electronics"],
+ "dimensions": [18.5, 7.2, 21.0],
+ "inventory_location": [101, 102],
+ "available_quantity": 50,
+ },
+ {
+ "name": "Ergonomic Office Chair",
+ "code": "EC002",
+ "price": 299.00,
+ "is_available": True,
+ "release_date": "2023-08-15",
+ "tags": ["furniture", "office", "ergonomic"],
+ "dimensions": [65.0, 60.0, 110.0],
+ "inventory_location": [201],
+ "available_quantity": 10,
+ },
+ {
+ "name": "Stainless Steel Water Bottle",
+ "code": "WB003",
+ "price": 25.50,
+ "is_available": False,
+ "release_date": "2024-01-05",
+ "tags": ["hydration", "eco-friendly", "kitchen"],
+ "dimensions": [7.5, 7.5, 25.0],
+ "available_quantity": 0,
+ },
+ {
+ "name": "Smart Fitness Tracker",
+ "code": "FT004",
+ "price": 79.95,
+ "is_available": True,
+ "release_date": "2023-11-12",
+ "tags": ["fitness", "wearable", "technology"],
+ "dimensions": [2.0, 1.0, 25.0],
+ "inventory_location": [401],
+ "available_quantity": 100,
+ },
+]
+
+FILTERING_TEST_CASES = [
+ # These tests only involve equality checks
+ (
+ {"code": "FT004"},
+ ["FT004"],
+ ),
+ # String field
+ (
+ # check name
+ {"name": "Smart Fitness Tracker"},
+ ["FT004"],
+ ),
+ # Boolean fields
+ (
+ {"is_available": True},
+ ["WH001", "FT004", "EC002"],
+ ),
+ # And semantics for top level filtering
+ (
+ {"code": "WH001", "is_available": True},
+ ["WH001"],
+ ),
+ # These involve equality checks and other operators
+ # like $ne, $gt, $gte, $lt, $lte
+ (
+ {"available_quantity": {"$eq": 10}},
+ ["EC002"],
+ ),
+ (
+ {"available_quantity": {"$ne": 0}},
+ ["WH001", "FT004", "EC002"],
+ ),
+ (
+ {"available_quantity": {"$gt": 60}},
+ ["FT004"],
+ ),
+ (
+ {"available_quantity": {"$gte": 50}},
+ ["WH001", "FT004"],
+ ),
+ (
+ {"available_quantity": {"$lt": 5}},
+ ["WB003"],
+ ),
+ (
+ {"available_quantity": {"$lte": 10}},
+ ["WB003", "EC002"],
+ ),
+ # Repeat all the same tests with name (string column)
+ (
+ {"code": {"$eq": "WH001"}},
+ ["WH001"],
+ ),
+ (
+ {"code": {"$ne": "WB003"}},
+ ["WH001", "FT004", "EC002"],
+ ),
+ # And also gt, gte, lt, lte relying on lexicographical ordering
+ (
+ {"name": {"$gt": "Wireless Headphones"}},
+ [],
+ ),
+ (
+ {"name": {"$gte": "Wireless Headphones"}},
+ ["WH001"],
+ ),
+ (
+ {"name": {"$lt": "Smart Fitness Tracker"}},
+ ["EC002"],
+ ),
+ (
+ {"name": {"$lte": "Smart Fitness Tracker"}},
+ ["FT004", "EC002"],
+ ),
+ (
+ {"is_available": {"$eq": True}},
+ ["WH001", "FT004", "EC002"],
+ ),
+ (
+ {"is_available": {"$ne": True}},
+ ["WB003"],
+ ),
+ # Test float column.
+ (
+ {"price": {"$gt": 200.0}},
+ ["EC002"],
+ ),
+ (
+ {"price": {"$gte": 149.99}},
+ ["WH001", "EC002"],
+ ),
+ (
+ {"price": {"$lt": 50.0}},
+ ["WB003"],
+ ),
+ (
+ {"price": {"$lte": 79.95}},
+ ["FT004", "WB003"],
+ ),
+ # These involve usage of AND, OR and NOT operators
+ (
+ {"$or": [{"code": "WH001"}, {"code": "EC002"}]},
+ ["WH001", "EC002"],
+ ),
+ (
+ {"$or": [{"code": "WH001"}, {"available_quantity": 10}]},
+ ["WH001", "EC002"],
+ ),
+ (
+ {"$and": [{"code": "WH001"}, {"code": "EC002"}]},
+ [],
+ ),
+ # Test for $not operator
+ (
+ {"$not": {"code": "WB003"}},
+ ["WH001", "FT004", "EC002"],
+ ),
+ (
+ {"$not": [{"code": "WB003"}]},
+ ["WH001", "FT004", "EC002"],
+ ),
+ (
+ {"$not": {"available_quantity": 0}},
+ ["WH001", "FT004", "EC002"],
+ ),
+ (
+ {"$not": [{"available_quantity": 0}]},
+ ["WH001", "FT004", "EC002"],
+ ),
+ (
+ {"$not": {"is_available": True}},
+ ["WB003"],
+ ),
+ (
+ {"$not": [{"is_available": True}]},
+ ["WB003"],
+ ),
+ (
+ {"$not": {"price": {"$gt": 150.0}}},
+ ["WH001", "FT004", "WB003"],
+ ),
+ (
+ {"$not": [{"price": {"$gt": 150.0}}]},
+ ["WH001", "FT004", "WB003"],
+ ),
+ # These involve special operators like $in, $nin, $between
+ # Test between
+ (
+ {"available_quantity": {"$between": (40, 60)}},
+ ["WH001"],
+ ),
+ # Test in
+ (
+ {"name": {"$in": ["Smart Fitness Tracker", "Stainless Steel Water Bottle"]}},
+ ["FT004", "WB003"],
+ ),
+ # With numeric fields
+ (
+ {"available_quantity": {"$in": [0, 10]}},
+ ["WB003", "EC002"],
+ ),
+ # Test nin
+ (
+ {"name": {"$nin": ["Smart Fitness Tracker", "Stainless Steel Water Bottle"]}},
+ ["WH001", "EC002"],
+ ),
+ ## with numeric fields
+ (
+ {"available_quantity": {"$nin": [50, 0, 10]}},
+ ["FT004"],
+ ),
+ # These involve special operators like $like, $ilike that
+ # may be specified to certain databases.
+ (
+ {"name": {"$like": "Wireless%"}},
+ ["WH001"],
+ ),
+ (
+ {"name": {"$like": "%less%"}}, # adam and jane
+ ["WH001", "WB003"],
+ ),
+ # These involve the special operator $exists
+ (
+ {"tags": {"$exists": False}},
+ [],
+ ),
+ (
+ {"inventory_location": {"$exists": False}},
+ ["WB003"],
+ ),
+]
+
+NEGATIVE_TEST_CASES = [
+ {"$nor": [{"code": "WH001"}, {"code": "EC002"}]},
+ {"$and": {"is_available": True}},
+ {"is_available": {"$and": True}},
+ {"is_available": {"name": "{Wireless Headphones", "code": "EC002"}},
+ {"my column": {"$and": True}},
+ {"is_available": {"code": "WH001", "code": "EC002"}},
+ {"$and": {}},
+ {"$and": []},
+ {"$not": True},
+]
diff --git a/tests/unit_tests/test_imports.py b/tests/unit_tests/test_imports.py
index 4513d181..445a4b1e 100644
--- a/tests/unit_tests/test_imports.py
+++ b/tests/unit_tests/test_imports.py
@@ -2,7 +2,11 @@
EXPECTED_ALL = [
"__version__",
+ "Column",
+ "ColumnDict",
+ "PGEngine",
"PGVector",
+ "PGVectorStore",
"PGVectorTranslator",
"PostgresChatMessageHistory",
]
diff --git a/tests/unit_tests/v1/__init__.py b/tests/unit_tests/v1/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/unit_tests/test_chat_histories.py b/tests/unit_tests/v1/test_chat_histories.py
similarity index 100%
rename from tests/unit_tests/test_chat_histories.py
rename to tests/unit_tests/v1/test_chat_histories.py
diff --git a/tests/unit_tests/test_vectorstore.py b/tests/unit_tests/v1/test_vectorstore.py
similarity index 99%
rename from tests/unit_tests/test_vectorstore.py
rename to tests/unit_tests/v1/test_vectorstore.py
index 2383daf3..a4f0f9f6 100644
--- a/tests/unit_tests/test_vectorstore.py
+++ b/tests/unit_tests/v1/test_vectorstore.py
@@ -1,4 +1,5 @@
"""Test PGVector functionality."""
+
import contextlib
from typing import Any, AsyncGenerator, Dict, Generator, List, Optional, Sequence
diff --git a/tests/unit_tests/test_vectorstore_standard_tests.py b/tests/unit_tests/v1/test_vectorstore_standard_tests.py
similarity index 93%
rename from tests/unit_tests/test_vectorstore_standard_tests.py
rename to tests/unit_tests/v1/test_vectorstore_standard_tests.py
index a8834f7a..cbf42b94 100644
--- a/tests/unit_tests/test_vectorstore_standard_tests.py
+++ b/tests/unit_tests/v1/test_vectorstore_standard_tests.py
@@ -4,7 +4,7 @@
from langchain_core.vectorstores import VectorStore
from langchain_tests.integration_tests import VectorStoreIntegrationTests
-from tests.unit_tests.test_vectorstore import aget_vectorstore, get_vectorstore
+from tests.unit_tests.v1.test_vectorstore import aget_vectorstore, get_vectorstore
class TestSync(VectorStoreIntegrationTests):
diff --git a/tests/unit_tests/v2/__init__.py b/tests/unit_tests/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/unit_tests/v2/test_async_pg_vectorstore.py b/tests/unit_tests/v2/test_async_pg_vectorstore.py
new file mode 100644
index 00000000..bcf37e8b
--- /dev/null
+++ b/tests/unit_tests/v2/test_async_pg_vectorstore.py
@@ -0,0 +1,338 @@
+import uuid
+from typing import AsyncIterator, Sequence
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+from sqlalchemy.engine.row import RowMapping
+
+from langchain_postgres import Column, PGEngine
+from langchain_postgres.v2.async_vectorstore import AsyncPGVectorStore
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "default" + str(uuid.uuid4())
+DEFAULT_TABLE_SYNC = "default_sync" + str(uuid.uuid4())
+CUSTOM_TABLE = "custom" + str(uuid.uuid4())
+VECTOR_SIZE = 768
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+texts = ["foo", "bar", "baz"]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query(texts[i]) for i in range(len(texts))]
+
+
+async def aexecute(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+
+async def afetch(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(text(query))
+ result_map = result.mappings()
+ result_fetch = result_map.fetchall()
+ return result_fetch
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio(scope="class")
+class TestVectorStore:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+
+ yield engine
+ await aexecute(engine, f'DROP TABLE IF EXISTS "{DEFAULT_TABLE}"')
+ await aexecute(engine, f'DROP TABLE IF EXISTS "{CUSTOM_TABLE}"')
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs(self, engine: PGEngine) -> AsyncIterator[AsyncPGVectorStore]:
+ await engine._ainit_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
+ vs = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ )
+ yield vs
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom(self, engine: PGEngine) -> AsyncIterator[AsyncPGVectorStore]:
+ await engine._ainit_vectorstore_table(
+ CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ metadata_json_column="mymeta",
+ )
+ vs = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ metadata_json_column="mymeta",
+ )
+ yield vs
+
+ async def test_init_with_constructor(self, engine: PGEngine) -> None:
+ with pytest.raises(Exception):
+ AsyncPGVectorStore(
+ key={},
+ engine=engine._pool,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="noname",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ metadata_json_column="mymeta",
+ )
+
+ async def test_post_init(self, engine: PGEngine) -> None:
+ with pytest.raises(ValueError):
+ await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="noname",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ metadata_json_column="mymeta",
+ )
+
+ async def test_aadd_texts(self, engine: PGEngine, vs: AsyncPGVectorStore) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, metadatas, ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 6
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_aadd_texts_edge_cases(
+ self, engine: PGEngine, vs: AsyncPGVectorStore
+ ) -> None:
+ texts = ["Taylor's", '"Swift"', "best-friend"]
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_aadd_docs(self, engine: PGEngine, vs: AsyncPGVectorStore) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_documents(docs, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_aadd_docs_no_ids(
+ self, engine: PGEngine, vs: AsyncPGVectorStore
+ ) -> None:
+ await vs.aadd_documents(docs)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_adelete(self, engine: PGEngine, vs: AsyncPGVectorStore) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ # delete an ID
+ await vs.adelete([ids[0]])
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 2
+ # delete with no ids
+ result = await vs.adelete()
+ assert result == False
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ ##### Custom Vector Store #####
+ async def test_aadd_embeddings(
+ self, engine: PGEngine, vs_custom: AsyncPGVectorStore
+ ) -> None:
+ await vs_custom.aadd_embeddings(
+ texts=texts, embeddings=embeddings, metadatas=metadatas
+ )
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] == "0"
+ assert results[0]["source"] == "postgres"
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_aadd_texts_custom(
+ self, engine: PGEngine, vs_custom: AsyncPGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs_custom.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] is None
+ assert results[0]["source"] is None
+
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs_custom.aadd_texts(texts, metadatas, ids)
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 6
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_aadd_docs_custom(
+ self, engine: PGEngine, vs_custom: AsyncPGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ docs = [
+ Document(
+ page_content=texts[i],
+ metadata={"page": str(i), "source": "postgres"},
+ )
+ for i in range(len(texts))
+ ]
+ await vs_custom.aadd_documents(docs, ids=ids)
+
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] == "0"
+ assert results[0]["source"] == "postgres"
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_adelete_custom(
+ self, engine: PGEngine, vs_custom: AsyncPGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs_custom.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ content = [result["mycontent"] for result in results]
+ assert len(results) == 3
+ assert "foo" in content
+ # delete an ID
+ await vs_custom.adelete([ids[0]])
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ content = [result["mycontent"] for result in results]
+ assert len(results) == 2
+ assert "foo" not in content
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_ignore_metadata_columns(self, engine: PGEngine) -> None:
+ column_to_ignore = "source"
+ vs = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ ignore_metadata_columns=[column_to_ignore],
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_json_column="mymeta",
+ )
+ assert column_to_ignore not in vs.metadata_columns
+
+ async def test_create_vectorstore_with_invalid_parameters_1(
+ self, engine: PGEngine
+ ) -> None:
+ with pytest.raises(ValueError):
+ await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["random_column"], # invalid metadata column
+ )
+
+ async def test_create_vectorstore_with_invalid_parameters_2(
+ self, engine: PGEngine
+ ) -> None:
+ with pytest.raises(ValueError):
+ await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="langchain_id", # invalid content column type
+ embedding_column="myembedding",
+ metadata_columns=["random_column"],
+ )
+
+ async def test_create_vectorstore_with_invalid_parameters_3(
+ self, engine: PGEngine
+ ) -> None:
+ with pytest.raises(ValueError):
+ await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="random_column", # invalid embedding column
+ metadata_columns=["random_column"],
+ )
+
+ async def test_create_vectorstore_with_invalid_parameters_4(
+ self, engine: PGEngine
+ ) -> None:
+ with pytest.raises(ValueError):
+ await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="langchain_id", # invalid embedding column data type
+ metadata_columns=["random_column"],
+ )
+
+ async def test_create_vectorstore_with_invalid_parameters_5(
+ self, engine: PGEngine
+ ) -> None:
+ with pytest.raises(ValueError):
+ await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="langchain_id",
+ metadata_columns=["random_column"],
+ ignore_metadata_columns=[
+ "one",
+ "two",
+ ], # invalid use of metadata_columns and ignore columns
+ )
+
+ async def test_create_vectorstore_with_init(self, engine: PGEngine) -> None:
+ with pytest.raises(Exception):
+ AsyncPGVectorStore(
+ key={},
+ engine=engine._pool,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["random_column"], # invalid metadata column
+ )
diff --git a/tests/unit_tests/v2/test_async_pg_vectorstore_from_methods.py b/tests/unit_tests/v2/test_async_pg_vectorstore_from_methods.py
new file mode 100644
index 00000000..85bb6a65
--- /dev/null
+++ b/tests/unit_tests/v2/test_async_pg_vectorstore_from_methods.py
@@ -0,0 +1,187 @@
+import os
+import uuid
+from typing import AsyncIterator, Sequence
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+from sqlalchemy.engine.row import RowMapping
+
+from langchain_postgres import Column, PGEngine
+from langchain_postgres.v2.async_vectorstore import AsyncPGVectorStore
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "default" + str(uuid.uuid4()).replace("-", "_")
+DEFAULT_TABLE_SYNC = "default_sync" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE = "custom" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE_WITH_INT_ID = "custom_sync" + str(uuid.uuid4()).replace("-", "_")
+VECTOR_SIZE = 768
+
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+texts = ["foo", "bar", "baz"]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query(texts[i]) for i in range(len(texts))]
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+
+async def afetch(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(text(query))
+ result_map = result.mappings()
+ result_fetch = result_map.fetchall()
+ return result_fetch
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio
+class TestVectorStoreFromMethods:
+ @pytest_asyncio.fixture
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ await engine._ainit_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
+ await engine._ainit_vectorstore_table(
+ CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=False,
+ )
+ await engine._ainit_vectorstore_table(
+ CUSTOM_TABLE_WITH_INT_ID,
+ VECTOR_SIZE,
+ id_column=Column(name="integer_id", data_type="INTEGER", nullable=False),
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=False,
+ )
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_TABLE_WITH_INT_ID}")
+ await engine.close()
+
+ async def test_afrom_texts(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await AsyncPGVectorStore.afrom_texts(
+ texts,
+ embeddings_service,
+ engine,
+ DEFAULT_TABLE,
+ metadatas=metadatas,
+ ids=ids,
+ )
+ results = await afetch(engine, f"SELECT * FROM {DEFAULT_TABLE}")
+ assert len(results) == 3
+ await aexecute(engine, f"TRUNCATE TABLE {DEFAULT_TABLE}")
+
+ async def test_afrom_docs(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await AsyncPGVectorStore.afrom_documents(
+ docs,
+ embeddings_service,
+ engine,
+ DEFAULT_TABLE,
+ ids=ids,
+ )
+ results = await afetch(engine, f"SELECT * FROM {DEFAULT_TABLE}")
+ assert len(results) == 3
+ await aexecute(engine, f"TRUNCATE TABLE {DEFAULT_TABLE}")
+
+ async def test_afrom_texts_custom(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await AsyncPGVectorStore.afrom_texts(
+ texts,
+ embeddings_service,
+ engine,
+ CUSTOM_TABLE,
+ ids=ids,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ )
+ results = await afetch(engine, f"SELECT * FROM {CUSTOM_TABLE}")
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] is None
+ assert results[0]["source"] is None
+
+ async def test_afrom_docs_custom(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ docs = [
+ Document(
+ page_content=texts[i],
+ metadata={"page": str(i), "source": "postgres"},
+ )
+ for i in range(len(texts))
+ ]
+ await AsyncPGVectorStore.afrom_documents(
+ docs,
+ embeddings_service,
+ engine,
+ CUSTOM_TABLE,
+ ids=ids,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ )
+
+ results = await afetch(engine, f"SELECT * FROM {CUSTOM_TABLE}")
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] == "0"
+ assert results[0]["source"] == "postgres"
+ await aexecute(engine, f"TRUNCATE TABLE {CUSTOM_TABLE}")
+
+ async def test_afrom_docs_custom_with_int_id(self, engine: PGEngine) -> None:
+ ids = [i for i in range(len(texts))]
+ docs = [
+ Document(
+ page_content=texts[i],
+ metadata={"page": str(i), "source": "postgres"},
+ )
+ for i in range(len(texts))
+ ]
+ await AsyncPGVectorStore.afrom_documents(
+ docs,
+ embeddings_service,
+ engine,
+ CUSTOM_TABLE_WITH_INT_ID,
+ ids=ids,
+ id_column="integer_id",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ )
+
+ results = await afetch(engine, f"SELECT * FROM {CUSTOM_TABLE_WITH_INT_ID}")
+ assert len(results) == 3
+ for row in results:
+ assert isinstance(row["integer_id"], int)
+ await aexecute(engine, f"TRUNCATE TABLE {CUSTOM_TABLE_WITH_INT_ID}")
diff --git a/tests/unit_tests/v2/test_async_pg_vectorstore_index.py b/tests/unit_tests/v2/test_async_pg_vectorstore_index.py
new file mode 100644
index 00000000..3796ef5a
--- /dev/null
+++ b/tests/unit_tests/v2/test_async_pg_vectorstore_index.py
@@ -0,0 +1,126 @@
+import os
+import uuid
+from typing import AsyncIterator
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+
+from langchain_postgres import PGEngine
+from langchain_postgres.v2.async_vectorstore import AsyncPGVectorStore
+from langchain_postgres.v2.indexes import (
+ DistanceStrategy,
+ HNSWIndex,
+ IVFFlatIndex,
+)
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+uuid_str = str(uuid.uuid4()).replace("-", "_")
+DEFAULT_TABLE = "default" + uuid_str
+DEFAULT_INDEX_NAME = "index" + uuid_str
+VECTOR_SIZE = 768
+SIMPLE_TABLE = "default_table"
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+texts = ["foo", "bar", "baz"]
+ids = [str(uuid.uuid4()) for i in range(len(texts))]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query("foo") for i in range(len(texts))]
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio(scope="class")
+class TestIndex:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {SIMPLE_TABLE}")
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs(self, engine: PGEngine) -> AsyncIterator[AsyncPGVectorStore]:
+ await engine._ainit_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
+ vs = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ )
+
+ await vs.aadd_texts(texts, ids=ids)
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME)
+ yield vs
+
+ async def test_apply_default_name_vector_index(self, engine: PGEngine) -> None:
+ await engine._ainit_vectorstore_table(SIMPLE_TABLE, VECTOR_SIZE)
+ vs = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=SIMPLE_TABLE,
+ )
+ await vs.aadd_texts(texts, ids=ids)
+ await vs.adrop_vector_index()
+ index = HNSWIndex()
+ await vs.aapply_vector_index(index)
+ assert await vs.is_valid_index()
+ await vs.adrop_vector_index()
+
+ async def test_aapply_vector_index(self, vs: AsyncPGVectorStore) -> None:
+ index = HNSWIndex(name=DEFAULT_INDEX_NAME)
+ await vs.aapply_vector_index(index)
+ assert await vs.is_valid_index(DEFAULT_INDEX_NAME)
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME)
+
+ async def test_areindex(self, vs: AsyncPGVectorStore) -> None:
+ if not await vs.is_valid_index(DEFAULT_INDEX_NAME):
+ index = HNSWIndex(name=DEFAULT_INDEX_NAME)
+ await vs.aapply_vector_index(index)
+ await vs.areindex(DEFAULT_INDEX_NAME)
+ await vs.areindex(DEFAULT_INDEX_NAME)
+ assert await vs.is_valid_index(DEFAULT_INDEX_NAME)
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME)
+
+ async def test_dropindex(self, vs: AsyncPGVectorStore) -> None:
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME)
+ result = await vs.is_valid_index(DEFAULT_INDEX_NAME)
+ assert not result
+
+ async def test_aapply_vector_index_ivfflat(self, vs: AsyncPGVectorStore) -> None:
+ index = IVFFlatIndex(
+ name=DEFAULT_INDEX_NAME, distance_strategy=DistanceStrategy.EUCLIDEAN
+ )
+ await vs.aapply_vector_index(index, concurrently=True)
+ assert await vs.is_valid_index(DEFAULT_INDEX_NAME)
+ index = IVFFlatIndex(
+ name="secondindex",
+ distance_strategy=DistanceStrategy.INNER_PRODUCT,
+ )
+ await vs.aapply_vector_index(index)
+ assert await vs.is_valid_index("secondindex")
+ await vs.adrop_vector_index("secondindex")
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME)
+
+ async def test_is_valid_index(self, vs: AsyncPGVectorStore) -> None:
+ is_valid = await vs.is_valid_index("invalid_index")
+ assert is_valid == False
diff --git a/tests/unit_tests/v2/test_async_pg_vectorstore_search.py b/tests/unit_tests/v2/test_async_pg_vectorstore_search.py
new file mode 100644
index 00000000..8e5e371c
--- /dev/null
+++ b/tests/unit_tests/v2/test_async_pg_vectorstore_search.py
@@ -0,0 +1,305 @@
+import os
+import uuid
+from typing import AsyncIterator
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+
+from langchain_postgres import Column, PGEngine
+from langchain_postgres.v2.async_vectorstore import AsyncPGVectorStore
+from langchain_postgres.v2.indexes import DistanceStrategy, HNSWQueryOptions
+from tests.unit_tests.fixtures.metadata_filtering_data import (
+ FILTERING_TEST_CASES,
+ METADATAS,
+)
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "default" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE = "custom" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_FILTER_TABLE = "custom_filter" + str(uuid.uuid4()).replace("-", "_")
+VECTOR_SIZE = 768
+sync_method_exception_str = "Sync methods are not implemented for AsyncPGVectorStore. Use PGVectorStore interface instead."
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+# Note: The following texts are chosen to produce diverse
+# similarity scores when using the DeterministicFakeEmbedding service. This ensures
+# that the test cases can effectively validate the filtering and scoring logic.
+# The scoring might be different if using a different embedding service.
+texts = ["foo", "bar", "baz", "boo"]
+ids = [str(uuid.uuid4()) for i in range(len(texts))]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query("foo") for i in range(len(texts))]
+
+filter_docs = [
+ Document(page_content=texts[i], metadata=METADATAS[i]) for i in range(len(texts))
+]
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(
+ engine: PGEngine,
+ query: str,
+) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio(scope="class")
+class TestVectorStoreSearch:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_FILTER_TABLE}")
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs(self, engine: PGEngine) -> AsyncIterator[AsyncPGVectorStore]:
+ await engine._ainit_vectorstore_table(
+ DEFAULT_TABLE, VECTOR_SIZE, store_metadata=False
+ )
+ vs = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ )
+ await vs.aadd_documents(docs, ids=ids)
+ yield vs
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom(self, engine: PGEngine) -> AsyncIterator[AsyncPGVectorStore]:
+ await engine._ainit_vectorstore_table(
+ CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[
+ Column("page", "TEXT"),
+ Column("source", "TEXT"),
+ ],
+ store_metadata=False,
+ )
+
+ vs_custom = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ index_query_options=HNSWQueryOptions(ef_search=1),
+ )
+ await vs_custom.aadd_documents(docs, ids=ids)
+ yield vs_custom
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom_filter(
+ self, engine: PGEngine
+ ) -> AsyncIterator[AsyncPGVectorStore]:
+ await engine._ainit_vectorstore_table(
+ CUSTOM_FILTER_TABLE,
+ VECTOR_SIZE,
+ metadata_columns=[
+ Column("name", "TEXT"),
+ Column("code", "TEXT"),
+ Column("price", "FLOAT"),
+ Column("is_available", "BOOLEAN"),
+ Column("tags", "TEXT[]"),
+ Column("inventory_location", "INTEGER[]"),
+ Column("available_quantity", "INTEGER", nullable=True),
+ ],
+ id_column="langchain_id",
+ store_metadata=False,
+ )
+
+ vs_custom_filter = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_FILTER_TABLE,
+ metadata_columns=[
+ "name",
+ "code",
+ "price",
+ "is_available",
+ "tags",
+ "inventory_location",
+ "available_quantity",
+ ],
+ id_column="langchain_id",
+ )
+ await vs_custom_filter.aadd_documents(filter_docs, ids=ids)
+ yield vs_custom_filter
+
+ async def test_asimilarity_search_score(self, vs: AsyncPGVectorStore) -> None:
+ results = await vs.asimilarity_search_with_score("foo")
+ assert len(results) == 4
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+ assert results[0][1] == 0
+
+ async def test_asimilarity_search_by_vector(self, vs: AsyncPGVectorStore) -> None:
+ embedding = embeddings_service.embed_query("foo")
+ results = await vs.asimilarity_search_by_vector(embedding)
+ assert len(results) == 4
+ assert results[0] == Document(page_content="foo", id=ids[0])
+ result = await vs.asimilarity_search_with_score_by_vector(embedding=embedding)
+ assert result[0][0] == Document(page_content="foo", id=ids[0])
+ assert result[0][1] == 0
+
+ async def test_similarity_search_with_relevance_scores_threshold_cosine(
+ self, vs: AsyncPGVectorStore
+ ) -> None:
+ score_threshold = {"score_threshold": 0}
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo", **score_threshold
+ )
+ # Note: Since tests use FakeEmbeddings which are non-normalized vectors, results might have scores beyond the range [0,1].
+ # For a normalized embedding service, a threshold of zero will yield all matched documents.
+ assert len(results) == 2
+
+ score_threshold = {"score_threshold": 0.02} # type: ignore
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo", **score_threshold
+ )
+ assert len(results) == 2
+
+ score_threshold = {"score_threshold": 0.9} # type: ignore
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo", **score_threshold
+ )
+ assert len(results) == 1
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+
+ score_threshold = {"score_threshold": 0.02} # type: ignore
+ vs.distance_strategy = DistanceStrategy.EUCLIDEAN
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo", **score_threshold
+ )
+ assert len(results) == 1
+
+ async def test_similarity_search_with_relevance_scores_threshold_euclidean(
+ self, engine: PGEngine
+ ) -> None:
+ vs = await AsyncPGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ distance_strategy=DistanceStrategy.EUCLIDEAN,
+ )
+
+ score_threshold = {"score_threshold": 0.9}
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo",
+ **score_threshold, # type: ignore
+ )
+ assert len(results) == 1
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+
+ async def test_amax_marginal_relevance_search_vector(
+ self, vs: AsyncPGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = await vs.amax_marginal_relevance_search_by_vector(embedding)
+ assert results[0] == Document(page_content="bar", id=ids[1])
+
+ async def test_amax_marginal_relevance_search_vector_score(
+ self, vs: AsyncPGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = await vs.amax_marginal_relevance_search_with_score_by_vector(
+ embedding
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ results = await vs.amax_marginal_relevance_search_with_score_by_vector(
+ embedding, lambda_mult=0.75, fetch_k=10
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ async def test_similarity_search_score(self, vs_custom: AsyncPGVectorStore) -> None:
+ results = await vs_custom.asimilarity_search_with_score("foo")
+ assert len(results) == 4
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+ assert results[0][1] == 0
+
+ async def test_similarity_search_by_vector(
+ self, vs_custom: AsyncPGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("foo")
+ results = await vs_custom.asimilarity_search_by_vector(embedding)
+ assert len(results) == 4
+ assert results[0] == Document(page_content="foo", id=ids[0])
+ result = await vs_custom.asimilarity_search_with_score_by_vector(
+ embedding=embedding
+ )
+ assert result[0][0] == Document(page_content="foo", id=ids[0])
+ assert result[0][1] == 0
+
+ async def test_max_marginal_relevance_search_vector(
+ self, vs_custom: AsyncPGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = await vs_custom.amax_marginal_relevance_search_by_vector(embedding)
+ assert results[0] == Document(page_content="bar", id=ids[1])
+
+ async def test_max_marginal_relevance_search_vector_score(
+ self, vs_custom: AsyncPGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = await vs_custom.amax_marginal_relevance_search_with_score_by_vector(
+ embedding
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ results = await vs_custom.amax_marginal_relevance_search_with_score_by_vector(
+ embedding, lambda_mult=0.75, fetch_k=10
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ async def test_aget_by_ids(self, vs: AsyncPGVectorStore) -> None:
+ test_ids = [ids[0]]
+ results = await vs.aget_by_ids(ids=test_ids)
+
+ assert results[0] == Document(page_content="foo", id=ids[0])
+
+ async def test_aget_by_ids_custom_vs(self, vs_custom: AsyncPGVectorStore) -> None:
+ test_ids = [ids[0]]
+ results = await vs_custom.aget_by_ids(ids=test_ids)
+
+ assert results[0] == Document(page_content="foo", id=ids[0])
+
+ def test_get_by_ids(self, vs: AsyncPGVectorStore) -> None:
+ test_ids = [ids[0]]
+ with pytest.raises(Exception, match=sync_method_exception_str):
+ vs.get_by_ids(ids=test_ids)
+
+ @pytest.mark.parametrize("test_filter, expected_ids", FILTERING_TEST_CASES)
+ async def test_vectorstore_with_metadata_filters(
+ self,
+ vs_custom_filter: AsyncPGVectorStore,
+ test_filter: dict,
+ expected_ids: list[str],
+ ) -> None:
+ """Test end to end construction and search."""
+ docs = await vs_custom_filter.asimilarity_search(
+ "meow", k=5, filter=test_filter
+ )
+ assert [doc.metadata["code"] for doc in docs] == expected_ids, test_filter
diff --git a/tests/unit_tests/v2/test_engine.py b/tests/unit_tests/v2/test_engine.py
new file mode 100644
index 00000000..cdd051a0
--- /dev/null
+++ b/tests/unit_tests/v2/test_engine.py
@@ -0,0 +1,357 @@
+import os
+import uuid
+from typing import AsyncIterator, Sequence
+
+import pytest
+import pytest_asyncio
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import VARCHAR, text
+from sqlalchemy.engine.row import RowMapping
+from sqlalchemy.ext.asyncio import create_async_engine
+from sqlalchemy.pool import NullPool
+
+from langchain_postgres import Column, PGEngine
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "default" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE = "custom" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TYPEDDICT_TABLE = "custom_td" + str(uuid.uuid4()).replace("-", "_")
+INT_ID_CUSTOM_TABLE = "custom_int_id" + str(uuid.uuid4()).replace("-", "_")
+DEFAULT_TABLE_SYNC = "default_sync" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE_SYNC = "custom_sync" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TYPEDDICT_TABLE_SYNC = "custom_td_sync" + str(uuid.uuid4()).replace("-", "_")
+INT_ID_CUSTOM_TABLE_SYNC = "custom_int_id_sync" + str(uuid.uuid4()).replace("-", "_")
+VECTOR_SIZE = 768
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(
+ engine: PGEngine,
+ query: str,
+) -> None:
+ async def run(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ await engine._run_as_async(run(engine, query))
+
+
+async def afetch(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async def run(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(text(query))
+ result_map = result.mappings()
+ result_fetch = result_map.fetchall()
+ return result_fetch
+
+ return await engine._run_as_async(run(engine, query))
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio
+class TestEngineAsync:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ kwargs = {
+ "pool_size": 3,
+ "max_overflow": 2,
+ }
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING, **kwargs)
+
+ yield engine
+ await aexecute(engine, f'DROP TABLE "{CUSTOM_TABLE}"')
+ await aexecute(engine, f'DROP TABLE "{CUSTOM_TYPEDDICT_TABLE}"')
+ await aexecute(engine, f'DROP TABLE "{DEFAULT_TABLE}"')
+ await aexecute(engine, f'DROP TABLE "{INT_ID_CUSTOM_TABLE}"')
+ await engine.close()
+
+ async def test_init_table(self, engine: PGEngine) -> None:
+ await engine.ainit_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
+ id = str(uuid.uuid4())
+ content = "coffee"
+ embedding = await embeddings_service.aembed_query(content)
+ # Note: DeterministicFakeEmbedding generates a numpy array, converting to list a list of float values
+ embedding_string = [float(dimension) for dimension in embedding]
+ stmt = f"INSERT INTO {DEFAULT_TABLE} (langchain_id, content, embedding) VALUES ('{id}', '{content}','{embedding_string}');"
+ await aexecute(engine, stmt)
+
+ async def test_engine_args(self, engine: PGEngine) -> None:
+ assert "Pool size: 3" in engine._pool.pool.status()
+
+ async def test_init_table_custom(self, engine: PGEngine) -> None:
+ await engine.ainit_vectorstore_table(
+ CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column="uuid",
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=True,
+ )
+ stmt = f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{CUSTOM_TABLE}';"
+ results = await afetch(engine, stmt)
+ expected = [
+ {"column_name": "uuid", "data_type": "uuid"},
+ {"column_name": "my_embedding", "data_type": "USER-DEFINED"},
+ {"column_name": "langchain_metadata", "data_type": "json"},
+ {"column_name": "my-content", "data_type": "text"},
+ {"column_name": "page", "data_type": "text"},
+ {"column_name": "source", "data_type": "text"},
+ ]
+ for row in results:
+ assert row in expected
+
+ async def test_invalid_typed_dict(self, engine: PGEngine) -> None:
+ with pytest.raises(TypeError):
+ await engine.ainit_vectorstore_table(
+ CUSTOM_TYPEDDICT_TABLE,
+ VECTOR_SIZE,
+ id_column={"name": "uuid", "data_type": "UUID"}, # type: ignore
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[
+ {"name": "page", "data_type": "TEXT", "nullable": True},
+ {"name": "source", "data_type": "TEXT", "nullable": True},
+ ],
+ store_metadata=True,
+ overwrite_existing=True,
+ )
+ with pytest.raises(TypeError):
+ await engine.ainit_vectorstore_table(
+ CUSTOM_TYPEDDICT_TABLE,
+ VECTOR_SIZE,
+ id_column={"name": "uuid", "data_type": "UUID", "nullable": False},
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[
+ {"name": "page", "nullable": True}, # type: ignore
+ {"data_type": "TEXT", "nullable": True}, # type: ignore
+ ],
+ store_metadata=True,
+ overwrite_existing=True,
+ )
+
+ async def test_init_table_custom_with_typed_dict(self, engine: PGEngine) -> None:
+ await engine.ainit_vectorstore_table(
+ CUSTOM_TYPEDDICT_TABLE,
+ VECTOR_SIZE,
+ id_column={"name": "uuid", "data_type": "UUID", "nullable": False},
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[
+ {"name": "page", "data_type": "TEXT", "nullable": True},
+ {"name": "source", "data_type": "TEXT", "nullable": True},
+ ],
+ store_metadata=True,
+ overwrite_existing=True,
+ )
+ stmt = f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{CUSTOM_TYPEDDICT_TABLE}';"
+ results = await afetch(engine, stmt)
+ expected = [
+ {"column_name": "uuid", "data_type": "uuid"},
+ {"column_name": "my_embedding", "data_type": "USER-DEFINED"},
+ {"column_name": "langchain_metadata", "data_type": "json"},
+ {"column_name": "my-content", "data_type": "text"},
+ {"column_name": "page", "data_type": "text"},
+ {"column_name": "source", "data_type": "text"},
+ ]
+ for row in results:
+ assert row in expected
+
+ async def test_init_table_with_int_id(self, engine: PGEngine) -> None:
+ await engine.ainit_vectorstore_table(
+ INT_ID_CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column=Column(name="integer_id", data_type="INTEGER", nullable=False),
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=True,
+ )
+ stmt = f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{INT_ID_CUSTOM_TABLE}';"
+ results = await afetch(engine, stmt)
+ expected = [
+ {"column_name": "integer_id", "data_type": "integer"},
+ {"column_name": "my_embedding", "data_type": "USER-DEFINED"},
+ {"column_name": "langchain_metadata", "data_type": "json"},
+ {"column_name": "my-content", "data_type": "text"},
+ {"column_name": "page", "data_type": "text"},
+ {"column_name": "source", "data_type": "text"},
+ ]
+ for row in results:
+ assert row in expected
+
+ async def test_from_engine(self) -> None:
+ engine = create_async_engine(
+ CONNECTION_STRING,
+ )
+
+ pg_engine = PGEngine.from_engine(engine=engine)
+ await aexecute(pg_engine, "SELECT 1")
+ await pg_engine.close()
+
+ async def test_from_connection_string(self) -> None:
+ engine = PGEngine.from_connection_string(
+ CONNECTION_STRING,
+ echo=True,
+ poolclass=NullPool,
+ )
+ await aexecute(engine, "SELECT 1")
+ await engine.close()
+
+ async def test_from_connection_string_url_error(
+ self,
+ ) -> None:
+ with pytest.raises(ValueError):
+ PGEngine.from_connection_string(
+ "postgresql+pg8000://user:password@host:port/db_name",
+ )
+
+ async def test_column(self, engine: PGEngine) -> None:
+ with pytest.raises(ValueError):
+ Column("test", VARCHAR) # type: ignore
+ with pytest.raises(ValueError):
+ Column(1, "INTEGER") # type: ignore
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio
+class TestEngineSync:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f'DROP TABLE "{CUSTOM_TABLE_SYNC}"')
+ await aexecute(engine, f'DROP TABLE "{DEFAULT_TABLE_SYNC}"')
+ await aexecute(engine, f'DROP TABLE "{INT_ID_CUSTOM_TABLE_SYNC}"')
+ await aexecute(engine, f'DROP TABLE "{CUSTOM_TYPEDDICT_TABLE_SYNC}"')
+ await engine.close()
+
+ async def test_init_table(self, engine: PGEngine) -> None:
+ engine.init_vectorstore_table(DEFAULT_TABLE_SYNC, VECTOR_SIZE)
+ id = str(uuid.uuid4())
+ content = "coffee"
+ embedding = await embeddings_service.aembed_query(content)
+ # Note: DeterministicFakeEmbedding generates a numpy array, converting to list a list of float values
+ embedding_string = [float(dimension) for dimension in embedding]
+ stmt = f"INSERT INTO {DEFAULT_TABLE_SYNC} (langchain_id, content, embedding) VALUES ('{id}', '{content}','{embedding_string}');"
+ await aexecute(engine, stmt)
+
+ async def test_init_table_custom(self, engine: PGEngine) -> None:
+ engine.init_vectorstore_table(
+ CUSTOM_TABLE_SYNC,
+ VECTOR_SIZE,
+ id_column="uuid",
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=True,
+ )
+ stmt = f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{CUSTOM_TABLE_SYNC}';"
+ results = await afetch(engine, stmt)
+ expected = [
+ {"column_name": "uuid", "data_type": "uuid"},
+ {"column_name": "my_embedding", "data_type": "USER-DEFINED"},
+ {"column_name": "langchain_metadata", "data_type": "json"},
+ {"column_name": "my-content", "data_type": "text"},
+ {"column_name": "page", "data_type": "text"},
+ {"column_name": "source", "data_type": "text"},
+ ]
+ for row in results:
+ assert row in expected
+
+ async def test_invalid_typed_dict(self, engine: PGEngine) -> None:
+ with pytest.raises(TypeError):
+ engine.init_vectorstore_table(
+ CUSTOM_TYPEDDICT_TABLE_SYNC,
+ VECTOR_SIZE,
+ id_column={"name": "uuid", "data_type": "UUID"}, # type: ignore
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[
+ {"name": "page", "data_type": "TEXT", "nullable": True},
+ {"name": "source", "data_type": "TEXT", "nullable": True},
+ ],
+ store_metadata=True,
+ overwrite_existing=True,
+ )
+ with pytest.raises(TypeError):
+ engine.init_vectorstore_table(
+ CUSTOM_TYPEDDICT_TABLE_SYNC,
+ VECTOR_SIZE,
+ id_column={"name": "uuid", "data_type": "UUID", "nullable": False},
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[
+ {"name": "page", "nullable": True}, # type: ignore
+ {"data_type": "TEXT", "nullable": True}, # type: ignore
+ ],
+ store_metadata=True,
+ overwrite_existing=True,
+ )
+
+ async def test_init_table_custom_with_typed_dict(self, engine: PGEngine) -> None:
+ engine.init_vectorstore_table(
+ CUSTOM_TYPEDDICT_TABLE_SYNC,
+ VECTOR_SIZE,
+ id_column={"name": "uuid", "data_type": "UUID", "nullable": False},
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[
+ {"name": "page", "data_type": "TEXT", "nullable": True},
+ {"name": "source", "data_type": "TEXT", "nullable": True},
+ ],
+ store_metadata=True,
+ )
+ stmt = f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{CUSTOM_TYPEDDICT_TABLE_SYNC}';"
+ results = await afetch(engine, stmt)
+ expected = [
+ {"column_name": "uuid", "data_type": "uuid"},
+ {"column_name": "my_embedding", "data_type": "USER-DEFINED"},
+ {"column_name": "langchain_metadata", "data_type": "json"},
+ {"column_name": "my-content", "data_type": "text"},
+ {"column_name": "page", "data_type": "text"},
+ {"column_name": "source", "data_type": "text"},
+ ]
+ for row in results:
+ assert row in expected
+
+ async def test_init_table_with_int_id(self, engine: PGEngine) -> None:
+ engine.init_vectorstore_table(
+ INT_ID_CUSTOM_TABLE_SYNC,
+ VECTOR_SIZE,
+ id_column=Column(name="integer_id", data_type="INTEGER", nullable=False),
+ content_column="my-content",
+ embedding_column="my_embedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=True,
+ )
+ stmt = f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{INT_ID_CUSTOM_TABLE_SYNC}';"
+ results = await afetch(engine, stmt)
+ expected = [
+ {"column_name": "integer_id", "data_type": "integer"},
+ {"column_name": "my_embedding", "data_type": "USER-DEFINED"},
+ {"column_name": "langchain_metadata", "data_type": "json"},
+ {"column_name": "my-content", "data_type": "text"},
+ {"column_name": "page", "data_type": "text"},
+ {"column_name": "source", "data_type": "text"},
+ ]
+ for row in results:
+ assert row in expected
+
+ async def test_engine_constructor_key(
+ self,
+ engine: PGEngine,
+ ) -> None:
+ key = object()
+ with pytest.raises(Exception):
+ PGEngine(key, engine._pool, None, None)
diff --git a/tests/unit_tests/v2/test_indexes.py b/tests/unit_tests/v2/test_indexes.py
new file mode 100644
index 00000000..8359b48e
--- /dev/null
+++ b/tests/unit_tests/v2/test_indexes.py
@@ -0,0 +1,63 @@
+import warnings
+
+import pytest
+
+from langchain_postgres.v2.indexes import (
+ DistanceStrategy,
+ HNSWIndex,
+ HNSWQueryOptions,
+ IVFFlatIndex,
+ IVFFlatQueryOptions,
+)
+
+
+@pytest.mark.enable_socket
+class TestPGIndex:
+ def test_distance_strategy(self) -> None:
+ assert DistanceStrategy.EUCLIDEAN.operator == "<->"
+ assert DistanceStrategy.EUCLIDEAN.search_function == "l2_distance"
+ assert DistanceStrategy.EUCLIDEAN.index_function == "vector_l2_ops"
+
+ assert DistanceStrategy.COSINE_DISTANCE.operator == "<=>"
+ assert DistanceStrategy.COSINE_DISTANCE.search_function == "cosine_distance"
+ assert DistanceStrategy.COSINE_DISTANCE.index_function == "vector_cosine_ops"
+
+ assert DistanceStrategy.INNER_PRODUCT.operator == "<#>"
+ assert DistanceStrategy.INNER_PRODUCT.search_function == "inner_product"
+ assert DistanceStrategy.INNER_PRODUCT.index_function == "vector_ip_ops"
+
+ def test_hnsw_index(self) -> None:
+ index = HNSWIndex(name="test_index", m=32, ef_construction=128)
+ assert index.index_type == "hnsw"
+ assert index.m == 32
+ assert index.ef_construction == 128
+ assert index.index_options() == "(m = 32, ef_construction = 128)"
+
+ def test_hnsw_query_options(self) -> None:
+ options = HNSWQueryOptions(ef_search=80)
+ assert options.to_parameter() == ["hnsw.ef_search = 80"]
+
+ with warnings.catch_warnings(record=True) as w:
+ options.to_string()
+
+ assert len(w) == 1
+ assert "to_string is deprecated, use to_parameter instead." in str(
+ w[-1].message
+ )
+
+ def test_ivfflat_index(self) -> None:
+ index = IVFFlatIndex(name="test_index", lists=200)
+ assert index.index_type == "ivfflat"
+ assert index.lists == 200
+ assert index.index_options() == "(lists = 200)"
+
+ def test_ivfflat_query_options(self) -> None:
+ options = IVFFlatQueryOptions(probes=2)
+ assert options.to_parameter() == ["ivfflat.probes = 2"]
+
+ with warnings.catch_warnings(record=True) as w:
+ options.to_string()
+ assert len(w) == 1
+ assert "to_string is deprecated, use to_parameter instead." in str(
+ w[-1].message
+ )
diff --git a/tests/unit_tests/v2/test_pg_vectorstore.py b/tests/unit_tests/v2/test_pg_vectorstore.py
new file mode 100644
index 00000000..d9765fa9
--- /dev/null
+++ b/tests/unit_tests/v2/test_pg_vectorstore.py
@@ -0,0 +1,486 @@
+import asyncio
+import os
+import uuid
+from threading import Thread
+from typing import AsyncIterator, Iterator, Sequence
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+from sqlalchemy.engine.row import RowMapping
+from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
+
+from langchain_postgres import Column, PGEngine, PGVectorStore
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "test_table" + str(uuid.uuid4())
+DEFAULT_TABLE_SYNC = "test_table_sync" + str(uuid.uuid4())
+CUSTOM_TABLE = "test-table-custom" + str(uuid.uuid4())
+VECTOR_SIZE = 768
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+texts = ["foo", "bar", "baz"]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query(texts[i]) for i in range(len(texts))]
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(
+ engine: PGEngine,
+ query: str,
+) -> None:
+ async def run(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ await engine._run_as_async(run(engine, query))
+
+
+async def afetch(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async def run(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(text(query))
+ result_map = result.mappings()
+ result_fetch = result_map.fetchall()
+ return result_fetch
+
+ return await engine._run_as_async(run(engine, query))
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio(scope="class")
+class TestVectorStore:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+
+ yield engine
+ await aexecute(engine, f'DROP TABLE IF EXISTS "{DEFAULT_TABLE}"')
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs(self, engine: PGEngine) -> AsyncIterator[PGVectorStore]:
+ await engine.ainit_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ )
+ yield vs
+
+ @pytest_asyncio.fixture(scope="class")
+ async def engine_sync(self) -> AsyncIterator[PGEngine]:
+ engine_sync = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine_sync
+
+ await aexecute(engine_sync, f'DROP TABLE IF EXISTS "{DEFAULT_TABLE_SYNC}"')
+ await engine_sync.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ def vs_sync(self, engine_sync: PGEngine) -> Iterator[PGVectorStore]:
+ engine_sync.init_vectorstore_table(DEFAULT_TABLE_SYNC, VECTOR_SIZE)
+
+ vs = PGVectorStore.create_sync(
+ engine_sync,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE_SYNC,
+ )
+ yield vs
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom(self, engine: PGEngine) -> AsyncIterator[PGVectorStore]:
+ await engine.ainit_vectorstore_table(
+ CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ metadata_json_column="mymeta",
+ )
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ metadata_json_column="mymeta",
+ )
+ yield vs
+ await aexecute(engine, f'DROP TABLE IF EXISTS "{CUSTOM_TABLE}"')
+
+ async def test_init_with_constructor(self, engine: PGEngine) -> None:
+ with pytest.raises(Exception):
+ PGVectorStore( # type: ignore
+ engine=engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="noname",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ metadata_json_column="mymeta",
+ )
+
+ async def test_post_init(self, engine: PGEngine) -> None:
+ with pytest.raises(ValueError):
+ await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="noname",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ metadata_json_column="mymeta",
+ )
+
+ async def test_aadd_texts(self, engine: PGEngine, vs: PGVectorStore) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, metadatas, ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 6
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_cross_env_add_texts(
+ self, engine: PGEngine, vs: PGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ vs.add_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ vs.delete(ids)
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_aadd_texts_edge_cases(
+ self, engine: PGEngine, vs: PGVectorStore
+ ) -> None:
+ texts = ["Taylor's", '"Swift"', "best-friend"]
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_aadd_docs(self, engine: PGEngine, vs: PGVectorStore) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_documents(docs, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_aadd_embeddings(
+ self, engine: PGEngine, vs_custom: PGVectorStore
+ ) -> None:
+ await vs_custom.aadd_embeddings(
+ texts=texts, embeddings=embeddings, metadatas=metadatas
+ )
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] == "0"
+ assert results[0]["source"] == "postgres"
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_adelete(self, engine: PGEngine, vs: PGVectorStore) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 3
+ # delete an ID
+ await vs.adelete([ids[0]])
+ results = await afetch(engine, f'SELECT * FROM "{DEFAULT_TABLE}"')
+ assert len(results) == 2
+ await aexecute(engine, f'TRUNCATE TABLE "{DEFAULT_TABLE}"')
+
+ async def test_aadd_texts_custom(
+ self, engine: PGEngine, vs_custom: PGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs_custom.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] is None
+ assert results[0]["source"] is None
+
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs_custom.aadd_texts(texts, metadatas, ids)
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 6
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_aadd_docs_custom(
+ self, engine: PGEngine, vs_custom: PGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ docs = [
+ Document(
+ page_content=texts[i],
+ metadata={"page": str(i), "source": "postgres"},
+ )
+ for i in range(len(texts))
+ ]
+ await vs_custom.aadd_documents(docs, ids=ids)
+
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] == "0"
+ assert results[0]["source"] == "postgres"
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_adelete_custom(
+ self, engine: PGEngine, vs_custom: PGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs_custom.aadd_texts(texts, ids=ids)
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ content = [result["mycontent"] for result in results]
+ assert len(results) == 3
+ assert "foo" in content
+ # delete an ID
+ await vs_custom.adelete([ids[0]])
+ results = await afetch(engine, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ content = [result["mycontent"] for result in results]
+ assert len(results) == 2
+ assert "foo" not in content
+ await aexecute(engine, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_add_docs(
+ self, engine_sync: PGEngine, vs_sync: PGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ vs_sync.add_documents(docs, ids=ids)
+ results = await afetch(engine_sync, f'SELECT * FROM "{DEFAULT_TABLE_SYNC}"')
+ assert len(results) == 3
+ vs_sync.delete(ids)
+ await aexecute(engine_sync, f'TRUNCATE TABLE "{DEFAULT_TABLE_SYNC}"')
+
+ async def test_add_texts(
+ self, engine_sync: PGEngine, vs_sync: PGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ vs_sync.add_texts(texts, ids=ids)
+ results = await afetch(engine_sync, f'SELECT * FROM "{DEFAULT_TABLE_SYNC}"')
+ assert len(results) == 3
+ await vs_sync.adelete(ids)
+ await aexecute(engine_sync, f'TRUNCATE TABLE "{DEFAULT_TABLE_SYNC}"')
+
+ async def test_cross_env(
+ self, engine_sync: PGEngine, vs_sync: PGVectorStore
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await vs_sync.aadd_texts(texts, ids=ids)
+ results = await afetch(engine_sync, f'SELECT * FROM "{DEFAULT_TABLE_SYNC}"')
+ assert len(results) == 3
+ await vs_sync.adelete(ids)
+ await aexecute(engine_sync, f'TRUNCATE TABLE "{DEFAULT_TABLE_SYNC}"')
+
+ async def test_add_embeddings(
+ self, engine_sync: PGEngine, vs_custom: PGVectorStore
+ ) -> None:
+ vs_custom.add_embeddings(
+ texts=texts,
+ embeddings=embeddings,
+ metadatas=[
+ {"page": str(i), "source": "postgres"} for i in range(len(texts))
+ ],
+ )
+ results = await afetch(engine_sync, f'SELECT * FROM "{CUSTOM_TABLE}"')
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] == "0"
+ assert results[0]["source"] == "postgres"
+ await aexecute(engine_sync, f'TRUNCATE TABLE "{CUSTOM_TABLE}"')
+
+ async def test_create_vectorstore_with_invalid_parameters(
+ self, engine: PGEngine
+ ) -> None:
+ with pytest.raises(ValueError):
+ await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["random_column"], # invalid metadata column
+ )
+ with pytest.raises(ValueError):
+ await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="langchain_id", # invalid content column type
+ embedding_column="myembedding",
+ metadata_columns=["random_column"],
+ )
+ with pytest.raises(ValueError):
+ await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="random_column", # invalid embedding column
+ metadata_columns=["random_column"],
+ )
+ with pytest.raises(ValueError):
+ await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="langchain_id", # invalid embedding column data type
+ metadata_columns=["random_column"],
+ )
+
+ async def test_from_engine(self) -> None:
+ async_engine = create_async_engine(url=CONNECTION_STRING)
+
+ engine = PGEngine.from_engine(async_engine)
+ table_name = "test_table" + str(uuid.uuid4()).replace("-", "_")
+ await engine.ainit_vectorstore_table(table_name, VECTOR_SIZE)
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=table_name,
+ )
+ await vs.aadd_texts(["foo"])
+ results = await afetch(engine, f"SELECT * FROM {table_name}")
+ assert len(results) == 1
+
+ await aexecute(engine, f"DROP TABLE {table_name}")
+ await engine.close()
+
+ async def test_from_engine_loop_connector(
+ self,
+ ) -> None:
+ async def init_connection_pool() -> AsyncEngine:
+ pool = create_async_engine(url=CONNECTION_STRING)
+ return pool
+
+ loop = asyncio.new_event_loop()
+ thread = Thread(target=loop.run_forever, daemon=True)
+ thread.start()
+
+ coro = init_connection_pool()
+ pool = asyncio.run_coroutine_threadsafe(coro, loop).result()
+ engine = PGEngine.from_engine(pool, loop)
+ table_name = "test_table" + str(uuid.uuid4()).replace("-", "_")
+ await engine.ainit_vectorstore_table(table_name, VECTOR_SIZE)
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=table_name,
+ )
+ await vs.aadd_texts(["foo"])
+ vs.add_texts(["foo"])
+ results = await afetch(engine, f"SELECT * FROM {table_name}")
+ assert len(results) == 2
+
+ await aexecute(engine, f"TRUNCATE TABLE {table_name}")
+ await engine.close()
+
+ vs = PGVectorStore.create_sync(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=table_name,
+ )
+ await vs.aadd_texts(["foo"])
+ vs.add_texts(["foo"])
+ results = await afetch(engine, f"SELECT * FROM {table_name}")
+ assert len(results) == 2
+
+ await aexecute(engine, f"DROP TABLE {table_name}")
+
+ async def test_from_connection_string(self) -> None:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ table_name = "test_table" + str(uuid.uuid4()).replace("-", "_")
+ await engine.ainit_vectorstore_table(table_name, VECTOR_SIZE)
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=table_name,
+ )
+ await vs.aadd_texts(["foo"])
+ vs.add_texts(["foo"])
+ results = await afetch(engine, f"SELECT * FROM {table_name}")
+ assert len(results) == 2
+
+ await aexecute(engine, f"TRUNCATE TABLE {table_name}")
+ vs = PGVectorStore.create_sync(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=table_name,
+ )
+ await vs.aadd_texts(["foo"])
+ vs.add_texts(["bar"])
+ results = await afetch(engine, f"SELECT * FROM {table_name}")
+ assert len(results) == 2
+ await aexecute(engine, f"DROP TABLE {table_name}")
+ await engine.close()
+
+ async def test_from_engine_loop(self) -> None:
+ loop = asyncio.new_event_loop()
+ thread = Thread(target=loop.run_forever, daemon=True)
+ thread.start()
+ pool = create_async_engine(url=CONNECTION_STRING)
+ engine = PGEngine.from_engine(pool, loop)
+
+ table_name = "test_table" + str(uuid.uuid4()).replace("-", "_")
+ await engine.ainit_vectorstore_table(table_name, VECTOR_SIZE)
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=table_name,
+ )
+ await vs.aadd_texts(["foo"])
+ vs.add_texts(["foo"])
+ results = await afetch(engine, f"SELECT * FROM {table_name}")
+ assert len(results) == 2
+
+ await aexecute(engine, f"TRUNCATE TABLE {table_name}")
+ vs = PGVectorStore.create_sync(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=table_name,
+ )
+ await vs.aadd_texts(["foo"])
+ vs.add_texts(["bar"])
+ results = await afetch(engine, f"SELECT * FROM {table_name}")
+ assert len(results) == 2
+ await aexecute(engine, f"DROP TABLE {table_name}")
+ await engine.close()
+
+ @pytest.mark.filterwarnings("ignore")
+ def test_get_table_name(self, vs: PGVectorStore) -> None:
+ assert vs.get_table_name() == DEFAULT_TABLE
diff --git a/tests/unit_tests/v2/test_pg_vectorstore_from_methods.py b/tests/unit_tests/v2/test_pg_vectorstore_from_methods.py
new file mode 100644
index 00000000..a2e8f927
--- /dev/null
+++ b/tests/unit_tests/v2/test_pg_vectorstore_from_methods.py
@@ -0,0 +1,286 @@
+import os
+import uuid
+from typing import AsyncIterator, Sequence
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+from sqlalchemy.engine.row import RowMapping
+
+from langchain_postgres import Column, PGEngine, PGVectorStore
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "default" + str(uuid.uuid4()).replace("-", "_")
+DEFAULT_TABLE_SYNC = "default_sync" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE = "custom" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE_WITH_INT_ID = "custom_int_id" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE_WITH_INT_ID_SYNC = "custom_int_id_sync" + str(uuid.uuid4()).replace(
+ "-", "_"
+)
+VECTOR_SIZE = 768
+
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+texts = ["foo", "bar", "baz"]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query(texts[i]) for i in range(len(texts))]
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(
+ engine: PGEngine,
+ query: str,
+) -> None:
+ async def run(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ await engine._run_as_async(run(engine, query))
+
+
+async def afetch(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async def run(engine: PGEngine, query: str) -> Sequence[RowMapping]:
+ async with engine._pool.connect() as conn:
+ result = await conn.execute(text(query))
+ result_map = result.mappings()
+ result_fetch = result_map.fetchall()
+ return result_fetch
+
+ return await engine._run_as_async(run(engine, query))
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio
+class TestVectorStoreFromMethods:
+ @pytest_asyncio.fixture
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ await engine.ainit_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
+ await engine.ainit_vectorstore_table(
+ CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=False,
+ )
+ await engine.ainit_vectorstore_table(
+ CUSTOM_TABLE_WITH_INT_ID,
+ VECTOR_SIZE,
+ id_column=Column(name="integer_id", data_type="INTEGER", nullable=False),
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=False,
+ )
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_TABLE_WITH_INT_ID}")
+ await engine.close()
+
+ @pytest_asyncio.fixture
+ async def engine_sync(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ engine.init_vectorstore_table(DEFAULT_TABLE_SYNC, VECTOR_SIZE)
+ engine.init_vectorstore_table(
+ CUSTOM_TABLE_WITH_INT_ID_SYNC,
+ VECTOR_SIZE,
+ id_column=Column(name="integer_id", data_type="INTEGER", nullable=False),
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[Column("page", "TEXT"), Column("source", "TEXT")],
+ store_metadata=False,
+ )
+
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE_SYNC}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_TABLE_WITH_INT_ID_SYNC}")
+ await engine.close()
+
+ async def test_afrom_texts(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await PGVectorStore.afrom_texts(
+ texts,
+ embeddings_service,
+ engine,
+ DEFAULT_TABLE,
+ metadatas=metadatas,
+ ids=ids,
+ )
+ results = await afetch(engine, f"SELECT * FROM {DEFAULT_TABLE}")
+ assert len(results) == 3
+ await aexecute(engine, f"TRUNCATE TABLE {DEFAULT_TABLE}")
+
+ async def test_from_texts(self, engine_sync: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ PGVectorStore.from_texts(
+ texts,
+ embeddings_service,
+ engine_sync,
+ DEFAULT_TABLE_SYNC,
+ metadatas=metadatas,
+ ids=ids,
+ )
+ results = await afetch(engine_sync, f"SELECT * FROM {DEFAULT_TABLE_SYNC}")
+ assert len(results) == 3
+ await aexecute(engine_sync, f"TRUNCATE TABLE {DEFAULT_TABLE_SYNC}")
+
+ async def test_afrom_docs(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await PGVectorStore.afrom_documents(
+ docs,
+ embeddings_service,
+ engine,
+ DEFAULT_TABLE,
+ ids=ids,
+ )
+ results = await afetch(engine, f"SELECT * FROM {DEFAULT_TABLE}")
+ assert len(results) == 3
+ await aexecute(engine, f"TRUNCATE TABLE {DEFAULT_TABLE}")
+
+ async def test_from_docs(self, engine_sync: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ PGVectorStore.from_documents(
+ docs,
+ embeddings_service,
+ engine_sync,
+ DEFAULT_TABLE_SYNC,
+ ids=ids,
+ )
+ results = await afetch(engine_sync, f"SELECT * FROM {DEFAULT_TABLE_SYNC}")
+ assert len(results) == 3
+ await aexecute(engine_sync, f"TRUNCATE TABLE {DEFAULT_TABLE_SYNC}")
+
+ async def test_afrom_docs_cross_env(self, engine_sync: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await PGVectorStore.afrom_documents(
+ docs,
+ embeddings_service,
+ engine_sync,
+ DEFAULT_TABLE_SYNC,
+ ids=ids,
+ )
+ results = await afetch(engine_sync, f"SELECT * FROM {DEFAULT_TABLE_SYNC}")
+ assert len(results) == 3
+ await aexecute(engine_sync, f"TRUNCATE TABLE {DEFAULT_TABLE_SYNC}")
+
+ async def test_from_docs_cross_env(
+ self, engine: PGEngine, engine_sync: PGEngine
+ ) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ PGVectorStore.from_documents(
+ docs,
+ embeddings_service,
+ engine,
+ DEFAULT_TABLE_SYNC,
+ ids=ids,
+ )
+ results = await afetch(engine, f"SELECT * FROM {DEFAULT_TABLE_SYNC}")
+ assert len(results) == 3
+ await aexecute(engine, f"TRUNCATE TABLE {DEFAULT_TABLE_SYNC}")
+
+ async def test_afrom_texts_custom(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ await PGVectorStore.afrom_texts(
+ texts,
+ embeddings_service,
+ engine,
+ CUSTOM_TABLE,
+ ids=ids,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ )
+ results = await afetch(engine, f"SELECT * FROM {CUSTOM_TABLE}")
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] is None
+ assert results[0]["source"] is None
+
+ async def test_afrom_docs_custom(self, engine: PGEngine) -> None:
+ ids = [str(uuid.uuid4()) for i in range(len(texts))]
+ docs = [
+ Document(
+ page_content=texts[i],
+ metadata={"page": str(i), "source": "postgres"},
+ )
+ for i in range(len(texts))
+ ]
+ await PGVectorStore.afrom_documents(
+ docs,
+ embeddings_service,
+ engine,
+ CUSTOM_TABLE,
+ ids=ids,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ )
+
+ results = await afetch(engine, f"SELECT * FROM {CUSTOM_TABLE}")
+ assert len(results) == 3
+ assert results[0]["mycontent"] == "foo"
+ assert results[0]["myembedding"]
+ assert results[0]["page"] == "0"
+ assert results[0]["source"] == "postgres"
+ await aexecute(engine, f"TRUNCATE TABLE {CUSTOM_TABLE}")
+
+ async def test_afrom_texts_custom_with_int_id(self, engine: PGEngine) -> None:
+ ids = [i for i in range(len(texts))]
+ await PGVectorStore.afrom_texts(
+ texts,
+ embeddings_service,
+ engine,
+ CUSTOM_TABLE_WITH_INT_ID,
+ metadatas=metadatas,
+ ids=ids,
+ id_column="integer_id",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ )
+ results = await afetch(engine, f"SELECT * FROM {CUSTOM_TABLE_WITH_INT_ID}")
+ assert len(results) == 3
+ for row in results:
+ assert isinstance(row["integer_id"], int)
+ await aexecute(engine, f"TRUNCATE TABLE {CUSTOM_TABLE_WITH_INT_ID}")
+
+ async def test_from_texts_custom_with_int_id(self, engine_sync: PGEngine) -> None:
+ ids = [i for i in range(len(texts))]
+ PGVectorStore.from_texts(
+ texts,
+ embeddings_service,
+ engine_sync,
+ CUSTOM_TABLE_WITH_INT_ID_SYNC,
+ ids=ids,
+ id_column="integer_id",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=["page", "source"],
+ )
+ results = await afetch(
+ engine_sync, f"SELECT * FROM {CUSTOM_TABLE_WITH_INT_ID_SYNC}"
+ )
+ assert len(results) == 3
+ for row in results:
+ assert isinstance(row["integer_id"], int)
+ await aexecute(engine_sync, f"TRUNCATE TABLE {CUSTOM_TABLE_WITH_INT_ID_SYNC}")
diff --git a/tests/unit_tests/v2/test_pg_vectorstore_index.py b/tests/unit_tests/v2/test_pg_vectorstore_index.py
new file mode 100644
index 00000000..405ce8cf
--- /dev/null
+++ b/tests/unit_tests/v2/test_pg_vectorstore_index.py
@@ -0,0 +1,181 @@
+import os
+import uuid
+from typing import AsyncIterator
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+
+from langchain_postgres import PGEngine, PGVectorStore
+from langchain_postgres.v2.indexes import (
+ DistanceStrategy,
+ HNSWIndex,
+ IVFFlatIndex,
+)
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+uuid_str = str(uuid.uuid4()).replace("-", "_")
+uuid_str_sync = str(uuid.uuid4()).replace("-", "_")
+DEFAULT_TABLE = "default" + uuid_str
+DEFAULT_TABLE_ASYNC = "default_sync" + uuid_str_sync
+CUSTOM_TABLE = "custom" + str(uuid.uuid4()).replace("-", "_")
+DEFAULT_INDEX_NAME = "index" + uuid_str
+DEFAULT_INDEX_NAME_ASYNC = "index" + uuid_str_sync
+VECTOR_SIZE = 768
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+texts = ["foo", "bar", "baz"]
+ids = [str(uuid.uuid4()) for i in range(len(texts))]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query("foo") for i in range(len(texts))]
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(
+ engine: PGEngine,
+ query: str,
+) -> None:
+ async def run(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ await engine._run_as_async(run(engine, query))
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio(scope="class")
+class TestIndex:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE}")
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs(self, engine: PGEngine) -> AsyncIterator[PGVectorStore]:
+ engine.init_vectorstore_table(DEFAULT_TABLE, VECTOR_SIZE)
+ vs = PGVectorStore.create_sync(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ )
+
+ vs.add_texts(texts, ids=ids)
+ vs.drop_vector_index(DEFAULT_INDEX_NAME)
+ yield vs
+
+ async def test_aapply_vector_index(self, vs: PGVectorStore) -> None:
+ index = HNSWIndex(name=DEFAULT_INDEX_NAME)
+ vs.apply_vector_index(index)
+ assert vs.is_valid_index(DEFAULT_INDEX_NAME)
+ vs.drop_vector_index(DEFAULT_INDEX_NAME)
+
+ async def test_areindex(self, vs: PGVectorStore) -> None:
+ if not vs.is_valid_index(DEFAULT_INDEX_NAME):
+ index = HNSWIndex(name=DEFAULT_INDEX_NAME)
+ vs.apply_vector_index(index)
+ vs.reindex(DEFAULT_INDEX_NAME)
+ vs.reindex(DEFAULT_INDEX_NAME)
+ assert vs.is_valid_index(DEFAULT_INDEX_NAME)
+ vs.drop_vector_index(DEFAULT_INDEX_NAME)
+
+ async def test_dropindex(self, vs: PGVectorStore) -> None:
+ vs.drop_vector_index(DEFAULT_INDEX_NAME)
+ result = vs.is_valid_index(DEFAULT_INDEX_NAME)
+ assert not result
+
+ async def test_aapply_vector_index_ivfflat(self, vs: PGVectorStore) -> None:
+ index = IVFFlatIndex(
+ name=DEFAULT_INDEX_NAME, distance_strategy=DistanceStrategy.EUCLIDEAN
+ )
+ vs.apply_vector_index(index, concurrently=True)
+ assert vs.is_valid_index(DEFAULT_INDEX_NAME)
+ index = IVFFlatIndex(
+ name="secondindex",
+ distance_strategy=DistanceStrategy.INNER_PRODUCT,
+ )
+ vs.apply_vector_index(index)
+ assert vs.is_valid_index("secondindex")
+ vs.drop_vector_index("secondindex")
+ vs.drop_vector_index(DEFAULT_INDEX_NAME)
+
+ async def test_is_valid_index(self, vs: PGVectorStore) -> None:
+ is_valid = vs.is_valid_index("invalid_index")
+ assert is_valid == False
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio(scope="class")
+class TestAsyncIndex:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE_ASYNC}")
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs(self, engine: PGEngine) -> AsyncIterator[PGVectorStore]:
+ await engine.ainit_vectorstore_table(DEFAULT_TABLE_ASYNC, VECTOR_SIZE)
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE_ASYNC,
+ )
+
+ await vs.aadd_texts(texts, ids=ids)
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME_ASYNC)
+ yield vs
+
+ async def test_aapply_vector_index(self, vs: PGVectorStore) -> None:
+ index = HNSWIndex(name=DEFAULT_INDEX_NAME_ASYNC)
+ await vs.aapply_vector_index(index)
+ assert await vs.ais_valid_index(DEFAULT_INDEX_NAME_ASYNC)
+
+ async def test_areindex(self, vs: PGVectorStore) -> None:
+ if not await vs.ais_valid_index(DEFAULT_INDEX_NAME_ASYNC):
+ index = HNSWIndex(name=DEFAULT_INDEX_NAME_ASYNC)
+ await vs.aapply_vector_index(index)
+ await vs.areindex(DEFAULT_INDEX_NAME_ASYNC)
+ await vs.areindex(DEFAULT_INDEX_NAME_ASYNC)
+ assert await vs.ais_valid_index(DEFAULT_INDEX_NAME_ASYNC)
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME_ASYNC)
+
+ async def test_dropindex(self, vs: PGVectorStore) -> None:
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME_ASYNC)
+ result = await vs.ais_valid_index(DEFAULT_INDEX_NAME_ASYNC)
+ assert not result
+
+ async def test_aapply_vector_index_ivfflat(self, vs: PGVectorStore) -> None:
+ index = IVFFlatIndex(
+ name=DEFAULT_INDEX_NAME_ASYNC, distance_strategy=DistanceStrategy.EUCLIDEAN
+ )
+ await vs.aapply_vector_index(index, concurrently=True)
+ assert await vs.ais_valid_index(DEFAULT_INDEX_NAME_ASYNC)
+ index = IVFFlatIndex(
+ name="secondindex",
+ distance_strategy=DistanceStrategy.INNER_PRODUCT,
+ )
+ await vs.aapply_vector_index(index)
+ assert await vs.ais_valid_index("secondindex")
+ await vs.adrop_vector_index("secondindex")
+ await vs.adrop_vector_index(DEFAULT_INDEX_NAME_ASYNC)
+
+ async def test_is_valid_index(self, vs: PGVectorStore) -> None:
+ is_valid = await vs.ais_valid_index("invalid_index")
+ assert is_valid == False
diff --git a/tests/unit_tests/v2/test_pg_vectorstore_search.py b/tests/unit_tests/v2/test_pg_vectorstore_search.py
new file mode 100644
index 00000000..379f5295
--- /dev/null
+++ b/tests/unit_tests/v2/test_pg_vectorstore_search.py
@@ -0,0 +1,403 @@
+import os
+import uuid
+from typing import AsyncIterator
+
+import pytest
+import pytest_asyncio
+from langchain_core.documents import Document
+from langchain_core.embeddings import DeterministicFakeEmbedding
+from sqlalchemy import text
+
+from langchain_postgres import Column, PGEngine, PGVectorStore
+from langchain_postgres.v2.indexes import DistanceStrategy, HNSWQueryOptions
+from tests.unit_tests.fixtures.metadata_filtering_data import (
+ FILTERING_TEST_CASES,
+ METADATAS,
+ NEGATIVE_TEST_CASES,
+)
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "default" + str(uuid.uuid4()).replace("-", "_")
+DEFAULT_TABLE_SYNC = "default_sync" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_TABLE = "custom" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_FILTER_TABLE = "custom_filter" + str(uuid.uuid4()).replace("-", "_")
+CUSTOM_FILTER_TABLE_SYNC = "custom_filter_sync" + str(uuid.uuid4()).replace("-", "_")
+VECTOR_SIZE = 768
+
+embeddings_service = DeterministicFakeEmbedding(size=VECTOR_SIZE)
+
+# Note: The following texts are chosen to produce diverse
+# similarity scores when using the DeterministicFakeEmbedding service. This ensures
+# that the test cases can effectively validate the filtering and scoring logic.
+# The scoring might be different if using a different embedding service.
+texts = ["foo", "bar", "baz", "boo"]
+ids = [str(uuid.uuid4()) for i in range(len(texts))]
+metadatas = [{"page": str(i), "source": "postgres"} for i in range(len(texts))]
+docs = [
+ Document(page_content=texts[i], metadata=metadatas[i]) for i in range(len(texts))
+]
+filter_docs = [
+ Document(page_content=texts[i], metadata=METADATAS[i]) for i in range(len(texts))
+]
+
+embeddings = [embeddings_service.embed_query("foo") for i in range(len(texts))]
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(
+ engine: PGEngine,
+ query: str,
+) -> None:
+ async def run(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ await engine._run_as_async(run(engine, query))
+
+
+@pytest.mark.enable_socket
+@pytest.mark.asyncio(scope="class")
+class TestVectorStoreSearch:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_FILTER_TABLE}")
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs(self, engine: PGEngine) -> AsyncIterator[PGVectorStore]:
+ await engine.ainit_vectorstore_table(
+ DEFAULT_TABLE, VECTOR_SIZE, store_metadata=False
+ )
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ )
+
+ await vs.aadd_documents(docs, ids=ids)
+ yield vs
+
+ @pytest_asyncio.fixture(scope="class")
+ async def engine_sync(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_TABLE}")
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom(self, engine_sync: PGEngine) -> AsyncIterator[PGVectorStore]:
+ engine_sync.init_vectorstore_table(
+ CUSTOM_TABLE,
+ VECTOR_SIZE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[
+ Column("page", "TEXT"),
+ Column("source", "TEXT"),
+ ],
+ store_metadata=False,
+ )
+
+ vs_custom = PGVectorStore.create_sync(
+ engine_sync,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_TABLE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ index_query_options=HNSWQueryOptions(ef_search=1),
+ )
+ vs_custom.add_documents(docs, ids=ids)
+ yield vs_custom
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom_filter(self, engine: PGEngine) -> AsyncIterator[PGVectorStore]:
+ await engine.ainit_vectorstore_table(
+ CUSTOM_FILTER_TABLE,
+ VECTOR_SIZE,
+ metadata_columns=[
+ Column("name", "TEXT"),
+ Column("code", "TEXT"),
+ Column("price", "FLOAT"),
+ Column("is_available", "BOOLEAN"),
+ Column("tags", "TEXT[]"),
+ Column("inventory_location", "INTEGER[]"),
+ Column("available_quantity", "INTEGER", nullable=True),
+ ],
+ id_column="langchain_id",
+ store_metadata=False,
+ overwrite_existing=True,
+ )
+
+ vs_custom_filter = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_FILTER_TABLE,
+ metadata_columns=[
+ "name",
+ "code",
+ "price",
+ "is_available",
+ "tags",
+ "inventory_location",
+ "available_quantity",
+ ],
+ id_column="langchain_id",
+ )
+ await vs_custom_filter.aadd_documents(filter_docs, ids=ids)
+ yield vs_custom_filter
+
+ async def test_asimilarity_search_score(self, vs: PGVectorStore) -> None:
+ results = await vs.asimilarity_search_with_score("foo")
+ assert len(results) == 4
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+ assert results[0][1] == 0
+
+ async def test_asimilarity_search_by_vector(self, vs: PGVectorStore) -> None:
+ embedding = embeddings_service.embed_query("foo")
+ results = await vs.asimilarity_search_by_vector(embedding)
+ assert len(results) == 4
+ assert results[0] == Document(page_content="foo", id=ids[0])
+ result = await vs.asimilarity_search_with_score_by_vector(embedding=embedding)
+ assert result[0][0] == Document(page_content="foo", id=ids[0])
+ assert result[0][1] == 0
+
+ async def test_similarity_search_with_relevance_scores_threshold_cosine(
+ self, vs: PGVectorStore
+ ) -> None:
+ score_threshold = {"score_threshold": 0}
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo", **score_threshold
+ )
+ # Note: Since tests use FakeEmbeddings which are non-normalized vectors, results might have scores beyond the range [0,1].
+ # For a normalized embedding service, a threshold of zero will yield all matched documents.
+ assert len(results) == 2
+
+ score_threshold = {"score_threshold": 0.02} # type: ignore
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo", **score_threshold
+ )
+ assert len(results) == 2
+
+ score_threshold = {"score_threshold": 0.9} # type: ignore
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo", **score_threshold
+ )
+ assert len(results) == 1
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+
+ async def test_similarity_search_with_relevance_scores_threshold_euclidean(
+ self, engine: PGEngine
+ ) -> None:
+ vs = await PGVectorStore.create(
+ engine,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE,
+ distance_strategy=DistanceStrategy.EUCLIDEAN,
+ )
+
+ score_threshold = {"score_threshold": 0.9}
+ results = await vs.asimilarity_search_with_relevance_scores(
+ "foo",
+ **score_threshold, # type: ignore
+ )
+ assert len(results) == 1
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+
+ async def test_amax_marginal_relevance_search_vector(
+ self, vs: PGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = await vs.amax_marginal_relevance_search_by_vector(embedding)
+ assert results[0] == Document(page_content="bar", id=ids[1])
+
+ async def test_amax_marginal_relevance_search_vector_score(
+ self, vs: PGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = await vs.amax_marginal_relevance_search_with_score_by_vector(
+ embedding
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ results = await vs.amax_marginal_relevance_search_with_score_by_vector(
+ embedding, lambda_mult=0.75, fetch_k=10
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ async def test_aget_by_ids(self, vs: PGVectorStore) -> None:
+ test_ids = [ids[0]]
+ results = await vs.aget_by_ids(ids=test_ids)
+
+ assert results[0] == Document(page_content="foo", id=ids[0])
+
+ async def test_aget_by_ids_custom_vs(self, vs_custom: PGVectorStore) -> None:
+ test_ids = [ids[0]]
+ results = await vs_custom.aget_by_ids(ids=test_ids)
+
+ assert results[0] == Document(page_content="foo", id=ids[0])
+
+ @pytest.mark.parametrize("test_filter, expected_ids", FILTERING_TEST_CASES)
+ async def test_vectorstore_with_metadata_filters(
+ self,
+ vs_custom_filter: PGVectorStore,
+ test_filter: dict,
+ expected_ids: list[str],
+ ) -> None:
+ """Test end to end construction and search."""
+ docs = await vs_custom_filter.asimilarity_search(
+ "meow", k=5, filter=test_filter
+ )
+ assert [doc.metadata["code"] for doc in docs] == expected_ids, test_filter
+
+
+@pytest.mark.enable_socket
+class TestVectorStoreSearchSync:
+ @pytest_asyncio.fixture(scope="class")
+ async def engine_sync(self) -> AsyncIterator[PGEngine]:
+ engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield engine
+ await aexecute(engine, f"DROP TABLE IF EXISTS {DEFAULT_TABLE_SYNC}")
+ await aexecute(engine, f"DROP TABLE IF EXISTS {CUSTOM_FILTER_TABLE_SYNC}")
+ await engine.close()
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom(self, engine_sync: PGEngine) -> AsyncIterator[PGVectorStore]:
+ engine_sync.init_vectorstore_table(
+ DEFAULT_TABLE_SYNC,
+ VECTOR_SIZE,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ metadata_columns=[
+ Column("page", "TEXT"),
+ Column("source", "TEXT"),
+ ],
+ store_metadata=False,
+ )
+
+ vs_custom = await PGVectorStore.create(
+ engine_sync,
+ embedding_service=embeddings_service,
+ table_name=DEFAULT_TABLE_SYNC,
+ id_column="myid",
+ content_column="mycontent",
+ embedding_column="myembedding",
+ index_query_options=HNSWQueryOptions(ef_search=1),
+ )
+ vs_custom.add_documents(docs, ids=ids)
+ yield vs_custom
+
+ @pytest_asyncio.fixture(scope="class")
+ async def vs_custom_filter_sync(
+ self, engine_sync: PGEngine
+ ) -> AsyncIterator[PGVectorStore]:
+ engine_sync.init_vectorstore_table(
+ CUSTOM_FILTER_TABLE_SYNC,
+ VECTOR_SIZE,
+ metadata_columns=[
+ Column("name", "TEXT"),
+ Column("code", "TEXT"),
+ Column("price", "FLOAT"),
+ Column("is_available", "BOOLEAN"),
+ Column("tags", "TEXT[]"),
+ Column("inventory_location", "INTEGER[]"),
+ Column("available_quantity", "INTEGER", nullable=True),
+ ],
+ id_column="langchain_id",
+ store_metadata=False,
+ overwrite_existing=True,
+ )
+
+ vs_custom_filter_sync = await PGVectorStore.create(
+ engine_sync,
+ embedding_service=embeddings_service,
+ table_name=CUSTOM_FILTER_TABLE_SYNC,
+ metadata_columns=[
+ "name",
+ "code",
+ "price",
+ "is_available",
+ "tags",
+ "inventory_location",
+ "available_quantity",
+ ],
+ id_column="langchain_id",
+ )
+
+ vs_custom_filter_sync.add_documents(filter_docs, ids=ids)
+ yield vs_custom_filter_sync
+
+ def test_similarity_search_score(self, vs_custom: PGVectorStore) -> None:
+ results = vs_custom.similarity_search_with_score("foo")
+ assert len(results) == 4
+ assert results[0][0] == Document(page_content="foo", id=ids[0])
+ assert results[0][1] == 0
+
+ def test_similarity_search_by_vector(self, vs_custom: PGVectorStore) -> None:
+ embedding = embeddings_service.embed_query("foo")
+ results = vs_custom.similarity_search_by_vector(embedding)
+ assert len(results) == 4
+ assert results[0] == Document(page_content="foo", id=ids[0])
+ result = vs_custom.similarity_search_with_score_by_vector(embedding=embedding)
+ assert result[0][0] == Document(page_content="foo", id=ids[0])
+ assert result[0][1] == 0
+
+ def test_max_marginal_relevance_search_vector(
+ self, vs_custom: PGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = vs_custom.max_marginal_relevance_search_by_vector(embedding)
+ assert results[0] == Document(page_content="bar", id=ids[1])
+
+ def test_max_marginal_relevance_search_vector_score(
+ self, vs_custom: PGVectorStore
+ ) -> None:
+ embedding = embeddings_service.embed_query("bar")
+ results = vs_custom.max_marginal_relevance_search_with_score_by_vector(
+ embedding
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ results = vs_custom.max_marginal_relevance_search_with_score_by_vector(
+ embedding, lambda_mult=0.75, fetch_k=10
+ )
+ assert results[0][0] == Document(page_content="bar", id=ids[1])
+
+ def test_get_by_ids_custom_vs(self, vs_custom: PGVectorStore) -> None:
+ test_ids = [ids[0]]
+ results = vs_custom.get_by_ids(ids=test_ids)
+
+ assert results[0] == Document(page_content="foo", id=ids[0])
+
+ @pytest.mark.parametrize("test_filter, expected_ids", FILTERING_TEST_CASES)
+ def test_sync_vectorstore_with_metadata_filters(
+ self,
+ vs_custom_filter_sync: PGVectorStore,
+ test_filter: dict,
+ expected_ids: list[str],
+ ) -> None:
+ """Test end to end construction and search."""
+
+ docs = vs_custom_filter_sync.similarity_search("meow", k=5, filter=test_filter)
+ assert [doc.metadata["code"] for doc in docs] == expected_ids, test_filter
+
+ @pytest.mark.parametrize("test_filter", NEGATIVE_TEST_CASES)
+ def test_metadata_filter_negative_tests(
+ self, vs_custom_filter_sync: PGVectorStore, test_filter: dict
+ ) -> None:
+ with pytest.raises((ValueError, NotImplementedError)):
+ docs = vs_custom_filter_sync.similarity_search(
+ "meow", k=5, filter=test_filter
+ )
diff --git a/tests/unit_tests/v2/test_pg_vectorstore_standard_suite.py b/tests/unit_tests/v2/test_pg_vectorstore_standard_suite.py
new file mode 100644
index 00000000..d400ead4
--- /dev/null
+++ b/tests/unit_tests/v2/test_pg_vectorstore_standard_suite.py
@@ -0,0 +1,91 @@
+import os
+import uuid
+from typing import AsyncIterator
+
+import pytest
+import pytest_asyncio
+from langchain_tests.integration_tests import VectorStoreIntegrationTests
+from langchain_tests.integration_tests.vectorstores import EMBEDDING_SIZE
+from sqlalchemy import text
+
+from langchain_postgres import Column, PGEngine, PGVectorStore
+from tests.utils import VECTORSTORE_CONNECTION_STRING as CONNECTION_STRING
+
+DEFAULT_TABLE = "standard" + str(uuid.uuid4())
+DEFAULT_TABLE_SYNC = "sync_standard" + str(uuid.uuid4())
+
+
+def get_env_var(key: str, desc: str) -> str:
+ v = os.environ.get(key)
+ if v is None:
+ raise ValueError(f"Must set env var {key} to: {desc}")
+ return v
+
+
+async def aexecute(
+ engine: PGEngine,
+ query: str,
+) -> None:
+ async def run(engine: PGEngine, query: str) -> None:
+ async with engine._pool.connect() as conn:
+ await conn.execute(text(query))
+ await conn.commit()
+
+ await engine._run_as_async(run(engine, query))
+
+
+@pytest.mark.enable_socket
+# @pytest.mark.filterwarnings("ignore")
+@pytest.mark.asyncio
+class TestStandardSuiteSync(VectorStoreIntegrationTests):
+ @pytest_asyncio.fixture(scope="function")
+ async def sync_engine(self) -> AsyncIterator[PGEngine]:
+ sync_engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield sync_engine
+ await aexecute(sync_engine, f'DROP TABLE IF EXISTS "{DEFAULT_TABLE_SYNC}"')
+ await sync_engine.close()
+
+ @pytest.fixture(scope="function")
+ def vectorstore(self, sync_engine: PGEngine) -> PGVectorStore: # type: ignore
+ """Get an empty vectorstore for unit tests."""
+ sync_engine.init_vectorstore_table(
+ DEFAULT_TABLE_SYNC,
+ EMBEDDING_SIZE,
+ id_column=Column(name="langchain_id", data_type="VARCHAR", nullable=False),
+ )
+
+ vs = PGVectorStore.create_sync(
+ sync_engine,
+ embedding_service=self.get_embeddings(),
+ table_name=DEFAULT_TABLE_SYNC,
+ )
+ yield vs
+
+
+@pytest.mark.enable_socket
+# @pytest.mark.filterwarnings("ignore")
+@pytest.mark.asyncio
+class TestStandardSuiteAsync(VectorStoreIntegrationTests):
+ @pytest_asyncio.fixture(scope="function")
+ async def async_engine(self) -> AsyncIterator[PGEngine]:
+ async_engine = PGEngine.from_connection_string(url=CONNECTION_STRING)
+ yield async_engine
+ await aexecute(async_engine, f'DROP TABLE IF EXISTS "{DEFAULT_TABLE}"')
+ await async_engine.close()
+
+ @pytest_asyncio.fixture(scope="function")
+ async def vectorstore(self, async_engine: PGEngine) -> AsyncIterator[PGVectorStore]:
+ """Get an empty vectorstore for unit tests."""
+ await async_engine.ainit_vectorstore_table(
+ DEFAULT_TABLE,
+ EMBEDDING_SIZE,
+ id_column=Column(name="langchain_id", data_type="VARCHAR", nullable=False),
+ )
+
+ vs = await PGVectorStore.create(
+ async_engine,
+ embedding_service=self.get_embeddings(),
+ table_name=DEFAULT_TABLE,
+ )
+
+ yield vs
diff --git a/tests/utils.py b/tests/utils.py
index a61d38bc..54f80ca4 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -1,4 +1,5 @@
"""Get fixtures for the database connection."""
+
import os
from contextlib import asynccontextmanager, contextmanager