Pinecone Python SDK

repository·main·Indexed 19 days ago

https://github.com/pinecone-io/python-sdk

A client for the Pinecone vector database that allows developers to manage indexes, upsert vectors, and perform similarity searches. The SDK supports both synchronous and asynchronous operations via AsyncPinecone, and provides two index interfaces: a general-purpose REST Index and a high-throughput gRPC GrpcIndex. It requires Python 3.10+ and supports serverless index creation, data isolation through namespaces, and hybrid search using sparse values and metadata filtering.

Tokens
43.3K
Snippets
150
Records
203
Agent score
64%

What's inside pinecone-io-python-sdk

  1. How Paginator and AsyncPaginator work

    main

    Some SDK operations return results in pages rather than a single list. To handle this, the SDK provides Paginator (for synchronous code) and AsyncPaginator (for asynchronous code). These objects allow you to iterate over results lazily, fetching subsequent pages only when requested.

    Both paginators support the following interface:

    • __iter__ / __aiter__: Iterate over individual items across all pages sequentially.
    • .pages(): Iterate over Page objects instead of individual items.
    • .to_list(): Fetch all items from all pages into a single list in one call.
    • .pagination_token: Access the token for the next page; returns None when all pages have been consumed.
    # Sync example: iterating over items
    from pinecone import Pinecone
    
    pc = Pinecone()
    for assistant in pc.assistants.list():
        print(assistant.name)
    
    # Async example: iterating over items
    import asyncio
    from pinecone import AsyncPinecone
    
    async def main() -> None:
        async with AsyncPinecone() as pc:
            async for assistant in pc.assistants.list():
                print(assistant.name)
    
    asyncio.run(main())
  2. Navigate the Pinecone SDK namespace pattern

    main

    The Pinecone client uses a namespace pattern to group related operations, keeping the top-level API surface clean. Key namespaces include:

    • pc.indexes: Manage index lifecycle (create, list, describe, configure, delete).
    • pc.collections: Manage collections (create, list, describe, delete).
    • pc.inference: Perform embedding and reranking tasks.
    • pc.assistants: Manage Pinecone Assistants.
    # Example of using the indexes namespace
    for index_model in pc.indexes.list():
        print(index_model.name, index_model.status.ready)
    
    desc = pc.indexes.describe("movie-recommendations")
    pc.indexes.delete("movie-recommendations")
  3. How adaptive concurrency works for bulk operations

    main

    When performing bulk operations like upsert(), the SDK uses an AIMD (Additive Increase, Multiplicative Decrease) algorithm to manage concurrency.

    • Throttling: If the SDK receives a retryable response (like 429 or 503), it halves the effective concurrency floor for that host.
    • Recovery: After a streak of successful requests, it recovers by one slot.
    • Configuration: You do not configure the limiter directly. The max_concurrency parameter in methods like upsert() acts as a ceiling. The SDK self-tunes the actual number of in-flight requests between 1 and that ceiling based on server capacity.
    from pinecone import Pinecone
    
    pc = Pinecone()
    index = pc.index(host="product-search-abc123.svc.pinecone.io")
    
    # max_concurrency=8 is the ceiling. The SDK will scale below this if throttled.
    response = index.upsert(
        vectors=large_list,
        batch_size=200,
        max_concurrency=8,
    )
  4. Configure replicas and pods for availability and capacity

    main

    In a pod-based index, pods control the total storage capacity, while replicas increase availability and query throughput. You can specify both in the PodSpec.

    from pinecone import Pinecone, PodSpec
    
    pc = Pinecone(api_key="your-api-key")
    
    pc.indexes.create(
        name="product-search-ha",
        dimension=1536,
        metric="cosine",
        spec=PodSpec(
            environment="us-east1-gcp",
            pod_type="p1.x1",
            pods=2,
            replicas=2,
        ),
    )
  5. Understand the EmbeddingsList response format

    main

    The pc.inference.embed method returns an EmbeddingsList object. This object contains:

    • .data: A list of DenseEmbedding or SparseEmbedding objects (one per input).
    • .model: The name of the model used.
    • .usage.total_tokens: The total token count consumed by the request.

    Accessing Dense Embeddings: Iterate through the result and access .values to get a list of floats.

    Accessing Sparse Embeddings: For models like pinecone-sparse-english-v0, access .sparse_indices and .sparse_values from the embedding object.

    Hybrid Embeddings: Note that some models return hybrid (dense + sparse) embeddings as two separate items per input.

    # For Dense Embeddings
    for emb in result:
        print(emb.values)       # DenseEmbedding: list of floats
    
    # For Sparse Embeddings
    result = pc.inference.embed(
        model="pinecone-sparse-english-v0",
        inputs=["machine learning frameworks"],
    )
    sparse = result.data[0]
    print(sparse.sparse_indices)
    print(sparse.sparse_values)
  6. Understand the Pinecone exception hierarchy

    main

    All exceptions raised by the SDK are subclasses of PineconeError. You can catch all SDK-related errors using a single except PineconeError block, or catch specific subclasses to handle different failure modes (like network issues vs. API errors) uniquely.

    Hierarchy Overview:

    • PineconeError (Base class)
      • ApiError (HTTP error responses from the server)
        • NotFoundError (404)
        • ConflictError (409)
        • UnauthorizedError (401)
        • ForbiddenError (403)
        • RateLimitError (429)
        • ServiceError (5xx)
      • PineconeConnectionError (Network-level failures like DNS or refused connections)
      • PineconeTimeoutError (Operation exceeded its timeout)
      • PineconeValueError (Invalid value passed to the SDK)
      • PineconeTypeError (Wrong type passed to the SDK)
    from pinecone.errors import PineconeError
    
    try:
        # SDK operation
        pass
    except PineconeError as e:
        print(f"An SDK error occurred: {e}")
  7. Choosing between Sync and Async clients

    main

    The Pinecone SDK provides two pairs of clients depending on your execution model:

    ComponentSync ClientAsync Client
    Control planePineconeAsyncPinecone
    Data planeIndexAsyncIndex
    Transporthttpx (sync)httpx (async)
    Context managerwith Pinecone() as pc:async with AsyncPinecone() as pc:

    When to use which:

    • Sync Client: Best for scripts, CLI tools, and simple integrations where blocking calls are acceptable.
    • Async Client: Best for async frameworks (FastAPI, Starlette, aiohttp) or any application driving many concurrent operations.
  8. Use AsyncPinecone for asynchronous resource management

    main

    The AsyncPinecone class is the asynchronous control-plane client. It is designed to be used within an async with block to manage high-level resources like indexes, collections, backups, and assistants.

    Sub-clients for specific resource types are accessed as properties (e.g., pc.indexes, pc.collections, pc.backups, pc.restore_jobs, pc.inference, pc.assistants) and are lazily initialized upon their first access.

    Important Note on Index Access: Unlike the synchronous Pinecone client, AsyncPinecone.index() cannot automatically resolve an index host using only its name. To connect to an index, you must either:

    1. Call await pc.indexes.describe("index-name") first to populate the internal cache, then call pc.index("index-name").
    2. Explicitly provide the host by calling desc = await pc.indexes.describe("index-name") and then passing host=desc.host to pc.index().
    from pinecone import AsyncPinecone
    
    async with AsyncPinecone(api_key="your-api-key") as pc:
        # 1. Describe the index to get host information
        desc = await pc.indexes.describe("my-index")
        
        # 2. Connect to the index using the host
        index = pc.index(host=desc.host)
        
        # 3. Use the index within an async context manager
        async with index:
            results = await index.query(
                vector=[0.012, -0.087, 0.153],
                top_k=10,
            )
  9. Handle partial-success in batched upserts in v9

    main

    The behavior of index.upsert() changed when using the batch_size parameter.

    v8 Behavior: Raised an exception on the first batch failure, potentially leaving subsequent batches unattempted. v9 Behavior: Batches are submitted concurrently. Failures that exceed the retry budget are captured in the returned UpsertResponse rather than being raised as exceptions.

    How to handle errors in v9: Instead of using try/except to catch batch failures, inspect the has_errors property on the returned response object.

    Example:

    # v9 — inspect response.has_errors instead
    response = idx.upsert(vectors=batch, batch_size=100)
    if response.has_errors:
        # Optionally retry only the failures:
        idx.upsert(vectors=response.failed_items, batch_size=100)
        # ...or roll back if any failure is unacceptable

    Note: Single-request upserts (batch_size=None, the default) retain the v8 'raise-on-failure' semantics.

    # v9 — inspect response.has_errors instead
    response = idx.upsert(vectors=batch, batch_size=100)
    if response.has_errors:
        # Optionally retry only the failures:
        idx.upsert(vectors=response.failed_items, batch_size=100)
        # …or roll back if any failure is unacceptable
  10. Understand the Pinecone SDK exception hierarchy

    main

    The SDK uses a structured hierarchy of exceptions to differentiate between configuration issues, network problems, and API responses.

    Hierarchy Overview

    • PineconeError (Base Class)
      • PineconeValueError (also ValueError)
      • PineconeTypeError (also TypeError)
      • PineconeConnectionError (Network issues)
      • PineconeTimeoutError (also TimeoutError)
      • ResponseParsingError (Data format issues)
      • IndexInitFailedError
      • ApiError (Server-side responses)
        • ConflictError (409)
        • NotFoundError (404)
        • ForbiddenError (403)
        • UnauthorizedError (401)
        • ServiceError (5xx)
  11. Understand Control Plane vs Data Plane operations

    main

    Pinecone operations are split into two planes:

    1. Control Plane: Manages index lifecycle (create, list, describe, configure, delete) and collections/backups. These are accessed via the Pinecone client and routed through api.pinecone.io.
    2. Data Plane: Performs vector operations (upsert, query, fetch, update, delete, list). These are accessed via the Index (or AsyncIndex) client and connect directly to the index's host URL.
    from pinecone import Pinecone
    
    pc = Pinecone()
    
    # Control plane: describe an index to get its host
    desc = pc.indexes.describe("movie-recommendations")
    
    # Data plane: connect directly to the index
    index = pc.index(host=desc.host)
    index.upsert(vectors=[("movie-42", [0.1, 0.2, ...])])