Skip to content

Commit 01ecb04

Browse files
VinciGit00claude
andcommitted
feat: add location_geo_code param to search endpoint and camelCase serialization
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5b43ae8 commit 01ecb04

6 files changed

Lines changed: 61 additions & 1 deletion

File tree

scrapegraph-py/scrapegraph_py/async_client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ async def search(
355355
query: str,
356356
num_results: int = 5,
357357
output_schema: Optional[Any] = None,
358+
location_geo_code: Optional[str] = None,
358359
llm_config: Optional[LlmConfig] = None,
359360
) -> Dict[str, Any]:
360361
"""Search the web and extract structured results.
@@ -363,6 +364,7 @@ async def search(
363364
query: The search query
364365
num_results: Number of results (3-20, default 5)
365366
output_schema: JSON Schema dict or Pydantic BaseModel class for output structure
367+
location_geo_code: Two-letter country code for geo-targeted results (e.g. 'us', 'gb')
366368
llm_config: LLM configuration options
367369
"""
368370
logger.info(f"Searching: {query}")
@@ -382,6 +384,7 @@ async def search(
382384
query=query,
383385
num_results=num_results,
384386
output_schema=schema_dict,
387+
location_geo_code=location_geo_code,
385388
llm_config=llm_config,
386389
)
387390
return await self._make_request(

scrapegraph-py/scrapegraph_py/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ def search(
402402
query: str,
403403
num_results: int = 5,
404404
output_schema: Optional[Any] = None,
405+
location_geo_code: Optional[str] = None,
405406
llm_config: Optional[LlmConfig] = None,
406407
) -> Dict[str, Any]:
407408
"""Search the web and extract structured results.
@@ -410,6 +411,7 @@ def search(
410411
query: The search query
411412
num_results: Number of results (3-20, default 5)
412413
output_schema: JSON Schema dict or Pydantic BaseModel class for output structure
414+
location_geo_code: Two-letter country code for geo-targeted results (e.g. 'us', 'gb')
413415
llm_config: LLM configuration options
414416
"""
415417
logger.info(f"Searching: {query}")
@@ -429,6 +431,7 @@ def search(
429431
query=query,
430432
num_results=num_results,
431433
output_schema=schema_dict,
434+
location_geo_code=location_geo_code,
432435
llm_config=llm_config,
433436
)
434437
return self._make_request(

scrapegraph-py/scrapegraph_py/models/search.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,34 @@
66

77
from typing import Any, Dict, Optional
88

9-
from pydantic import BaseModel, Field, conint, model_validator
9+
from pydantic import BaseModel, ConfigDict, Field, conint, model_validator
10+
from pydantic.alias_generators import to_camel
1011

1112
from .shared import LlmConfig
1213

1314

1415
class SearchRequest(BaseModel):
1516
"""Request model for POST /v2/search."""
1617

18+
model_config = ConfigDict(
19+
alias_generator=to_camel,
20+
populate_by_name=True,
21+
)
22+
1723
query: str = Field(..., description="The search query")
1824
num_results: conint(ge=3, le=20) = Field(
1925
default=5, description="Number of results to return (3-20)"
2026
)
2127
output_schema: Optional[Dict[str, Any]] = Field(
2228
default=None,
29+
alias="schema",
2330
description="JSON Schema defining the structure of the extracted data",
2431
)
32+
location_geo_code: Optional[str] = Field(
33+
default=None,
34+
max_length=10,
35+
description="Two-letter country code for geo-targeted search results (e.g. 'us', 'gb', 'de')",
36+
)
2537
llm_config: Optional[LlmConfig] = Field(
2638
default=None, description="LLM configuration options"
2739
)
@@ -34,4 +46,5 @@ def validate_query(self) -> "SearchRequest":
3446

3547
def model_dump(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
3648
kwargs.setdefault("exclude_none", True)
49+
kwargs.setdefault("by_alias", True)
3750
return super().model_dump(*args, **kwargs)

scrapegraph-py/tests/test_async_client.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@ async def test_search(client):
124124
assert "results" in result
125125

126126

127+
@pytest.mark.asyncio
128+
async def test_search_with_location_geo_code(client):
129+
with aioresponses() as mocked:
130+
mocked.post(
131+
f"{API_BASE_URL}/search",
132+
payload={
133+
"request_id": str(uuid4()),
134+
"results": [{"url": "https://example.it"}],
135+
},
136+
)
137+
result = await client.search("best restaurants", location_geo_code="it")
138+
assert "results" in result
139+
140+
127141
# ------------------------------------------------------------------
128142
# Credits
129143
# ------------------------------------------------------------------

scrapegraph-py/tests/test_client.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,17 @@ def test_search_with_num_results(client):
159159
assert "results" in result
160160

161161

162+
@responses.activate
163+
def test_search_with_location_geo_code(client):
164+
responses.add(
165+
responses.POST,
166+
f"{API_BASE_URL}/search",
167+
json={"request_id": str(uuid4()), "results": [{"url": "https://example.it"}]},
168+
)
169+
result = client.search("best restaurants", location_geo_code="it")
170+
assert "results" in result
171+
172+
162173
# ------------------------------------------------------------------
163174
# Credits
164175
# ------------------------------------------------------------------

scrapegraph-py/tests/test_models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,22 @@ def test_search_request_num_results_bounds():
122122
SearchRequest(query="test", num_results=21)
123123

124124

125+
def test_search_request_with_location_geo_code():
126+
req = SearchRequest(query="test", location_geo_code="us")
127+
assert req.location_geo_code == "us"
128+
129+
130+
def test_search_request_location_geo_code_excluded_when_none():
131+
req = SearchRequest(query="test")
132+
data = req.model_dump()
133+
assert "location_geo_code" not in data
134+
135+
136+
def test_search_request_location_geo_code_too_long():
137+
with pytest.raises(ValueError):
138+
SearchRequest(query="test", location_geo_code="a" * 11)
139+
140+
125141
# ------------------------------------------------------------------
126142
# Crawl
127143
# ------------------------------------------------------------------

0 commit comments

Comments
 (0)