Source code for pinecone.admin.resources.project

from typing import Optional
from pinecone.exceptions import NotFoundException, PineconeException
from pinecone.openapi_support import ApiClient
from pinecone.core.openapi.admin.apis import ProjectsApi
from pinecone.utils import parse_non_empty_args, require_kwargs
from pinecone.core.openapi.admin.models import CreateProjectRequest, UpdateProjectRequest
import logging
import time

logger = logging.getLogger(__name__)


[docs] class ProjectResource: """ This class is used to create, delete, list, fetch, and update projects. .. note:: The class should not be instantiated directly. Instead, access this classes methods through the :class:`pinecone.Admin` class's :attr:`project` or :attr:`projects` attributes. .. code-block:: python from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() # Now call project methods on the projects namespace project = admin.projects.create( name="my-project", max_pods=10, force_encryption_with_cmek=False ) """ def __init__(self, api_client: ApiClient): """ Initialize the ProjectResource. .. warning:: This class should not be instantiated directly. Instead, access this classes methods through the :class:`pinecone.Admin` class's :attr:`project` or :attr:`projects` attributes. :param api_client: The API client to use. :type api_client: ApiClient """ self._projects_api = ProjectsApi(api_client=api_client) self._api_client = api_client
[docs] @require_kwargs def list(self): """ List all projects in the organization. :return: An object with a list of projects. :rtype: {"data": [Project]} .. code-block:: python :caption: List all projects in the organization :emphasize-lines: 8 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() # List all projects in the organization projects_response = admin.projects.list() for project in projects_response.data: print(project.id) print(project.name) print(project.max_pods) print(project.force_encryption_with_cmek) """ return self._projects_api.list_projects()
[docs] @require_kwargs def fetch(self, project_id: Optional[str] = None, name: Optional[str] = None): """ Fetch a project by project_id or name. :param project_id: The project_id of the project to fetch. :type project_id: str :param name: The name of the project to fetch. :type name: str :return: The project. :rtype: Project Examples -------- .. code-block:: python :caption: Fetch a project by project_id :emphasize-lines: 7-9 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project = admin.projects.fetch( project_id="42ca341d-43bf-47cb-9f27-e645dbfabea6" ) print(project.id) print(project.name) print(project.max_pods) print(project.force_encryption_with_cmek) print(project.organization_id) print(project.created_at) .. code-block:: python :caption: Fetch a project by name :emphasize-lines: 7 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project = admin.projects.fetch(name="my-project-name") print(project.id) print(project.name) print(project.max_pods) print(project.force_encryption_with_cmek) print(project.organization_id) print(project.created_at) """ if project_id is not None and name is not None: raise ValueError("Either project_id or name must be provided but not both") elif project_id is None and name is None: raise ValueError("Either project_id or name must be provided") if project_id is not None: return self._projects_api.fetch_project(project_id=project_id) else: projects = self.list().data projects = [project for project in projects if project.name == name] if len(projects) == 0: raise NotFoundException(f"Project with name '{name}' not found") elif len(projects) > 1: ids = [project.id for project in projects] raise PineconeException( f"Multiple projects found with name '{name}'. Please use project_id to fetch a specific project. Matching project ids: {ids}" ) else: return projects[0]
[docs] @require_kwargs def get(self, project_id: Optional[str] = None, name: Optional[str] = None): """Alias for :func:`fetch` Examples -------- .. code-block:: python :caption: Get a project by project_id :emphasize-lines: 7-9 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project = admin.project.get( project_id="42ca341d-43bf-47cb-9f27-e645dbfabea6" ) print(project.id) print(project.name) print(project.max_pods) print(project.force_encryption_with_cmek) """ return self.fetch(project_id=project_id, name=name)
[docs] @require_kwargs def describe(self, project_id: Optional[str] = None, name: Optional[str] = None): """Alias for :func:`fetch` Examples -------- .. code-block:: python :caption: Describe a project by project_id :emphasize-lines: 7-9 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project = admin.project.describe( project_id="42ca341d-43bf-47cb-9f27-e645dbfabea6" ) print(project.id) print(project.name) print(project.max_pods) print(project.force_encryption_with_cmek) """ return self.fetch(project_id=project_id, name=name)
[docs] @require_kwargs def exists(self, project_id: Optional[str] = None, name: Optional[str] = None): """ Check if a project exists by project_id or name. :param project_id: The project_id of the project to check. :type project_id: str :param name: The name of the project to check. :type name: str :return: True if the project exists, False otherwise. :rtype: bool :raises ValueError: If both project_id and name are provided. Examples -------- .. code-block:: python :caption: Check if a project exists by project name :emphasize-lines: 8 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project_name = "my-project-name" if admin.project.exists(name=project_name): print(f"Project {project_name} exists") else: admin.project.create( name=project_name, max_pods=10, force_encryption_with_cmek=False ) .. code-block:: python :caption: Check if a project exists by project_id :emphasize-lines: 8 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project_id = "42ca341d-43bf-47cb-9f27-e645dbfabea6" if admin.project.exists(project_id=project_id): print(f"Project {project_id} exists") else: print(f"Project {project_id} does not exist") """ if project_id is not None and name is not None: raise ValueError("Either project_id or name must be provided but not both") elif project_id is None and name is None: raise ValueError("Either project_id or name must be provided") try: args = [("project_id", project_id), ("name", name)] self.fetch(**parse_non_empty_args(args)) return True except NotFoundException: return False
[docs] @require_kwargs def create( self, name: str, max_pods: Optional[int] = None, force_encryption_with_cmek: Optional[bool] = None, ): """ Create a project. :param name: The name of the project to create. :type name: str :param max_pods: The maximum number of pods for the project. :type max_pods: int :param force_encryption_with_cmek: Whether to force encryption with CMEK. :type force_encryption_with_cmek: bool :return: The created project. :rtype: Project Examples -------- .. code-block:: python :caption: Create a project :emphasize-lines: 7-11 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project = admin.project.create( name="my-project-name", max_pods=10, force_encryption_with_cmek=False ) print(project.id) print(project.name) print(project.organization_id) print(project.max_pods) print(project.force_encryption_with_cmek) print(project.created_at) """ args = [ ("name", name), ("max_pods", max_pods), ("force_encryption_with_cmek", force_encryption_with_cmek), ] create_request = CreateProjectRequest(**parse_non_empty_args(args)) return self._projects_api.create_project(create_project_request=create_request)
[docs] @require_kwargs def update( self, project_id: str, name: Optional[str] = None, max_pods: Optional[int] = None, force_encryption_with_cmek: Optional[bool] = None, ): """ Update a project. :param project_id: The project_id of the project to update. :type project_id: str :param name: The name of the project to update. :type name: str :param max_pods: The maximum number of pods for the project. :type max_pods: int :param force_encryption_with_cmek: Whether to force encryption with CMEK. :type force_encryption_with_cmek: bool :return: The updated project. :rtype: Project Examples -------- .. code-block:: python :caption: Update a project by project_id :emphasize-lines: 10-13, 16-19 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project = admin.project.get(name='my-project-name') # Update max pods to 10 project = admin.project.update( project_id=project.id, max_pods=10 ) # Update force_encryption_with_cmek to True project = admin.project.update( project_id=project.id, force_encryption_with_cmek=True ) """ args = [ ("name", name), ("max_pods", max_pods), ("force_encryption_with_cmek", force_encryption_with_cmek), ] update_request = UpdateProjectRequest(**parse_non_empty_args(args)) return self._projects_api.update_project( project_id=project_id, update_project_request=update_request )
[docs] @require_kwargs def delete( self, project_id: str, delete_all_indexes: bool = False, delete_all_collections: bool = False, delete_all_backups: bool = False, ): """ .. warning:: Deleting a project is a permanent and irreversible operation. Please be very sure you want to delete the project and everything associated with it before calling this function. Projects can only be deleted if they are empty. The delete operation will fail if the project contains any resources such as indexes, collections, or backups. If you pass additional options such as ``delete_all_indexes=True``, ``delete_all_collections=True``, or ``delete_all_backups=True``, this function will attempt to delete all of these resources before deleting the project itself. **These deletions are permanent and cannot be undone.** :param project_id: The project_id of the project to delete. :type project_id: str :param delete_all_indexes: Attempt to delete all indexes associated with the project. :type delete_all_indexes: bool :param delete_all_collections: Attempt to delete all collections associated with the project. :type delete_all_collections: bool :param delete_all_backups: Attempt to delete all backups associated with the project. :type delete_all_backups: bool :return: ``None`` Examples -------- .. code-block:: python :caption: Delete a project by project_id :emphasize-lines: 9 from pinecone import Admin # Credentials read from PINECONE_CLIENT_ID and # PINECONE_CLIENT_SECRET environment variables admin = Admin() project = admin.project.get(name='my-project-name') admin.project.delete(project_id=project.id) .. code-block:: python :caption: Delete a project that still contains indexes, collections, and backups :emphasize-lines: 7-12 from pinecone import Admin admin = Admin() project = admin.project.get(name='my-project-name') admin.project.delete( project_id=project.id, delete_all_indexes=True, delete_all_collections=True, delete_all_backups=True ) if not admin.project.exists(project_id=project.id): print("Project deleted successfully") else: print("Project deletion failed") """ project = self.get(project_id=project_id) if not (delete_all_indexes or delete_all_collections or delete_all_backups): return self._projects_api.delete_project(project_id=project_id) from .api_key import ApiKeyResource api_key_resource = ApiKeyResource(self._api_client) logger.debug(f"Creating API key 'cleanup-key' for project {project.id}") key_create_response = api_key_resource.create( project_id=project.id, name="cleanup-key", roles=["ProjectEditor"] ) api_key = key_create_response.value try: from ..eraser.project_eraser import _ProjectEraser done = False retries = 0 while not done and retries < 5: project_eraser = _ProjectEraser(api_key=api_key) if delete_all_collections: project_eraser.delete_all_collections() if delete_all_backups: project_eraser.delete_all_backups() if delete_all_indexes: project_eraser.delete_all_indexes() done = not project_eraser.retry_needed() retries += 1 if not done: logger.debug( f"Retrying deletion of resources for project {project.id}. There were {len(project_eraser.undeleteable_resources)} undeleteable resources" ) time.sleep(30) finally: logger.debug(f"Deleting API key 'cleanup-key' for project {project.id}") api_key_resource.delete(api_key_id=key_create_response.key.id) logger.info(f"Deleting project {project_id}") return self._projects_api.delete_project(project_id=project_id)