search1api 0.3.0__tar.gz → 0.4.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.
- search1api-0.4.0/CHANGELOG.md +5 -0
- {search1api-0.3.0 → search1api-0.4.0}/PKG-INFO +6 -2
- {search1api-0.3.0 → search1api-0.4.0}/README.md +5 -1
- {search1api-0.3.0 → search1api-0.4.0}/openapi/search1api.openapi.json +15 -5
- {search1api-0.3.0 → search1api-0.4.0}/pyproject.toml +1 -1
- {search1api-0.3.0 → search1api-0.4.0}/src/search1api/__init__.py +1 -1
- {search1api-0.3.0 → search1api-0.4.0}/src/search1api/types.py +7 -3
- {search1api-0.3.0 → search1api-0.4.0}/tests/test_client.py +33 -0
- {search1api-0.3.0 → search1api-0.4.0}/.github/workflows/ci.yml +0 -0
- {search1api-0.3.0 → search1api-0.4.0}/.github/workflows/release.yml +0 -0
- {search1api-0.3.0 → search1api-0.4.0}/.gitignore +0 -0
- {search1api-0.3.0 → search1api-0.4.0}/LICENSE +0 -0
- {search1api-0.3.0 → search1api-0.4.0}/openapi/README.md +0 -0
- {search1api-0.3.0 → search1api-0.4.0}/src/search1api/client.py +0 -0
- {search1api-0.3.0 → search1api-0.4.0}/src/search1api/errors.py +0 -0
- {search1api-0.3.0 → search1api-0.4.0}/src/search1api/py.typed +0 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.0 - 2026-10-12
|
|
4
|
+
|
|
5
|
+
Breaking: search/news engine-specific fields move from each result's top level to optional `metadata` (`kind`, `stars`, `language`, `num_comments`, `points`, `story_url`). Read e.g. `result.metadata.stars` instead of `result.stars`. `published_date` stays at the top level. No legacy field aliases.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: search1api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Official Python client for Search1API
|
|
5
5
|
Project-URL: Homepage, https://s1.dev
|
|
6
6
|
Project-URL: Documentation, https://s1.dev/docs/integrations/sdks
|
|
@@ -81,7 +81,11 @@ for result in response["results"]:
|
|
|
81
81
|
`bingcn`, `yandex`, `reddit`, `github`, `arxiv`, `wikipedia`, or `grokipedia`.
|
|
82
82
|
`page` requests a later results page on engines with native pagination
|
|
83
83
|
(`bing`, `bingcn`, `baidu`, `grokipedia`). Results carry `published_date` when the source
|
|
84
|
-
exposes one.
|
|
84
|
+
exposes one. Engine-specific fields are in each result's optional `metadata`:
|
|
85
|
+
GitHub uses `metadata.kind`, `metadata.stars`, `metadata.language`, and
|
|
86
|
+
`metadata.num_comments`; Hacker News news results use `metadata.story_url`,
|
|
87
|
+
`metadata.points`, and `metadata.num_comments`. The former top-level paths
|
|
88
|
+
are removed in 0.4.0; `published_date` stays at the top level.
|
|
85
89
|
|
|
86
90
|
Use the client as a context manager when it owns the HTTP connection pool:
|
|
87
91
|
|
|
@@ -30,7 +30,11 @@ for result in response["results"]:
|
|
|
30
30
|
`bingcn`, `yandex`, `reddit`, `github`, `arxiv`, `wikipedia`, or `grokipedia`.
|
|
31
31
|
`page` requests a later results page on engines with native pagination
|
|
32
32
|
(`bing`, `bingcn`, `baidu`, `grokipedia`). Results carry `published_date` when the source
|
|
33
|
-
exposes one.
|
|
33
|
+
exposes one. Engine-specific fields are in each result's optional `metadata`:
|
|
34
|
+
GitHub uses `metadata.kind`, `metadata.stars`, `metadata.language`, and
|
|
35
|
+
`metadata.num_comments`; Hacker News news results use `metadata.story_url`,
|
|
36
|
+
`metadata.points`, and `metadata.num_comments`. The former top-level paths
|
|
37
|
+
are removed in 0.4.0; `published_date` stays at the top level.
|
|
34
38
|
|
|
35
39
|
Use the client as a context manager when it owns the HTTP connection pool:
|
|
36
40
|
|
|
@@ -348,6 +348,16 @@
|
|
|
348
348
|
"description": "When the page was published, as ISO 8601: `YYYY-MM-DD` when only the day is known (web search engines), or `YYYY-MM-DDTHH:MM:SSZ` in UTC when the source carries a time (x, reddit, github, arxiv, youtube, bilibili, wechat, news feeds). Omitted when the source exposes no date, so treat it as optional per result.",
|
|
349
349
|
"example": "2026-09-03"
|
|
350
350
|
},
|
|
351
|
+
"metadata": {
|
|
352
|
+
"$ref": "#/components/schemas/SearchResultMetadata"
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
"additionalProperties": true
|
|
356
|
+
},
|
|
357
|
+
"SearchResultMetadata": {
|
|
358
|
+
"type": "object",
|
|
359
|
+
"description": "Optional engine-specific fields. Omitted when none apply. GitHub fields appear on POST /search; Hacker News fields appear on POST /news.",
|
|
360
|
+
"properties": {
|
|
351
361
|
"kind": {
|
|
352
362
|
"type": "string",
|
|
353
363
|
"enum": [
|
|
@@ -360,11 +370,11 @@
|
|
|
360
370
|
},
|
|
361
371
|
"stars": {
|
|
362
372
|
"type": "integer",
|
|
363
|
-
"description": "Stargazer count of a `github` repository result (`kind: \"repo\"`)."
|
|
373
|
+
"description": "Stargazer count of a `github` repository result (`metadata.kind: \"repo\"`)."
|
|
364
374
|
},
|
|
365
375
|
"language": {
|
|
366
376
|
"type": "string",
|
|
367
|
-
"description": "Primary language of a `github` repository result (`kind: \"repo\"`). Omitted when GitHub reports none."
|
|
377
|
+
"description": "Primary language of a `github` repository result (`metadata.kind: \"repo\"`). Omitted when GitHub reports none."
|
|
368
378
|
},
|
|
369
379
|
"num_comments": {
|
|
370
380
|
"type": "integer",
|
|
@@ -373,7 +383,7 @@
|
|
|
373
383
|
"story_url": {
|
|
374
384
|
"type": "string",
|
|
375
385
|
"format": "uri",
|
|
376
|
-
"description": "POST /news with `search_service: \"hackernews\"` only: the submitted article. `link` is the Hacker News discussion thread; `story_url` is
|
|
386
|
+
"description": "POST /news with `search_service: \"hackernews\"` only: the submitted article. `link` is the Hacker News discussion thread; `metadata.story_url` is omitted for Ask HN / Show HN text posts."
|
|
377
387
|
},
|
|
378
388
|
"points": {
|
|
379
389
|
"type": "integer",
|
|
@@ -631,7 +641,7 @@
|
|
|
631
641
|
"properties": {
|
|
632
642
|
"search_query": {
|
|
633
643
|
"type": "string",
|
|
634
|
-
"description": "
|
|
644
|
+
"description": "Query sent to the first engine in `sources`. Each engine searches its own span of the request words, without platform names; the time window is applied as a filter."
|
|
635
645
|
},
|
|
636
646
|
"sources": {
|
|
637
647
|
"type": "array",
|
|
@@ -652,7 +662,7 @@
|
|
|
652
662
|
"year",
|
|
653
663
|
null
|
|
654
664
|
],
|
|
655
|
-
"description": "Publication window applied, or null for none."
|
|
665
|
+
"description": "Publication window applied, or null for none. year means the past 365 days, not the current calendar year."
|
|
656
666
|
}
|
|
657
667
|
}
|
|
658
668
|
},
|
|
@@ -54,9 +54,7 @@ class SearchResultRequired(TypedDict):
|
|
|
54
54
|
snippet: str
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
class
|
|
58
|
-
content: str
|
|
59
|
-
published_date: str
|
|
57
|
+
class SearchResultMetadata(TypedDict, total=False):
|
|
60
58
|
kind: Literal["repo", "issue", "pr", "discussion"]
|
|
61
59
|
stars: int
|
|
62
60
|
language: str
|
|
@@ -65,6 +63,12 @@ class SearchResult(SearchResultRequired, total=False):
|
|
|
65
63
|
story_url: str
|
|
66
64
|
|
|
67
65
|
|
|
66
|
+
class SearchResult(SearchResultRequired, total=False):
|
|
67
|
+
content: str
|
|
68
|
+
published_date: str
|
|
69
|
+
metadata: SearchResultMetadata
|
|
70
|
+
|
|
71
|
+
|
|
68
72
|
class SearchResponseRequired(TypedDict):
|
|
69
73
|
searchParameters: SearchRequest
|
|
70
74
|
results: List[SearchResult]
|
|
@@ -24,6 +24,39 @@ def test_requires_api_key(monkeypatch):
|
|
|
24
24
|
Search1API()
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
@pytest.mark.parametrize("method", ["search", "news"])
|
|
28
|
+
@pytest.mark.parametrize("asynchronous", [False, True])
|
|
29
|
+
def test_preserves_nested_metadata(method, asynchronous):
|
|
30
|
+
body = {
|
|
31
|
+
"searchParameters": {"query": "q"},
|
|
32
|
+
"results": [
|
|
33
|
+
{
|
|
34
|
+
"title": "Thread",
|
|
35
|
+
"link": "https://example.com/thread",
|
|
36
|
+
"snippet": "Discussion",
|
|
37
|
+
"published_date": "2026-10-12",
|
|
38
|
+
"metadata": {"num_comments": 0},
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
}
|
|
42
|
+
transport = httpx.MockTransport(lambda request: json_response(200, body, request))
|
|
43
|
+
|
|
44
|
+
async def run():
|
|
45
|
+
async with httpx.AsyncClient(transport=transport) as http_client:
|
|
46
|
+
async with AsyncSearch1API("test-key", client=http_client) as client:
|
|
47
|
+
return await getattr(client, method)("q")
|
|
48
|
+
|
|
49
|
+
if asynchronous:
|
|
50
|
+
response = asyncio.run(run())
|
|
51
|
+
else:
|
|
52
|
+
with httpx.Client(transport=transport) as http_client:
|
|
53
|
+
with Search1API("test-key", client=http_client) as client:
|
|
54
|
+
response = getattr(client, method)("q")
|
|
55
|
+
assert response == body
|
|
56
|
+
assert response["results"][0]["metadata"]["num_comments"] == 0
|
|
57
|
+
assert "num_comments" not in response["results"][0]
|
|
58
|
+
|
|
59
|
+
|
|
27
60
|
def test_rejects_invalid_retry_and_timeout_settings():
|
|
28
61
|
with pytest.raises(Search1APIConfigurationError, match="max_retries"):
|
|
29
62
|
Search1API("test-key", max_retries=-1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|