exa-py 1.15.1__tar.gz → 1.15.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of exa-py might be problematic. Click here for more details.
- {exa_py-1.15.1 → exa_py-1.15.2}/PKG-INFO +1 -1
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/api.py +3 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/__init__.py +2 -1
- exa_py-1.15.1/exa_py/websets/client.py → exa_py-1.15.2/exa_py/websets/async_client.py +44 -47
- exa_py-1.15.2/exa_py/websets/client.py +289 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/core/__init__.py +4 -2
- exa_py-1.15.2/exa_py/websets/core/async_base.py +77 -0
- exa_py-1.15.2/exa_py/websets/enrichments/__init__.py +3 -0
- exa_py-1.15.2/exa_py/websets/enrichments/client.py +156 -0
- exa_py-1.15.2/exa_py/websets/events/__init__.py +3 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/events/client.py +82 -0
- exa_py-1.15.2/exa_py/websets/imports/__init__.py +3 -0
- exa_py-1.15.2/exa_py/websets/imports/client.py +347 -0
- exa_py-1.15.2/exa_py/websets/items/__init__.py +3 -0
- exa_py-1.15.2/exa_py/websets/items/client.py +153 -0
- exa_py-1.15.2/exa_py/websets/monitors/__init__.py +4 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/monitors/client.py +36 -0
- exa_py-1.15.2/exa_py/websets/monitors/runs/__init__.py +3 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/monitors/runs/client.py +18 -0
- exa_py-1.15.2/exa_py/websets/searches/__init__.py +3 -0
- exa_py-1.15.2/exa_py/websets/searches/client.py +101 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/types.py +13 -4
- exa_py-1.15.2/exa_py/websets/webhooks/__init__.py +3 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/webhooks/client.py +63 -1
- {exa_py-1.15.1 → exa_py-1.15.2}/pyproject.toml +2 -1
- exa_py-1.15.1/exa_py/websets/enrichments/__init__.py +0 -3
- exa_py-1.15.1/exa_py/websets/enrichments/client.py +0 -82
- exa_py-1.15.1/exa_py/websets/events/__init__.py +0 -3
- exa_py-1.15.1/exa_py/websets/imports/__init__.py +0 -3
- exa_py-1.15.1/exa_py/websets/imports/client.py +0 -179
- exa_py-1.15.1/exa_py/websets/items/__init__.py +0 -3
- exa_py-1.15.1/exa_py/websets/items/client.py +0 -80
- exa_py-1.15.1/exa_py/websets/monitors/__init__.py +0 -4
- exa_py-1.15.1/exa_py/websets/monitors/runs/__init__.py +0 -3
- exa_py-1.15.1/exa_py/websets/searches/__init__.py +0 -3
- exa_py-1.15.1/exa_py/websets/searches/client.py +0 -54
- exa_py-1.15.1/exa_py/websets/webhooks/__init__.py +0 -3
- {exa_py-1.15.1 → exa_py-1.15.2}/README.md +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/__init__.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/py.typed +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/research/__init__.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/research/async_client.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/research/base.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/research/models.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/research/sync_client.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/research/utils.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/utils.py +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/_generator/pydantic/BaseModel.jinja2 +0 -0
- {exa_py-1.15.1 → exa_py-1.15.2}/exa_py/websets/core/base.py +0 -0
|
@@ -23,6 +23,7 @@ from typing import (
|
|
|
23
23
|
overload,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
+
from .websets import AsyncWebsetsClient
|
|
26
27
|
import httpx
|
|
27
28
|
import requests
|
|
28
29
|
from openai import OpenAI
|
|
@@ -2413,6 +2414,8 @@ class AsyncExa(Exa):
|
|
|
2413
2414
|
super().__init__(api_key, api_base)
|
|
2414
2415
|
# Override the synchronous ResearchClient with its async counterpart.
|
|
2415
2416
|
self.research = AsyncResearchClient(self)
|
|
2417
|
+
# Override the synchronous WebsetsClient with its async counterpart.
|
|
2418
|
+
self.websets = AsyncWebsetsClient(self)
|
|
2416
2419
|
self._client = None
|
|
2417
2420
|
|
|
2418
2421
|
@property
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from .client import WebsetsClient
|
|
1
|
+
from .client import WebsetsClient, AsyncWebsetsClient
|
|
2
2
|
from .imports import ImportsClient
|
|
3
3
|
from .events import EventsClient
|
|
4
4
|
|
|
5
5
|
__all__ = [
|
|
6
6
|
"WebsetsClient",
|
|
7
|
+
"AsyncWebsetsClient",
|
|
7
8
|
"ImportsClient",
|
|
8
9
|
"EventsClient",
|
|
9
10
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import asyncio
|
|
4
4
|
from typing import List, Optional, Literal, Dict, Any, Union
|
|
5
5
|
|
|
6
6
|
from .types import (
|
|
@@ -13,29 +13,29 @@ from .types import (
|
|
|
13
13
|
PreviewWebsetParameters,
|
|
14
14
|
PreviewWebsetResponse,
|
|
15
15
|
)
|
|
16
|
-
from .core.
|
|
17
|
-
from .
|
|
18
|
-
from .
|
|
19
|
-
from .
|
|
20
|
-
from .
|
|
21
|
-
from .
|
|
22
|
-
from .
|
|
23
|
-
from .
|
|
16
|
+
from .core.async_base import WebsetsAsyncBaseClient
|
|
17
|
+
from .async_items.client import AsyncWebsetItemsClient
|
|
18
|
+
from .async_searches.client import AsyncWebsetSearchesClient
|
|
19
|
+
from .async_enrichments.client import AsyncWebsetEnrichmentsClient
|
|
20
|
+
from .async_webhooks.client import AsyncWebsetWebhooksClient
|
|
21
|
+
from .async_monitors.client import AsyncMonitorsClient
|
|
22
|
+
from .async_imports.client import AsyncImportsClient
|
|
23
|
+
from .async_events.client import AsyncEventsClient
|
|
24
24
|
|
|
25
|
-
class
|
|
26
|
-
"""
|
|
25
|
+
class AsyncWebsetsClient(WebsetsAsyncBaseClient):
|
|
26
|
+
"""Async client for managing Websets."""
|
|
27
27
|
|
|
28
28
|
def __init__(self, client):
|
|
29
29
|
super().__init__(client)
|
|
30
|
-
self.items =
|
|
31
|
-
self.searches =
|
|
32
|
-
self.enrichments =
|
|
33
|
-
self.webhooks =
|
|
34
|
-
self.monitors =
|
|
35
|
-
self.imports =
|
|
36
|
-
self.events =
|
|
30
|
+
self.items = AsyncWebsetItemsClient(client)
|
|
31
|
+
self.searches = AsyncWebsetSearchesClient(client)
|
|
32
|
+
self.enrichments = AsyncWebsetEnrichmentsClient(client)
|
|
33
|
+
self.webhooks = AsyncWebsetWebhooksClient(client)
|
|
34
|
+
self.monitors = AsyncMonitorsClient(client)
|
|
35
|
+
self.imports = AsyncImportsClient(client)
|
|
36
|
+
self.events = AsyncEventsClient(client)
|
|
37
37
|
|
|
38
|
-
def create(self, params: Union[Dict[str, Any], CreateWebsetParameters]) -> Webset:
|
|
38
|
+
async def create(self, params: Union[Dict[str, Any], CreateWebsetParameters]) -> Webset:
|
|
39
39
|
"""Create a new Webset.
|
|
40
40
|
|
|
41
41
|
Args:
|
|
@@ -44,42 +44,39 @@ class WebsetsClient(WebsetsBaseClient):
|
|
|
44
44
|
Returns:
|
|
45
45
|
Webset: The created webset.
|
|
46
46
|
"""
|
|
47
|
-
response = self.request("/v0/websets", data=params)
|
|
47
|
+
response = await self.request("/v0/websets", data=params)
|
|
48
48
|
return Webset.model_validate(response)
|
|
49
49
|
|
|
50
|
-
def preview(self, params: Union[Dict[str, Any], PreviewWebsetParameters]) -> PreviewWebsetResponse:
|
|
51
|
-
"""Preview a
|
|
52
|
-
|
|
53
|
-
Preview how a search query will be decomposed before creating a webset.
|
|
54
|
-
This endpoint performs the same query analysis that happens during webset creation,
|
|
55
|
-
allowing you to see the detected entity type, generated search criteria, and
|
|
56
|
-
available enrichment columns in advance.
|
|
50
|
+
async def preview(self, params: Union[Dict[str, Any], PreviewWebsetParameters]) -> PreviewWebsetResponse:
|
|
51
|
+
"""Preview a Webset before creating it.
|
|
57
52
|
|
|
58
53
|
Args:
|
|
59
54
|
params (PreviewWebsetParameters): The parameters for previewing a webset.
|
|
60
55
|
|
|
61
56
|
Returns:
|
|
62
|
-
PreviewWebsetResponse: The preview
|
|
57
|
+
PreviewWebsetResponse: The preview results.
|
|
63
58
|
"""
|
|
64
|
-
response = self.request("/v0/websets/preview", data=params)
|
|
59
|
+
response = await self.request("/v0/websets/preview", data=params)
|
|
65
60
|
return PreviewWebsetResponse.model_validate(response)
|
|
66
61
|
|
|
67
|
-
def get(self, id: str, *, expand: Optional[List[Literal["items"]]] = None) -> GetWebsetResponse:
|
|
62
|
+
async def get(self, id: str, *, expand: Optional[List[Literal["items"]]] = None) -> GetWebsetResponse:
|
|
68
63
|
"""Get a Webset by ID.
|
|
69
64
|
|
|
70
65
|
Args:
|
|
71
66
|
id (str): The id or externalId of the Webset.
|
|
72
|
-
expand (List[Literal["items"]], optional): Expand the response
|
|
73
|
-
Allowed values: ["items"]
|
|
67
|
+
expand (List[Literal["items"]], optional): Expand items in the response.
|
|
74
68
|
|
|
75
69
|
Returns:
|
|
76
70
|
GetWebsetResponse: The retrieved webset.
|
|
77
71
|
"""
|
|
78
|
-
params = {
|
|
79
|
-
|
|
72
|
+
params = {}
|
|
73
|
+
if expand is not None:
|
|
74
|
+
params["expand"] = expand
|
|
75
|
+
|
|
76
|
+
response = await self.request(f"/v0/websets/{id}", params=params, method="GET")
|
|
80
77
|
return GetWebsetResponse.model_validate(response)
|
|
81
78
|
|
|
82
|
-
def list(self, *, cursor: Optional[str] = None, limit: Optional[int] = None) -> ListWebsetsResponse:
|
|
79
|
+
async def list(self, *, cursor: Optional[str] = None, limit: Optional[int] = None) -> ListWebsetsResponse:
|
|
83
80
|
"""List all Websets.
|
|
84
81
|
|
|
85
82
|
Args:
|
|
@@ -90,10 +87,10 @@ class WebsetsClient(WebsetsBaseClient):
|
|
|
90
87
|
ListWebsetsResponse: List of websets.
|
|
91
88
|
"""
|
|
92
89
|
params = {k: v for k, v in {"cursor": cursor, "limit": limit}.items() if v is not None}
|
|
93
|
-
response = self.request("/v0/websets", params=params, method="GET")
|
|
90
|
+
response = await self.request("/v0/websets", params=params, method="GET")
|
|
94
91
|
return ListWebsetsResponse.model_validate(response)
|
|
95
92
|
|
|
96
|
-
def update(self, id: str, params: Union[Dict[str, Any], UpdateWebsetRequest]) -> Webset:
|
|
93
|
+
async def update(self, id: str, params: Union[Dict[str, Any], UpdateWebsetRequest]) -> Webset:
|
|
97
94
|
"""Update a Webset.
|
|
98
95
|
|
|
99
96
|
Args:
|
|
@@ -103,10 +100,10 @@ class WebsetsClient(WebsetsBaseClient):
|
|
|
103
100
|
Returns:
|
|
104
101
|
Webset: The updated webset.
|
|
105
102
|
"""
|
|
106
|
-
response = self.request(f"/v0/websets/{id}", data=params, method="POST")
|
|
103
|
+
response = await self.request(f"/v0/websets/{id}", data=params, method="POST")
|
|
107
104
|
return Webset.model_validate(response)
|
|
108
105
|
|
|
109
|
-
def delete(self, id: str) -> Webset:
|
|
106
|
+
async def delete(self, id: str) -> Webset:
|
|
110
107
|
"""Delete a Webset.
|
|
111
108
|
|
|
112
109
|
Args:
|
|
@@ -115,10 +112,10 @@ class WebsetsClient(WebsetsBaseClient):
|
|
|
115
112
|
Returns:
|
|
116
113
|
Webset: The deleted webset.
|
|
117
114
|
"""
|
|
118
|
-
response = self.request(f"/v0/websets/{id}", method="DELETE")
|
|
115
|
+
response = await self.request(f"/v0/websets/{id}", method="DELETE")
|
|
119
116
|
return Webset.model_validate(response)
|
|
120
117
|
|
|
121
|
-
def cancel(self, id: str) -> Webset:
|
|
118
|
+
async def cancel(self, id: str) -> Webset:
|
|
122
119
|
"""Cancel a running Webset.
|
|
123
120
|
|
|
124
121
|
Args:
|
|
@@ -127,10 +124,10 @@ class WebsetsClient(WebsetsBaseClient):
|
|
|
127
124
|
Returns:
|
|
128
125
|
Webset: The canceled webset.
|
|
129
126
|
"""
|
|
130
|
-
response = self.request(f"/v0/websets/{id}/cancel", method="POST")
|
|
127
|
+
response = await self.request(f"/v0/websets/{id}/cancel", method="POST")
|
|
131
128
|
return Webset.model_validate(response)
|
|
132
129
|
|
|
133
|
-
def wait_until_idle(self, id: str, *, timeout: int = 3600, poll_interval: int = 5) -> Webset:
|
|
130
|
+
async def wait_until_idle(self, id: str, *, timeout: int = 3600, poll_interval: int = 5) -> Webset:
|
|
134
131
|
"""Wait until a Webset is idle.
|
|
135
132
|
|
|
136
133
|
Args:
|
|
@@ -144,13 +141,13 @@ class WebsetsClient(WebsetsBaseClient):
|
|
|
144
141
|
Raises:
|
|
145
142
|
TimeoutError: If the webset does not become idle within the timeout period.
|
|
146
143
|
"""
|
|
147
|
-
start_time =
|
|
144
|
+
start_time = asyncio.get_event_loop().time()
|
|
148
145
|
while True:
|
|
149
|
-
webset = self.get(id)
|
|
146
|
+
webset = await self.get(id)
|
|
150
147
|
if webset.status == WebsetStatus.idle.value:
|
|
151
148
|
return webset
|
|
152
149
|
|
|
153
|
-
if
|
|
150
|
+
if asyncio.get_event_loop().time() - start_time > timeout:
|
|
154
151
|
raise TimeoutError(f"Webset {id} did not become idle within {timeout} seconds")
|
|
155
152
|
|
|
156
|
-
|
|
153
|
+
await asyncio.sleep(poll_interval)
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import asyncio
|
|
5
|
+
from typing import List, Optional, Literal, Dict, Any, Union
|
|
6
|
+
|
|
7
|
+
from .types import (
|
|
8
|
+
Webset,
|
|
9
|
+
ListWebsetsResponse,
|
|
10
|
+
GetWebsetResponse,
|
|
11
|
+
UpdateWebsetRequest,
|
|
12
|
+
WebsetStatus,
|
|
13
|
+
CreateWebsetParameters,
|
|
14
|
+
PreviewWebsetParameters,
|
|
15
|
+
PreviewWebsetResponse,
|
|
16
|
+
)
|
|
17
|
+
from .core.base import WebsetsBaseClient
|
|
18
|
+
from .core.async_base import WebsetsAsyncBaseClient
|
|
19
|
+
from .items import WebsetItemsClient, AsyncWebsetItemsClient
|
|
20
|
+
from .searches import WebsetSearchesClient, AsyncWebsetSearchesClient
|
|
21
|
+
from .enrichments import WebsetEnrichmentsClient, AsyncWebsetEnrichmentsClient
|
|
22
|
+
from .webhooks import WebsetWebhooksClient, AsyncWebsetWebhooksClient
|
|
23
|
+
from .monitors import MonitorsClient, AsyncMonitorsClient
|
|
24
|
+
from .imports import ImportsClient, AsyncImportsClient
|
|
25
|
+
from .events import EventsClient, AsyncEventsClient
|
|
26
|
+
|
|
27
|
+
class WebsetsClient(WebsetsBaseClient):
|
|
28
|
+
"""Client for managing Websets."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, client):
|
|
31
|
+
super().__init__(client)
|
|
32
|
+
self.items = WebsetItemsClient(client)
|
|
33
|
+
self.searches = WebsetSearchesClient(client)
|
|
34
|
+
self.enrichments = WebsetEnrichmentsClient(client)
|
|
35
|
+
self.webhooks = WebsetWebhooksClient(client)
|
|
36
|
+
self.monitors = MonitorsClient(client)
|
|
37
|
+
self.imports = ImportsClient(client)
|
|
38
|
+
self.events = EventsClient(client)
|
|
39
|
+
|
|
40
|
+
def create(self, params: Union[Dict[str, Any], CreateWebsetParameters]) -> Webset:
|
|
41
|
+
"""Create a new Webset.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
params (CreateWebsetParameters): The parameters for creating a webset.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Webset: The created webset.
|
|
48
|
+
"""
|
|
49
|
+
response = self.request("/v0/websets", data=params)
|
|
50
|
+
return Webset.model_validate(response)
|
|
51
|
+
|
|
52
|
+
def preview(self, params: Union[Dict[str, Any], PreviewWebsetParameters]) -> PreviewWebsetResponse:
|
|
53
|
+
"""Preview a webset query.
|
|
54
|
+
|
|
55
|
+
Preview how a search query will be decomposed before creating a webset.
|
|
56
|
+
This endpoint performs the same query analysis that happens during webset creation,
|
|
57
|
+
allowing you to see the detected entity type, generated search criteria, and
|
|
58
|
+
available enrichment columns in advance.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
params (PreviewWebsetParameters): The parameters for previewing a webset.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
PreviewWebsetResponse: The preview response showing how the query will be decomposed.
|
|
65
|
+
"""
|
|
66
|
+
response = self.request("/v0/websets/preview", data=params)
|
|
67
|
+
return PreviewWebsetResponse.model_validate(response)
|
|
68
|
+
|
|
69
|
+
def get(self, id: str, *, expand: Optional[List[Literal["items"]]] = None) -> GetWebsetResponse:
|
|
70
|
+
"""Get a Webset by ID.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
id (str): The id or externalId of the Webset.
|
|
74
|
+
expand (List[Literal["items"]], optional): Expand the response with specified resources.
|
|
75
|
+
Allowed values: ["items"]
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
GetWebsetResponse: The retrieved webset.
|
|
79
|
+
"""
|
|
80
|
+
params = {"expand": expand} if expand else {}
|
|
81
|
+
response = self.request(f"/v0/websets/{id}", params=params, method="GET")
|
|
82
|
+
return GetWebsetResponse.model_validate(response)
|
|
83
|
+
|
|
84
|
+
def list(self, *, cursor: Optional[str] = None, limit: Optional[int] = None) -> ListWebsetsResponse:
|
|
85
|
+
"""List all Websets.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
cursor (str, optional): The cursor to paginate through the results.
|
|
89
|
+
limit (int, optional): The number of results to return (max 200).
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
ListWebsetsResponse: List of websets.
|
|
93
|
+
"""
|
|
94
|
+
params = {k: v for k, v in {"cursor": cursor, "limit": limit}.items() if v is not None}
|
|
95
|
+
response = self.request("/v0/websets", params=params, method="GET")
|
|
96
|
+
return ListWebsetsResponse.model_validate(response)
|
|
97
|
+
|
|
98
|
+
def update(self, id: str, params: Union[Dict[str, Any], UpdateWebsetRequest]) -> Webset:
|
|
99
|
+
"""Update a Webset.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
id (str): The id or externalId of the Webset.
|
|
103
|
+
params (UpdateWebsetRequest): The parameters for updating a webset.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Webset: The updated webset.
|
|
107
|
+
"""
|
|
108
|
+
response = self.request(f"/v0/websets/{id}", data=params, method="POST")
|
|
109
|
+
return Webset.model_validate(response)
|
|
110
|
+
|
|
111
|
+
def delete(self, id: str) -> Webset:
|
|
112
|
+
"""Delete a Webset.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
id (str): The id or externalId of the Webset.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Webset: The deleted webset.
|
|
119
|
+
"""
|
|
120
|
+
response = self.request(f"/v0/websets/{id}", method="DELETE")
|
|
121
|
+
return Webset.model_validate(response)
|
|
122
|
+
|
|
123
|
+
def cancel(self, id: str) -> Webset:
|
|
124
|
+
"""Cancel a running Webset.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
id (str): The id or externalId of the Webset.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Webset: The canceled webset.
|
|
131
|
+
"""
|
|
132
|
+
response = self.request(f"/v0/websets/{id}/cancel", method="POST")
|
|
133
|
+
return Webset.model_validate(response)
|
|
134
|
+
|
|
135
|
+
def wait_until_idle(self, id: str, *, timeout: int = 3600, poll_interval: int = 5) -> Webset:
|
|
136
|
+
"""Wait until a Webset is idle.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
id (str): The id or externalId of the Webset.
|
|
140
|
+
timeout (int, optional): Maximum time to wait in seconds. Defaults to 3600.
|
|
141
|
+
poll_interval (int, optional): Time to wait between polls in seconds. Defaults to 5.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Webset: The webset once it's idle.
|
|
145
|
+
|
|
146
|
+
Raises:
|
|
147
|
+
TimeoutError: If the webset does not become idle within the timeout period.
|
|
148
|
+
"""
|
|
149
|
+
start_time = time.time()
|
|
150
|
+
while True:
|
|
151
|
+
webset = self.get(id)
|
|
152
|
+
if webset.status == WebsetStatus.idle.value:
|
|
153
|
+
return webset
|
|
154
|
+
|
|
155
|
+
if time.time() - start_time > timeout:
|
|
156
|
+
raise TimeoutError(f"Webset {id} did not become idle within {timeout} seconds")
|
|
157
|
+
|
|
158
|
+
time.sleep(poll_interval)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class AsyncWebsetsClient(WebsetsAsyncBaseClient):
|
|
162
|
+
"""Async client for managing Websets."""
|
|
163
|
+
|
|
164
|
+
def __init__(self, client):
|
|
165
|
+
super().__init__(client)
|
|
166
|
+
self.items = AsyncWebsetItemsClient(client)
|
|
167
|
+
self.searches = AsyncWebsetSearchesClient(client)
|
|
168
|
+
self.enrichments = AsyncWebsetEnrichmentsClient(client)
|
|
169
|
+
self.webhooks = AsyncWebsetWebhooksClient(client)
|
|
170
|
+
self.monitors = AsyncMonitorsClient(client)
|
|
171
|
+
self.imports = AsyncImportsClient(client)
|
|
172
|
+
self.events = AsyncEventsClient(client)
|
|
173
|
+
|
|
174
|
+
async def create(self, params: Union[Dict[str, Any], CreateWebsetParameters]) -> Webset:
|
|
175
|
+
"""Create a new Webset.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
params (CreateWebsetParameters): The parameters for creating a webset.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Webset: The created webset.
|
|
182
|
+
"""
|
|
183
|
+
response = await self.request("/v0/websets", data=params)
|
|
184
|
+
return Webset.model_validate(response)
|
|
185
|
+
|
|
186
|
+
async def preview(self, params: Union[Dict[str, Any], PreviewWebsetParameters]) -> PreviewWebsetResponse:
|
|
187
|
+
"""Preview a Webset before creating it.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
params (PreviewWebsetParameters): The parameters for previewing a webset.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
PreviewWebsetResponse: The preview results.
|
|
194
|
+
"""
|
|
195
|
+
response = await self.request("/v0/websets/preview", data=params)
|
|
196
|
+
return PreviewWebsetResponse.model_validate(response)
|
|
197
|
+
|
|
198
|
+
async def get(self, id: str, *, expand: Optional[List[Literal["items"]]] = None) -> GetWebsetResponse:
|
|
199
|
+
"""Get a Webset by ID.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
id (str): The id or externalId of the Webset.
|
|
203
|
+
expand (List[Literal["items"]], optional): Expand items in the response.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
GetWebsetResponse: The retrieved webset.
|
|
207
|
+
"""
|
|
208
|
+
params = {}
|
|
209
|
+
if expand is not None:
|
|
210
|
+
params["expand"] = expand
|
|
211
|
+
|
|
212
|
+
response = await self.request(f"/v0/websets/{id}", params=params, method="GET")
|
|
213
|
+
return GetWebsetResponse.model_validate(response)
|
|
214
|
+
|
|
215
|
+
async def list(self, *, cursor: Optional[str] = None, limit: Optional[int] = None) -> ListWebsetsResponse:
|
|
216
|
+
"""List all Websets.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
cursor (str, optional): The cursor to paginate through the results.
|
|
220
|
+
limit (int, optional): The number of results to return (max 200).
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
ListWebsetsResponse: List of websets.
|
|
224
|
+
"""
|
|
225
|
+
params = {k: v for k, v in {"cursor": cursor, "limit": limit}.items() if v is not None}
|
|
226
|
+
response = await self.request("/v0/websets", params=params, method="GET")
|
|
227
|
+
return ListWebsetsResponse.model_validate(response)
|
|
228
|
+
|
|
229
|
+
async def update(self, id: str, params: Union[Dict[str, Any], UpdateWebsetRequest]) -> Webset:
|
|
230
|
+
"""Update a Webset.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
id (str): The id or externalId of the Webset.
|
|
234
|
+
params (UpdateWebsetRequest): The parameters for updating a webset.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
Webset: The updated webset.
|
|
238
|
+
"""
|
|
239
|
+
response = await self.request(f"/v0/websets/{id}", data=params, method="POST")
|
|
240
|
+
return Webset.model_validate(response)
|
|
241
|
+
|
|
242
|
+
async def delete(self, id: str) -> Webset:
|
|
243
|
+
"""Delete a Webset.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
id (str): The id or externalId of the Webset.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Webset: The deleted webset.
|
|
250
|
+
"""
|
|
251
|
+
response = await self.request(f"/v0/websets/{id}", method="DELETE")
|
|
252
|
+
return Webset.model_validate(response)
|
|
253
|
+
|
|
254
|
+
async def cancel(self, id: str) -> Webset:
|
|
255
|
+
"""Cancel a running Webset.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
id (str): The id or externalId of the Webset.
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Webset: The canceled webset.
|
|
262
|
+
"""
|
|
263
|
+
response = await self.request(f"/v0/websets/{id}/cancel", method="POST")
|
|
264
|
+
return Webset.model_validate(response)
|
|
265
|
+
|
|
266
|
+
async def wait_until_idle(self, id: str, *, timeout: int = 3600, poll_interval: int = 5) -> Webset:
|
|
267
|
+
"""Wait until a Webset is idle.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
id (str): The id or externalId of the Webset.
|
|
271
|
+
timeout (int, optional): Maximum time to wait in seconds. Defaults to 3600.
|
|
272
|
+
poll_interval (int, optional): Time to wait between polls in seconds. Defaults to 5.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
Webset: The webset once it's idle.
|
|
276
|
+
|
|
277
|
+
Raises:
|
|
278
|
+
TimeoutError: If the webset does not become idle within the timeout period.
|
|
279
|
+
"""
|
|
280
|
+
start_time = asyncio.get_event_loop().time()
|
|
281
|
+
while True:
|
|
282
|
+
webset = await self.get(id)
|
|
283
|
+
if webset.status == WebsetStatus.idle.value:
|
|
284
|
+
return webset
|
|
285
|
+
|
|
286
|
+
if asyncio.get_event_loop().time() - start_time > timeout:
|
|
287
|
+
raise TimeoutError(f"Webset {id} did not become idle within {timeout} seconds")
|
|
288
|
+
|
|
289
|
+
await asyncio.sleep(poll_interval)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from ..types import *
|
|
2
|
+
from .base import WebsetsBaseClient
|
|
3
|
+
from .async_base import WebsetsAsyncBaseClient
|
|
2
4
|
import sys
|
|
3
5
|
|
|
4
6
|
# Get all public names from model module that don't start with underscore
|
|
5
7
|
model_module = sys.modules[__name__]
|
|
6
|
-
__all__ = ['WebsetsBaseClient', 'ExaBaseModel'] + [
|
|
8
|
+
__all__ = ['WebsetsBaseClient', 'WebsetsAsyncBaseClient', 'ExaBaseModel'] + [
|
|
7
9
|
name for name in dir(model_module)
|
|
8
|
-
if not name.startswith('_') and name not in ('WebsetsBaseClient', 'ExaBaseModel')
|
|
10
|
+
if not name.startswith('_') and name not in ('WebsetsBaseClient', 'WebsetsAsyncBaseClient', 'ExaBaseModel')
|
|
9
11
|
]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import asyncio
|
|
5
|
+
from typing import Any, Dict, Optional, Type, TypeVar, Union
|
|
6
|
+
|
|
7
|
+
from .base import ExaBaseModel
|
|
8
|
+
|
|
9
|
+
# Generic type for any ExaBaseModel
|
|
10
|
+
ModelT = TypeVar('ModelT', bound=ExaBaseModel)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WebsetsAsyncBaseClient:
|
|
15
|
+
base_url: str
|
|
16
|
+
|
|
17
|
+
"""Base async client for Exa API resources."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, client):
|
|
20
|
+
"""Initialize the async client.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
client: The parent AsyncExa client.
|
|
24
|
+
"""
|
|
25
|
+
self._client = client
|
|
26
|
+
|
|
27
|
+
def _prepare_data(self, data: Union[Dict[str, Any], ExaBaseModel, str], model_class: Optional[Type[ModelT]] = None) -> Union[Dict[str, Any], str]:
|
|
28
|
+
"""Prepare data for API request, converting dict to model if needed.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
data: Either a dictionary, model instance, or string
|
|
32
|
+
model_class: The model class to use if data is a dictionary
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Dictionary prepared for API request or string if string data was provided
|
|
36
|
+
"""
|
|
37
|
+
if isinstance(data, str):
|
|
38
|
+
# Return string as is
|
|
39
|
+
return data
|
|
40
|
+
elif isinstance(data, dict) and model_class:
|
|
41
|
+
# Convert dict to model instance
|
|
42
|
+
model_instance = model_class.model_validate(data)
|
|
43
|
+
return model_instance.model_dump(mode='json', by_alias=True, exclude_none=True)
|
|
44
|
+
elif isinstance(data, ExaBaseModel):
|
|
45
|
+
# Use model's dump method
|
|
46
|
+
return data.model_dump(mode='json', by_alias=True, exclude_none=True)
|
|
47
|
+
elif isinstance(data, dict):
|
|
48
|
+
# Use dict directly
|
|
49
|
+
return data
|
|
50
|
+
else:
|
|
51
|
+
raise TypeError(f"Expected dict, ExaBaseModel, or str, got {type(data)}")
|
|
52
|
+
|
|
53
|
+
async def request(self, endpoint: str, data: Optional[Union[Dict[str, Any], ExaBaseModel, str]] = None,
|
|
54
|
+
method: str = "POST", params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
55
|
+
"""Make an async request to the Exa API.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
endpoint (str): The API endpoint to request.
|
|
59
|
+
data (Union[Dict[str, Any], ExaBaseModel, str], optional): The request data. Can be a dictionary, model instance, or string. Defaults to None.
|
|
60
|
+
method (str, optional): The HTTP method. Defaults to "POST".
|
|
61
|
+
params (Dict[str, Any], optional): The query parameters. Defaults to None.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Dict[str, Any]: The API response.
|
|
65
|
+
"""
|
|
66
|
+
if isinstance(data, str):
|
|
67
|
+
# If data is a string, pass it as is
|
|
68
|
+
pass
|
|
69
|
+
elif data is not None and isinstance(data, ExaBaseModel):
|
|
70
|
+
# If data is a model instance, convert it to a dict
|
|
71
|
+
data = data.model_dump(mode='json', by_alias=True, exclude_none=True)
|
|
72
|
+
|
|
73
|
+
# Ensure proper URL construction by removing leading slash from endpoint if present
|
|
74
|
+
if endpoint.startswith("/"):
|
|
75
|
+
endpoint = endpoint[1:]
|
|
76
|
+
|
|
77
|
+
return await self._client.async_request("/websets/" + endpoint, data=data, method=method, params=params)
|