tavily-python 0.7.11__tar.gz → 0.7.13__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.
Files changed (25) hide show
  1. {tavily_python-0.7.11 → tavily_python-0.7.13}/PKG-INFO +2 -2
  2. {tavily_python-0.7.11 → tavily_python-0.7.13}/setup.py +2 -2
  3. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily/async_tavily.py +13 -29
  4. tavily_python-0.7.13/tavily/config.py +2 -0
  5. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily/errors.py +1 -1
  6. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily/tavily.py +15 -33
  7. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily_python.egg-info/PKG-INFO +2 -2
  8. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily_python.egg-info/SOURCES.txt +1 -3
  9. {tavily_python-0.7.11 → tavily_python-0.7.13}/tests/test_crawl.py +0 -3
  10. {tavily_python-0.7.11 → tavily_python-0.7.13}/tests/test_map.py +1 -4
  11. tavily_python-0.7.11/tavily/config.py +0 -12
  12. tavily_python-0.7.11/tests/test_async_search.py +0 -219
  13. tavily_python-0.7.11/tests/test_sync_search.py +0 -219
  14. {tavily_python-0.7.11 → tavily_python-0.7.13}/LICENSE +0 -0
  15. {tavily_python-0.7.11 → tavily_python-0.7.13}/README.md +0 -0
  16. {tavily_python-0.7.11 → tavily_python-0.7.13}/setup.cfg +0 -0
  17. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily/__init__.py +0 -0
  18. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily/hybrid_rag/__init__.py +0 -0
  19. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily/hybrid_rag/hybrid_rag.py +0 -0
  20. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily/utils.py +0 -0
  21. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily_python.egg-info/dependency_links.txt +0 -0
  22. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily_python.egg-info/requires.txt +0 -0
  23. {tavily_python-0.7.11 → tavily_python-0.7.13}/tavily_python.egg-info/top_level.txt +0 -0
  24. {tavily_python-0.7.11 → tavily_python-0.7.13}/tests/test_errors.py +0 -0
  25. {tavily_python-0.7.11 → tavily_python-0.7.13}/tests/test_search.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tavily-python
3
- Version: 0.7.11
3
+ Version: 0.7.13
4
4
  Summary: Python wrapper for the Tavily API
5
5
  Home-page: https://github.com/tavily-ai/tavily-python
6
6
  Author: Tavily AI
@@ -8,7 +8,7 @@ Author-email: support@tavily.com
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.6
11
+ Requires-Python: >=3.8
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: requests
@@ -5,7 +5,7 @@ with open('README.md', 'r', encoding='utf-8') as f:
5
5
 
6
6
  setup(
7
7
  name='tavily-python',
8
- version='0.7.11',
8
+ version='0.7.13',
9
9
  url='https://github.com/tavily-ai/tavily-python',
10
10
  author='Tavily AI',
11
11
  author_email='support@tavily.com',
@@ -19,5 +19,5 @@ setup(
19
19
  'License :: OSI Approved :: MIT License',
20
20
  'Operating System :: OS Independent',
21
21
  ],
22
- python_requires='>=3.6',
22
+ python_requires='>=3.8',
23
23
  )
@@ -7,7 +7,6 @@ import httpx
7
7
 
8
8
  from .utils import get_max_items_from_list
9
9
  from .errors import UsageLimitExceededError, InvalidAPIKeyError, MissingAPIKeyError, BadRequestError, ForbiddenError, TimeoutError
10
- from .config import AllowedCategory
11
10
 
12
11
 
13
12
  class AsyncTavilyClient:
@@ -67,7 +66,7 @@ class AsyncTavilyClient:
67
66
  include_answer: Union[bool, Literal["basic", "advanced"]] = None,
68
67
  include_raw_content: Union[bool, Literal["markdown", "text"]] = None,
69
68
  include_images: bool = None,
70
- timeout: int = 60,
69
+ timeout: float = 60,
71
70
  country: str = None,
72
71
  auto_parameters: bool = None,
73
72
  include_favicon: bool = None,
@@ -142,7 +141,7 @@ class AsyncTavilyClient:
142
141
  include_answer: Union[bool, Literal["basic", "advanced"]] = None,
143
142
  include_raw_content: Union[bool, Literal["markdown", "text"]] = None,
144
143
  include_images: bool = None,
145
- timeout: int = 60,
144
+ timeout: float = 60,
146
145
  country: str = None,
147
146
  auto_parameters: bool = None,
148
147
  include_favicon: bool = None,
@@ -184,7 +183,7 @@ class AsyncTavilyClient:
184
183
  include_images: bool = None,
185
184
  extract_depth: Literal["basic", "advanced"] = None,
186
185
  format: Literal["markdown", "text"] = None,
187
- timeout: int = 30,
186
+ timeout: float = 30,
188
187
  include_favicon: bool = None,
189
188
  **kwargs
190
189
  ) -> dict:
@@ -206,8 +205,6 @@ class AsyncTavilyClient:
206
205
  if kwargs:
207
206
  data.update(kwargs)
208
207
 
209
- timeout = min(timeout, 120)
210
-
211
208
  async with self._client_creator() as client:
212
209
  try:
213
210
  response = await client.post("/extract", content=json.dumps(data), timeout=timeout)
@@ -240,7 +237,7 @@ class AsyncTavilyClient:
240
237
  include_images: bool = None,
241
238
  extract_depth: Literal["basic", "advanced"] = None,
242
239
  format: Literal["markdown", "text"] = None,
243
- timeout: int = 30,
240
+ timeout: float = 30,
244
241
  include_favicon: bool = None,
245
242
  **kwargs, # Accept custom arguments
246
243
  ) -> dict:
@@ -248,7 +245,6 @@ class AsyncTavilyClient:
248
245
  Combined extract method.
249
246
  include_favicon: If True, include the favicon in the extraction results.
250
247
  """
251
- timeout = min(timeout, 120)
252
248
  response_dict = await self._extract(urls,
253
249
  include_images,
254
250
  extract_depth,
@@ -278,10 +274,9 @@ class AsyncTavilyClient:
278
274
  exclude_domains: Sequence[str] = None,
279
275
  allow_external: bool = None,
280
276
  include_images: bool = None,
281
- categories: Sequence[AllowedCategory] = None,
282
277
  extract_depth: Literal["basic", "advanced"] = None,
283
278
  format: Literal["markdown", "text"] = None,
284
- timeout: int = 60,
279
+ timeout: float = 150,
285
280
  include_favicon: bool = None,
286
281
  **kwargs
287
282
  ) -> dict:
@@ -299,10 +294,10 @@ class AsyncTavilyClient:
299
294
  "exclude_paths": exclude_paths,
300
295
  "exclude_domains": exclude_domains,
301
296
  "allow_external": allow_external,
302
- "categories": categories,
303
297
  "include_images": include_images,
304
298
  "extract_depth": extract_depth,
305
299
  "format": format,
300
+ "timeout": timeout,
306
301
  "include_favicon": include_favicon,
307
302
  }
308
303
 
@@ -311,8 +306,6 @@ class AsyncTavilyClient:
311
306
 
312
307
  data = {k: v for k, v in data.items() if v is not None}
313
308
 
314
- timeout = min(timeout, 120)
315
-
316
309
  async with self._client_creator() as client:
317
310
  try:
318
311
  response = await client.post("/crawl", content=json.dumps(data), timeout=timeout)
@@ -350,11 +343,10 @@ class AsyncTavilyClient:
350
343
  exclude_paths: Sequence[str] = None,
351
344
  exclude_domains: Sequence[str] = None,
352
345
  allow_external: bool = None,
353
- categories: Sequence[AllowedCategory] = None,
354
346
  extract_depth: Literal["basic", "advanced"] = None,
355
347
  include_images: bool = None,
356
348
  format: Literal["markdown", "text"] = None,
357
- timeout: int = 60,
349
+ timeout: float = 150,
358
350
  include_favicon: bool = None,
359
351
  **kwargs
360
352
  ) -> dict:
@@ -362,7 +354,6 @@ class AsyncTavilyClient:
362
354
  Combined crawl method.
363
355
 
364
356
  """
365
- timeout = min(timeout, 120)
366
357
  response_dict = await self._crawl(url,
367
358
  max_depth=max_depth,
368
359
  max_breadth=max_breadth,
@@ -373,7 +364,6 @@ class AsyncTavilyClient:
373
364
  exclude_paths=exclude_paths,
374
365
  exclude_domains=exclude_domains,
375
366
  allow_external=allow_external,
376
- categories=categories,
377
367
  extract_depth=extract_depth,
378
368
  include_images=include_images,
379
369
  format=format,
@@ -395,8 +385,7 @@ class AsyncTavilyClient:
395
385
  exclude_domains: Sequence[str] = None,
396
386
  allow_external: bool = None,
397
387
  include_images: bool = None,
398
- categories: Sequence[AllowedCategory] = None,
399
- timeout: int = 60,
388
+ timeout: float = 150,
400
389
  **kwargs
401
390
  ) -> dict:
402
391
  """
@@ -414,7 +403,7 @@ class AsyncTavilyClient:
414
403
  "exclude_domains": exclude_domains,
415
404
  "allow_external": allow_external,
416
405
  "include_images": include_images,
417
- "categories": categories,
406
+ "timeout": timeout,
418
407
  }
419
408
 
420
409
  if kwargs:
@@ -422,8 +411,6 @@ class AsyncTavilyClient:
422
411
 
423
412
  data = {k: v for k, v in data.items() if v is not None}
424
413
 
425
- timeout = min(timeout, 120)
426
-
427
414
  async with self._client_creator() as client:
428
415
  try:
429
416
  response = await client.post("/map", content=json.dumps(data), timeout=timeout)
@@ -462,15 +449,13 @@ class AsyncTavilyClient:
462
449
  exclude_domains: Sequence[str] = None,
463
450
  allow_external: bool = None,
464
451
  include_images: bool = None,
465
- categories: Sequence[AllowedCategory] = None,
466
- timeout: int = 60,
452
+ timeout: float = 150,
467
453
  **kwargs
468
454
  ) -> dict:
469
455
  """
470
456
  Combined map method.
471
457
 
472
458
  """
473
- timeout = min(timeout, 120)
474
459
  response_dict = await self._map(url,
475
460
  max_depth=max_depth,
476
461
  max_breadth=max_breadth,
@@ -482,7 +467,6 @@ class AsyncTavilyClient:
482
467
  exclude_domains=exclude_domains,
483
468
  allow_external=allow_external,
484
469
  include_images=include_images,
485
- categories=categories,
486
470
  timeout=timeout,
487
471
  **kwargs)
488
472
 
@@ -497,7 +481,7 @@ class AsyncTavilyClient:
497
481
  include_domains: Sequence[str] = None,
498
482
  exclude_domains: Sequence[str] = None,
499
483
  max_tokens: int = 4000,
500
- timeout: int = 60,
484
+ timeout: float = 60,
501
485
  country: str = None,
502
486
  include_favicon: bool = None,
503
487
  **kwargs, # Accept custom arguments
@@ -538,7 +522,7 @@ class AsyncTavilyClient:
538
522
  max_results: int = 5,
539
523
  include_domains: Sequence[str] = None,
540
524
  exclude_domains: Sequence[str] = None,
541
- timeout: int = 60,
525
+ timeout: float = 60,
542
526
  country: str = None,
543
527
  include_favicon: bool = None,
544
528
  **kwargs, # Accept custom arguments
@@ -568,7 +552,7 @@ class AsyncTavilyClient:
568
552
  query: str,
569
553
  search_depth: Literal["basic", "advanced"] = "advanced",
570
554
  max_results: int = 5,
571
- timeout: int = 60,
555
+ timeout: float = 60,
572
556
  country: str = None,
573
557
  ) -> Sequence[dict]:
574
558
  """ Company information search method. Search depth is advanced by default to get the best answer. """
@@ -0,0 +1,2 @@
1
+ DEFAULT_MODEL_ENCODING = "gpt-3.5-turbo"
2
+ DEFAULT_MAX_TOKENS = 4000
@@ -17,7 +17,7 @@ class InvalidAPIKeyError(Exception):
17
17
  super().__init__(message)
18
18
 
19
19
  class TimeoutError(Exception):
20
- def __init__(self, timeout: int):
20
+ def __init__(self, timeout: float):
21
21
  super().__init__(f"Request timed out after {timeout} seconds.")
22
22
 
23
23
  class MissingAPIKeyError(Exception):
@@ -6,7 +6,6 @@ from typing import Literal, Sequence, Optional, List, Union
6
6
  from concurrent.futures import ThreadPoolExecutor, as_completed
7
7
  from .utils import get_max_items_from_list
8
8
  from .errors import UsageLimitExceededError, InvalidAPIKeyError, MissingAPIKeyError, BadRequestError, ForbiddenError, TimeoutError
9
- from .config import AllowedCategory
10
9
 
11
10
  class TavilyClient:
12
11
  """
@@ -50,7 +49,7 @@ class TavilyClient:
50
49
  include_answer: Union[bool, Literal["basic", "advanced"]] = None,
51
50
  include_raw_content: Union[bool, Literal["markdown", "text"]] = None,
52
51
  include_images: bool = None,
53
- timeout: int = 60,
52
+ timeout: float = 60,
54
53
  country: str = None,
55
54
  auto_parameters: bool = None,
56
55
  include_favicon: bool = None,
@@ -127,7 +126,7 @@ class TavilyClient:
127
126
  include_answer: Union[bool, Literal["basic", "advanced"]] = None,
128
127
  include_raw_content: Union[bool, Literal["markdown", "text"]] = None,
129
128
  include_images: bool = None,
130
- timeout: int = 60,
129
+ timeout: float = 60,
131
130
  country: str = None,
132
131
  auto_parameters: bool = None,
133
132
  include_favicon: bool = None,
@@ -136,7 +135,7 @@ class TavilyClient:
136
135
  """
137
136
  Combined search method.
138
137
  """
139
- timeout = min(timeout, 120)
138
+
140
139
  response_dict = self._search(query,
141
140
  search_depth=search_depth,
142
141
  topic=topic,
@@ -168,7 +167,7 @@ class TavilyClient:
168
167
  include_images: bool = None,
169
168
  extract_depth: Literal["basic", "advanced"] = None,
170
169
  format: Literal["markdown", "text"] = None,
171
- timeout: int = 30,
170
+ timeout: float = 30,
172
171
  include_favicon: bool = None,
173
172
  **kwargs
174
173
  ) -> dict:
@@ -189,8 +188,6 @@ class TavilyClient:
189
188
  if kwargs:
190
189
  data.update(kwargs)
191
190
 
192
- timeout = min(timeout, 120)
193
-
194
191
  try:
195
192
  response = requests.post(self.base_url + "/extract", data=json.dumps(data), headers=self.headers, timeout=timeout, proxies=self.proxies)
196
193
  except requests.exceptions.Timeout:
@@ -221,14 +218,13 @@ class TavilyClient:
221
218
  include_images: bool = None,
222
219
  extract_depth: Literal["basic", "advanced"] = None,
223
220
  format: Literal["markdown", "text"] = None,
224
- timeout: int = 30,
221
+ timeout: float = 30,
225
222
  include_favicon: bool = None,
226
223
  **kwargs, # Accept custom arguments
227
224
  ) -> dict:
228
225
  """
229
226
  Combined extract method.
230
227
  """
231
- timeout = min(timeout, 120)
232
228
  response_dict = self._extract(urls,
233
229
  include_images,
234
230
  extract_depth,
@@ -257,10 +253,9 @@ class TavilyClient:
257
253
  exclude_domains: Sequence[str] = None,
258
254
  allow_external: bool = None,
259
255
  include_images: bool = None,
260
- categories: Sequence[AllowedCategory] = None,
261
256
  extract_depth: Literal["basic", "advanced"] = None,
262
257
  format: Literal["markdown", "text"] = None,
263
- timeout: int = 60,
258
+ timeout: float = 150,
264
259
  include_favicon: bool = None,
265
260
  **kwargs
266
261
  ) -> dict:
@@ -280,9 +275,9 @@ class TavilyClient:
280
275
  "exclude_domains": exclude_domains,
281
276
  "allow_external": allow_external,
282
277
  "include_images": include_images,
283
- "categories": categories,
284
278
  "extract_depth": extract_depth,
285
279
  "format": format,
280
+ "timeout": timeout,
286
281
  "include_favicon": include_favicon,
287
282
  }
288
283
 
@@ -290,8 +285,6 @@ class TavilyClient:
290
285
  data.update(kwargs)
291
286
 
292
287
  data = {k: v for k, v in data.items() if v is not None}
293
-
294
- timeout = min(timeout, 120)
295
288
 
296
289
  try:
297
290
  response = requests.post(
@@ -331,10 +324,9 @@ class TavilyClient:
331
324
  exclude_domains: Sequence[str] = None,
332
325
  allow_external: bool = None,
333
326
  include_images: bool = None,
334
- categories: Sequence[AllowedCategory] = None,
335
327
  extract_depth: Literal["basic", "advanced"] = None,
336
328
  format: Literal["markdown", "text"] = None,
337
- timeout: int = 60,
329
+ timeout: float = 150,
338
330
  include_favicon: bool = None,
339
331
  **kwargs
340
332
  ) -> dict:
@@ -342,7 +334,6 @@ class TavilyClient:
342
334
  Combined crawl method.
343
335
  include_favicon: If True, include the favicon in the crawl results.
344
336
  """
345
- timeout = min(timeout, 120)
346
337
  response_dict = self._crawl(url,
347
338
  max_depth=max_depth,
348
339
  max_breadth=max_breadth,
@@ -354,7 +345,6 @@ class TavilyClient:
354
345
  exclude_domains=exclude_domains,
355
346
  allow_external=allow_external,
356
347
  include_images=include_images,
357
- categories=categories,
358
348
  extract_depth=extract_depth,
359
349
  format=format,
360
350
  timeout=timeout,
@@ -375,8 +365,7 @@ class TavilyClient:
375
365
  exclude_domains: Sequence[str] = None,
376
366
  allow_external: bool = None,
377
367
  include_images: bool = None,
378
- categories: Sequence[AllowedCategory] = None,
379
- timeout: int = 60,
368
+ timeout: float = 150,
380
369
  **kwargs
381
370
  ) -> dict:
382
371
  """
@@ -394,7 +383,7 @@ class TavilyClient:
394
383
  "exclude_domains": exclude_domains,
395
384
  "allow_external": allow_external,
396
385
  "include_images": include_images,
397
- "categories": categories,
386
+ "timeout": timeout,
398
387
  }
399
388
 
400
389
  if kwargs:
@@ -402,8 +391,6 @@ class TavilyClient:
402
391
 
403
392
  data = {k: v for k, v in data.items() if v is not None}
404
393
 
405
- timeout = min(timeout, 120)
406
-
407
394
  try:
408
395
  response = requests.post(
409
396
  self.base_url + "/map", data=json.dumps(data), headers=self.headers, timeout=timeout, proxies=self.proxies)
@@ -442,15 +429,13 @@ class TavilyClient:
442
429
  exclude_domains: Sequence[str] = None,
443
430
  allow_external: bool = None,
444
431
  include_images: bool = None,
445
- categories: Sequence[AllowedCategory] = None,
446
- timeout: int = 60,
432
+ timeout: float = 150,
447
433
  **kwargs
448
434
  ) -> dict:
449
435
  """
450
436
  Combined map method.
451
437
 
452
438
  """
453
- timeout = min(timeout, 120)
454
439
  response_dict = self._map(url,
455
440
  max_depth=max_depth,
456
441
  max_breadth=max_breadth,
@@ -462,7 +447,6 @@ class TavilyClient:
462
447
  exclude_domains=exclude_domains,
463
448
  allow_external=allow_external,
464
449
  include_images=include_images,
465
- categories=categories,
466
450
  timeout=timeout,
467
451
  **kwargs)
468
452
 
@@ -477,7 +461,7 @@ class TavilyClient:
477
461
  include_domains: Sequence[str] = None,
478
462
  exclude_domains: Sequence[str] = None,
479
463
  max_tokens: int = 4000,
480
- timeout: int = 60,
464
+ timeout: float = 60,
481
465
  country: str = None,
482
466
  include_favicon: bool = None,
483
467
  **kwargs, # Accept custom arguments
@@ -490,7 +474,7 @@ class TavilyClient:
490
474
 
491
475
  Returns a string of JSON containing the search context up to context limit.
492
476
  """
493
- timeout = min(timeout, 120)
477
+
494
478
  response_dict = self._search(query,
495
479
  search_depth=search_depth,
496
480
  topic=topic,
@@ -519,7 +503,7 @@ class TavilyClient:
519
503
  max_results: int = 5,
520
504
  include_domains: Sequence[str] = None,
521
505
  exclude_domains: Sequence[str] = None,
522
- timeout: int = 60,
506
+ timeout: float = 60,
523
507
  country: str = None,
524
508
  include_favicon: bool = None,
525
509
  **kwargs, # Accept custom arguments
@@ -527,7 +511,6 @@ class TavilyClient:
527
511
  """
528
512
  Q&A search method. Search depth is advanced by default to get the best answer.
529
513
  """
530
- timeout = min(timeout, 120)
531
514
  response_dict = self._search(query,
532
515
  search_depth=search_depth,
533
516
  topic=topic,
@@ -550,11 +533,10 @@ class TavilyClient:
550
533
  search_depth: Literal["basic",
551
534
  "advanced"] = "advanced",
552
535
  max_results: int = 5,
553
- timeout: int = 60,
536
+ timeout: float = 60,
554
537
  country: str = None,
555
538
  ) -> Sequence[dict]:
556
539
  """ Company information search method. Search depth is advanced by default to get the best answer. """
557
- timeout = min(timeout, 120)
558
540
  def _perform_search(topic):
559
541
  return self._search(query,
560
542
  search_depth=search_depth,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tavily-python
3
- Version: 0.7.11
3
+ Version: 0.7.13
4
4
  Summary: Python wrapper for the Tavily API
5
5
  Home-page: https://github.com/tavily-ai/tavily-python
6
6
  Author: Tavily AI
@@ -8,7 +8,7 @@ Author-email: support@tavily.com
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.6
11
+ Requires-Python: >=3.8
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: requests
@@ -14,9 +14,7 @@ tavily_python.egg-info/SOURCES.txt
14
14
  tavily_python.egg-info/dependency_links.txt
15
15
  tavily_python.egg-info/requires.txt
16
16
  tavily_python.egg-info/top_level.txt
17
- tests/test_async_search.py
18
17
  tests/test_crawl.py
19
18
  tests/test_errors.py
20
19
  tests/test_map.py
21
- tests/test_search.py
22
- tests/test_sync_search.py
20
+ tests/test_search.py
@@ -40,7 +40,6 @@ def validate_specific(request, response):
40
40
  "exclude_domains": ["example.com"],
41
41
  "allow_external": False,
42
42
  "include_images": True,
43
- "categories": ["pricing", "documentation"],
44
43
  "extract_depth": "advanced"
45
44
  }.items():
46
45
  assert request_json.get(key) == value
@@ -67,7 +66,6 @@ def test_sync_crawl_specific(sync_interceptor, sync_client):
67
66
  exclude_domains=["example.com"],
68
67
  allow_external=False,
69
68
  include_images=True,
70
- categories=["pricing", "documentation"],
71
69
  extract_depth="advanced",
72
70
  timeout=10
73
71
  )
@@ -95,7 +93,6 @@ def test_async_crawl_specific(async_interceptor, async_client):
95
93
  exclude_domains=["example.com"],
96
94
  allow_external=False,
97
95
  include_images=True,
98
- categories=["pricing", "documentation"],
99
96
  extract_depth="advanced",
100
97
  timeout=10
101
98
  ))
@@ -38,8 +38,7 @@ def validate_specific(request, response):
38
38
  "exclude_paths": ["/blog"],
39
39
  "exclude_domains": ["example.com"],
40
40
  "allow_external": False,
41
- "include_images": True,
42
- "categories": ["pricing", "documentation"]
41
+ "include_images": True
43
42
  }.items():
44
43
  assert request_json.get(key) == value
45
44
 
@@ -65,7 +64,6 @@ def test_sync_map_specific(sync_interceptor, sync_client):
65
64
  exclude_domains=["example.com"],
66
65
  allow_external=False,
67
66
  include_images=True,
68
- categories=["pricing", "documentation"],
69
67
  timeout=10
70
68
  )
71
69
 
@@ -92,7 +90,6 @@ def test_async_map_specific(async_interceptor, async_client):
92
90
  exclude_domains=["example.com"],
93
91
  allow_external=False,
94
92
  include_images=True,
95
- categories=["pricing", "documentation"],
96
93
  timeout=10
97
94
  ))
98
95
 
@@ -1,12 +0,0 @@
1
- from typing import Literal
2
-
3
- DEFAULT_MODEL_ENCODING = "gpt-3.5-turbo"
4
- DEFAULT_MAX_TOKENS = 4000
5
-
6
- # Create a type that represents all allowed categories
7
- AllowedCategory = Literal[
8
- "Documentation", "Blog", "Blogs", "Community", "About", "Contact",
9
- "Privacy", "Terms", "Status", "Pricing", "Enterprise", "Careers",
10
- "E-Commerce", "Authentication", "Developer", "Developers", "Solutions",
11
- "Partners", "Downloads", "Media", "Events", "People"
12
- ]
@@ -1,219 +0,0 @@
1
- import unittest
2
- import os
3
- from tavily import AsyncTavilyClient, MissingAPIKeyError, InvalidAPIKeyError
4
- from urllib.parse import urlparse
5
- import asyncio
6
-
7
- from unit_tests import cases
8
- class SearchTest(unittest.TestCase):
9
-
10
- def setUp(self) -> None:
11
- self.tavily_client = AsyncTavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
12
- return super().setUp()
13
-
14
- def tearDown(self) -> None:
15
- return super().tearDown()
16
-
17
- # Every single search result should have these properties
18
- def common_search_result_properties(self, result) -> None:
19
- self.assertIsInstance(result, dict)
20
- self.assertIn("title", result)
21
- self.assertIn("url", result)
22
- self.assertIn("content", result)
23
- self.assertIn("score", result)
24
-
25
- # General search results should have these properties
26
- def general_search_result_properties(self, result) -> None:
27
- self.common_search_result_properties(result)
28
- self.assertIn("raw_content", result)
29
-
30
- # News search results should have these properties
31
- def news_search_result_properties(self, result) -> None:
32
- self.common_search_result_properties(result)
33
- self.assertIn("published_date", result)
34
-
35
- # Topic-specific properties
36
- def topic_specific_properties(self, result, **params) -> None:
37
- if params.get("topic", "general") == "general":
38
- self.assertIn("raw_content", result)
39
- elif params.get("topic", "general") == "news":
40
- self.assertIn("published_date", result)
41
-
42
- # Domain inclusion/exclusion-dependent properties
43
- def domain_dependent_properties(self, response, **params) -> None:
44
- if params.get("topic", "general") != "general":
45
- return
46
-
47
- if params.get("include_domains", False) and len(params["include_domains"]) > 0:
48
- for result in response["results"]:
49
- self.assertTrue(any(domain in urlparse(result["url"]).netloc for domain in params["include_domains"]))
50
-
51
- if params.get("exclude_domains", False) and len(params["exclude_domains"]) > 0:
52
- for result in response["results"]:
53
- self.assertFalse(any(domain in urlparse(result["url"]).netloc for domain in params["exclude_domains"]))
54
-
55
- # Image-dependent properties
56
- def image_properties(self, response, **params) -> None:
57
- if params.get("topic", "general") == "general" and params.get("include_images", False):
58
- self.assertIsNotNone(response["images"])
59
- self.assertIsInstance(response["images"], list)
60
- for image in response["images"]:
61
- self.assertIsInstance(image, str)
62
-
63
- # Answer-dependent properties
64
- def answer_properties(self, response, **params) -> None:
65
- if params.get("include_answer", False):
66
- self.assertIn("answer", response)
67
- self.assertIsInstance(response["answer"], str)
68
-
69
-
70
- # Every single search response should have these properties
71
- def common_response_properties(self, response) -> None:
72
- self.assertIsNotNone(response)
73
- self.assertIsInstance(response, dict)
74
- self.assertIn("answer", response)
75
- self.assertIn("query", response)
76
- self.assertIn("results", response)
77
- self.assertIn("images", response)
78
- self.assertIn("response_time", response)
79
- self.assertIn("follow_up_questions", response)
80
-
81
- self.assertIsNotNone(response["query"])
82
- self.assertIsNotNone(response["results"])
83
- self.assertIsNotNone(response["response_time"])
84
- self.assertIsNotNone(response["images"])
85
-
86
- self.assertIsInstance(response["query"], str)
87
- self.assertIsInstance(response["results"], list)
88
- self.assertIsInstance(response["response_time"], float)
89
- self.assertIsInstance(response["images"], list)
90
-
91
- # Search responses also have properties that depend on the request params
92
- def custom_response_properties(self, response, **params) -> None:
93
- self.domain_dependent_properties(response, **params)
94
- self.image_properties(response, **params)
95
- self.answer_properties(response, **params)
96
- for result in response["results"]:
97
- self.topic_specific_properties(result, **params)
98
-
99
- def test_internal_search(self) -> None:
100
- for test_case in cases:
101
- with self.subTest(msg=test_case["name"]):
102
- response = asyncio.run(self.tavily_client._search(**test_case["params"]))
103
- self.common_response_properties(response)
104
- if test_case["params"].get("topic", "general") == "general":
105
- for search_result in response["results"]:
106
- self.general_search_result_properties(search_result)
107
- elif test_case["params"].get("topic", "general") == "news":
108
- for search_result in response["results"]:
109
- self.news_search_result_properties(search_result)
110
- self.custom_response_properties(response, **test_case["params"])
111
-
112
- def test_external_search(self) -> None:
113
- for test_case in cases:
114
- with self.subTest(msg=test_case["name"]):
115
- response = asyncio.run(self.tavily_client.search(**test_case["params"]))
116
- self.common_response_properties(response)
117
- if test_case["params"].get("topic", "general") == "general":
118
- for search_result in response["results"]:
119
- self.general_search_result_properties(search_result)
120
- elif test_case["params"].get("topic", "general") == "news":
121
- for search_result in response["results"]:
122
- self.news_search_result_properties(search_result)
123
- self.custom_response_properties(response, **test_case["params"])
124
-
125
- class QNASearchTest(unittest.TestCase):
126
-
127
- def setUp(self) -> None:
128
- self.tavily_client = AsyncTavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
129
- return super().setUp()
130
-
131
- def tearDown(self) -> None:
132
- return super().tearDown()
133
-
134
- def test_qna_search(self) -> None:
135
- for test_case in cases:
136
- if "include_answer" in test_case["params"]:
137
- del test_case["params"]["include_answer"]
138
- if "include_raw_content" in test_case["params"]:
139
- del test_case["params"]["include_raw_content"]
140
- if "include_images" in test_case["params"]:
141
- del test_case["params"]["include_images"]
142
- with self.subTest(msg=test_case["name"]):
143
- response = asyncio.run(self.tavily_client.qna_search(**test_case["params"]))
144
- self.assertIsNotNone(response)
145
- self.assertIsInstance(response, str)
146
- self.assertTrue(len(response) > 0)
147
-
148
- class CompanyInfoSearchTest(unittest.TestCase):
149
-
150
- def setUp(self) -> None:
151
- self.tavily_client = AsyncTavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
152
- return super().setUp()
153
-
154
- def tearDown(self) -> None:
155
- return super().tearDown()
156
-
157
- # Every single search result should have these properties
158
- def common_search_result_properties(self, result) -> None:
159
- self.assertIsInstance(result, dict)
160
- self.assertIn("title", result)
161
- self.assertIn("url", result)
162
- self.assertIn("content", result)
163
- self.assertIn("score", result)
164
-
165
- def test_company_info_search(self) -> None:
166
- for test_case in cases:
167
- if "topic" in test_case["params"]:
168
- del test_case["params"]["topic"]
169
- if "include_domains" in test_case["params"]:
170
- del test_case["params"]["include_domains"]
171
- if "exclude_domains" in test_case["params"]:
172
- del test_case["params"]["exclude_domains"]
173
- if "include_raw_content" in test_case["params"]:
174
- del test_case["params"]["include_raw_content"]
175
- if "include_images" in test_case["params"]:
176
- del test_case["params"]["include_images"]
177
- if "include_answer" in test_case["params"]:
178
- del test_case["params"]["include_answer"]
179
- if "use_cache" in test_case["params"]:
180
- del test_case["params"]["use_cache"]
181
- with self.subTest(msg=test_case["name"]):
182
- response = asyncio.run(self.tavily_client.get_company_info(**test_case["params"]))
183
- self.assertIsNotNone(response)
184
- self.assertIsInstance(response, list)
185
- self.assertTrue(len(response) > 0)
186
- for search_result in response:
187
- self.common_search_result_properties(search_result)
188
-
189
- class ErrorTest(unittest.TestCase):
190
-
191
- def setUp(self) -> None:
192
- return super().setUp()
193
-
194
- def tearDown(self) -> None:
195
- return super().tearDown()
196
-
197
- # This test is here to ensure that no MissingAPIKeyError is raised when the API key is in the environment
198
- def test_load_key_from_env(self) -> None:
199
- self.assertIn('results', asyncio.run(AsyncTavilyClient().search("Why is Tavily the best search API?")))
200
-
201
- def test_missing_api_key(self) -> None:
202
- with self.assertRaises(MissingAPIKeyError):
203
- AsyncTavilyClient(api_key='')
204
-
205
- old_key = os.getenv("TAVILY_API_KEY")
206
- del os.environ["TAVILY_API_KEY"]
207
- with self.assertRaises(MissingAPIKeyError):
208
- AsyncTavilyClient()
209
-
210
- os.environ["TAVILY_API_KEY"] = old_key
211
-
212
-
213
- def test_invalid_api_key(self) -> None:
214
- with self.assertRaises(InvalidAPIKeyError):
215
- asyncio.run(AsyncTavilyClient(api_key="invalid_api_key").search("Why is Tavily the best search API?"))
216
-
217
- if __name__ == "__main__":
218
-
219
- unittest.main()
@@ -1,219 +0,0 @@
1
- import unittest
2
- import os
3
- from tavily import TavilyClient, InvalidAPIKeyError, MissingAPIKeyError
4
- from urllib.parse import urlparse
5
-
6
- from unit_tests import cases
7
-
8
- class SearchTest(unittest.TestCase):
9
-
10
- def setUp(self) -> None:
11
- self.tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
12
- return super().setUp()
13
-
14
- def tearDown(self) -> None:
15
- return super().tearDown()
16
-
17
- # Every single search result should have these properties
18
- def common_search_result_properties(self, result) -> None:
19
- self.assertIsInstance(result, dict)
20
- self.assertIn("title", result)
21
- self.assertIn("url", result)
22
- self.assertIn("content", result)
23
- self.assertIn("score", result)
24
-
25
- # General search results should have these properties
26
- def general_search_result_properties(self, result) -> None:
27
- self.common_search_result_properties(result)
28
- self.assertIn("raw_content", result)
29
-
30
- # News search results should have these properties
31
- def news_search_result_properties(self, result) -> None:
32
- self.common_search_result_properties(result)
33
- self.assertIn("published_date", result)
34
-
35
- # Topic-specific properties
36
- def topic_specific_properties(self, result, **params) -> None:
37
- if params.get("topic", "general") == "general":
38
- self.assertIn("raw_content", result)
39
- elif params.get("topic", "general") == "news":
40
- self.assertIn("published_date", result)
41
-
42
- # Domain inclusion/exclusion-dependent properties
43
- def domain_dependent_properties(self, response, **params) -> None:
44
- if params.get("topic", "general") != "general":
45
- return
46
-
47
- if params.get("include_domains", False) and len(params["include_domains"]) > 0:
48
- for result in response["results"]:
49
- self.assertTrue(any(domain in urlparse(result["url"]).netloc for domain in params["include_domains"]))
50
-
51
- if params.get("exclude_domains", False) and len(params["exclude_domains"]) > 0:
52
- for result in response["results"]:
53
- self.assertFalse(any(domain in urlparse(result["url"]).netloc for domain in params["exclude_domains"]))
54
-
55
- # Image-dependent properties
56
- def image_properties(self, response, **params) -> None:
57
- if params.get("topic", "general") == "general" and params.get("include_images", False):
58
- self.assertIsNotNone(response["images"])
59
- self.assertIsInstance(response["images"], list)
60
- for image in response["images"]:
61
- self.assertIsInstance(image, str)
62
-
63
- # Answer-dependent properties
64
- def answer_properties(self, response, **params) -> None:
65
- if params.get("include_answer", False):
66
- self.assertIn("answer", response)
67
- self.assertIsInstance(response["answer"], str)
68
-
69
-
70
- # Every single search response should have these properties
71
- def common_response_properties(self, response) -> None:
72
- self.assertIsNotNone(response)
73
- self.assertIsInstance(response, dict)
74
- self.assertIn("answer", response)
75
- self.assertIn("query", response)
76
- self.assertIn("results", response)
77
- self.assertIn("images", response)
78
- self.assertIn("response_time", response)
79
- self.assertIn("follow_up_questions", response)
80
-
81
- self.assertIsNotNone(response["query"])
82
- self.assertIsNotNone(response["results"])
83
- self.assertIsNotNone(response["response_time"])
84
- self.assertIsNotNone(response["images"])
85
-
86
- self.assertIsInstance(response["query"], str)
87
- self.assertIsInstance(response["results"], list)
88
- self.assertIsInstance(response["response_time"], float)
89
- self.assertIsInstance(response["images"], list)
90
-
91
- # Search responses also have properties that depend on the request params
92
- def custom_response_properties(self, response, **params) -> None:
93
- self.domain_dependent_properties(response, **params)
94
- self.image_properties(response, **params)
95
- self.answer_properties(response, **params)
96
- for result in response["results"]:
97
- self.topic_specific_properties(result, **params)
98
-
99
- def test_internal_search(self) -> None:
100
- for test_case in cases:
101
- with self.subTest(msg=test_case["name"]):
102
- result = self.tavily_client._search(**test_case["params"])
103
- self.common_response_properties(result)
104
- if test_case["params"].get("topic", "general") == "general":
105
- for search_result in result["results"]:
106
- self.general_search_result_properties(search_result)
107
- elif test_case["params"].get("topic", "general") == "news":
108
- for search_result in result["results"]:
109
- self.news_search_result_properties(search_result)
110
- self.custom_response_properties(result, **test_case["params"])
111
-
112
- def test_external_search(self) -> None:
113
- for test_case in cases:
114
- with self.subTest(msg=test_case["name"]):
115
- response = self.tavily_client._search(**test_case["params"])
116
- self.common_response_properties(response)
117
- if test_case["params"].get("topic", "general") == "general":
118
- for search_result in response["results"]:
119
- self.general_search_result_properties(search_result)
120
- elif test_case["params"].get("topic", "general") == "news":
121
- for search_result in response["results"]:
122
- self.news_search_result_properties(search_result)
123
- self.custom_response_properties(response, **test_case["params"])
124
-
125
- class QNASearchTest(unittest.TestCase):
126
-
127
- def setUp(self) -> None:
128
- self.tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
129
- return super().setUp()
130
-
131
- def tearDown(self) -> None:
132
- return super().tearDown()
133
-
134
- def test_qna_search(self) -> None:
135
- for test_case in cases:
136
- if "include_answer" in test_case["params"]:
137
- del test_case["params"]["include_answer"]
138
- if "include_raw_content" in test_case["params"]:
139
- del test_case["params"]["include_raw_content"]
140
- if "include_images" in test_case["params"]:
141
- del test_case["params"]["include_images"]
142
- with self.subTest(msg=test_case["name"]):
143
- response = self.tavily_client.qna_search(**test_case["params"])
144
- self.assertIsNotNone(response)
145
- self.assertIsInstance(response, str)
146
- self.assertTrue(len(response) > 0)
147
-
148
- class CompanyInfoSearchTest(unittest.TestCase):
149
-
150
- def setUp(self) -> None:
151
- self.tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
152
- return super().setUp()
153
-
154
- def tearDown(self) -> None:
155
- return super().tearDown()
156
-
157
- # Every single search result should have these properties
158
- def common_search_result_properties(self, result) -> None:
159
- self.assertIsInstance(result, dict)
160
- self.assertIn("title", result)
161
- self.assertIn("url", result)
162
- self.assertIn("content", result)
163
- self.assertIn("score", result)
164
-
165
- def test_company_info_search(self) -> None:
166
- for test_case in cases:
167
- if "topic" in test_case["params"]:
168
- del test_case["params"]["topic"]
169
- if "include_domains" in test_case["params"]:
170
- del test_case["params"]["include_domains"]
171
- if "exclude_domains" in test_case["params"]:
172
- del test_case["params"]["exclude_domains"]
173
- if "include_raw_content" in test_case["params"]:
174
- del test_case["params"]["include_raw_content"]
175
- if "include_images" in test_case["params"]:
176
- del test_case["params"]["include_images"]
177
- if "include_answer" in test_case["params"]:
178
- del test_case["params"]["include_answer"]
179
- if "use_cache" in test_case["params"]:
180
- del test_case["params"]["use_cache"]
181
- with self.subTest(msg=test_case["name"]):
182
- response = self.tavily_client.get_company_info(**test_case["params"])
183
- self.assertIsNotNone(response)
184
- self.assertIsInstance(response, list)
185
- self.assertTrue(len(response) > 0)
186
- for search_result in response:
187
- self.common_search_result_properties(search_result)
188
-
189
- class ErrorTest(unittest.TestCase):
190
-
191
- def setUp(self) -> None:
192
- return super().setUp()
193
-
194
- def tearDown(self) -> None:
195
- return super().tearDown()
196
-
197
- # This test is here to ensure that no MissingAPIKeyError is raised when the API key is in the environment
198
- def test_load_key_from_env(self) -> None:
199
- self.assertIn('results', TavilyClient().search("Why is Tavily the best search API?"))
200
-
201
- def test_missing_api_key(self) -> None:
202
- with self.assertRaises(MissingAPIKeyError):
203
- TavilyClient(api_key='')
204
-
205
- old_key = os.getenv("TAVILY_API_KEY")
206
- del os.environ["TAVILY_API_KEY"]
207
- with self.assertRaises(MissingAPIKeyError):
208
- TavilyClient()
209
-
210
- os.environ["TAVILY_API_KEY"] = old_key
211
-
212
-
213
- def test_invalid_api_key(self) -> None:
214
- with self.assertRaises(InvalidAPIKeyError):
215
- TavilyClient(api_key="invalid_api_key").search("Why is Tavily the best search API?")
216
-
217
- if __name__ == "__main__":
218
-
219
- unittest.main()
File without changes
File without changes
File without changes