From 46539e722eda60590a86c33b8a51bd0c8888bde0 Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:41:26 -0700 Subject: [PATCH 01/11] basic upsert --- pinecone/repository/data/interfaces.py | 21 +++++++ pinecone/repository/data/repository.py | 83 ++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 pinecone/repository/data/interfaces.py create mode 100644 pinecone/repository/data/repository.py diff --git a/pinecone/repository/data/interfaces.py b/pinecone/repository/data/interfaces.py new file mode 100644 index 00000000..4d4b7748 --- /dev/null +++ b/pinecone/repository/data/interfaces.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod +from typing import Union, Dict, Any + +from pinecone.core.openapi.ckb_knowledge_data.models import ( + DocumentForUpsert, + UpsertDocumentResponse, +) + + +class RepositoryInterface(ABC): + @abstractmethod + def upsert( + self, namespace: str, document: Union[Dict[str, Any], DocumentForUpsert], **kwargs + ) -> UpsertDocumentResponse: + """ + Upserts a document into a Pinecone Repository. + + Returns: + `UpsertDocumentResponse`, includes the number of vectors upserted. + """ + pass diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py new file mode 100644 index 00000000..e283889d --- /dev/null +++ b/pinecone/repository/data/repository.py @@ -0,0 +1,83 @@ +import logging +from typing import Union, Optional, Dict, Any + +from pinecone.config import ConfigBuilder + + +from pinecone.core.openapi.ckb_knowledge_data.api.document_operations_api import ( + DocumentOperationsApi, +) +from pinecone.core.openapi.ckb_knowledge_data import API_VERSION + +from pinecone.openapi_support import ApiClient +from pinecone.core.openapi.ckb_knowledge_data.models import ( + DocumentForUpsert, + UpsertDocumentResponse, +) + +from .interfaces import RepositoryInterface + +from pinecone.utils import setup_openapi_client + +from multiprocessing import cpu_count + + +logger = logging.getLogger(__name__) +""" :meta private: """ + + +class Repository(RepositoryInterface): + """ + A client for interacting with a Pinecone Repository API. + """ + + def __init__( + self, + api_key: str, + host: str, + pool_threads: Optional[int] = None, + additional_headers: Optional[Dict[str, str]] = {}, + openapi_config=None, + **kwargs, + ): + self._config = ConfigBuilder.build( + api_key=api_key, host=host, additional_headers=additional_headers, **kwargs + ) + """ :meta private: """ + self._openapi_config = ConfigBuilder.build_openapi_config(self._config, openapi_config) + """ :meta private: """ + + if pool_threads is None: + self._pool_threads = 5 * cpu_count() + """ :meta private: """ + else: + self._pool_threads = pool_threads + """ :meta private: """ + + if kwargs.get("connection_pool_maxsize", None): + self._openapi_config.connection_pool_maxsize = kwargs.get("connection_pool_maxsize") + + self._repository_api = setup_openapi_client( + api_client_klass=ApiClient, + api_klass=DocumentOperationsApi, + config=self._config, + openapi_config=self._openapi_config, + pool_threads=self._pool_threads, + api_version=API_VERSION, + ) + + self._api_client = self._vector_api.api_client + + self._bulk_import_resource = None + """ :meta private: """ + + self._namespace_resource = None + """ :meta private: """ + + # Pass the same api_client to the ImportFeatureMixin + super().__init__(api_client=self._api_client) + + def upsert( + self, namespace: str, document: Union[Dict[str, Any], DocumentForUpsert], **kwargs + ) -> UpsertDocumentResponse: + self._repository_api.upsert_document(namespace=namespace, document=document, **kwargs) From 938c37972469b480300ad4fd9f38503d45affb1f Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Thu, 21 Aug 2025 23:37:04 -0700 Subject: [PATCH 02/11] upsert working? --- pinecone/pinecone.py | 30 ++++++++++++++++++++++++++ pinecone/repository/data/__init__.py | 13 +++++++++++ pinecone/repository/data/repository.py | 18 ++++++---------- 3 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 pinecone/repository/data/__init__.py diff --git a/pinecone/pinecone.py b/pinecone/pinecone.py index d8c8a1b4..3440e54a 100644 --- a/pinecone/pinecone.py +++ b/pinecone/pinecone.py @@ -16,6 +16,7 @@ if TYPE_CHECKING: from pinecone.config import Config, OpenApiConfiguration from pinecone.db_data import _Index as Index, _IndexAsyncio as IndexAsyncio + from pinecone.repository.data import _Repository as Repository from pinecone.db_control.index_host_store import IndexHostStore from pinecone.core.openapi.db_control.api.manage_indexes_api import ManageIndexesApi from pinecone.db_control.types import CreateIndexForModelEmbedTypedDict, ConfigureIndexEmbed @@ -518,6 +519,35 @@ def IndexAsyncio(self, host: str, **kwargs) -> "IndexAsyncio": **kwargs, ) + def Repository(self, name: str = "", host: str = "", **kwargs) -> "Repository": + from pinecone.repository.data import _Repository + + if name == "" and host == "": + raise ValueError("Either name or host must be specified") + + pt = kwargs.pop("pool_threads", None) or self._pool_threads + api_key = self._config.api_key + openapi_config = self._openapi_config + + if host != "": + check_realistic_host(host) + + # Use host url if it is provided + repository_host = normalize_host(host) + else: + # TODO, get host url from describe_kb using the index name + # index_host = self.db.index._get_host(name) + raise ValueError("host lookup not yet supported, specify host parameter") + + return _Repository( + host=repository_host, + api_key=api_key, + pool_threads=pt, + openapi_config=openapi_config, + source_tag=self.config.source_tag, + **kwargs, + ) + def check_realistic_host(host: str) -> None: """:meta private: diff --git a/pinecone/repository/data/__init__.py b/pinecone/repository/data/__init__.py new file mode 100644 index 00000000..0dbfe3b2 --- /dev/null +++ b/pinecone/repository/data/__init__.py @@ -0,0 +1,13 @@ +from .repository import Repository, DocumentForUpsert, UpsertDocumentResponse + + +_Repository = Repository # alias for backwards compatibility + + +__all__ = ["_Repository", "DocumentForUpsert", "UpsertDocumentResponse"] + + +def __getattr__(name): + if name in locals(): + return locals()[name] + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py index e283889d..00aaf9d3 100644 --- a/pinecone/repository/data/repository.py +++ b/pinecone/repository/data/repository.py @@ -66,18 +66,14 @@ def __init__( api_version=API_VERSION, ) - self._api_client = self._vector_api.api_client - - self._bulk_import_resource = None - """ :meta private: """ - - self._namespace_resource = None - """ :meta private: """ - - # Pass the same api_client to the ImportFeatureMixin - super().__init__(api_client=self._api_client) + self._api_client = self._repository_api.api_client def upsert( self, namespace: str, document: Union[Dict[str, Any], DocumentForUpsert], **kwargs ) -> UpsertDocumentResponse: - self._repository_api.upsert_document(namespace=namespace, document=document, **kwargs) + if isinstance(document, dict): + document = DocumentForUpsert(**document) + + return self._repository_api.upsert_document( + namespace=namespace, document_for_upsert=document, **kwargs + ) From 4f10bc7c1e3607c135edd8f34f94c85a3c2df5c6 Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 08:16:19 -0700 Subject: [PATCH 03/11] temp routing name --- .../api/document_operations_api.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py b/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py index 9985bccd..feeeb530 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py +++ b/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py @@ -93,7 +93,7 @@ def __delete_document(self, namespace, document_id, **kwargs: ExtraOpenApiKwargs settings={ "response_type": (DeleteDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents/{document_id}", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents/{document_id}", "operation_id": "delete_document", "http_method": "DELETE", "servers": None, @@ -164,7 +164,7 @@ def __get_document(self, namespace, document_id, **kwargs: ExtraOpenApiKwargsTyp settings={ "response_type": (GetDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents/{document_id}", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents/{document_id}", "operation_id": "get_document", "http_method": "GET", "servers": None, @@ -233,7 +233,7 @@ def __list_documents(self, namespace, **kwargs: ExtraOpenApiKwargsTypedDict): settings={ "response_type": (ListDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents", "operation_id": "list_documents", "http_method": "GET", "servers": None, @@ -306,7 +306,7 @@ def __upsert_document( settings={ "response_type": (UpsertDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents/upsert", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents/upsert", "operation_id": "upsert_document", "http_method": "POST", "servers": None, @@ -382,7 +382,7 @@ async def __delete_document(self, namespace, document_id, **kwargs): settings={ "response_type": (DeleteDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents/{document_id}", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents/{document_id}", "operation_id": "delete_document", "http_method": "DELETE", "servers": None, @@ -446,7 +446,7 @@ async def __get_document(self, namespace, document_id, **kwargs): settings={ "response_type": (GetDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents/{document_id}", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents/{document_id}", "operation_id": "get_document", "http_method": "GET", "servers": None, @@ -508,7 +508,7 @@ async def __list_documents(self, namespace, **kwargs): settings={ "response_type": (ListDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents", "operation_id": "list_documents", "http_method": "GET", "servers": None, @@ -572,7 +572,7 @@ async def __upsert_document(self, namespace, document_for_upsert, **kwargs): settings={ "response_type": (UpsertDocumentResponse,), "auth": ["ApiKeyAuth"], - "endpoint_path": "/namespaces/{namespace}/documents/upsert", + "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents/upsert", "operation_id": "upsert_document", "http_method": "POST", "servers": None, From 408a4af72710253b1f48b69896a2b3c08e30efbe Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 11:43:08 -0700 Subject: [PATCH 04/11] fetch --- pinecone/repository/data/interfaces.py | 13 ++++++++++++- pinecone/repository/data/repository.py | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pinecone/repository/data/interfaces.py b/pinecone/repository/data/interfaces.py index 4d4b7748..8affdedc 100644 --- a/pinecone/repository/data/interfaces.py +++ b/pinecone/repository/data/interfaces.py @@ -4,6 +4,7 @@ from pinecone.core.openapi.ckb_knowledge_data.models import ( DocumentForUpsert, UpsertDocumentResponse, + GetDocumentResponse, ) @@ -16,6 +17,16 @@ def upsert( Upserts a document into a Pinecone Repository. Returns: - `UpsertDocumentResponse`, includes the number of vectors upserted. + `UpsertDocumentResponse` + """ + pass + + @abstractmethod + def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentResponse: + """ + Fetches a document from a Pinecone Repository. + + Returns: + `GetDocumentResponse` """ pass diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py index 00aaf9d3..891fed08 100644 --- a/pinecone/repository/data/repository.py +++ b/pinecone/repository/data/repository.py @@ -13,6 +13,7 @@ from pinecone.core.openapi.ckb_knowledge_data.models import ( DocumentForUpsert, UpsertDocumentResponse, + GetDocumentResponse, ) from .interfaces import RepositoryInterface @@ -77,3 +78,8 @@ def upsert( return self._repository_api.upsert_document( namespace=namespace, document_for_upsert=document, **kwargs ) + + def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentResponse: + return self._repository_api.get_document( + namespace=namespace, document_id=document_id, **kwargs + ) From 9d3e95a586dae89a089b1001334f4fdcec4ee27a Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 11:50:13 -0700 Subject: [PATCH 05/11] list --- pinecone/repository/data/interfaces.py | 11 +++++++++++ pinecone/repository/data/repository.py | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/pinecone/repository/data/interfaces.py b/pinecone/repository/data/interfaces.py index 8affdedc..a17d4aef 100644 --- a/pinecone/repository/data/interfaces.py +++ b/pinecone/repository/data/interfaces.py @@ -5,6 +5,7 @@ DocumentForUpsert, UpsertDocumentResponse, GetDocumentResponse, + ListDocumentResponse, ) @@ -30,3 +31,13 @@ def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentRespon `GetDocumentResponse` """ pass + + @abstractmethod + def list(self, namespace: str, **kwargs) -> ListDocumentResponse: + """ + Lists the documents in a Pinecone Repository. + + Returns: + `ListDocumentsResponse` + """ + pass diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py index 891fed08..110d7862 100644 --- a/pinecone/repository/data/repository.py +++ b/pinecone/repository/data/repository.py @@ -14,6 +14,7 @@ DocumentForUpsert, UpsertDocumentResponse, GetDocumentResponse, + ListDocumentResponse, ) from .interfaces import RepositoryInterface @@ -83,3 +84,6 @@ def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentRespon return self._repository_api.get_document( namespace=namespace, document_id=document_id, **kwargs ) + + def list(self, namespace: str, **kwargs) -> ListDocumentResponse: + return self._repository_api.list_documents(namespace=namespace, **kwargs) From b1c8a11ff5acd792cb47171e111959ac876162cc Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 11:54:06 -0700 Subject: [PATCH 06/11] type name --- .../api/document_operations_api.py | 12 ++++++------ ...cument_response.py => list_documents_response.py} | 8 ++++---- .../openapi/ckb_knowledge_data/models/__init__.py | 4 ++-- pinecone/repository/data/interfaces.py | 4 ++-- pinecone/repository/data/repository.py | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) rename pinecone/core/openapi/ckb_knowledge_data/model/{list_document_response.py => list_documents_response.py} (98%) diff --git a/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py b/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py index feeeb530..58b97fd8 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py +++ b/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py @@ -28,8 +28,8 @@ ) from pinecone.core.openapi.ckb_knowledge_data.model.document_for_upsert import DocumentForUpsert from pinecone.core.openapi.ckb_knowledge_data.model.get_document_response import GetDocumentResponse -from pinecone.core.openapi.ckb_knowledge_data.model.list_document_response import ( - ListDocumentResponse, +from pinecone.core.openapi.ckb_knowledge_data.model.list_documents_response import ( + ListDocumentsResponse, ) from pinecone.core.openapi.ckb_knowledge_data.model.upsert_document_response import ( UpsertDocumentResponse, @@ -221,7 +221,7 @@ def __list_documents(self, namespace, **kwargs: ExtraOpenApiKwargsTypedDict): async_req (bool): execute request asynchronously Returns: - ListDocumentResponse + ListDocumentsResponse If the method is called asynchronously, returns the request thread. """ @@ -231,7 +231,7 @@ def __list_documents(self, namespace, **kwargs: ExtraOpenApiKwargsTypedDict): self.list_documents = _Endpoint( settings={ - "response_type": (ListDocumentResponse,), + "response_type": (ListDocumentsResponse,), "auth": ["ApiKeyAuth"], "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents", "operation_id": "list_documents", @@ -498,7 +498,7 @@ async def __list_documents(self, namespace, **kwargs): Default is True. Returns: - ListDocumentResponse + ListDocumentsResponse """ self._process_openapi_kwargs(kwargs) kwargs["namespace"] = namespace @@ -506,7 +506,7 @@ async def __list_documents(self, namespace, **kwargs): self.list_documents = _AsyncioEndpoint( settings={ - "response_type": (ListDocumentResponse,), + "response_type": (ListDocumentsResponse,), "auth": ["ApiKeyAuth"], "endpoint_path": "/ckb-stub-namespaces/{namespace}/documents", "operation_id": "list_documents", diff --git a/pinecone/core/openapi/ckb_knowledge_data/model/list_document_response.py b/pinecone/core/openapi/ckb_knowledge_data/model/list_documents_response.py similarity index 98% rename from pinecone/core/openapi/ckb_knowledge_data/model/list_document_response.py rename to pinecone/core/openapi/ckb_knowledge_data/model/list_documents_response.py index 340a894e..acc1535c 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/model/list_document_response.py +++ b/pinecone/core/openapi/ckb_knowledge_data/model/list_documents_response.py @@ -44,10 +44,10 @@ def lazy_import(): from typing import Dict, Literal, Tuple, Set, Any, Type, TypeVar from pinecone.openapi_support import PropertyValidationTypedDict, cached_class_property -T = TypeVar("T", bound="ListDocumentResponse") +T = TypeVar("T", bound="ListDocumentsResponse") -class ListDocumentResponse(ModelNormal): +class ListDocumentsResponse(ModelNormal): """NOTE: This class is @generated using OpenAPI. Do not edit the class manually. @@ -128,7 +128,7 @@ def discriminator(cls): def _from_openapi_data( cls: Type[T], namespace, documents, usage, lsn_status, *args, **kwargs ) -> T: # noqa: E501 - """ListDocumentResponse - a model defined in OpenAPI + """ListDocumentsResponse - a model defined in OpenAPI Args: namespace (str): Namespace of the documents to fetch. @@ -228,7 +228,7 @@ def _from_openapi_data( @convert_js_args_to_python_args def __init__(self, namespace, documents, usage, lsn_status, *args, **kwargs) -> None: # noqa: E501 - """ListDocumentResponse - a model defined in OpenAPI + """ListDocumentsResponse - a model defined in OpenAPI Args: namespace (str): Namespace of the documents to fetch. diff --git a/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py b/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py index 48f85e20..eda1a229 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py +++ b/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py @@ -17,8 +17,8 @@ from pinecone.core.openapi.ckb_knowledge_data.model.document_list import DocumentList from pinecone.core.openapi.ckb_knowledge_data.model.get_document_response import GetDocumentResponse from pinecone.core.openapi.ckb_knowledge_data.model.lsn_status import LSNStatus -from pinecone.core.openapi.ckb_knowledge_data.model.list_document_response import ( - ListDocumentResponse, +from pinecone.core.openapi.ckb_knowledge_data.model.list_documents_response import ( + ListDocumentsResponse, ) from pinecone.core.openapi.ckb_knowledge_data.model.pagination_response import PaginationResponse from pinecone.core.openapi.ckb_knowledge_data.model.upsert_document_response import ( diff --git a/pinecone/repository/data/interfaces.py b/pinecone/repository/data/interfaces.py index a17d4aef..4b18e23e 100644 --- a/pinecone/repository/data/interfaces.py +++ b/pinecone/repository/data/interfaces.py @@ -5,7 +5,7 @@ DocumentForUpsert, UpsertDocumentResponse, GetDocumentResponse, - ListDocumentResponse, + ListDocumentsResponse, ) @@ -33,7 +33,7 @@ def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentRespon pass @abstractmethod - def list(self, namespace: str, **kwargs) -> ListDocumentResponse: + def list(self, namespace: str, **kwargs) -> ListDocumentsResponse: """ Lists the documents in a Pinecone Repository. diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py index 110d7862..dca8ca01 100644 --- a/pinecone/repository/data/repository.py +++ b/pinecone/repository/data/repository.py @@ -14,7 +14,7 @@ DocumentForUpsert, UpsertDocumentResponse, GetDocumentResponse, - ListDocumentResponse, + ListDocumentsResponse, ) from .interfaces import RepositoryInterface @@ -85,5 +85,5 @@ def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentRespon namespace=namespace, document_id=document_id, **kwargs ) - def list(self, namespace: str, **kwargs) -> ListDocumentResponse: + def list(self, namespace: str, **kwargs) -> ListDocumentsResponse: return self._repository_api.list_documents(namespace=namespace, **kwargs) From bbd88c2a7f021e2c6361dc0039e00db3fbabc45a Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 12:14:09 -0700 Subject: [PATCH 07/11] inline request body for upsert --- .../api/document_operations_api.py | 39 +-- .../model/document_for_upsert.py | 270 ------------------ .../ckb_knowledge_data/models/__init__.py | 1 - 3 files changed, 21 insertions(+), 289 deletions(-) delete mode 100644 pinecone/core/openapi/ckb_knowledge_data/model/document_for_upsert.py diff --git a/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py b/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py index 58b97fd8..bd7f1f6b 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py +++ b/pinecone/core/openapi/ckb_knowledge_data/api/document_operations_api.py @@ -26,7 +26,6 @@ from pinecone.core.openapi.ckb_knowledge_data.model.delete_document_response import ( DeleteDocumentResponse, ) -from pinecone.core.openapi.ckb_knowledge_data.model.document_for_upsert import DocumentForUpsert from pinecone.core.openapi.ckb_knowledge_data.model.get_document_response import GetDocumentResponse from pinecone.core.openapi.ckb_knowledge_data.model.list_documents_response import ( ListDocumentsResponse, @@ -258,21 +257,19 @@ def __list_documents(self, namespace, **kwargs: ExtraOpenApiKwargsTypedDict): callable=__list_documents, ) - def __upsert_document( - self, namespace, document_for_upsert, **kwargs: ExtraOpenApiKwargsTypedDict - ): + def __upsert_document(self, namespace, request_body, **kwargs: ExtraOpenApiKwargsTypedDict): """Create or update a document in the given namespace # noqa: E501 Upserts a document into the specified namespace. The request body may contain any valid JSON document that conforms to the schema. Optionally, an `_id` field can be provided to use as the document's identifier; if omitted, the system will assign one. # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.upsert_document(namespace, document_for_upsert, async_req=True) + >>> thread = api.upsert_document(namespace, request_body, async_req=True) >>> result = thread.get() Args: namespace (str): Namespace where the document will be stored. - document_for_upsert (DocumentForUpsert): + request_body ({str: (bool, dict, float, int, list, str, none_type)}): Keyword Args: _return_http_data_only (bool): response data without head status @@ -299,7 +296,7 @@ def __upsert_document( """ kwargs = self._process_openapi_kwargs(kwargs) kwargs["namespace"] = namespace - kwargs["document_for_upsert"] = document_for_upsert + kwargs["request_body"] = request_body return self.call_with_http_info(**kwargs) self.upsert_document = _Endpoint( @@ -312,8 +309,8 @@ def __upsert_document( "servers": None, }, params_map={ - "all": ["namespace", "document_for_upsert"], - "required": ["namespace", "document_for_upsert"], + "all": ["namespace", "request_body"], + "required": ["namespace", "request_body"], "nullable": [], "enum": [], "validation": [], @@ -321,9 +318,12 @@ def __upsert_document( root_map={ "validations": {}, "allowed_values": {}, - "openapi_types": {"namespace": (str,), "document_for_upsert": (DocumentForUpsert,)}, + "openapi_types": { + "namespace": (str,), + "request_body": ({str: (bool, dict, float, int, list, str, none_type)},), + }, "attribute_map": {"namespace": "namespace"}, - "location_map": {"namespace": "path", "document_for_upsert": "body"}, + "location_map": {"namespace": "path", "request_body": "body"}, "collection_format_map": {}, }, headers_map={"accept": ["application/json"], "content_type": ["application/json"]}, @@ -533,7 +533,7 @@ async def __list_documents(self, namespace, **kwargs): callable=__list_documents, ) - async def __upsert_document(self, namespace, document_for_upsert, **kwargs): + async def __upsert_document(self, namespace, request_body, **kwargs): """Create or update a document in the given namespace # noqa: E501 Upserts a document into the specified namespace. The request body may contain any valid JSON document that conforms to the schema. Optionally, an `_id` field can be provided to use as the document's identifier; if omitted, the system will assign one. # noqa: E501 @@ -541,7 +541,7 @@ async def __upsert_document(self, namespace, document_for_upsert, **kwargs): Args: namespace (str): Namespace where the document will be stored. - document_for_upsert (DocumentForUpsert): + request_body ({str: (bool, dict, float, int, list, str, none_type)}): Keyword Args: _return_http_data_only (bool): response data without head status @@ -565,7 +565,7 @@ async def __upsert_document(self, namespace, document_for_upsert, **kwargs): """ self._process_openapi_kwargs(kwargs) kwargs["namespace"] = namespace - kwargs["document_for_upsert"] = document_for_upsert + kwargs["request_body"] = request_body return await self.call_with_http_info(**kwargs) self.upsert_document = _AsyncioEndpoint( @@ -578,8 +578,8 @@ async def __upsert_document(self, namespace, document_for_upsert, **kwargs): "servers": None, }, params_map={ - "all": ["namespace", "document_for_upsert"], - "required": ["namespace", "document_for_upsert"], + "all": ["namespace", "request_body"], + "required": ["namespace", "request_body"], "nullable": [], "enum": [], "validation": [], @@ -587,9 +587,12 @@ async def __upsert_document(self, namespace, document_for_upsert, **kwargs): root_map={ "validations": {}, "allowed_values": {}, - "openapi_types": {"namespace": (str,), "document_for_upsert": (DocumentForUpsert,)}, + "openapi_types": { + "namespace": (str,), + "request_body": ({str: (bool, dict, float, int, list, str, none_type)},), + }, "attribute_map": {"namespace": "namespace"}, - "location_map": {"namespace": "path", "document_for_upsert": "body"}, + "location_map": {"namespace": "path", "request_body": "body"}, "collection_format_map": {}, }, headers_map={"accept": ["application/json"], "content_type": ["application/json"]}, diff --git a/pinecone/core/openapi/ckb_knowledge_data/model/document_for_upsert.py b/pinecone/core/openapi/ckb_knowledge_data/model/document_for_upsert.py deleted file mode 100644 index 1c8b4b67..00000000 --- a/pinecone/core/openapi/ckb_knowledge_data/model/document_for_upsert.py +++ /dev/null @@ -1,270 +0,0 @@ -""" -Pinecone Knowledge Base Data Plane API - -Pinecone Knowledge Base builds on the vector database to make it easy to store, search and retrieve your data. # noqa: E501 - -This file is @generated using OpenAPI. - -The version of the OpenAPI document: unstable -Contact: support@pinecone.io -""" - -from pinecone.openapi_support.model_utils import ( # noqa: F401 - PineconeApiTypeError, - ModelComposed, - ModelNormal, - ModelSimple, - OpenApiModel, - cached_property, - change_keys_js_to_python, - convert_js_args_to_python_args, - date, - datetime, - file_type, - none_type, - validate_get_composed_info, -) -from pinecone.openapi_support.exceptions import PineconeApiAttributeError - - -from typing import Dict, Literal, Tuple, Set, Any, Type, TypeVar -from pinecone.openapi_support import PropertyValidationTypedDict, cached_class_property - -T = TypeVar("T", bound="DocumentForUpsert") - - -class DocumentForUpsert(ModelNormal): - """NOTE: This class is @generated using OpenAPI. - - Do not edit the class manually. - - Attributes: - allowed_values (dict): The key is the tuple path to the attribute - and the for var_name this is (var_name,). The value is a dict - with a capitalized key describing the allowed value and an allowed - value. These dicts store the allowed enum values. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - discriminator_value_class_map (dict): A dict to go from the discriminator - variable value to the discriminator class name. - validations (dict): The key is the tuple path to the attribute - and the for var_name this is (var_name,). The value is a dict - that stores validations for max_length, min_length, max_items, - min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum, - inclusive_minimum, and regex. - additional_properties_type (tuple): A tuple of classes accepted - as additional properties values. - """ - - _data_store: Dict[str, Any] - _check_type: bool - - allowed_values: Dict[Tuple[str, ...], Dict[str, Any]] = {} - - validations: Dict[Tuple[str, ...], PropertyValidationTypedDict] = {} - - @cached_class_property - def additional_properties_type(cls): - """ - This must be a method because a model may have properties that are - of type self, this must run after the class is loaded - """ - return (bool, dict, float, int, list, str, none_type) # noqa: E501 - - _nullable = False - - @cached_class_property - def openapi_types(cls): - """ - This must be a method because a model may have properties that are - of type self, this must run after the class is loaded - - Returns - openapi_types (dict): The key is attribute name - and the value is attribute type. - """ - return { - "id": (str,) # noqa: E501 - } - - @cached_class_property - def discriminator(cls): - return None - - attribute_map: Dict[str, str] = { - "id": "_id" # noqa: E501 - } - - read_only_vars: Set[str] = set([]) - - _composed_schemas: Dict[Literal["allOf", "oneOf", "anyOf"], Any] = {} - - @classmethod - @convert_js_args_to_python_args - def _from_openapi_data(cls: Type[T], *args, **kwargs) -> T: # noqa: E501 - """DocumentForUpsert - a model defined in OpenAPI - - Keyword Args: - _check_type (bool): if True, values for parameters in openapi_types - will be type checked and a TypeError will be - raised if the wrong type is input. - Defaults to True - _path_to_item (tuple/list): This is a list of keys or values to - drill down to the model in received_data - when deserializing a response - _spec_property_naming (bool): True if the variable names in the input data - are serialized names, as specified in the OpenAPI document. - False if the variable names in the input data - are pythonic names, e.g. snake case (default) - _configuration (Configuration): the instance to use when - deserializing a file_type parameter. - If passed, type conversion is attempted - If omitted no type conversion is done. - _visited_composed_classes (tuple): This stores a tuple of - classes that we have traveled through so that - if we see that class again we will not use its - discriminator again. - When traveling through a discriminator, the - composed schema that is - is traveled through is added to this set. - For example if Animal has a discriminator - petType and we pass in "Dog", and the class Dog - allOf includes Animal, we move through Animal - once using the discriminator, and pick Dog. - Then in Dog, we will make an instance of the - Animal class but this time we won't travel - through its discriminator because we passed in - _visited_composed_classes = (Animal,) - id (str): Optional unique identifier for the document. If not provided, a new ID will be generated. [optional] # noqa: E501 - """ - - _enforce_allowed_values = kwargs.pop("_enforce_allowed_values", False) - _enforce_validations = kwargs.pop("_enforce_validations", False) - _check_type = kwargs.pop("_check_type", True) - _spec_property_naming = kwargs.pop("_spec_property_naming", False) - _path_to_item = kwargs.pop("_path_to_item", ()) - _configuration = kwargs.pop("_configuration", None) - _visited_composed_classes = kwargs.pop("_visited_composed_classes", ()) - - self = super(OpenApiModel, cls).__new__(cls) - - if args: - raise PineconeApiTypeError( - "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." - % (args, self.__class__.__name__), - path_to_item=_path_to_item, - valid_classes=(self.__class__,), - ) - - self._data_store = {} - self._enforce_allowed_values = _enforce_allowed_values - self._enforce_validations = _enforce_validations - self._check_type = _check_type - self._spec_property_naming = _spec_property_naming - self._path_to_item = _path_to_item - self._configuration = _configuration - self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - - for var_name, var_value in kwargs.items(): - if ( - var_name not in self.attribute_map - and self._configuration is not None - and self._configuration.discard_unknown_keys - and self.additional_properties_type is None - ): - # discard variable. - continue - setattr(self, var_name, var_value) - return self - - required_properties = set( - [ - "_enforce_allowed_values", - "_enforce_validations", - "_data_store", - "_check_type", - "_spec_property_naming", - "_path_to_item", - "_configuration", - "_visited_composed_classes", - ] - ) - - @convert_js_args_to_python_args - def __init__(self, *args, **kwargs) -> None: # noqa: E501 - """DocumentForUpsert - a model defined in OpenAPI - - Keyword Args: - _check_type (bool): if True, values for parameters in openapi_types - will be type checked and a TypeError will be - raised if the wrong type is input. - Defaults to True - _path_to_item (tuple/list): This is a list of keys or values to - drill down to the model in received_data - when deserializing a response - _spec_property_naming (bool): True if the variable names in the input data - are serialized names, as specified in the OpenAPI document. - False if the variable names in the input data - are pythonic names, e.g. snake case (default) - _configuration (Configuration): the instance to use when - deserializing a file_type parameter. - If passed, type conversion is attempted - If omitted no type conversion is done. - _visited_composed_classes (tuple): This stores a tuple of - classes that we have traveled through so that - if we see that class again we will not use its - discriminator again. - When traveling through a discriminator, the - composed schema that is - is traveled through is added to this set. - For example if Animal has a discriminator - petType and we pass in "Dog", and the class Dog - allOf includes Animal, we move through Animal - once using the discriminator, and pick Dog. - Then in Dog, we will make an instance of the - Animal class but this time we won't travel - through its discriminator because we passed in - _visited_composed_classes = (Animal,) - id (str): Optional unique identifier for the document. If not provided, a new ID will be generated. [optional] # noqa: E501 - """ - - _enforce_allowed_values = kwargs.pop("_enforce_allowed_values", True) - _enforce_validations = kwargs.pop("_enforce_validations", True) - _check_type = kwargs.pop("_check_type", True) - _spec_property_naming = kwargs.pop("_spec_property_naming", False) - _path_to_item = kwargs.pop("_path_to_item", ()) - _configuration = kwargs.pop("_configuration", None) - _visited_composed_classes = kwargs.pop("_visited_composed_classes", ()) - - if args: - raise PineconeApiTypeError( - "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." - % (args, self.__class__.__name__), - path_to_item=_path_to_item, - valid_classes=(self.__class__,), - ) - - self._data_store = {} - self._enforce_allowed_values = _enforce_allowed_values - self._enforce_validations = _enforce_validations - self._check_type = _check_type - self._spec_property_naming = _spec_property_naming - self._path_to_item = _path_to_item - self._configuration = _configuration - self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - - for var_name, var_value in kwargs.items(): - if ( - var_name not in self.attribute_map - and self._configuration is not None - and self._configuration.discard_unknown_keys - and self.additional_properties_type is None - ): - # discard variable. - continue - setattr(self, var_name, var_value) - if var_name in self.read_only_vars: - raise PineconeApiAttributeError( - f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " - f"class with read only attributes." - ) diff --git a/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py b/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py index eda1a229..2ed32fa1 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py +++ b/pinecone/core/openapi/ckb_knowledge_data/models/__init__.py @@ -13,7 +13,6 @@ DeleteDocumentResponse, ) from pinecone.core.openapi.ckb_knowledge_data.model.document import Document -from pinecone.core.openapi.ckb_knowledge_data.model.document_for_upsert import DocumentForUpsert from pinecone.core.openapi.ckb_knowledge_data.model.document_list import DocumentList from pinecone.core.openapi.ckb_knowledge_data.model.get_document_response import GetDocumentResponse from pinecone.core.openapi.ckb_knowledge_data.model.lsn_status import LSNStatus From 49ed4e218b65637f6d8d64ba75fd2e160f6511b8 Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 12:24:16 -0700 Subject: [PATCH 08/11] upsert request body --- pinecone/repository/data/__init__.py | 4 ++-- pinecone/repository/data/interfaces.py | 7 ++----- pinecone/repository/data/repository.py | 12 +++--------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/pinecone/repository/data/__init__.py b/pinecone/repository/data/__init__.py index 0dbfe3b2..53ed5c59 100644 --- a/pinecone/repository/data/__init__.py +++ b/pinecone/repository/data/__init__.py @@ -1,10 +1,10 @@ -from .repository import Repository, DocumentForUpsert, UpsertDocumentResponse +from .repository import Repository, UpsertDocumentResponse _Repository = Repository # alias for backwards compatibility -__all__ = ["_Repository", "DocumentForUpsert", "UpsertDocumentResponse"] +__all__ = ["_Repository", "UpsertDocumentResponse"] def __getattr__(name): diff --git a/pinecone/repository/data/interfaces.py b/pinecone/repository/data/interfaces.py index 4b18e23e..def1b497 100644 --- a/pinecone/repository/data/interfaces.py +++ b/pinecone/repository/data/interfaces.py @@ -1,8 +1,7 @@ from abc import ABC, abstractmethod -from typing import Union, Dict, Any +from typing import Dict, Any from pinecone.core.openapi.ckb_knowledge_data.models import ( - DocumentForUpsert, UpsertDocumentResponse, GetDocumentResponse, ListDocumentsResponse, @@ -11,9 +10,7 @@ class RepositoryInterface(ABC): @abstractmethod - def upsert( - self, namespace: str, document: Union[Dict[str, Any], DocumentForUpsert], **kwargs - ) -> UpsertDocumentResponse: + def upsert(self, namespace: str, document: Dict[str, Any], **kwargs) -> UpsertDocumentResponse: """ Upserts a document into a Pinecone Repository. diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py index dca8ca01..a7a155ed 100644 --- a/pinecone/repository/data/repository.py +++ b/pinecone/repository/data/repository.py @@ -1,5 +1,5 @@ import logging -from typing import Union, Optional, Dict, Any +from typing import Optional, Dict, Any from pinecone.config import ConfigBuilder @@ -11,7 +11,6 @@ from pinecone.openapi_support import ApiClient from pinecone.core.openapi.ckb_knowledge_data.models import ( - DocumentForUpsert, UpsertDocumentResponse, GetDocumentResponse, ListDocumentsResponse, @@ -70,14 +69,9 @@ def __init__( self._api_client = self._repository_api.api_client - def upsert( - self, namespace: str, document: Union[Dict[str, Any], DocumentForUpsert], **kwargs - ) -> UpsertDocumentResponse: - if isinstance(document, dict): - document = DocumentForUpsert(**document) - + def upsert(self, namespace: str, document: Dict[str, Any], **kwargs) -> UpsertDocumentResponse: return self._repository_api.upsert_document( - namespace=namespace, document_for_upsert=document, **kwargs + namespace=namespace, request_body=document, **kwargs ) def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentResponse: From c8b45483df87070200f587e56176d761cb8c57f7 Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:45:49 -0700 Subject: [PATCH 09/11] _id magic --- .../model/delete_document_response.py | 16 ++++++++-------- .../openapi/ckb_knowledge_data/model/document.py | 16 ++++++++-------- .../model/upsert_document_response.py | 16 ++++++++-------- pinecone/repository/data/repository.py | 10 ++++++++-- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/pinecone/core/openapi/ckb_knowledge_data/model/delete_document_response.py b/pinecone/core/openapi/ckb_knowledge_data/model/delete_document_response.py index 8de62577..92eeebdd 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/model/delete_document_response.py +++ b/pinecone/core/openapi/ckb_knowledge_data/model/delete_document_response.py @@ -94,7 +94,7 @@ def openapi_types(cls): """ lazy_import() return { - "id": (str,), # noqa: E501 + "_id": (str,), # noqa: E501 "namespace": (str,), # noqa: E501 "usage": (Usage,), # noqa: E501 "lsn_status": (LSNStatus,), # noqa: E501 @@ -105,7 +105,7 @@ def discriminator(cls): return None attribute_map: Dict[str, str] = { - "id": "_id", # noqa: E501 + "_id": "_id", # noqa: E501 "namespace": "namespace", # noqa: E501 "usage": "usage", # noqa: E501 "lsn_status": "_lsn_status", # noqa: E501 @@ -117,11 +117,11 @@ def discriminator(cls): @classmethod @convert_js_args_to_python_args - def _from_openapi_data(cls: Type[T], id, namespace, usage, lsn_status, *args, **kwargs) -> T: # noqa: E501 + def _from_openapi_data(cls: Type[T], _id, namespace, usage, lsn_status, *args, **kwargs) -> T: # noqa: E501 """DeleteDocumentResponse - a model defined in OpenAPI Args: - id (str): Identifier of the document to be deleted. + _id (str): Identifier of the document to be deleted. namespace (str): Namespace of the document to be deleted. usage (Usage): lsn_status (LSNStatus): @@ -186,7 +186,7 @@ def _from_openapi_data(cls: Type[T], id, namespace, usage, lsn_status, *args, ** self._configuration = _configuration self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - self.id = id + self._id = _id self.namespace = namespace self.usage = usage self.lsn_status = lsn_status @@ -216,11 +216,11 @@ def _from_openapi_data(cls: Type[T], id, namespace, usage, lsn_status, *args, ** ) @convert_js_args_to_python_args - def __init__(self, id, namespace, usage, lsn_status, *args, **kwargs) -> None: # noqa: E501 + def __init__(self, _id, namespace, usage, lsn_status, *args, **kwargs) -> None: # noqa: E501 """DeleteDocumentResponse - a model defined in OpenAPI Args: - id (str): Identifier of the document to be deleted. + _id (str): Identifier of the document to be deleted. namespace (str): Namespace of the document to be deleted. usage (Usage): lsn_status (LSNStatus): @@ -283,7 +283,7 @@ def __init__(self, id, namespace, usage, lsn_status, *args, **kwargs) -> None: self._configuration = _configuration self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - self.id = id + self._id = _id self.namespace = namespace self.usage = usage self.lsn_status = lsn_status diff --git a/pinecone/core/openapi/ckb_knowledge_data/model/document.py b/pinecone/core/openapi/ckb_knowledge_data/model/document.py index e6b69feb..66138f14 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/model/document.py +++ b/pinecone/core/openapi/ckb_knowledge_data/model/document.py @@ -84,7 +84,7 @@ def openapi_types(cls): and the value is attribute type. """ return { - "id": (str,) # noqa: E501 + "_id": (str,) # noqa: E501 } @cached_class_property @@ -92,7 +92,7 @@ def discriminator(cls): return None attribute_map: Dict[str, str] = { - "id": "_id" # noqa: E501 + "_id": "_id" # noqa: E501 } read_only_vars: Set[str] = set([]) @@ -101,11 +101,11 @@ def discriminator(cls): @classmethod @convert_js_args_to_python_args - def _from_openapi_data(cls: Type[T], id, *args, **kwargs) -> T: # noqa: E501 + def _from_openapi_data(cls: Type[T], _id, *args, **kwargs) -> T: # noqa: E501 """Document - a model defined in OpenAPI Args: - id (str): Unique identifier for the document. + _id (str): Unique identifier for the document. Keyword Args: _check_type (bool): if True, values for parameters in openapi_types @@ -167,7 +167,7 @@ def _from_openapi_data(cls: Type[T], id, *args, **kwargs) -> T: # noqa: E501 self._configuration = _configuration self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - self.id = id + self._id = _id for var_name, var_value in kwargs.items(): if ( var_name not in self.attribute_map @@ -194,11 +194,11 @@ def _from_openapi_data(cls: Type[T], id, *args, **kwargs) -> T: # noqa: E501 ) @convert_js_args_to_python_args - def __init__(self, id, *args, **kwargs) -> None: # noqa: E501 + def __init__(self, _id, *args, **kwargs) -> None: # noqa: E501 """Document - a model defined in OpenAPI Args: - id (str): Unique identifier for the document. + _id (str): Unique identifier for the document. Keyword Args: _check_type (bool): if True, values for parameters in openapi_types @@ -258,7 +258,7 @@ def __init__(self, id, *args, **kwargs) -> None: # noqa: E501 self._configuration = _configuration self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - self.id = id + self._id = _id for var_name, var_value in kwargs.items(): if ( var_name not in self.attribute_map diff --git a/pinecone/core/openapi/ckb_knowledge_data/model/upsert_document_response.py b/pinecone/core/openapi/ckb_knowledge_data/model/upsert_document_response.py index 0df0c51b..b0f0eebe 100644 --- a/pinecone/core/openapi/ckb_knowledge_data/model/upsert_document_response.py +++ b/pinecone/core/openapi/ckb_knowledge_data/model/upsert_document_response.py @@ -92,7 +92,7 @@ def openapi_types(cls): """ lazy_import() return { - "id": (str,), # noqa: E501 + "_id": (str,), # noqa: E501 "namespace": (str,), # noqa: E501 "lsn_status": (LSNStatus,), # noqa: E501 } @@ -102,7 +102,7 @@ def discriminator(cls): return None attribute_map: Dict[str, str] = { - "id": "_id", # noqa: E501 + "_id": "_id", # noqa: E501 "namespace": "namespace", # noqa: E501 "lsn_status": "_lsn_status", # noqa: E501 } @@ -113,11 +113,11 @@ def discriminator(cls): @classmethod @convert_js_args_to_python_args - def _from_openapi_data(cls: Type[T], id, namespace, lsn_status, *args, **kwargs) -> T: # noqa: E501 + def _from_openapi_data(cls: Type[T], _id, namespace, lsn_status, *args, **kwargs) -> T: # noqa: E501 """UpsertDocumentResponse - a model defined in OpenAPI Args: - id (str): Identifier of the document to be created or updated. + _id (str): Identifier of the document to be created or updated. namespace (str): Namespace of the document to be created or updated. lsn_status (LSNStatus): @@ -181,7 +181,7 @@ def _from_openapi_data(cls: Type[T], id, namespace, lsn_status, *args, **kwargs) self._configuration = _configuration self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - self.id = id + self._id = _id self.namespace = namespace self.lsn_status = lsn_status for var_name, var_value in kwargs.items(): @@ -210,11 +210,11 @@ def _from_openapi_data(cls: Type[T], id, namespace, lsn_status, *args, **kwargs) ) @convert_js_args_to_python_args - def __init__(self, id, namespace, lsn_status, *args, **kwargs) -> None: # noqa: E501 + def __init__(self, _id, namespace, lsn_status, *args, **kwargs) -> None: # noqa: E501 """UpsertDocumentResponse - a model defined in OpenAPI Args: - id (str): Identifier of the document to be created or updated. + _id (str): Identifier of the document to be created or updated. namespace (str): Namespace of the document to be created or updated. lsn_status (LSNStatus): @@ -276,7 +276,7 @@ def __init__(self, id, namespace, lsn_status, *args, **kwargs) -> None: # noqa: self._configuration = _configuration self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - self.id = id + self._id = _id self.namespace = namespace self.lsn_status = lsn_status for var_name, var_value in kwargs.items(): diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py index a7a155ed..0b41719e 100644 --- a/pinecone/repository/data/repository.py +++ b/pinecone/repository/data/repository.py @@ -70,8 +70,14 @@ def __init__( self._api_client = self._repository_api.api_client def upsert(self, namespace: str, document: Dict[str, Any], **kwargs) -> UpsertDocumentResponse: - return self._repository_api.upsert_document( - namespace=namespace, request_body=document, **kwargs + return self._repository_api.api_client.call_api( + resource_path=f"/ckb-stub-namespaces/{namespace}/documents/upsert", + method="POST", + path_params={"namespace": namespace}, + body=document, + header_params={"Content-Type": "application/json", "Accept": "application/json"}, + response_type=(UpsertDocumentResponse,), + _return_http_data_only=True, ) def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentResponse: From ed0b0824532a8ce3661e5d2af337e29fa0dee585 Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:46:09 -0700 Subject: [PATCH 10/11] . --- pinecone/repository/data/__init__.py | 4 +- pinecone/repository/data/repository.bak | 89 +++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 pinecone/repository/data/repository.bak diff --git a/pinecone/repository/data/__init__.py b/pinecone/repository/data/__init__.py index 53ed5c59..841989d8 100644 --- a/pinecone/repository/data/__init__.py +++ b/pinecone/repository/data/__init__.py @@ -1,10 +1,10 @@ -from .repository import Repository, UpsertDocumentResponse +from .repository import Repository _Repository = Repository # alias for backwards compatibility -__all__ = ["_Repository", "UpsertDocumentResponse"] +__all__ = ["_Repository"] def __getattr__(name): diff --git a/pinecone/repository/data/repository.bak b/pinecone/repository/data/repository.bak new file mode 100644 index 00000000..0b41719e --- /dev/null +++ b/pinecone/repository/data/repository.bak @@ -0,0 +1,89 @@ +import logging +from typing import Optional, Dict, Any + +from pinecone.config import ConfigBuilder + + +from pinecone.core.openapi.ckb_knowledge_data.api.document_operations_api import ( + DocumentOperationsApi, +) +from pinecone.core.openapi.ckb_knowledge_data import API_VERSION + +from pinecone.openapi_support import ApiClient +from pinecone.core.openapi.ckb_knowledge_data.models import ( + UpsertDocumentResponse, + GetDocumentResponse, + ListDocumentsResponse, +) + +from .interfaces import RepositoryInterface + +from pinecone.utils import setup_openapi_client + +from multiprocessing import cpu_count + + +logger = logging.getLogger(__name__) +""" :meta private: """ + + +class Repository(RepositoryInterface): + """ + A client for interacting with a Pinecone Repository API. + """ + + def __init__( + self, + api_key: str, + host: str, + pool_threads: Optional[int] = None, + additional_headers: Optional[Dict[str, str]] = {}, + openapi_config=None, + **kwargs, + ): + self._config = ConfigBuilder.build( + api_key=api_key, host=host, additional_headers=additional_headers, **kwargs + ) + """ :meta private: """ + self._openapi_config = ConfigBuilder.build_openapi_config(self._config, openapi_config) + """ :meta private: """ + + if pool_threads is None: + self._pool_threads = 5 * cpu_count() + """ :meta private: """ + else: + self._pool_threads = pool_threads + """ :meta private: """ + + if kwargs.get("connection_pool_maxsize", None): + self._openapi_config.connection_pool_maxsize = kwargs.get("connection_pool_maxsize") + + self._repository_api = setup_openapi_client( + api_client_klass=ApiClient, + api_klass=DocumentOperationsApi, + config=self._config, + openapi_config=self._openapi_config, + pool_threads=self._pool_threads, + api_version=API_VERSION, + ) + + self._api_client = self._repository_api.api_client + + def upsert(self, namespace: str, document: Dict[str, Any], **kwargs) -> UpsertDocumentResponse: + return self._repository_api.api_client.call_api( + resource_path=f"/ckb-stub-namespaces/{namespace}/documents/upsert", + method="POST", + path_params={"namespace": namespace}, + body=document, + header_params={"Content-Type": "application/json", "Accept": "application/json"}, + response_type=(UpsertDocumentResponse,), + _return_http_data_only=True, + ) + + def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentResponse: + return self._repository_api.get_document( + namespace=namespace, document_id=document_id, **kwargs + ) + + def list(self, namespace: str, **kwargs) -> ListDocumentsResponse: + return self._repository_api.list_documents(namespace=namespace, **kwargs) From b1d0308721368082fb786fd65cdaf79e6711021e Mon Sep 17 00:00:00 2001 From: Silas Smith <163026730+ssmith-pc@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:47:03 -0700 Subject: [PATCH 11/11] Simple HTTP impl --- pinecone/repository/data/repository.py | 242 ++++++++++++++++++------- 1 file changed, 179 insertions(+), 63 deletions(-) diff --git a/pinecone/repository/data/repository.py b/pinecone/repository/data/repository.py index 0b41719e..a5082aff 100644 --- a/pinecone/repository/data/repository.py +++ b/pinecone/repository/data/repository.py @@ -1,35 +1,49 @@ import logging -from typing import Optional, Dict, Any +import json +from typing import Optional, Dict, Any, Tuple +from urllib.parse import urljoin -from pinecone.config import ConfigBuilder - - -from pinecone.core.openapi.ckb_knowledge_data.api.document_operations_api import ( - DocumentOperationsApi, -) +import requests +from requests.adapters import HTTPAdapter +from urllib3.util.retry import Retry +from multiprocessing import cpu_count from pinecone.core.openapi.ckb_knowledge_data import API_VERSION -from pinecone.openapi_support import ApiClient -from pinecone.core.openapi.ckb_knowledge_data.models import ( - UpsertDocumentResponse, - GetDocumentResponse, - ListDocumentsResponse, -) +logger = logging.getLogger(__name__) -from .interfaces import RepositoryInterface -from pinecone.utils import setup_openapi_client +def _ensure_https_host(host: str) -> str: + """ + Normalizes the host value to include scheme and no trailing slash. + Accepts: "kb.example.com", "https://kb.example.com/", "http://..." + Returns: "https://kb.example.com" + """ + host = (host or "").strip() + if not host: + raise ValueError("host must be provided (e.g., 'kb.your-company.com').") + if not host.startswith(("http://", "https://")): + host = "https://" + host + # strip single trailing slash + if host.endswith("/"): + host = host[:-1] + return host -from multiprocessing import cpu_count +class HTTPError(Exception): + """Rich HTTP error including status code and server payload (if any).""" -logger = logging.getLogger(__name__) -""" :meta private: """ + def __init__(self, status_code: int, message: str, payload: Optional[dict] = None): + super().__init__(f"{status_code}: {message}") + self.status_code = status_code + self.payload = payload or {} -class Repository(RepositoryInterface): +class Repository: """ - A client for interacting with a Pinecone Repository API. + A client for interacting with the Pinecone Knowledge Base Data Plane (Documents). + Uses `requests` directly, with retries and sane defaults. + + Methods return plain `dict` responses parsed from JSON. """ def __init__( @@ -37,53 +51,155 @@ def __init__( api_key: str, host: str, pool_threads: Optional[int] = None, - additional_headers: Optional[Dict[str, str]] = {}, - openapi_config=None, + additional_headers: Optional[Dict[str, str]] = None, + openapi_config=None, # kept for backward compat; unused + echo: bool = False, **kwargs, ): - self._config = ConfigBuilder.build( - api_key=api_key, host=host, additional_headers=additional_headers, **kwargs - ) - """ :meta private: """ - self._openapi_config = ConfigBuilder.build_openapi_config(self._config, openapi_config) - """ :meta private: """ - - if pool_threads is None: - self._pool_threads = 5 * cpu_count() - """ :meta private: """ - else: - self._pool_threads = pool_threads - """ :meta private: """ - - if kwargs.get("connection_pool_maxsize", None): - self._openapi_config.connection_pool_maxsize = kwargs.get("connection_pool_maxsize") - - self._repository_api = setup_openapi_client( - api_client_klass=ApiClient, - api_klass=DocumentOperationsApi, - config=self._config, - openapi_config=self._openapi_config, - pool_threads=self._pool_threads, - api_version=API_VERSION, + self._api_key = api_key + self._base_url = _ensure_https_host(host) + self._echo = echo # store the flag + + # Connection pool sizing + self._pool_threads = 5 * cpu_count() if pool_threads is None else pool_threads + pool_maxsize = kwargs.get("connection_pool_maxsize", self._pool_threads) + + # Timeouts (connect, read). Allow overrides via kwargs + # e.g., timeout=(3.05, 30) + self._timeout: Tuple[float, float] = kwargs.get("timeout", (5.0, 60.0)) + + # Retries: conservative defaults; override via kwargs["retries"] + retries = kwargs.get( + "retries", + Retry( + total=5, + backoff_factor=0.5, + status_forcelist=(429, 500, 502, 503, 504), + allowed_methods=frozenset(["GET", "POST", "DELETE"]), + raise_on_status=False, + ), ) - self._api_client = self._repository_api.api_client - - def upsert(self, namespace: str, document: Dict[str, Any], **kwargs) -> UpsertDocumentResponse: - return self._repository_api.api_client.call_api( - resource_path=f"/ckb-stub-namespaces/{namespace}/documents/upsert", - method="POST", - path_params={"namespace": namespace}, - body=document, - header_params={"Content-Type": "application/json", "Accept": "application/json"}, - response_type=(UpsertDocumentResponse,), - _return_http_data_only=True, + self._session = requests.Session() + adapter = HTTPAdapter( + pool_connections=self._pool_threads, pool_maxsize=pool_maxsize, max_retries=retries ) - - def fetch(self, namespace: str, document_id: str, **kwargs) -> GetDocumentResponse: - return self._repository_api.get_document( - namespace=namespace, document_id=document_id, **kwargs + self._session.mount("https://", adapter) + self._session.mount("http://", adapter) + + self._default_headers = { + "Api-Key": self._api_key, + "Accept": "application/json", + "x-pinecone-api-version": API_VERSION, + # Content-Type set per request when needed + } + if additional_headers: + self._default_headers.update(additional_headers) + + # ----------------------- + # Internal request helper + # ----------------------- + def _request( + self, + method: str, + path: str, + *, + json_body: Optional[dict] = None, + headers: Optional[dict] = None, + params: Optional[dict] = None, + echo: Optional[bool] = None, + ) -> dict: + url = urljoin(self._base_url + "/", path.lstrip("/")) + hdrs = dict(self._default_headers) + if headers: + hdrs.update(headers) + if json_body is not None: + hdrs.setdefault("Content-Type", "application/json") + + logger.debug("HTTP %s %s params=%s json=%s", method, url, params, json_body) + + # decide whether to echo this call + do_echo = self._echo if echo is None else echo + if do_echo: + print("----- HTTP Request -----") + print(f"{method} {url}") + if params: + print("Params:", params) + + safe_headers = dict(hdrs) + for k, v in hdrs.items(): + print(f"checking........... {k}: {v}") + if k.lower() == "api-key": + masked = (v[:5] + "...") if isinstance(v, str) and len(v) > 5 else "..." + safe_headers[k] = masked + else: + safe_headers[k] = v + + print("Headers:", safe_headers) + if json_body is not None: + print("Body:", json.dumps(json_body, indent=2)) + print("------------------------") + + resp = self._session.request( + method=method, + url=url, + headers=hdrs, + params=params, + json=json_body, + timeout=self._timeout, ) - def list(self, namespace: str, **kwargs) -> ListDocumentsResponse: - return self._repository_api.list_documents(namespace=namespace, **kwargs) + # Try to parse JSON payload (even on errors) for better messages + payload: Optional[dict] + try: + payload = resp.json() if resp.content else None + except json.JSONDecodeError: + payload = None + + if not (200 <= resp.status_code < 300): + msg = payload.get("message") if isinstance(payload, dict) else resp.text + raise HTTPError(resp.status_code, msg or "HTTP request failed", payload) + + if payload is None: + return {} + return payload + + # ------------- + # API methods + # ------------- + def upsert(self, namespace: str, document: Dict[str, Any], **kwargs) -> dict: + """ + POST /ckb-stub-namespaces/{namespace}/documents/upsert + Returns UpsertDocumentResponse as dict. + """ + if not isinstance(document, dict): + raise TypeError("document must be a dict (JSON-serializable).") + + path = f"/ckb-stub-namespaces/{namespace}/documents/upsert" + return self._request("POST", path, json_body=document, **kwargs) + + def fetch(self, namespace: str, document_id: str, **kwargs) -> dict: + """ + GET /ckb-stub-namespaces/{namespace}/documents/{document_id} + Returns GetDocumentResponse as dict. + """ + path = f"/ckb-stub-namespaces/{namespace}/documents/{document_id}" + return self._request("GET", path, **kwargs) + + def list(self, namespace: str, **kwargs) -> dict: + """ + GET /ckb-stub-namespaces/{namespace}/documents + Returns ListDocumentsResponse as dict. + """ + path = f"/ckb-stub-namespaces/{namespace}/documents" + # Spec does not define query params, but keep hook if server adds (e.g., pagination). + params = kwargs.get("params") + return self._request("GET", path, params=params, **kwargs) + + def delete(self, namespace: str, document_id: str, **kwargs) -> dict: + """ + DELETE /ckb-stub-namespaces/{namespace}/documents/{document_id} + Returns DeleteDocumentResponse as dict. + """ + path = f"/ckb-stub-namespaces/{namespace}/documents/{document_id}" + return self._request("DELETE", path, **kwargs)