Skip to content

Commit 8553b93

Browse files
authored
Add describe, delete, and list namespaces (REST) (#507)
## Problem Add support for describe, delete, and and list namespaces for index and async index classes. ## Solution Following methods were added to the index and async index classes: 1. describe_namespace(self, namespace: str, **kwargs) -> "NamespaceDescription" 2. delete_namespace(self, namespace: str, **kwargs) -> Dict[str, Any] 3. list_namespaces: - list_namespaces(self, **kwargs) -> Iterator[ListNamespacesResponse] (for index.py) - list_namespaces(self, **kwargs) -> AsyncIterator[ListNamespacesResponse] (for index_asyncio.py) 4. list_namespaces_paginated( self, limit: Optional[int] = None, pagination_token: Optional[str] = None, **kwargs ) -> ListNamespacesResponse ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [X] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update - [ ] Infrastructure change (CI configs, etc) - [ ] Non-code change (docs, etc) - [ ] None of the above: (explain here) ## Test Plan Added integration tests for both index and async index classes
1 parent 965d353 commit 8553b93

File tree

11 files changed

+846
-2
lines changed

11 files changed

+846
-2
lines changed

pinecone/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"QueryResponse": ("pinecone.db_data.models", "QueryResponse"),
5656
"UpsertResponse": ("pinecone.db_data.models", "UpsertResponse"),
5757
"UpdateRequest": ("pinecone.db_data.models", "UpdateRequest"),
58+
"NamespaceDescription": ("pinecone.core.openapi.db_data.models", "NamespaceDescription"),
5859
"ImportErrorMode": ("pinecone.db_data.resources.sync.bulk_import", "ImportErrorMode"),
5960
"VectorDictionaryMissingKeysError": (
6061
"pinecone.db_data.errors",

pinecone/__init__.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ from pinecone.db_data.models import (
4646
UpsertResponse,
4747
UpdateRequest,
4848
)
49+
from pinecone.core.openapi.db_data.models import NamespaceDescription
4950
from pinecone.db_data.resources.sync.bulk_import import ImportErrorMode
5051
from pinecone.db_data.errors import (
5152
VectorDictionaryMissingKeysError,
@@ -130,6 +131,7 @@ __all__ = [
130131
"QueryResponse",
131132
"UpsertResponse",
132133
"UpdateRequest",
134+
"NamespaceDescription",
133135
"ImportErrorMode",
134136
# Error classes
135137
"VectorDictionaryMissingKeysError",

pinecone/db_data/index.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
UpsertResponse,
1616
ListResponse,
1717
SearchRecordsResponse,
18+
ListNamespacesResponse,
19+
NamespaceDescription,
1820
)
1921
from .dataclasses import Vector, SparseValues, FetchResponse, SearchQuery, SearchRerank
2022
from .interfaces import IndexInterface
@@ -35,6 +37,7 @@
3537
validate_and_convert_errors,
3638
filter_dict,
3739
PluginAware,
40+
require_kwargs,
3841
)
3942
from .query_results_aggregator import QueryResultsAggregator, QueryNamespacesResults
4043
from pinecone.openapi_support import OPENAPI_ENDPOINT_PARAMS
@@ -47,6 +50,7 @@
4750
if TYPE_CHECKING:
4851
from pinecone.config import Config, OpenApiConfiguration
4952
from .resources.sync.bulk_import import BulkImportResource
53+
from .resources.sync.namespace import NamespaceResource
5054

5155
from pinecone.core.openapi.db_data.models import (
5256
StartImportResponse,
@@ -75,6 +79,9 @@ class Index(PluginAware, IndexInterface):
7579
_bulk_import_resource: Optional["BulkImportResource"]
7680
""" :meta private: """
7781

82+
_namespace_resource: Optional["NamespaceResource"]
83+
""" :meta private: """
84+
7885
def __init__(
7986
self,
8087
api_key: str,
@@ -115,6 +122,9 @@ def __init__(
115122
self._bulk_import_resource = None
116123
""" :meta private: """
117124

125+
self._namespace_resource = None
126+
""" :meta private: """
127+
118128
# Pass the same api_client to the ImportFeatureMixin
119129
super().__init__(api_client=self._api_client)
120130

@@ -152,6 +162,20 @@ def bulk_import(self) -> "BulkImportResource":
152162
self._bulk_import_resource = BulkImportResource(api_client=self._api_client)
153163
return self._bulk_import_resource
154164

165+
@property
166+
def namespace(self) -> "NamespaceResource":
167+
""":meta private:"""
168+
if self._namespace_resource is None:
169+
from .resources.sync.namespace import NamespaceResource
170+
171+
self._namespace_resource = NamespaceResource(
172+
api_client=self._api_client,
173+
config=self._config,
174+
openapi_config=self._openapi_config,
175+
pool_threads=self._pool_threads,
176+
)
177+
return self._namespace_resource
178+
155179
def _openapi_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
156180
return filter_dict(kwargs, OPENAPI_ENDPOINT_PARAMS)
157181

@@ -605,3 +629,27 @@ def cancel_import(self, id: str):
605629
id (str): The id of the import operation to cancel.
606630
"""
607631
return self.bulk_import.cancel(id=id)
632+
633+
@validate_and_convert_errors
634+
@require_kwargs
635+
def describe_namespace(self, namespace: str, **kwargs) -> "NamespaceDescription":
636+
return self.namespace.describe(namespace=namespace, **kwargs)
637+
638+
@validate_and_convert_errors
639+
@require_kwargs
640+
def delete_namespace(self, namespace: str, **kwargs) -> Dict[str, Any]:
641+
return self.namespace.delete(namespace=namespace, **kwargs)
642+
643+
@validate_and_convert_errors
644+
@require_kwargs
645+
def list_namespaces(
646+
self, limit: Optional[int] = None, **kwargs
647+
) -> Iterator[ListNamespacesResponse]:
648+
return self.namespace.list(limit=limit, **kwargs)
649+
650+
@validate_and_convert_errors
651+
@require_kwargs
652+
def list_namespaces_paginated(
653+
self, limit: Optional[int] = None, pagination_token: Optional[str] = None, **kwargs
654+
) -> ListNamespacesResponse:
655+
return self.namespace.list_paginated(limit=limit, pagination_token=pagination_token, **kwargs)

pinecone/db_data/index_asyncio.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222
DeleteRequest,
2323
ListResponse,
2424
SearchRecordsResponse,
25+
ListNamespacesResponse,
26+
NamespaceDescription,
2527
)
2628

2729
from ..utils import (
2830
setup_async_openapi_client,
2931
parse_non_empty_args,
3032
validate_and_convert_errors,
3133
filter_dict,
34+
require_kwargs,
3235
)
3336
from .types import (
3437
SparseVectorTypedDict,
@@ -50,6 +53,7 @@
5053

5154
if TYPE_CHECKING:
5255
from .resources.asyncio.bulk_import_asyncio import BulkImportResourceAsyncio
56+
from .resources.asyncio.namespace_asyncio import NamespaceResourceAsyncio
5357

5458
from pinecone.core.openapi.db_data.models import (
5559
StartImportResponse,
@@ -140,6 +144,9 @@ async def main():
140144
_bulk_import_resource: Optional["BulkImportResourceAsyncio"]
141145
""" :meta private: """
142146

147+
_namespace_resource: Optional["NamespaceResourceAsyncio"]
148+
""" :meta private: """
149+
143150
def __init__(
144151
self,
145152
api_key: str,
@@ -173,6 +180,9 @@ def __init__(
173180
self._bulk_import_resource = None
174181
""" :meta private: """
175182

183+
self._namespace_resource = None
184+
""" :meta private: """
185+
176186
async def __aenter__(self):
177187
return self
178188

@@ -241,6 +251,15 @@ def bulk_import(self) -> "BulkImportResourceAsyncio":
241251
self._bulk_import_resource = BulkImportResourceAsyncio(api_client=self._api_client)
242252
return self._bulk_import_resource
243253

254+
@property
255+
def namespace(self) -> "NamespaceResourceAsyncio":
256+
""":meta private:"""
257+
if self._namespace_resource is None:
258+
from .resources.asyncio.namespace_asyncio import NamespaceResourceAsyncio
259+
260+
self._namespace_resource = NamespaceResourceAsyncio(api_client=self._api_client)
261+
return self._namespace_resource
262+
244263
@validate_and_convert_errors
245264
async def upsert(
246265
self,
@@ -650,5 +669,29 @@ async def cancel_import(self, id: str):
650669
"""
651670
return await self.bulk_import.cancel(id=id)
652671

672+
@validate_and_convert_errors
673+
@require_kwargs
674+
async def describe_namespace(self, namespace: str, **kwargs) -> "NamespaceDescription":
675+
return await self.namespace.describe(namespace=namespace, **kwargs)
676+
677+
@validate_and_convert_errors
678+
@require_kwargs
679+
async def delete_namespace(self, namespace: str, **kwargs) -> Dict[str, Any]:
680+
return await self.namespace.delete(namespace=namespace, **kwargs)
681+
682+
@validate_and_convert_errors
683+
@require_kwargs
684+
async def list_namespaces(
685+
self, limit: Optional[int] = None, **kwargs
686+
) -> AsyncIterator[ListNamespacesResponse]:
687+
async for namespace in self.namespace.list(limit=limit, **kwargs):
688+
yield namespace
689+
690+
@validate_and_convert_errors
691+
@require_kwargs
692+
async def list_namespaces_paginated(
693+
self, limit: Optional[int] = None, pagination_token: Optional[str] = None, **kwargs
694+
) -> ListNamespacesResponse:
695+
return await self.namespace.list_paginated(limit=limit, pagination_token=pagination_token, **kwargs)
653696

654697
IndexAsyncio = _IndexAsyncio

pinecone/db_data/index_asyncio_interface.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import ABC, abstractmethod
2-
from typing import Union, List, Optional, Dict, Any
2+
from typing import Union, List, Optional, Dict, Any, AsyncIterator
33

44
from pinecone.core.openapi.db_data.models import (
55
FetchResponse,
@@ -10,6 +10,8 @@
1010
ListResponse,
1111
SparseValues,
1212
SearchRecordsResponse,
13+
NamespaceDescription,
14+
ListNamespacesResponse,
1315
)
1416
from .query_results_aggregator import QueryNamespacesResults
1517
from .types import (
@@ -23,6 +25,7 @@
2325
SearchRerankTypedDict,
2426
)
2527
from .dataclasses import SearchQuery, SearchRerank
28+
from pinecone.utils import require_kwargs
2629

2730

2831
class IndexAsyncioInterface(ABC):
@@ -810,3 +813,77 @@ async def search_records(
810813
) -> SearchRecordsResponse:
811814
"""Alias of the search() method."""
812815
pass
816+
817+
@abstractmethod
818+
@require_kwargs
819+
async def describe_namespace(self, namespace: str, **kwargs) -> NamespaceDescription:
820+
"""Describe a namespace within an index, showing the vector count within the namespace.
821+
822+
Args:
823+
namespace (str): The namespace to describe
824+
825+
Returns:
826+
NamespaceDescription: Information about the namespace including vector count
827+
"""
828+
pass
829+
830+
@abstractmethod
831+
@require_kwargs
832+
async def delete_namespace(self, namespace: str, **kwargs) -> Dict[str, Any]:
833+
"""Delete a namespace from an index.
834+
835+
Args:
836+
namespace (str): The namespace to delete
837+
838+
Returns:
839+
Dict[str, Any]: Response from the delete operation
840+
"""
841+
pass
842+
843+
@abstractmethod
844+
@require_kwargs
845+
async def list_namespaces(
846+
self, limit: Optional[int] = None, **kwargs
847+
) -> AsyncIterator[ListNamespacesResponse]:
848+
"""List all namespaces in an index. This method automatically handles pagination to return all results.
849+
850+
Args:
851+
limit (Optional[int]): The maximum number of namespaces to return. If unspecified, the server will use a default value. [optional]
852+
853+
Returns:
854+
``ListNamespacesResponse``: Object containing the list of namespaces.
855+
856+
Examples:
857+
.. code-block:: python
858+
>>> async for namespace in index.list_namespaces(limit=5):
859+
... print(f"Namespace: {namespace.name}, Vector count: {namespace.vector_count}")
860+
Namespace: namespace1, Vector count: 1000
861+
Namespace: namespace2, Vector count: 2000
862+
"""
863+
pass
864+
865+
@abstractmethod
866+
@require_kwargs
867+
async def list_namespaces_paginated(
868+
self, limit: Optional[int] = None, pagination_token: Optional[str] = None, **kwargs
869+
) -> ListNamespacesResponse:
870+
"""List all namespaces in an index with pagination support. The response includes pagination information if there are more results available.
871+
872+
Consider using the ``list_namespaces`` method to avoid having to handle pagination tokens manually.
873+
874+
Args:
875+
limit (Optional[int]): The maximum number of namespaces to return. If unspecified, the server will use a default value. [optional]
876+
pagination_token (Optional[str]): A token needed to fetch the next page of results. This token is returned
877+
in the response if additional results are available. [optional]
878+
879+
Returns:
880+
``ListNamespacesResponse``: Object containing the list of namespaces and pagination information.
881+
882+
Examples:
883+
.. code-block:: python
884+
>>> results = await index.list_namespaces_paginated(limit=5)
885+
>>> results.pagination.next
886+
eyJza2lwX3Bhc3QiOiI5OTMiLCJwcmVmaXgiOiI5OSJ9
887+
>>> next_results = await index.list_namespaces_paginated(limit=5, pagination_token=results.pagination.next)
888+
"""
889+
pass

0 commit comments

Comments
 (0)