Skip to content

Commit 75ae5d5

Browse files
committed
feat: add deployment model classes (#584)
## Summary Add deployment model classes for different index deployment configurations. Closes SDK-103 ## Classes | Class | Deployment Type | Key Parameters | |-------|-----------------|----------------| | `ServerlessDeployment` | `serverless` | `cloud`, `region` | | `ByocDeployment` | `byoc` | `environment` | | `PodDeployment` | `pod` | `environment`, `pod_type`, `replicas`, `shards` | ## Usage Example ```python from pinecone import ServerlessDeployment, ByocDeployment, PodDeployment # Serverless deployment pc.create_index( name="my-index", schema=schema, deployment=ServerlessDeployment(cloud="aws", region="us-east-1"), ) # BYOC deployment pc.create_index( name="my-index", schema=schema, deployment=ByocDeployment(environment="aws-us-east-1-b92"), ) # Pod deployment pc.create_index( name="my-index", schema=schema, deployment=PodDeployment( environment="us-east-1-aws", pod_type="p1.x1", replicas=2, ), ) ``` ## Test Plan - [x] Unit tests for ServerlessDeployment serialization - [x] Unit tests for ByocDeployment serialization - [x] Unit tests for PodDeployment with various options - [x] mypy type checking passes <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: this PR only adds new model/dataclass types and exports them; it doesn’t change existing request flows, but downstream code may start relying on the new `to_dict` serialization format. > > **Overview** > Adds new deployment configuration dataclasses (`ServerlessDeployment`, `ByocDeployment`, `PodDeployment`) with `to_dict()` serialization and a `Deployment` union type in `db_control/models/deployment.py`. > > Exports these types through `pinecone.db_control.models` and top-level `pinecone` lazy imports, and adds unit tests validating constructor defaults and `to_dict()` output across deployment variants. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c2e965d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 578ec5c commit 75ae5d5

7 files changed

Lines changed: 621 additions & 1 deletion

File tree

codegen/apis

Submodule apis updated from d5ac931 to 4eac4da

pinecone/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@
116116
"SemanticTextField": ("pinecone.db_control.models", "SemanticTextField"),
117117
"SchemaField": ("pinecone.db_control.models", "SchemaField"),
118118
"SchemaBuilder": ("pinecone.db_control.models", "SchemaBuilder"),
119+
# Deployment classes
120+
"ServerlessDeployment": ("pinecone.db_control.models", "ServerlessDeployment"),
121+
"ByocDeployment": ("pinecone.db_control.models", "ByocDeployment"),
122+
"PodDeployment": ("pinecone.db_control.models", "PodDeployment"),
123+
"Deployment": ("pinecone.db_control.models", "Deployment"),
119124
# Read capacity TypedDict classes
120125
"ScalingConfigManualDict": (
121126
"pinecone.db_control.models.serverless_spec",

pinecone/db_control/models/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
SchemaField,
2222
)
2323
from .schema_builder import SchemaBuilder
24+
from .deployment import ServerlessDeployment, ByocDeployment, PodDeployment, Deployment
2425

2526

2627
__all__ = [
@@ -46,4 +47,8 @@
4647
"SemanticTextField",
4748
"SchemaField",
4849
"SchemaBuilder",
50+
"ServerlessDeployment",
51+
"ByocDeployment",
52+
"PodDeployment",
53+
"Deployment",
4954
]
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
"""Deployment model classes for index deployment configurations.
2+
3+
These classes represent different deployment configurations for Pinecone indexes,
4+
including serverless, BYOC (bring-your-own-cloud), and pod-based deployments.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
from dataclasses import dataclass
10+
11+
12+
@dataclass
13+
class ServerlessDeployment:
14+
"""Serverless deployment configuration.
15+
16+
Serverless indexes are fully managed by Pinecone and automatically scale
17+
based on usage.
18+
19+
:param cloud: The cloud provider ("aws", "gcp", or "azure").
20+
:param region: The cloud region (e.g., "us-east-1", "us-central1").
21+
22+
Example usage::
23+
24+
from pinecone import ServerlessDeployment
25+
26+
deployment = ServerlessDeployment(cloud="aws", region="us-east-1")
27+
28+
pc.create_index(
29+
name="my-index",
30+
schema=schema,
31+
deployment=deployment,
32+
)
33+
"""
34+
35+
cloud: str
36+
region: str
37+
38+
def to_dict(self) -> dict:
39+
"""Serialize to API format.
40+
41+
:returns: Dictionary representation for the API.
42+
"""
43+
return {"deployment_type": "serverless", "cloud": self.cloud, "region": self.region}
44+
45+
46+
@dataclass
47+
class ByocDeployment:
48+
"""Bring-your-own-cloud (BYOC) deployment configuration.
49+
50+
BYOC deployments run in your own cloud infrastructure with a
51+
Pinecone-managed control plane.
52+
53+
:param environment: The BYOC environment identifier.
54+
55+
Example usage::
56+
57+
from pinecone import ByocDeployment
58+
59+
deployment = ByocDeployment(environment="aws-us-east-1-b92")
60+
61+
pc.create_index(
62+
name="my-index",
63+
schema=schema,
64+
deployment=deployment,
65+
)
66+
"""
67+
68+
environment: str
69+
70+
def to_dict(self) -> dict:
71+
"""Serialize to API format.
72+
73+
:returns: Dictionary representation for the API.
74+
"""
75+
return {"deployment_type": "byoc", "environment": self.environment}
76+
77+
78+
@dataclass
79+
class PodDeployment:
80+
"""Pod-based deployment configuration.
81+
82+
Pod deployments provide dedicated compute resources with configurable
83+
replicas, shards, and pod types.
84+
85+
:param environment: The pod environment (e.g., "us-east-1-aws").
86+
:param pod_type: The pod type (e.g., "p1.x1", "s1.x1", "p2.x1").
87+
:param replicas: Number of replicas (default: 1).
88+
:param shards: Number of shards (default: 1).
89+
:param pods: Total number of pods (replicas * shards). If not specified,
90+
it will be calculated from replicas and shards.
91+
92+
Example usage::
93+
94+
from pinecone import PodDeployment
95+
96+
deployment = PodDeployment(
97+
environment="us-east-1-aws",
98+
pod_type="p1.x1",
99+
replicas=2,
100+
shards=1,
101+
)
102+
103+
pc.create_index(
104+
name="my-index",
105+
schema=schema,
106+
deployment=deployment,
107+
)
108+
"""
109+
110+
environment: str
111+
pod_type: str
112+
replicas: int = 1
113+
shards: int = 1
114+
pods: int | None = None
115+
116+
def to_dict(self) -> dict:
117+
"""Serialize to API format.
118+
119+
:returns: Dictionary representation for the API.
120+
"""
121+
result: dict = {
122+
"deployment_type": "pod",
123+
"environment": self.environment,
124+
"pod_type": self.pod_type,
125+
"replicas": self.replicas,
126+
"shards": self.shards,
127+
}
128+
if self.pods is not None:
129+
result["pods"] = self.pods
130+
return result
131+
132+
133+
# Type alias for any deployment type
134+
Deployment = ServerlessDeployment | ByocDeployment | PodDeployment

pinecone/db_control/request_factory.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
CreateIndexFromBackupRequest,
4545
)
4646
from pinecone.db_control.models import ServerlessSpec, PodSpec, ByocSpec, IndexModel, IndexEmbed
47+
from pinecone.db_control.models.deployment import (
48+
ServerlessDeployment,
49+
PodDeployment,
50+
ByocDeployment,
51+
)
52+
from pinecone.db_control.models.schema_fields import DenseVectorField, SparseVectorField
4753

4854
from pinecone.db_control.enums import (
4955
Metric,
@@ -361,6 +367,119 @@ def __parse_index_spec(spec: Dict | ServerlessSpec | PodSpec | ByocSpec) -> Inde
361367

362368
return cast(IndexSpec, index_spec)
363369

370+
@staticmethod
371+
def _translate_legacy_request(
372+
spec: Dict | ServerlessSpec | PodSpec | ByocSpec,
373+
dimension: int | None = None,
374+
metric: (Metric | str) | None = None,
375+
vector_type: (VectorType | str) | None = VectorType.DENSE,
376+
) -> tuple[dict[str, Any], dict[str, Any]]:
377+
"""Translate legacy spec-based request to deployment + schema format.
378+
379+
This method converts legacy index creation parameters (spec, dimension, metric,
380+
vector_type) to the new API format using deployment and schema structures.
381+
382+
:param spec: The legacy spec (ServerlessSpec, PodSpec, ByocSpec, or dict).
383+
:param dimension: The vector dimension (for dense vectors).
384+
:param metric: The distance metric (cosine, euclidean, dotproduct).
385+
:param vector_type: The vector type (dense or sparse).
386+
:returns: A tuple of (deployment_dict, schema_dict) for the new API format.
387+
388+
**Translation Mappings:**
389+
390+
* `ServerlessSpec(cloud, region)` → `deployment` with `deployment_type="serverless"`
391+
* `PodSpec(environment, ...)` → `deployment` with `deployment_type="pod"`
392+
* `ByocSpec(environment)` → `deployment` with `deployment_type="byoc"`
393+
* `dimension` + `metric` + `vector_type="dense"` → `schema.fields._values` (dense_vector)
394+
* `vector_type="sparse"` → `schema.fields._sparse_values` (sparse_vector)
395+
396+
Example::
397+
398+
deployment, schema = PineconeDBControlRequestFactory._translate_legacy_request(
399+
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
400+
dimension=1536,
401+
metric="cosine",
402+
vector_type="dense"
403+
)
404+
# Returns:
405+
# (
406+
# {"deployment_type": "serverless", "cloud": "aws", "region": "us-east-1"},
407+
# {"fields": {"_values": {"type": "dense_vector", "dimension": 1536, "metric": "cosine"}}}
408+
# )
409+
"""
410+
# Convert metric to string if it's an enum
411+
if metric is not None:
412+
metric = convert_enum_to_string(metric)
413+
if vector_type is not None:
414+
vector_type = convert_enum_to_string(vector_type)
415+
416+
# Translate spec to deployment
417+
deployment_dict: dict[str, Any]
418+
if isinstance(spec, dict):
419+
if "serverless" in spec:
420+
serverless_spec = spec["serverless"]
421+
deployment = ServerlessDeployment(
422+
cloud=serverless_spec.get("cloud", ""), region=serverless_spec.get("region", "")
423+
)
424+
deployment_dict = deployment.to_dict()
425+
elif "pod" in spec:
426+
pod_spec = spec["pod"]
427+
deployment = PodDeployment(
428+
environment=pod_spec.get("environment", ""),
429+
pod_type=pod_spec.get("pod_type", "p1.x1"),
430+
replicas=pod_spec.get("replicas", 1),
431+
shards=pod_spec.get("shards", 1),
432+
pods=pod_spec.get("pods"),
433+
)
434+
deployment_dict = deployment.to_dict()
435+
elif "byoc" in spec:
436+
byoc_spec = spec["byoc"]
437+
deployment = ByocDeployment(environment=byoc_spec.get("environment", ""))
438+
deployment_dict = deployment.to_dict()
439+
else:
440+
raise ValueError("spec must contain either 'serverless', 'pod', or 'byoc' key")
441+
elif isinstance(spec, ServerlessSpec):
442+
deployment = ServerlessDeployment(cloud=spec.cloud, region=spec.region)
443+
deployment_dict = deployment.to_dict()
444+
elif isinstance(spec, PodSpec):
445+
# PodDeployment requires pod_type, but PodSpec defaults to "p1.x1"
446+
pod_type = spec.pod_type if spec.pod_type is not None else "p1.x1"
447+
deployment = PodDeployment(
448+
environment=spec.environment,
449+
pod_type=pod_type,
450+
replicas=spec.replicas or 1,
451+
shards=spec.shards or 1,
452+
pods=spec.pods,
453+
)
454+
deployment_dict = deployment.to_dict()
455+
elif isinstance(spec, ByocSpec):
456+
deployment = ByocDeployment(environment=spec.environment)
457+
deployment_dict = deployment.to_dict()
458+
else:
459+
raise TypeError("spec must be of type dict, ServerlessSpec, PodSpec, or ByocSpec")
460+
461+
# Translate dimension/metric/vector_type to schema
462+
schema_dict: dict[str, Any] = {"fields": {}}
463+
if vector_type == VectorType.SPARSE.value:
464+
# Sparse vector: use _sparse_values field
465+
if metric is None:
466+
metric = "dotproduct" # Default for sparse vectors
467+
sparse_field = SparseVectorField(metric=metric)
468+
schema_dict["fields"]["_sparse_values"] = sparse_field.to_dict()
469+
elif vector_type == VectorType.DENSE.value:
470+
# Dense vector: use _values field
471+
if dimension is None:
472+
raise ValueError("dimension is required for dense vector indexes")
473+
if metric is None:
474+
metric = Metric.COSINE.value # Default for dense vectors
475+
dense_field = DenseVectorField(dimension=dimension, metric=metric)
476+
schema_dict["fields"]["_values"] = dense_field.to_dict()
477+
else:
478+
# No vector type specified - return empty schema fields
479+
pass
480+
481+
return deployment_dict, schema_dict
482+
364483
@staticmethod
365484
def create_index_request(
366485
name: str,

0 commit comments

Comments
 (0)