Files
Assaf Elovic 9140bde5bc fix(retrievers): tolerate malformed provider payloads
Consolidates 20 single-file PRs from @Bartok9 into one reviewable change.
Every provider parsed its JSON response with strict indexing, so one
malformed row from an upstream API aborted the whole search rather than
skipping that row: non-dict entries, missing link/href/url keys,
non-list result containers, and null nested objects.

Squashed from #1839 #1852 #1917 #1918 #1921 #1922 #1923 #1931 #1932
#1933 #1934 #1937 #1938 #1940 #1946 #1947 #1958 #1999 #2007 #2013.
Each was applied and run against the full suite individually before
being stacked. Duplicates that targeted the same file (#1914 #1920
#1962 #2001 on searchapi, #1971 on serper, #2006 on serpapi, #2008 on
crw, #2009 on getxapi, #1995 on xquik, #1998 on bing, #2000 on bocha)
are superseded by the version kept here.

Co-Authored-By: Bartok9 <noreply@github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:02:44 +03:00

54 lines
1.5 KiB
Python

"""ExaSearch.search must return [] on API failures, not raise."""
from types import SimpleNamespace
from gpt_researcher.retrievers.exa.exa import ExaSearch
def test_search_swallows_client_errors(monkeypatch):
searcher = ExaSearch.__new__(ExaSearch)
searcher.query = "q"
searcher.query_domains = None
class Boom:
def search(self, *a, **k):
raise RuntimeError("api down")
searcher.client = Boom()
assert searcher.search() == []
def test_search_tolerates_missing_results_list():
searcher = ExaSearch.__new__(ExaSearch)
searcher.query = "q"
searcher.query_domains = None
class Ok:
def search(self, *a, **k):
return SimpleNamespace(results=None)
searcher.client = Ok()
assert searcher.search() == []
def test_search_normalizes_hits():
searcher = ExaSearch.__new__(ExaSearch)
searcher.query = "q"
searcher.query_domains = None
class Ok:
def search(self, *a, **k):
return SimpleNamespace(
results=[
SimpleNamespace(url="https://a.example", text="body", summary=None),
SimpleNamespace(url=None, text="x", summary=None),
SimpleNamespace(url="https://b.example", text=None, summary="sum"),
]
)
searcher.client = Ok()
assert searcher.search() == [
{"href": "https://a.example", "body": "body"},
{"href": "https://b.example", "body": "sum"},
]