exa-py 1.15.5__tar.gz → 1.16.0__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.5 → exa_py-1.16.0}/PKG-INFO +3 -1
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/api.py +41 -14
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/client.py +11 -4
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/core/async_base.py +32 -2
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/core/base.py +32 -2
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/searches/client.py +12 -5
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/types.py +15 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/pyproject.toml +10 -7
- {exa_py-1.15.5 → exa_py-1.16.0}/README.md +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/py.typed +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/research/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/research/async_client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/research/base.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/research/models.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/research/sync_client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/research/utils.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/utils.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/_generator/pydantic/BaseModel.jinja2 +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/async_client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/core/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/enrichments/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/enrichments/client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/events/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/events/client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/imports/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/imports/client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/items/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/items/client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/monitors/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/monitors/client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/monitors/runs/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/monitors/runs/client.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/searches/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/webhooks/__init__.py +0 -0
- {exa_py-1.15.5 → exa_py-1.16.0}/exa_py/websets/webhooks/client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: exa-py
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.0
|
|
4
4
|
Summary: Python SDK for Exa API.
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Exa AI
|
|
@@ -13,9 +13,11 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Requires-Dist: httpcore (>=1.0.9)
|
|
16
17
|
Requires-Dist: httpx (>=0.28.1)
|
|
17
18
|
Requires-Dist: openai (>=1.48)
|
|
18
19
|
Requires-Dist: pydantic (>=2.10.6)
|
|
20
|
+
Requires-Dist: python-dotenv (>=1.0.1)
|
|
19
21
|
Requires-Dist: requests (>=2.32.3)
|
|
20
22
|
Requires-Dist: typing-extensions (>=4.12.2)
|
|
21
23
|
Description-Content-Type: text/markdown
|
|
@@ -142,7 +142,9 @@ SEARCH_OPTIONS_TYPES = {
|
|
|
142
142
|
list
|
|
143
143
|
], # Must not be present in webpage text. (One string, up to 5 words)
|
|
144
144
|
"use_autoprompt": [bool], # Convert query to Exa. (Default: false)
|
|
145
|
-
"type": [
|
|
145
|
+
"type": [
|
|
146
|
+
str
|
|
147
|
+
], # 'keyword', 'neural', 'hybrid', 'fast', 'deep', or 'auto' (Default: auto)
|
|
146
148
|
"category": [
|
|
147
149
|
str
|
|
148
150
|
], # A data category to focus on: 'company', 'research paper', 'news', 'pdf', 'github', 'tweet', 'personal site', 'linkedin profile', 'financial report'
|
|
@@ -260,6 +262,10 @@ class HighlightsContentsOptions(TypedDict, total=False):
|
|
|
260
262
|
query (str): The query string for the highlights.
|
|
261
263
|
num_sentences (int): Size of highlights to return, in sentences. Default: 5
|
|
262
264
|
highlights_per_url (int): Number of highlights to return per URL. Default: 1
|
|
265
|
+
|
|
266
|
+
NOTE: When using the "deep" search type, only the default highlights=True is supported.
|
|
267
|
+
These options will NOT be respected. Highlights will always be based on the user's query,
|
|
268
|
+
and the number and length may vary.
|
|
263
269
|
"""
|
|
264
270
|
|
|
265
271
|
query: str
|
|
@@ -1164,6 +1170,7 @@ class Exa:
|
|
|
1164
1170
|
data: Optional[Union[Dict[str, Any], str]] = None,
|
|
1165
1171
|
method: str = "POST",
|
|
1166
1172
|
params: Optional[Dict[str, Any]] = None,
|
|
1173
|
+
headers: Optional[Dict[str, str]] = None,
|
|
1167
1174
|
) -> Union[Dict[str, Any], requests.Response]:
|
|
1168
1175
|
"""Send a request to the Exa API, optionally streaming if data['stream'] is True.
|
|
1169
1176
|
|
|
@@ -1172,6 +1179,7 @@ class Exa:
|
|
|
1172
1179
|
data (dict, optional): The JSON payload to send. Defaults to None.
|
|
1173
1180
|
method (str, optional): The HTTP method to use. Defaults to "POST".
|
|
1174
1181
|
params (Dict[str, Any], optional): Query parameters to include. Defaults to None.
|
|
1182
|
+
headers (Dict[str, str], optional): Additional headers to include in the request. Defaults to None.
|
|
1175
1183
|
|
|
1176
1184
|
Returns:
|
|
1177
1185
|
Union[dict, requests.Response]: If streaming, returns the Response object.
|
|
@@ -1193,38 +1201,43 @@ class Exa:
|
|
|
1193
1201
|
params and params.get("stream") == "true"
|
|
1194
1202
|
)
|
|
1195
1203
|
|
|
1204
|
+
# Merge additional headers with existing headers
|
|
1205
|
+
request_headers = {**self.headers}
|
|
1206
|
+
if headers:
|
|
1207
|
+
request_headers.update(headers)
|
|
1208
|
+
|
|
1196
1209
|
if method.upper() == "GET":
|
|
1197
1210
|
if needs_streaming:
|
|
1198
1211
|
res = requests.get(
|
|
1199
1212
|
self.base_url + endpoint,
|
|
1200
|
-
headers=
|
|
1213
|
+
headers=request_headers,
|
|
1201
1214
|
params=params,
|
|
1202
1215
|
stream=True,
|
|
1203
1216
|
)
|
|
1204
1217
|
return res
|
|
1205
1218
|
else:
|
|
1206
1219
|
res = requests.get(
|
|
1207
|
-
self.base_url + endpoint, headers=
|
|
1220
|
+
self.base_url + endpoint, headers=request_headers, params=params
|
|
1208
1221
|
)
|
|
1209
1222
|
elif method.upper() == "POST":
|
|
1210
1223
|
if needs_streaming:
|
|
1211
1224
|
res = requests.post(
|
|
1212
1225
|
self.base_url + endpoint,
|
|
1213
1226
|
data=json_data,
|
|
1214
|
-
headers=
|
|
1227
|
+
headers=request_headers,
|
|
1215
1228
|
stream=True,
|
|
1216
1229
|
)
|
|
1217
1230
|
return res
|
|
1218
1231
|
else:
|
|
1219
1232
|
res = requests.post(
|
|
1220
|
-
self.base_url + endpoint, data=json_data, headers=
|
|
1233
|
+
self.base_url + endpoint, data=json_data, headers=request_headers
|
|
1221
1234
|
)
|
|
1222
1235
|
elif method.upper() == "PATCH":
|
|
1223
1236
|
res = requests.patch(
|
|
1224
|
-
self.base_url + endpoint, data=json_data, headers=
|
|
1237
|
+
self.base_url + endpoint, data=json_data, headers=request_headers
|
|
1225
1238
|
)
|
|
1226
1239
|
elif method.upper() == "DELETE":
|
|
1227
|
-
res = requests.delete(self.base_url + endpoint, headers=
|
|
1240
|
+
res = requests.delete(self.base_url + endpoint, headers=request_headers)
|
|
1228
1241
|
else:
|
|
1229
1242
|
raise ValueError(f"Unsupported HTTP method: {method}")
|
|
1230
1243
|
|
|
@@ -1268,7 +1281,7 @@ class Exa:
|
|
|
1268
1281
|
include_text (List[str], optional): Strings that must appear in the page text.
|
|
1269
1282
|
exclude_text (List[str], optional): Strings that must not appear in the page text.
|
|
1270
1283
|
use_autoprompt (bool, optional): Convert query to Exa (default False).
|
|
1271
|
-
type (str, optional): 'keyword', 'neural', 'hybrid', 'fast', or 'auto' (default 'auto').
|
|
1284
|
+
type (str, optional): 'keyword', 'neural', 'hybrid', 'fast', 'deep', or 'auto' (default 'auto').
|
|
1272
1285
|
category (str, optional): e.g. 'company'
|
|
1273
1286
|
flags (List[str], optional): Experimental flags for Exa usage.
|
|
1274
1287
|
moderation (bool, optional): If True, the search results will be moderated for safety.
|
|
@@ -2431,7 +2444,12 @@ class AsyncExa(Exa):
|
|
|
2431
2444
|
return self._client
|
|
2432
2445
|
|
|
2433
2446
|
async def async_request(
|
|
2434
|
-
self,
|
|
2447
|
+
self,
|
|
2448
|
+
endpoint: str,
|
|
2449
|
+
data=None,
|
|
2450
|
+
method: str = "POST",
|
|
2451
|
+
params=None,
|
|
2452
|
+
headers: Optional[Dict[str, str]] = None,
|
|
2435
2453
|
):
|
|
2436
2454
|
"""Send a request to the Exa API, optionally streaming if data['stream'] is True.
|
|
2437
2455
|
|
|
@@ -2440,6 +2458,7 @@ class AsyncExa(Exa):
|
|
|
2440
2458
|
data (dict, optional): The JSON payload to send.
|
|
2441
2459
|
method (str, optional): The HTTP method to use. Defaults to "POST".
|
|
2442
2460
|
params (dict, optional): Query parameters.
|
|
2461
|
+
headers (Dict[str, str], optional): Additional headers to include in the request. Defaults to None.
|
|
2443
2462
|
|
|
2444
2463
|
Returns:
|
|
2445
2464
|
Union[dict, httpx.Response]: If streaming, returns the Response object.
|
|
@@ -2453,27 +2472,35 @@ class AsyncExa(Exa):
|
|
|
2453
2472
|
params and params.get("stream") == "true"
|
|
2454
2473
|
)
|
|
2455
2474
|
|
|
2475
|
+
# Merge additional headers with existing headers
|
|
2476
|
+
request_headers = {**self.headers}
|
|
2477
|
+
if headers:
|
|
2478
|
+
request_headers.update(headers)
|
|
2479
|
+
|
|
2456
2480
|
if method.upper() == "GET":
|
|
2457
2481
|
if needs_streaming:
|
|
2458
2482
|
request = httpx.Request(
|
|
2459
|
-
"GET",
|
|
2483
|
+
"GET",
|
|
2484
|
+
self.base_url + endpoint,
|
|
2485
|
+
params=params,
|
|
2486
|
+
headers=request_headers,
|
|
2460
2487
|
)
|
|
2461
2488
|
res = await self.client.send(request, stream=True)
|
|
2462
2489
|
return res
|
|
2463
2490
|
else:
|
|
2464
2491
|
res = await self.client.get(
|
|
2465
|
-
self.base_url + endpoint, params=params, headers=
|
|
2492
|
+
self.base_url + endpoint, params=params, headers=request_headers
|
|
2466
2493
|
)
|
|
2467
2494
|
elif method.upper() == "POST":
|
|
2468
2495
|
if needs_streaming:
|
|
2469
2496
|
request = httpx.Request(
|
|
2470
|
-
"POST", self.base_url + endpoint, json=data, headers=
|
|
2497
|
+
"POST", self.base_url + endpoint, json=data, headers=request_headers
|
|
2471
2498
|
)
|
|
2472
2499
|
res = await self.client.send(request, stream=True)
|
|
2473
2500
|
return res
|
|
2474
2501
|
else:
|
|
2475
2502
|
res = await self.client.post(
|
|
2476
|
-
self.base_url + endpoint, json=data, headers=
|
|
2503
|
+
self.base_url + endpoint, json=data, headers=request_headers
|
|
2477
2504
|
)
|
|
2478
2505
|
if res.status_code != 200 and res.status_code != 201:
|
|
2479
2506
|
raise ValueError(
|
|
@@ -2515,7 +2542,7 @@ class AsyncExa(Exa):
|
|
|
2515
2542
|
include_text (List[str], optional): Strings that must appear in the page text.
|
|
2516
2543
|
exclude_text (List[str], optional): Strings that must not appear in the page text.
|
|
2517
2544
|
use_autoprompt (bool, optional): Convert query to Exa (default False).
|
|
2518
|
-
type (str, optional): 'keyword', 'neural', 'hybrid', 'fast', or 'auto' (default 'auto').
|
|
2545
|
+
type (str, optional): 'keyword', 'neural', 'hybrid', 'fast', 'deep', or 'auto' (default 'auto').
|
|
2519
2546
|
category (str, optional): e.g. 'company'
|
|
2520
2547
|
flags (List[str], optional): Experimental flags for Exa usage.
|
|
2521
2548
|
moderation (bool, optional): If True, the search results will be moderated for safety.
|
|
@@ -13,6 +13,7 @@ from .types import (
|
|
|
13
13
|
CreateWebsetParameters,
|
|
14
14
|
PreviewWebsetParameters,
|
|
15
15
|
PreviewWebsetResponse,
|
|
16
|
+
RequestOptions,
|
|
16
17
|
)
|
|
17
18
|
from .core.base import WebsetsBaseClient
|
|
18
19
|
from .core.async_base import WebsetsAsyncBaseClient
|
|
@@ -37,16 +38,19 @@ class WebsetsClient(WebsetsBaseClient):
|
|
|
37
38
|
self.imports = ImportsClient(client)
|
|
38
39
|
self.events = EventsClient(client)
|
|
39
40
|
|
|
40
|
-
def create(self, params: Union[Dict[str, Any], CreateWebsetParameters]
|
|
41
|
+
def create(self, params: Union[Dict[str, Any], CreateWebsetParameters],
|
|
42
|
+
options: Optional[Union[Dict[str, Any], RequestOptions]] = None) -> Webset:
|
|
41
43
|
"""Create a new Webset.
|
|
42
44
|
|
|
43
45
|
Args:
|
|
44
46
|
params (CreateWebsetParameters): The parameters for creating a webset.
|
|
47
|
+
options (RequestOptions, optional): Request options including priority and/or custom headers.
|
|
48
|
+
Can specify priority as 'low', 'medium', or 'high'.
|
|
45
49
|
|
|
46
50
|
Returns:
|
|
47
51
|
Webset: The created webset.
|
|
48
52
|
"""
|
|
49
|
-
response = self.request("/v0/websets", data=params)
|
|
53
|
+
response = self.request("/v0/websets", data=params, options=options)
|
|
50
54
|
return Webset.model_validate(response)
|
|
51
55
|
|
|
52
56
|
def preview(self, params: Union[Dict[str, Any], PreviewWebsetParameters]) -> PreviewWebsetResponse:
|
|
@@ -171,16 +175,19 @@ class AsyncWebsetsClient(WebsetsAsyncBaseClient):
|
|
|
171
175
|
self.imports = AsyncImportsClient(client)
|
|
172
176
|
self.events = AsyncEventsClient(client)
|
|
173
177
|
|
|
174
|
-
async def create(self, params: Union[Dict[str, Any], CreateWebsetParameters]
|
|
178
|
+
async def create(self, params: Union[Dict[str, Any], CreateWebsetParameters],
|
|
179
|
+
options: Optional[Union[Dict[str, Any], RequestOptions]] = None) -> Webset:
|
|
175
180
|
"""Create a new Webset.
|
|
176
181
|
|
|
177
182
|
Args:
|
|
178
183
|
params (CreateWebsetParameters): The parameters for creating a webset.
|
|
184
|
+
options (RequestOptions, optional): Request options including priority and/or custom headers.
|
|
185
|
+
Can specify priority as 'low', 'medium', or 'high'.
|
|
179
186
|
|
|
180
187
|
Returns:
|
|
181
188
|
Webset: The created webset.
|
|
182
189
|
"""
|
|
183
|
-
response = await self.request("/v0/websets", data=params)
|
|
190
|
+
response = await self.request("/v0/websets", data=params, options=options)
|
|
184
191
|
return Webset.model_validate(response)
|
|
185
192
|
|
|
186
193
|
async def preview(self, params: Union[Dict[str, Any], PreviewWebsetParameters]) -> PreviewWebsetResponse:
|
|
@@ -51,7 +51,8 @@ class WebsetsAsyncBaseClient:
|
|
|
51
51
|
raise TypeError(f"Expected dict, ExaBaseModel, or str, got {type(data)}")
|
|
52
52
|
|
|
53
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
|
|
54
|
+
method: str = "POST", params: Optional[Dict[str, Any]] = None,
|
|
55
|
+
headers: Optional[Dict[str, str]] = None, options: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
55
56
|
"""Make an async request to the Exa API.
|
|
56
57
|
|
|
57
58
|
Args:
|
|
@@ -59,6 +60,8 @@ class WebsetsAsyncBaseClient:
|
|
|
59
60
|
data (Union[Dict[str, Any], ExaBaseModel, str], optional): The request data. Can be a dictionary, model instance, or string. Defaults to None.
|
|
60
61
|
method (str, optional): The HTTP method. Defaults to "POST".
|
|
61
62
|
params (Dict[str, Any], optional): The query parameters. Defaults to None.
|
|
63
|
+
headers (Dict[str, str], optional): Custom headers to include in the request. Defaults to None.
|
|
64
|
+
options (Dict[str, Any], optional): Request options that may include 'priority' and/or 'headers'. Defaults to None.
|
|
62
65
|
|
|
63
66
|
Returns:
|
|
64
67
|
Dict[str, Any]: The API response.
|
|
@@ -70,8 +73,35 @@ class WebsetsAsyncBaseClient:
|
|
|
70
73
|
# If data is a model instance, convert it to a dict
|
|
71
74
|
data = data.model_dump(mode='json', by_alias=True, exclude_none=True)
|
|
72
75
|
|
|
76
|
+
# Process options to build headers
|
|
77
|
+
final_headers = {}
|
|
78
|
+
|
|
79
|
+
# If options are provided, process them
|
|
80
|
+
if options:
|
|
81
|
+
# Handle RequestOptions model
|
|
82
|
+
if hasattr(options, 'priority') or hasattr(options, 'headers'):
|
|
83
|
+
# It's a RequestOptions instance
|
|
84
|
+
if hasattr(options, 'priority') and options.priority:
|
|
85
|
+
final_headers['x-exa-websets-priority'] = options.priority
|
|
86
|
+
if hasattr(options, 'headers') and options.headers:
|
|
87
|
+
final_headers.update(options.headers)
|
|
88
|
+
# Handle dict options
|
|
89
|
+
elif isinstance(options, dict):
|
|
90
|
+
if 'priority' in options:
|
|
91
|
+
final_headers['x-exa-websets-priority'] = options['priority']
|
|
92
|
+
if 'headers' in options:
|
|
93
|
+
final_headers.update(options.get('headers', {}))
|
|
94
|
+
|
|
95
|
+
# Merge with any directly passed headers
|
|
96
|
+
if headers:
|
|
97
|
+
final_headers.update(headers)
|
|
98
|
+
|
|
73
99
|
# Ensure proper URL construction by removing leading slash from endpoint if present
|
|
74
100
|
if endpoint.startswith("/"):
|
|
75
101
|
endpoint = endpoint[1:]
|
|
76
102
|
|
|
77
|
-
|
|
103
|
+
# Only pass headers if there are any
|
|
104
|
+
if final_headers:
|
|
105
|
+
return await self._client.async_request("/websets/" + endpoint, data=data, method=method, params=params, headers=final_headers)
|
|
106
|
+
else:
|
|
107
|
+
return await self._client.async_request("/websets/" + endpoint, data=data, method=method, params=params)
|
|
@@ -73,7 +73,8 @@ class WebsetsBaseClient:
|
|
|
73
73
|
raise TypeError(f"Expected dict, ExaBaseModel, or str, got {type(data)}")
|
|
74
74
|
|
|
75
75
|
def request(self, endpoint: str, data: Optional[Union[Dict[str, Any], ExaBaseModel, str]] = None,
|
|
76
|
-
method: str = "POST", params: Optional[Dict[str, Any]] = None
|
|
76
|
+
method: str = "POST", params: Optional[Dict[str, Any]] = None,
|
|
77
|
+
headers: Optional[Dict[str, str]] = None, options: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
77
78
|
"""Make a request to the Exa API.
|
|
78
79
|
|
|
79
80
|
Args:
|
|
@@ -81,6 +82,8 @@ class WebsetsBaseClient:
|
|
|
81
82
|
data (Union[Dict[str, Any], ExaBaseModel, str], optional): The request data. Can be a dictionary, model instance, or string. Defaults to None.
|
|
82
83
|
method (str, optional): The HTTP method. Defaults to "POST".
|
|
83
84
|
params (Dict[str, Any], optional): The query parameters. Defaults to None.
|
|
85
|
+
headers (Dict[str, str], optional): Custom headers to include in the request. Defaults to None.
|
|
86
|
+
options (Dict[str, Any], optional): Request options that may include 'priority' and/or 'headers'. Defaults to None.
|
|
84
87
|
|
|
85
88
|
Returns:
|
|
86
89
|
Dict[str, Any]: The API response.
|
|
@@ -92,9 +95,36 @@ class WebsetsBaseClient:
|
|
|
92
95
|
# If data is a model instance, convert it to a dict
|
|
93
96
|
data = data.model_dump(mode='json', by_alias=True, exclude_none=True)
|
|
94
97
|
|
|
98
|
+
# Process options to build headers
|
|
99
|
+
final_headers = {}
|
|
100
|
+
|
|
101
|
+
# If options are provided, process them
|
|
102
|
+
if options:
|
|
103
|
+
# Handle RequestOptions model
|
|
104
|
+
if hasattr(options, 'priority') or hasattr(options, 'headers'):
|
|
105
|
+
# It's a RequestOptions instance
|
|
106
|
+
if hasattr(options, 'priority') and options.priority:
|
|
107
|
+
final_headers['x-exa-websets-priority'] = options.priority
|
|
108
|
+
if hasattr(options, 'headers') and options.headers:
|
|
109
|
+
final_headers.update(options.headers)
|
|
110
|
+
# Handle dict options
|
|
111
|
+
elif isinstance(options, dict):
|
|
112
|
+
if 'priority' in options:
|
|
113
|
+
final_headers['x-exa-websets-priority'] = options['priority']
|
|
114
|
+
if 'headers' in options:
|
|
115
|
+
final_headers.update(options.get('headers', {}))
|
|
116
|
+
|
|
117
|
+
# Merge with any directly passed headers
|
|
118
|
+
if headers:
|
|
119
|
+
final_headers.update(headers)
|
|
120
|
+
|
|
95
121
|
# Ensure proper URL construction by removing leading slash from endpoint if present
|
|
96
122
|
if endpoint.startswith("/"):
|
|
97
123
|
endpoint = endpoint[1:]
|
|
98
124
|
|
|
99
|
-
|
|
125
|
+
# Only pass headers if there are any
|
|
126
|
+
if final_headers:
|
|
127
|
+
return self._client.request("/websets/" + endpoint, data=data, method=method, params=params, headers=final_headers)
|
|
128
|
+
else:
|
|
129
|
+
return self._client.request("/websets/" + endpoint, data=data, method=method, params=params)
|
|
100
130
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Dict, Any, Union
|
|
3
|
+
from typing import Dict, Any, Union, Optional
|
|
4
4
|
|
|
5
5
|
from ..types import (
|
|
6
6
|
CreateWebsetSearchParameters,
|
|
7
7
|
WebsetSearch,
|
|
8
|
+
RequestOptions,
|
|
8
9
|
)
|
|
9
10
|
from ..core.base import WebsetsBaseClient
|
|
10
11
|
from ..core.async_base import WebsetsAsyncBaseClient
|
|
@@ -15,17 +16,20 @@ class WebsetSearchesClient(WebsetsBaseClient):
|
|
|
15
16
|
def __init__(self, client):
|
|
16
17
|
super().__init__(client)
|
|
17
18
|
|
|
18
|
-
def create(self, webset_id: str, params: Union[Dict[str, Any], CreateWebsetSearchParameters]
|
|
19
|
+
def create(self, webset_id: str, params: Union[Dict[str, Any], CreateWebsetSearchParameters],
|
|
20
|
+
options: Optional[Union[Dict[str, Any], RequestOptions]] = None) -> WebsetSearch:
|
|
19
21
|
"""Create a new Search for the Webset.
|
|
20
22
|
|
|
21
23
|
Args:
|
|
22
24
|
webset_id (str): The id of the Webset.
|
|
23
25
|
params (CreateWebsetSearchParameters): The parameters for creating a search.
|
|
26
|
+
options (RequestOptions, optional): Request options including priority and/or custom headers.
|
|
27
|
+
Can specify priority as 'low', 'medium', or 'high'.
|
|
24
28
|
|
|
25
29
|
Returns:
|
|
26
30
|
WebsetSearch: The created search.
|
|
27
31
|
"""
|
|
28
|
-
response = self.request(f"/v0/websets/{webset_id}/searches", data=params)
|
|
32
|
+
response = self.request(f"/v0/websets/{webset_id}/searches", data=params, options=options)
|
|
29
33
|
return WebsetSearch.model_validate(response)
|
|
30
34
|
|
|
31
35
|
def get(self, webset_id: str, id: str) -> WebsetSearch:
|
|
@@ -61,17 +65,20 @@ class AsyncWebsetSearchesClient(WebsetsAsyncBaseClient):
|
|
|
61
65
|
def __init__(self, client):
|
|
62
66
|
super().__init__(client)
|
|
63
67
|
|
|
64
|
-
async def create(self, webset_id: str, params: Union[Dict[str, Any], CreateWebsetSearchParameters]
|
|
68
|
+
async def create(self, webset_id: str, params: Union[Dict[str, Any], CreateWebsetSearchParameters],
|
|
69
|
+
options: Optional[Union[Dict[str, Any], RequestOptions]] = None) -> WebsetSearch:
|
|
65
70
|
"""Create a new Search for the Webset.
|
|
66
71
|
|
|
67
72
|
Args:
|
|
68
73
|
webset_id (str): The id of the Webset.
|
|
69
74
|
params (CreateWebsetSearchParameters): The parameters for creating a search.
|
|
75
|
+
options (RequestOptions, optional): Request options including priority and/or custom headers.
|
|
76
|
+
Can specify priority as 'low', 'medium', or 'high'.
|
|
70
77
|
|
|
71
78
|
Returns:
|
|
72
79
|
WebsetSearch: The created search.
|
|
73
80
|
"""
|
|
74
|
-
response = await self.request(f"/v0/websets/{webset_id}/searches", data=params)
|
|
81
|
+
response = await self.request(f"/v0/websets/{webset_id}/searches", data=params, options=options)
|
|
75
82
|
return WebsetSearch.model_validate(response)
|
|
76
83
|
|
|
77
84
|
async def get(self, webset_id: str, id: str) -> WebsetSearch:
|
|
@@ -12,6 +12,21 @@ from pydantic import AnyUrl, Field, PositiveInt
|
|
|
12
12
|
from .core.base import ExaBaseModel
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
class WebsetPriority(Enum):
|
|
16
|
+
"""Priority levels for webset operations."""
|
|
17
|
+
low = 'low'
|
|
18
|
+
medium = 'medium'
|
|
19
|
+
high = 'high'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RequestOptions(ExaBaseModel):
|
|
23
|
+
"""Options for API requests."""
|
|
24
|
+
priority: Optional[Literal['low', 'medium', 'high']] = None
|
|
25
|
+
"""Priority level for the request (low, medium, or high)."""
|
|
26
|
+
headers: Optional[Dict[str, str]] = None
|
|
27
|
+
"""Custom headers to include in the request."""
|
|
28
|
+
|
|
29
|
+
|
|
15
30
|
class WebsetSearchBehavior(Enum):
|
|
16
31
|
"""
|
|
17
32
|
The behavior of the Search when it is added to a Webset.
|
|
@@ -5,17 +5,18 @@ typing-extensions = "^4.12.2"
|
|
|
5
5
|
openai = "^1.48"
|
|
6
6
|
pydantic = "^2.10.6"
|
|
7
7
|
httpx = "^0.28.1"
|
|
8
|
+
httpcore = "^1.0.9"
|
|
9
|
+
python-dotenv = "^1.0.1"
|
|
8
10
|
|
|
9
11
|
[tool.poetry.group.dev.dependencies]
|
|
10
|
-
|
|
11
|
-
setuptools = "^74.0.0"
|
|
12
|
+
setuptools = "^78.1.1"
|
|
12
13
|
docutils = "^0.21.2"
|
|
13
14
|
twine = "^5.1.1"
|
|
14
15
|
datamodel-code-generator = "^0.28.4"
|
|
15
|
-
pytest = "^8.
|
|
16
|
-
pytest-cov = "^6.
|
|
17
|
-
pytest-mock = "^3.14.
|
|
18
|
-
pytest-asyncio = "^0.
|
|
16
|
+
pytest = "^8.4.1"
|
|
17
|
+
pytest-cov = "^6.2.1"
|
|
18
|
+
pytest-mock = "^3.14.1"
|
|
19
|
+
pytest-asyncio = "^1.0.0"
|
|
19
20
|
|
|
20
21
|
[build-system]
|
|
21
22
|
requires = ["poetry-core"]
|
|
@@ -23,7 +24,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
23
24
|
|
|
24
25
|
[project]
|
|
25
26
|
name = "exa-py"
|
|
26
|
-
version = "1.
|
|
27
|
+
version = "1.16.0"
|
|
27
28
|
description = "Python SDK for Exa API."
|
|
28
29
|
readme = "README.md"
|
|
29
30
|
requires-python = ">=3.9"
|
|
@@ -35,6 +36,8 @@ dependencies = [
|
|
|
35
36
|
"openai>=1.48",
|
|
36
37
|
"pydantic>=2.10.6",
|
|
37
38
|
"httpx>=0.28.1",
|
|
39
|
+
"httpcore>=1.0.9",
|
|
40
|
+
"python-dotenv>=1.0.1",
|
|
38
41
|
]
|
|
39
42
|
|
|
40
43
|
[dependency-groups]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|