Skip to content

Commit 79a4281

Browse files
authored
feat: add IndexModel compatibility shims for alpha API (#590)
## Summary This PR adds backward compatibility properties to `IndexModel` that map old-style accessor patterns to the new alpha API structure, ensuring existing code continues to work with the new API. ## Problem The alpha API (2026-01.alpha) has a different response structure than the previous API (2025-10): - **Old structure**: `spec` (with `serverless`/`pod`/`byoc` nested), `dimension`, `metric`, `vector_type` at the top level - **New structure**: `deployment` (with `deployment_type`, `cloud`, `region`, etc.), `schema` (with `fields` containing vector field configurations) Existing user code that accesses `index.spec.serverless.cloud` or `index.dimension` would break with the new API. ## Solution Add compatibility shims to `IndexModel` that provide the old-style access patterns: 1. **`spec` property**: Returns a `CompatibilitySpec` that builds the old `.spec.serverless`/`.spec.pod`/`.spec.byoc` access patterns from the new `deployment` data 2. **`dimension` property**: Extracts dimension from `schema.fields` (finds dense vector field) 3. **`metric` property**: Extracts metric from `schema.fields` (finds vector field with metric) 4. **`vector_type` property**: Returns "dense" or "sparse" based on vector field type, or None for FTS-only indexes ## Usage Examples ```python # New alpha API format with schema and deployment index = pc.describe_index("my-index") # Old-style access still works via compatibility shims print(index.spec.serverless.cloud) # "aws" - via CompatibilitySpec print(index.spec.serverless.region) # "us-east-1" print(index.dimension) # 1536 - extracted from schema.fields print(index.metric) # "cosine" - extracted from schema.fields print(index.vector_type) # "dense" - derived from field type # New-style access also works directly print(index.deployment.cloud) # "aws" print(index.schema.fields) # Field configurations ``` ## Handling FTS-Only Indexes Indexes with only text fields (no vectors) return `None` for vector properties: ```python fts_index = pc.describe_index("fts-only-index") print(fts_index.dimension) # None print(fts_index.metric) # None print(fts_index.vector_type) # None print(fts_index.spec.serverless.cloud) # "aws" - spec still works ``` ## Test Plan - [x] Unit tests for `CompatibilitySpec` with serverless/pod/byoc deployments - [x] Unit tests for `IndexModel` dimension/metric/vector_type extraction - [x] Unit tests for FTS-only indexes returning None for vector properties - [x] Unit tests for dict-style access (`index["dimension"]`) - [x] Mypy type checking passes ## Related Issues - Linear: SDK-107 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes `IndexModel` attribute resolution for `spec`/`dimension`/`metric`/`vector_type`, which may affect callers depending on prior `spec` parsing behavior when `deployment`/`schema` are missing or shaped differently. The logic is straightforward and covered by new unit tests, but it touches a commonly used wrapper. > > **Overview** > Adds a new `CompatibilitySpec` wrapper (plus `ServerlessSpecCompat`/`PodSpecCompat`/`ByocSpecCompat`) to recreate legacy `.spec.serverless`/`.spec.pod`/`.spec.byoc` access from the alpha API’s `deployment` object. > > Updates `IndexModel` to provide backward-compatible `dimension`, `metric`, and `vector_type` by extracting vector field info from `schema.fields` (including sparse-vector and FTS-only cases), and replaces the previous complex `spec` deserialization logic with the new deployment-based shim. > > Exports the new compatibility classes from `pinecone.db_control.models` and expands unit tests to cover serverless/pod/byoc deployments, sparse vectors, FTS-only indexes, and dict-style access. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8b4b59d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
2 parents 0ee543f + 8b4b59d commit 79a4281

4 files changed

Lines changed: 574 additions & 174 deletions

File tree

pinecone/db_control/models/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
)
2323
from .schema_builder import SchemaBuilder
2424
from .deployment import ServerlessDeployment, ByocDeployment, PodDeployment, Deployment
25+
from .compatibility_spec import (
26+
CompatibilitySpec,
27+
ServerlessSpecCompat,
28+
PodSpecCompat,
29+
ByocSpecCompat,
30+
)
2531

2632

2733
__all__ = [
@@ -51,4 +57,8 @@
5157
"ByocDeployment",
5258
"PodDeployment",
5359
"Deployment",
60+
"CompatibilitySpec",
61+
"ServerlessSpecCompat",
62+
"PodSpecCompat",
63+
"ByocSpecCompat",
5464
]
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
"""Compatibility shim classes for backward compatibility with the old spec-based API.
2+
3+
These classes map the new deployment-based API structure to the old spec-based
4+
access patterns, ensuring existing code continues to work with the new API.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
from dataclasses import dataclass
10+
from typing import TYPE_CHECKING
11+
12+
if TYPE_CHECKING:
13+
from typing import Dict
14+
15+
16+
@dataclass
17+
class ServerlessSpecCompat:
18+
"""Compatibility shim for serverless spec access.
19+
20+
Provides the same interface as the old ServerlessSpec response for
21+
backward compatibility.
22+
23+
:param cloud: The cloud provider (e.g., "aws", "gcp", "azure").
24+
:param region: The cloud region (e.g., "us-east-1").
25+
"""
26+
27+
cloud: str
28+
region: str
29+
30+
31+
@dataclass
32+
class PodSpecCompat:
33+
"""Compatibility shim for pod spec access.
34+
35+
Provides the same interface as the old PodSpec response for
36+
backward compatibility.
37+
38+
:param environment: The pod environment.
39+
:param pod_type: The pod type (e.g., "p1.x1").
40+
:param replicas: Number of replicas.
41+
:param shards: Number of shards.
42+
:param pods: Total number of pods.
43+
:param metadata_config: Metadata configuration dict.
44+
:param source_collection: Source collection name, if any.
45+
"""
46+
47+
environment: str
48+
pod_type: str
49+
replicas: int
50+
shards: int
51+
pods: int
52+
metadata_config: Dict[str, object] | None = None
53+
source_collection: str | None = None
54+
55+
56+
@dataclass
57+
class ByocSpecCompat:
58+
"""Compatibility shim for BYOC spec access.
59+
60+
Provides the same interface as the old ByocSpec response for
61+
backward compatibility.
62+
63+
:param environment: The BYOC environment identifier.
64+
"""
65+
66+
environment: str
67+
68+
69+
class CompatibilitySpec:
70+
"""Compatibility wrapper that provides old-style spec access from new deployment data.
71+
72+
This class wraps a deployment object from the alpha API and provides the old
73+
`.spec.serverless` / `.spec.pod` / `.spec.byoc` access patterns for backward
74+
compatibility.
75+
76+
:param deployment: The deployment object from the API response.
77+
"""
78+
79+
def __init__(self, deployment: object):
80+
self._deployment = deployment
81+
82+
@property
83+
def serverless(self) -> ServerlessSpecCompat | None:
84+
"""Get serverless spec if this is a serverless deployment.
85+
86+
:returns: ServerlessSpecCompat if serverless deployment, None otherwise.
87+
"""
88+
deployment_type = getattr(self._deployment, "deployment_type", None)
89+
if deployment_type == "serverless":
90+
cloud = getattr(self._deployment, "cloud", "")
91+
region = getattr(self._deployment, "region", "")
92+
return ServerlessSpecCompat(cloud=cloud, region=region)
93+
return None
94+
95+
@property
96+
def pod(self) -> PodSpecCompat | None:
97+
"""Get pod spec if this is a pod deployment.
98+
99+
:returns: PodSpecCompat if pod deployment, None otherwise.
100+
"""
101+
deployment_type = getattr(self._deployment, "deployment_type", None)
102+
if deployment_type == "pod":
103+
environment = getattr(self._deployment, "environment", "")
104+
pod_type = getattr(self._deployment, "pod_type", "p1.x1")
105+
replicas = getattr(self._deployment, "replicas", 1)
106+
shards = getattr(self._deployment, "shards", 1)
107+
pods = getattr(self._deployment, "pods", 1)
108+
metadata_config = getattr(self._deployment, "metadata_config", None)
109+
source_collection = getattr(self._deployment, "source_collection", None)
110+
return PodSpecCompat(
111+
environment=environment,
112+
pod_type=pod_type,
113+
replicas=replicas,
114+
shards=shards,
115+
pods=pods,
116+
metadata_config=metadata_config,
117+
source_collection=source_collection,
118+
)
119+
return None
120+
121+
@property
122+
def byoc(self) -> ByocSpecCompat | None:
123+
"""Get BYOC spec if this is a BYOC deployment.
124+
125+
:returns: ByocSpecCompat if BYOC deployment, None otherwise.
126+
"""
127+
deployment_type = getattr(self._deployment, "deployment_type", None)
128+
if deployment_type == "byoc":
129+
environment = getattr(self._deployment, "environment", "")
130+
return ByocSpecCompat(environment=environment)
131+
return None

0 commit comments

Comments
 (0)