Skip to content

Commit 5e8e5b1

Browse files
author
kashyapdayal
committed
Address review feedback and add KnowledgeBaseTimeoutError
1 parent 1e2e1ff commit 5e8e5b1

File tree

8 files changed

+126
-106
lines changed

8 files changed

+126
-106
lines changed

README.md

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -96,49 +96,6 @@ we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
9696
to add `DIGITALOCEAN_ACCESS_TOKEN="My Access Token"`, `GRADIENT_MODEL_ACCESS_KEY="My Model Access Key"` to your `.env` file
9797
so that your keys are not stored in source control.
9898

99-
## Knowledge Base Database Polling
100-
101-
When creating a Knowledge Base, the database deployment can take several minutes. The `wait_for_database()` helper function simplifies polling for the database status:
102-
103-
```python
104-
from gradient import Gradient
105-
from gradient.resources.knowledge_bases import KnowledgeBaseDatabaseError
106-
from gradient._exceptions import APITimeoutError
107-
108-
client = Gradient()
109-
110-
# Create a knowledge base
111-
kb_response = client.knowledge_bases.create(
112-
name="My Knowledge Base",
113-
region="nyc1",
114-
embedding_model_uuid="your-embedding-model-uuid",
115-
)
116-
117-
kb_uuid = kb_response.knowledge_base.uuid
118-
119-
try:
120-
# Wait for the database to be ready (default: 10 minute timeout, 5 second poll interval)
121-
result = client.knowledge_bases.wait_for_database(kb_uuid)
122-
print(f"Database status: {result.database_status}") # "ONLINE"
123-
124-
# Custom timeout and poll interval
125-
result = client.knowledge_bases.wait_for_database(
126-
kb_uuid,
127-
timeout=900.0, # 15 minutes
128-
poll_interval=10.0 # Check every 10 seconds
129-
)
130-
131-
except KnowledgeBaseDatabaseError as e:
132-
# Database entered a failed state (DECOMMISSIONED or UNHEALTHY)
133-
print(f"Database failed: {e}")
134-
135-
except APITimeoutError:
136-
# Database did not become ready within the timeout period
137-
print("Timeout: Database did not become ready in time")
138-
```
139-
140-
The helper handles all state transitions and will raise appropriate exceptions for failed states or timeouts.
141-
14299
## Async usage
143100

144101
Simply import `AsyncGradient` instead of `Gradient` and use `await` with each API call:
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""
2+
Example demonstrating how to use the wait_for_database helper function.
3+
4+
This example shows how to:
5+
1. Create a knowledge base
6+
2. Wait for its database to be ready
7+
3. Handle errors and timeouts appropriately
8+
"""
9+
10+
import os
11+
12+
from gradient import Gradient
13+
from gradient.resources.knowledge_bases import KnowledgeBaseTimeoutError, KnowledgeBaseDatabaseError
14+
15+
16+
def main() -> None:
17+
"""Create a knowledge base and wait for its database to be ready."""
18+
# Initialize the Gradient client
19+
# Note: DIGITALOCEAN_ACCESS_TOKEN must be set in your environment
20+
client = Gradient(
21+
access_token=os.environ.get("DIGITALOCEAN_ACCESS_TOKEN"),
22+
)
23+
24+
# Create a knowledge base
25+
# Replace these values with your actual configuration
26+
kb_response = client.knowledge_bases.create(
27+
name="My Knowledge Base",
28+
region="nyc1", # Choose your preferred region
29+
embedding_model_uuid="your-embedding-model-uuid", # Use your embedding model UUID
30+
)
31+
32+
kb_uuid = kb_response.knowledge_base.uuid
33+
print(f"Created knowledge base: {kb_uuid}")
34+
35+
try:
36+
# Wait for the database to be ready
37+
# Default: 10 minute timeout, 5 second poll interval
38+
print("Waiting for database to be ready...")
39+
result = client.knowledge_bases.wait_for_database(kb_uuid)
40+
print(f"Database status: {result.database_status}") # "ONLINE"
41+
print("Knowledge base is ready!")
42+
43+
# Alternative: Custom timeout and poll interval
44+
# result = client.knowledge_bases.wait_for_database(
45+
# kb_uuid,
46+
# timeout=900.0, # 15 minutes
47+
# poll_interval=10.0 # Check every 10 seconds
48+
# )
49+
50+
except KnowledgeBaseDatabaseError as e:
51+
# Database entered a failed state (DECOMMISSIONED or UNHEALTHY)
52+
print(f"Database failed: {e}")
53+
54+
except KnowledgeBaseTimeoutError as e:
55+
# Database did not become ready within the timeout period
56+
print(f"Timeout: {e}")
57+
58+
59+
if __name__ == "__main__":
60+
main()

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,4 @@ known-first-party = ["gradient", "tests"]
253253
[tool.ruff.lint.per-file-ignores]
254254
"bin/**.py" = ["T201", "T203"]
255255
"scripts/**.py" = ["T201", "T203"]
256-
"tests/**.py" = ["T201", "T203", "ARG001"]
257256
"examples/**.py" = ["T201", "T203"]

src/gradient/resources/knowledge_bases/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
)
1919
from .knowledge_bases import (
2020
KnowledgeBasesResource,
21-
AsyncKnowledgeBasesResource,
21+
KnowledgeBaseTimeoutError,
2222
KnowledgeBaseDatabaseError,
23+
AsyncKnowledgeBasesResource,
2324
KnowledgeBasesResourceWithRawResponse,
2425
AsyncKnowledgeBasesResourceWithRawResponse,
2526
KnowledgeBasesResourceWithStreamingResponse,
@@ -42,6 +43,7 @@
4243
"KnowledgeBasesResource",
4344
"AsyncKnowledgeBasesResource",
4445
"KnowledgeBaseDatabaseError",
46+
"KnowledgeBaseTimeoutError",
4547
"KnowledgeBasesResourceWithRawResponse",
4648
"AsyncKnowledgeBasesResourceWithRawResponse",
4749
"KnowledgeBasesResourceWithStreamingResponse",

src/gradient/resources/knowledge_bases/knowledge_bases.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
DataSourcesResourceWithStreamingResponse,
2828
AsyncDataSourcesResourceWithStreamingResponse,
2929
)
30-
from ..._exceptions import APITimeoutError
3130
from .indexing_jobs import (
3231
IndexingJobsResource,
3332
AsyncIndexingJobsResource,
@@ -43,7 +42,12 @@
4342
from ...types.knowledge_base_update_response import KnowledgeBaseUpdateResponse
4443
from ...types.knowledge_base_retrieve_response import KnowledgeBaseRetrieveResponse
4544

46-
__all__ = ["KnowledgeBasesResource", "AsyncKnowledgeBasesResource", "KnowledgeBaseDatabaseError"]
45+
__all__ = [
46+
"KnowledgeBasesResource",
47+
"AsyncKnowledgeBasesResource",
48+
"KnowledgeBaseDatabaseError",
49+
"KnowledgeBaseTimeoutError",
50+
]
4751

4852

4953
class KnowledgeBaseDatabaseError(Exception):
@@ -52,6 +56,12 @@ class KnowledgeBaseDatabaseError(Exception):
5256
pass
5357

5458

59+
class KnowledgeBaseTimeoutError(Exception):
60+
"""Raised when waiting for a knowledge base database times out."""
61+
62+
pass
63+
64+
5565
class KnowledgeBasesResource(SyncAPIResource):
5666
@cached_property
5767
def data_sources(self) -> DataSourcesResource:
@@ -377,7 +387,7 @@ def wait_for_database(
377387
Raises:
378388
KnowledgeBaseDatabaseError: If the database enters a failed state (DECOMMISSIONED, UNHEALTHY)
379389
380-
APITimeoutError: If the timeout is exceeded before the database becomes ONLINE
390+
KnowledgeBaseTimeoutError: If the timeout is exceeded before the database becomes ONLINE
381391
"""
382392
if not uuid:
383393
raise ValueError(f"Expected a non-empty value for `uuid` but received {uuid!r}")
@@ -388,11 +398,9 @@ def wait_for_database(
388398
while True:
389399
elapsed = time.time() - start_time
390400
if elapsed >= timeout:
391-
raise APITimeoutError(
392-
request=httpx.Request(
393-
method="GET",
394-
url=f"https://api.digitalocean.com/v2/gen-ai/knowledge_bases/{uuid}",
395-
)
401+
raise KnowledgeBaseTimeoutError(
402+
f"Timeout waiting for knowledge base database to become ready. "
403+
f"Database did not reach ONLINE status within {timeout} seconds."
396404
)
397405

398406
response = self.retrieve(
@@ -408,9 +416,7 @@ def wait_for_database(
408416
return response
409417

410418
if status in failed_states:
411-
raise KnowledgeBaseDatabaseError(
412-
f"Knowledge base database entered failed state: {status}"
413-
)
419+
raise KnowledgeBaseDatabaseError(f"Knowledge base database entered failed state: {status}")
414420

415421
# Sleep before next poll, but don't exceed timeout
416422
remaining_time = timeout - elapsed
@@ -744,7 +750,7 @@ async def wait_for_database(
744750
Raises:
745751
KnowledgeBaseDatabaseError: If the database enters a failed state (DECOMMISSIONED, UNHEALTHY)
746752
747-
APITimeoutError: If the timeout is exceeded before the database becomes ONLINE
753+
KnowledgeBaseTimeoutError: If the timeout is exceeded before the database becomes ONLINE
748754
"""
749755
if not uuid:
750756
raise ValueError(f"Expected a non-empty value for `uuid` but received {uuid!r}")
@@ -755,11 +761,9 @@ async def wait_for_database(
755761
while True:
756762
elapsed = time.time() - start_time
757763
if elapsed >= timeout:
758-
raise APITimeoutError(
759-
request=httpx.Request(
760-
method="GET",
761-
url=f"https://api.digitalocean.com/v2/gen-ai/knowledge_bases/{uuid}",
762-
)
764+
raise KnowledgeBaseTimeoutError(
765+
f"Timeout waiting for knowledge base database to become ready. "
766+
f"Database did not reach ONLINE status within {timeout} seconds."
763767
)
764768

765769
response = await self.retrieve(
@@ -775,9 +779,7 @@ async def wait_for_database(
775779
return response
776780

777781
if status in failed_states:
778-
raise KnowledgeBaseDatabaseError(
779-
f"Knowledge base database entered failed state: {status}"
780-
)
782+
raise KnowledgeBaseDatabaseError(f"Knowledge base database entered failed state: {status}")
781783

782784
# Sleep before next poll, but don't exceed timeout
783785
remaining_time = timeout - elapsed

0 commit comments

Comments
 (0)