Source code for pinecone.models.admin.api_key

"""API key response models for the Admin API."""

from __future__ import annotations

from collections.abc import Iterator
from enum import Enum
from typing import Any

from msgspec import Struct

from pinecone.models._mixin import StructDictMixin


[docs] class APIKeyRole(str, Enum): """Roles that can be assigned to a Pinecone API key. Possible values: ``PROJECT_EDITOR``, ``PROJECT_VIEWER``, ``CONTROL_PLANE_EDITOR``, ``CONTROL_PLANE_VIEWER``, ``DATA_PLANE_EDITOR``, ``DATA_PLANE_VIEWER``. Every role here is project-scoped: an API key's authority never reaches beyond the project it was created in. This is a ``str`` enum, so the plain role names are accepted interchangeably with the members. Examples: >>> from pinecone import Admin >>> from pinecone.models.admin.api_key import APIKeyRole >>> admin = Admin(client_id="your-client-id", client_secret="your-client-secret") >>> result = admin.api_keys.create( ... project_id="proj-abc123", ... name="search-service-key", ... roles=[APIKeyRole.DATA_PLANE_EDITOR], ... ) >>> result.key.roles [<APIKeyRole.DATA_PLANE_EDITOR: 'DataPlaneEditor'>] .. seealso:: - :class:`~pinecone.models.admin.role_binding.RoleName` — the roles used for users, service accounts, and invites. That set includes organization-scoped roles, which an API key cannot hold. - :meth:`ApiKeys.update() <pinecone.admin.api_keys.ApiKeys.update>` — changing a key's roles replaces the whole set rather than adding to it. """ PROJECT_EDITOR = "ProjectEditor" PROJECT_VIEWER = "ProjectViewer" CONTROL_PLANE_EDITOR = "ControlPlaneEditor" CONTROL_PLANE_VIEWER = "ControlPlaneViewer" DATA_PLANE_EDITOR = "DataPlaneEditor" DATA_PLANE_VIEWER = "DataPlaneViewer"
[docs] class APIKeyModel(StructDictMixin, Struct, kw_only=True): """Response model for a Pinecone API key. The secret is not included. Attributes: id (str): Unique identifier for the API key. This is what every API-key operation takes as ``api_key_id``, and it is not the secret. name (str | None): Name of the API key, or ``None`` when the backend has no display label set for this key. project_id (str): Identifier of the project the key belongs to. A key's authority never reaches outside that project. roles (list[APIKeyRole]): List of roles assigned to the key (see :class:`APIKeyRole`). Examples: >>> from pinecone import Admin >>> admin = Admin(client_id="your-client-id", client_secret="your-client-secret") >>> key = admin.api_keys.describe(api_key_id="key-abc123") >>> key.id 'key-abc123' >>> key.name 'prod-search-key' >>> key.roles [<APIKeyRole.DATA_PLANE_EDITOR: 'DataPlaneEditor'>] .. seealso:: - :class:`APIKeyWithSecret` — what :meth:`ApiKeys.create() <pinecone.admin.api_keys.ApiKeys.create>` returns instead, wrapping this model alongside the secret it shows only once. """ id: str name: str | None = None project_id: str roles: list[APIKeyRole] @property def role(self) -> APIKeyRole: """Singular alias for ``roles`` when the key has exactly one role. Returns: :class:`APIKeyRole`: The single role assigned to this key. Raises: :exc:`ValueError`: If the key has no roles or more than one role. Examples: >>> from pinecone import Admin >>> admin = Admin(client_id="your-client-id", client_secret="your-client-secret") >>> key = admin.api_keys.describe(api_key_id="key-abc123") >>> key.role <APIKeyRole.DATA_PLANE_EDITOR: 'DataPlaneEditor'> Keys with two or more roles raise :exc:`ValueError`, so reach for this only where a key is known to hold exactly one: >>> from pinecone.models.admin.api_key import APIKeyModel, APIKeyRole >>> multi_role_key = APIKeyModel( ... id="key-def456", ... name="ci-pipeline-key", ... project_id="proj-abc123", ... roles=[APIKeyRole.CONTROL_PLANE_EDITOR, APIKeyRole.DATA_PLANE_EDITOR], ... ) >>> multi_role_key.role Traceback (most recent call last): ... ValueError: API key has 2 roles; use .roles to access all """ if len(self.roles) == 0: raise ValueError("API key has no roles") if len(self.roles) > 1: raise ValueError(f"API key has {len(self.roles)} roles; use .roles to access all") return self.roles[0] def __getitem__(self, key: str) -> Any: """Support bracket access (e.g. api_key['name']).""" if key not in self.__struct_fields__: raise KeyError(key) return getattr(self, key) def __contains__(self, key: object) -> bool: """Support ``in`` operator (e.g. ``'name' in api_key``).""" return key in self.__struct_fields__
[docs] class APIKeyWithSecret(StructDictMixin, Struct, kw_only=True): """Response model for an API key together with its secret value. Returned only by :meth:`ApiKeys.create() <pinecone.admin.api_keys.ApiKeys.create>`, and the secret it carries is obtainable exactly once — no later request returns it, and there is no rotation for API keys, so a lost secret means creating a replacement key and deleting the old one. Attributes: key (APIKeyModel): The API key metadata, including the ``id`` every other API-key operation takes. value (str): The secret API key string — what :class:`~pinecone.Pinecone` is constructed with. Treat as a credential. Examples: >>> from pinecone import Admin >>> admin = Admin(client_id="your-client-id", client_secret="your-client-secret") >>> created = admin.api_keys.create(project_id="proj-abc123", name="prod-search-key") >>> created.key.id 'key-abc123' ``repr()`` keeps only the last four characters of the secret, so an object logged whole does not leak it: >>> repr(created).endswith("value='...alue')") True .. warning:: The masking stops at ``repr()``. ``to_dict()`` and JSON encoding return ``value`` in full, so a result serialized wholesale into a log line, an error report, or a cache writes the live credential out. """ key: APIKeyModel value: str def __repr__(self) -> str: masked = f"...{self.value[-4:]}" if len(self.value) >= 4 else "***" return f"APIKeyWithSecret(key={self.key!r}, value='{masked}')" def __str__(self) -> str: return repr(self) def __getitem__(self, key: str) -> Any: """Support bracket access (e.g. response['value']).""" if key not in self.__struct_fields__: raise KeyError(key) return getattr(self, key) def __contains__(self, key: object) -> bool: """Support ``in`` operator (e.g. ``'value' in response``).""" return key in self.__struct_fields__
[docs] class APIKeyList: """The API keys of one project, as returned by a list call. A sequence of :class:`APIKeyModel` — iterable, indexable, and sized — with :meth:`names` and :meth:`to_dict` on top. Not constructed directly; it is what :meth:`ApiKeys.list() <pinecone.admin.api_keys.ApiKeys.list>` returns. Unlike the organization-wide admin listings, this is not paginated: a project's keys arrive in one response, so there is no cursor to follow. Examples: >>> from pinecone.models.admin.api_key import APIKeyList, APIKeyModel, APIKeyRole >>> keys = APIKeyList( ... [ ... APIKeyModel( ... id="key-abc123", ... name="prod-search-key", ... project_id="proj-abc123", ... roles=[APIKeyRole.DATA_PLANE_EDITOR], ... ) ... ] ... ) >>> keys.names() ['prod-search-key'] """
[docs] def __init__(self, api_keys: list[APIKeyModel]) -> None: """Initialize an APIKeyList. Args: api_keys: List of :class:`APIKeyModel` instances representing Pinecone API keys. """ self._api_keys = api_keys
def __iter__(self) -> Iterator[APIKeyModel]: return iter(self._api_keys) def __len__(self) -> int: return len(self._api_keys) def __getitem__(self, index: int) -> APIKeyModel: return self._api_keys[index]
[docs] def to_dict(self) -> dict[str, Any]: """Return the list as a serializable dict. Returns: dict[str, Any]: A dict with a ``"data"`` key containing a list of API key dicts, each produced by :meth:`APIKeyModel.to_dict`. Examples: >>> from pinecone import Admin >>> admin = Admin(client_id="your-client-id", client_secret="your-client-secret") >>> keys = admin.api_keys.list(project_id="proj-abc123") >>> keys.to_dict() # doctest: +SKIP {'data': [{'name': 'prod-search-key', ...}, {'name': 'ci-pipeline-key', ...}]} """ return {"data": [k.to_dict() for k in self._api_keys]}
[docs] def names(self) -> list[str | None]: """Return a list of API key names. Returns: list[str | None]: API key names in the same order as the list. Elements are ``None`` for keys whose backend display label is unset. Examples: >>> from pinecone import Admin >>> admin = Admin(client_id="your-client-id", client_secret="your-client-secret") >>> keys = admin.api_keys.list(project_id="proj-abc123") >>> keys.names() # doctest: +SKIP ['prod-search-key', 'ci-pipeline-key'] """ return [api_key.name for api_key in self._api_keys]
def __repr__(self) -> str: summaries = ", ".join( f"<name={k.name!r}, project_id={k.project_id!r}>" for k in self._api_keys ) return f"APIKeyList([{summaries}])"