tinyfish 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.
- tinyfish-0.4.0/CHANGELOG.md +17 -0
- tinyfish-0.3.0/README.md → tinyfish-0.4.0/PKG-INFO +18 -0
- tinyfish-0.3.0/PKG-INFO → tinyfish-0.4.0/README.md +8 -10
- {tinyfish-0.3.0 → tinyfish-0.4.0}/pyproject.toml +1 -1
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/search/__init__.py +58 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_search.py +116 -0
- tinyfish-0.3.0/CHANGELOG.md +0 -9
- {tinyfish-0.3.0 → tinyfish-0.4.0}/.gitignore +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/.pre-commit-config.yaml +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/AGENTS.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/CLAUDE.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/RELEASE.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/docs/exceptions-and-errors-guide.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/docs/internal/api-integration-header.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/docs/internal/exceptions-and-errors-guide.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/docs/internal/publishing-private-guide.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/docs/pagination-guide.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/docs/proxy-and-browser-profiles.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/docs/streaming-guide.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/client/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/client/_base.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/client/async_.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/client/sync.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/exceptions.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/resource.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/_utils/sse_parser.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/agent/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/agent/types.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/browser/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/browser/types.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/client.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/fetch/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/fetch/types.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/py.typed +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/runs/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/runs/types.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/search/types.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/vault/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/src/tinyfish/vault/types.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/__init__.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/conftest.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_agent.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_browser.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_client.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_errors.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_fetch.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_runs.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/test_vault.py +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/tests/testing_guide.md +0 -0
- {tinyfish-0.3.0 → tinyfish-0.4.0}/uv.lock +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.4.0](https://github.com/tinyfish-io/ux-labs/compare/sdk-py/v0.3.0...sdk-py/v0.4.0) (2026-07-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **search:** add pub_year_min/pub_year_max publication-year filter ([#3691](https://github.com/tinyfish-io/ux-labs/issues/3691)) ([8728754](https://github.com/tinyfish-io/ux-labs/commit/8728754206fe4b7cf3a4ee8226c74bb364532869))
|
|
9
|
+
* **search:** expose include_domains/exclude_domains in SDKs, CLI, MCP prose (ML-2084) ([#3692](https://github.com/tinyfish-io/ux-labs/issues/3692)) ([6c2079f](https://github.com/tinyfish-io/ux-labs/commit/6c2079f52872f9c9472cde8ec95d70280f25defa))
|
|
10
|
+
|
|
11
|
+
## [0.3.0](https://github.com/tinyfish-io/ux-labs/compare/sdk-py/v0.2.6...sdk-py/v0.3.0) (2026-07-22)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **ci:** automate SDK/CLI releases via release-please ([#3632](https://github.com/tinyfish-io/ux-labs/issues/3632)) ([1b311ea](https://github.com/tinyfish-io/ux-labs/commit/1b311ea6d6277fad21b57baf0b7cfdc6619a3b93))
|
|
17
|
+
* **sdk:** add domain_type to search.query() in TypeScript and Python SDKs ([#3432](https://github.com/tinyfish-io/ux-labs/issues/3432)) ([1c2954c](https://github.com/tinyfish-io/ux-labs/commit/1c2954cb192324cdca1ce206515de72df2cd231d))
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tinyfish
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Official Python SDK for the TinyFish API
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: httpx>=0.27.0
|
|
7
|
+
Requires-Dist: pydantic>=2.0.0
|
|
8
|
+
Requires-Dist: tenacity>=8.0.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
1
11
|
# TinyFish Python SDK
|
|
2
12
|
|
|
3
13
|
The official Python SDK for [TinyFish](https://agent.tinyfish.ai)
|
|
@@ -309,6 +319,7 @@ Optional parameters:
|
|
|
309
319
|
- `recency_minutes` — freshness window in minutes (`1` to `5256000`)
|
|
310
320
|
- `after_date` / `before_date` — calendar date range in `YYYY-MM-DD`
|
|
311
321
|
- `domain_type` — result category: `"web"` (default), `"news"`, or `"research_paper"`
|
|
322
|
+
- `pub_year_min` / `pub_year_max` — publication-year range, inclusive (`0` to `9999`). Only supported for `domain_type="research_paper"`
|
|
312
323
|
|
|
313
324
|
```python
|
|
314
325
|
# geo-targeted
|
|
@@ -323,6 +334,11 @@ response = client.search.query("FIFA", after_date="2026-06-01", before_date="202
|
|
|
323
334
|
# domain type
|
|
324
335
|
response = client.search.query("FIFA", domain_type="news")
|
|
325
336
|
response = client.search.query("machine learning", domain_type="research_paper")
|
|
337
|
+
|
|
338
|
+
# publication-year range (research_paper only)
|
|
339
|
+
response = client.search.query(
|
|
340
|
+
"transformer architecture", domain_type="research_paper", pub_year_min=2019, pub_year_max=2022
|
|
341
|
+
)
|
|
326
342
|
```
|
|
327
343
|
|
|
328
344
|
Filter validation rules:
|
|
@@ -332,6 +348,8 @@ Filter validation rules:
|
|
|
332
348
|
- `recency_minutes` cannot be combined with `after_date` or `before_date`
|
|
333
349
|
- if both dates are present, `after_date` must be less than or equal to `before_date`
|
|
334
350
|
- `domain_type` must be one of `"web"`, `"news"`, or `"research_paper"`
|
|
351
|
+
- `pub_year_min` and `pub_year_max` must be integers from `0` to `9999`
|
|
352
|
+
- if both are present, `pub_year_min` must be less than or equal to `pub_year_max`
|
|
335
353
|
|
|
336
354
|
---
|
|
337
355
|
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: tinyfish
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: Official Python SDK for the TinyFish API
|
|
5
|
-
Requires-Python: >=3.11
|
|
6
|
-
Requires-Dist: httpx>=0.27.0
|
|
7
|
-
Requires-Dist: pydantic>=2.0.0
|
|
8
|
-
Requires-Dist: tenacity>=8.0.0
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
|
|
11
1
|
# TinyFish Python SDK
|
|
12
2
|
|
|
13
3
|
The official Python SDK for [TinyFish](https://agent.tinyfish.ai)
|
|
@@ -319,6 +309,7 @@ Optional parameters:
|
|
|
319
309
|
- `recency_minutes` — freshness window in minutes (`1` to `5256000`)
|
|
320
310
|
- `after_date` / `before_date` — calendar date range in `YYYY-MM-DD`
|
|
321
311
|
- `domain_type` — result category: `"web"` (default), `"news"`, or `"research_paper"`
|
|
312
|
+
- `pub_year_min` / `pub_year_max` — publication-year range, inclusive (`0` to `9999`). Only supported for `domain_type="research_paper"`
|
|
322
313
|
|
|
323
314
|
```python
|
|
324
315
|
# geo-targeted
|
|
@@ -333,6 +324,11 @@ response = client.search.query("FIFA", after_date="2026-06-01", before_date="202
|
|
|
333
324
|
# domain type
|
|
334
325
|
response = client.search.query("FIFA", domain_type="news")
|
|
335
326
|
response = client.search.query("machine learning", domain_type="research_paper")
|
|
327
|
+
|
|
328
|
+
# publication-year range (research_paper only)
|
|
329
|
+
response = client.search.query(
|
|
330
|
+
"transformer architecture", domain_type="research_paper", pub_year_min=2019, pub_year_max=2022
|
|
331
|
+
)
|
|
336
332
|
```
|
|
337
333
|
|
|
338
334
|
Filter validation rules:
|
|
@@ -342,6 +338,8 @@ Filter validation rules:
|
|
|
342
338
|
- `recency_minutes` cannot be combined with `after_date` or `before_date`
|
|
343
339
|
- if both dates are present, `after_date` must be less than or equal to `before_date`
|
|
344
340
|
- `domain_type` must be one of `"web"`, `"news"`, or `"research_paper"`
|
|
341
|
+
- `pub_year_min` and `pub_year_max` must be integers from `0` to `9999`
|
|
342
|
+
- if both are present, `pub_year_min` must be less than or equal to `pub_year_max`
|
|
345
343
|
|
|
346
344
|
---
|
|
347
345
|
|
|
@@ -26,16 +26,27 @@ def _validate_iso_date(field_name: str, value: str) -> str:
|
|
|
26
26
|
return value
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def _validate_pub_year(field_name: str, value: int) -> None:
|
|
30
|
+
if not isinstance(value, int) or isinstance(value, bool):
|
|
31
|
+
raise ValueError(f"{field_name} must be an integer")
|
|
32
|
+
if not 0 <= value <= 9999:
|
|
33
|
+
raise ValueError(f"{field_name} must be between 0 and 9999")
|
|
34
|
+
|
|
35
|
+
|
|
29
36
|
def _build_search_params(
|
|
30
37
|
*,
|
|
31
38
|
query: str,
|
|
32
39
|
purpose: str | None = None,
|
|
33
40
|
location: str | None = None,
|
|
34
41
|
language: str | None = None,
|
|
42
|
+
include_domains: str | None = None,
|
|
43
|
+
exclude_domains: str | None = None,
|
|
35
44
|
after_date: str | None = None,
|
|
36
45
|
before_date: str | None = None,
|
|
37
46
|
recency_minutes: int | None = None,
|
|
38
47
|
domain_type: str | None = None,
|
|
48
|
+
pub_year_min: int | None = None,
|
|
49
|
+
pub_year_max: int | None = None,
|
|
39
50
|
page: int | None = None,
|
|
40
51
|
) -> dict[str, str]:
|
|
41
52
|
if not query or not query.strip():
|
|
@@ -67,6 +78,12 @@ def _build_search_params(
|
|
|
67
78
|
raise ValueError("recency_minutes cannot be combined with after_date or before_date")
|
|
68
79
|
if after_date is not None and before_date is not None and after_date > before_date:
|
|
69
80
|
raise ValueError("after_date must be on or before before_date")
|
|
81
|
+
if pub_year_min is not None:
|
|
82
|
+
_validate_pub_year("pub_year_min", pub_year_min)
|
|
83
|
+
if pub_year_max is not None:
|
|
84
|
+
_validate_pub_year("pub_year_max", pub_year_max)
|
|
85
|
+
if pub_year_min is not None and pub_year_max is not None and pub_year_min > pub_year_max:
|
|
86
|
+
raise ValueError("pub_year_min must be less than or equal to pub_year_max")
|
|
70
87
|
|
|
71
88
|
params: dict[str, str] = {"query": query}
|
|
72
89
|
if purpose is not None:
|
|
@@ -75,6 +92,10 @@ def _build_search_params(
|
|
|
75
92
|
params["location"] = location
|
|
76
93
|
if language is not None:
|
|
77
94
|
params["language"] = language
|
|
95
|
+
if include_domains is not None:
|
|
96
|
+
params["include_domains"] = include_domains
|
|
97
|
+
if exclude_domains is not None:
|
|
98
|
+
params["exclude_domains"] = exclude_domains
|
|
78
99
|
if after_date is not None:
|
|
79
100
|
params["after_date"] = after_date
|
|
80
101
|
if before_date is not None:
|
|
@@ -83,6 +104,11 @@ def _build_search_params(
|
|
|
83
104
|
params["recency_minutes"] = str(recency_minutes)
|
|
84
105
|
if domain_type is not None:
|
|
85
106
|
params["domain_type"] = domain_type
|
|
107
|
+
# browser-search requires a 4-character year string, so zero-pad (e.g. 500 -> "0500").
|
|
108
|
+
if pub_year_min is not None:
|
|
109
|
+
params["pub_year_min"] = f"{pub_year_min:04d}"
|
|
110
|
+
if pub_year_max is not None:
|
|
111
|
+
params["pub_year_max"] = f"{pub_year_max:04d}"
|
|
86
112
|
if page is not None:
|
|
87
113
|
params["page"] = str(page)
|
|
88
114
|
return params
|
|
@@ -98,10 +124,14 @@ class SearchResource(BaseSyncAPIResource):
|
|
|
98
124
|
purpose: str | None = None,
|
|
99
125
|
location: str | None = None,
|
|
100
126
|
language: str | None = None,
|
|
127
|
+
include_domains: str | None = None,
|
|
128
|
+
exclude_domains: str | None = None,
|
|
101
129
|
after_date: str | None = None,
|
|
102
130
|
before_date: str | None = None,
|
|
103
131
|
recency_minutes: int | None = None,
|
|
104
132
|
domain_type: str | None = None,
|
|
133
|
+
pub_year_min: int | None = None,
|
|
134
|
+
pub_year_max: int | None = None,
|
|
105
135
|
page: int | None = None,
|
|
106
136
|
) -> SearchQueryResponse:
|
|
107
137
|
"""Execute a web search query.
|
|
@@ -115,10 +145,18 @@ class SearchResource(BaseSyncAPIResource):
|
|
|
115
145
|
characters.
|
|
116
146
|
location: Optional location to scope results (e.g. "United States").
|
|
117
147
|
language: Optional language code (e.g. "en").
|
|
148
|
+
include_domains: Optional comma-separated list of domains to restrict
|
|
149
|
+
results to (e.g. "github.com,arxiv.org").
|
|
150
|
+
exclude_domains: Optional comma-separated list of domains to exclude
|
|
151
|
+
from results (e.g. "pinterest.com,quora.com").
|
|
118
152
|
after_date: Optional date cutoff in YYYY-MM-DD format.
|
|
119
153
|
before_date: Optional date cutoff in YYYY-MM-DD format.
|
|
120
154
|
recency_minutes: Optional rolling freshness window in minutes (1 to 5256000).
|
|
121
155
|
domain_type: Optional search type — "web" (default), "news", or "research_paper".
|
|
156
|
+
pub_year_min: Optional minimum publication year, inclusive (0 to 9999). Only
|
|
157
|
+
supported for domain_type="research_paper".
|
|
158
|
+
pub_year_max: Optional maximum publication year, inclusive (0 to 9999). Only
|
|
159
|
+
supported for domain_type="research_paper".
|
|
122
160
|
page: Result page for pagination.
|
|
123
161
|
|
|
124
162
|
Returns:
|
|
@@ -135,10 +173,14 @@ class SearchResource(BaseSyncAPIResource):
|
|
|
135
173
|
purpose=purpose,
|
|
136
174
|
location=location,
|
|
137
175
|
language=language,
|
|
176
|
+
include_domains=include_domains,
|
|
177
|
+
exclude_domains=exclude_domains,
|
|
138
178
|
after_date=after_date,
|
|
139
179
|
before_date=before_date,
|
|
140
180
|
recency_minutes=recency_minutes,
|
|
141
181
|
domain_type=domain_type,
|
|
182
|
+
pub_year_min=pub_year_min,
|
|
183
|
+
pub_year_max=pub_year_max,
|
|
142
184
|
page=page,
|
|
143
185
|
)
|
|
144
186
|
return self._get("/v1/search", params=params, cast_to=SearchQueryResponse)
|
|
@@ -154,10 +196,14 @@ class AsyncSearchResource(BaseAsyncAPIResource):
|
|
|
154
196
|
purpose: str | None = None,
|
|
155
197
|
location: str | None = None,
|
|
156
198
|
language: str | None = None,
|
|
199
|
+
include_domains: str | None = None,
|
|
200
|
+
exclude_domains: str | None = None,
|
|
157
201
|
after_date: str | None = None,
|
|
158
202
|
before_date: str | None = None,
|
|
159
203
|
recency_minutes: int | None = None,
|
|
160
204
|
domain_type: str | None = None,
|
|
205
|
+
pub_year_min: int | None = None,
|
|
206
|
+
pub_year_max: int | None = None,
|
|
161
207
|
page: int | None = None,
|
|
162
208
|
) -> SearchQueryResponse:
|
|
163
209
|
"""Execute a web search query.
|
|
@@ -173,10 +219,18 @@ class AsyncSearchResource(BaseAsyncAPIResource):
|
|
|
173
219
|
characters.
|
|
174
220
|
location: Optional location to scope results (e.g. "United States").
|
|
175
221
|
language: Optional language code (e.g. "en").
|
|
222
|
+
include_domains: Optional comma-separated list of domains to restrict
|
|
223
|
+
results to (e.g. "github.com,arxiv.org").
|
|
224
|
+
exclude_domains: Optional comma-separated list of domains to exclude
|
|
225
|
+
from results (e.g. "pinterest.com,quora.com").
|
|
176
226
|
after_date: Optional date cutoff in YYYY-MM-DD format.
|
|
177
227
|
before_date: Optional date cutoff in YYYY-MM-DD format.
|
|
178
228
|
recency_minutes: Optional rolling freshness window in minutes (1 to 5256000).
|
|
179
229
|
domain_type: Optional search type — "web" (default), "news", or "research_paper".
|
|
230
|
+
pub_year_min: Optional minimum publication year, inclusive (0 to 9999). Only
|
|
231
|
+
supported for domain_type="research_paper".
|
|
232
|
+
pub_year_max: Optional maximum publication year, inclusive (0 to 9999). Only
|
|
233
|
+
supported for domain_type="research_paper".
|
|
180
234
|
page: Result page for pagination.
|
|
181
235
|
|
|
182
236
|
Returns:
|
|
@@ -193,10 +247,14 @@ class AsyncSearchResource(BaseAsyncAPIResource):
|
|
|
193
247
|
purpose=purpose,
|
|
194
248
|
location=location,
|
|
195
249
|
language=language,
|
|
250
|
+
include_domains=include_domains,
|
|
251
|
+
exclude_domains=exclude_domains,
|
|
196
252
|
after_date=after_date,
|
|
197
253
|
before_date=before_date,
|
|
198
254
|
recency_minutes=recency_minutes,
|
|
199
255
|
domain_type=domain_type,
|
|
256
|
+
pub_year_min=pub_year_min,
|
|
257
|
+
pub_year_max=pub_year_max,
|
|
200
258
|
page=page,
|
|
201
259
|
)
|
|
202
260
|
return await self._get("/v1/search", params=params, cast_to=SearchQueryResponse)
|
|
@@ -88,6 +88,8 @@ def test_query_parses_result_fields(client: TinyFish, respx_mock: MockRouter):
|
|
|
88
88
|
),
|
|
89
89
|
({"location": "United States"}, "location", "United States"),
|
|
90
90
|
({"language": "en"}, "language", "en"),
|
|
91
|
+
({"include_domains": "github.com,arxiv.org"}, "include_domains", "github.com,arxiv.org"),
|
|
92
|
+
({"exclude_domains": "pinterest.com"}, "exclude_domains", "pinterest.com"),
|
|
91
93
|
({"after_date": "2026-06-01"}, "after_date", "2026-06-01"),
|
|
92
94
|
({"before_date": "2026-06-18"}, "before_date", "2026-06-18"),
|
|
93
95
|
({"recency_minutes": 60}, "recency_minutes", "60"),
|
|
@@ -195,6 +197,17 @@ def test_query_rejects_non_integer_page(bad_page: Any, client: TinyFish):
|
|
|
195
197
|
{"after_date": "2026-06-18", "before_date": "2026-06-01"},
|
|
196
198
|
"after_date must be on or before before_date",
|
|
197
199
|
),
|
|
200
|
+
({"pub_year_min": True}, "pub_year_min must be an integer"),
|
|
201
|
+
({"pub_year_min": 1.5}, "pub_year_min must be an integer"),
|
|
202
|
+
({"pub_year_min": -1}, "pub_year_min must be between 0 and 9999"),
|
|
203
|
+
({"pub_year_max": True}, "pub_year_max must be an integer"),
|
|
204
|
+
({"pub_year_max": 1.5}, "pub_year_max must be an integer"),
|
|
205
|
+
({"pub_year_max": -1}, "pub_year_max must be between 0 and 9999"),
|
|
206
|
+
({"pub_year_max": 10_000}, "pub_year_max must be between 0 and 9999"),
|
|
207
|
+
(
|
|
208
|
+
{"pub_year_min": 2022, "pub_year_max": 2019},
|
|
209
|
+
"pub_year_min must be less than or equal to pub_year_max",
|
|
210
|
+
),
|
|
198
211
|
],
|
|
199
212
|
)
|
|
200
213
|
def test_query_rejects_invalid_search_filters(
|
|
@@ -238,6 +251,48 @@ def test_query_rejects_invalid_domain_type(client: TinyFish):
|
|
|
238
251
|
client.search.query("test", domain_type="video")
|
|
239
252
|
|
|
240
253
|
|
|
254
|
+
@pytest.mark.parametrize(
|
|
255
|
+
("pub_year_min", "pub_year_max", "expected_min", "expected_max"),
|
|
256
|
+
[
|
|
257
|
+
(2019, 2022, "2019", "2022"),
|
|
258
|
+
(500, 999, "0500", "0999"),
|
|
259
|
+
(0, 0, "0000", "0000"),
|
|
260
|
+
],
|
|
261
|
+
)
|
|
262
|
+
@pytest.mark.respx(base_url=BASE_URL)
|
|
263
|
+
def test_query_forwards_pub_year_zero_padded(
|
|
264
|
+
pub_year_min: int,
|
|
265
|
+
pub_year_max: int,
|
|
266
|
+
expected_min: str,
|
|
267
|
+
expected_max: str,
|
|
268
|
+
client: TinyFish,
|
|
269
|
+
respx_mock: MockRouter,
|
|
270
|
+
):
|
|
271
|
+
route = respx_mock.get(_SEARCH_PATH).mock(return_value=httpx.Response(200, json=_search_response()))
|
|
272
|
+
client.search.query("test", domain_type="research_paper", pub_year_min=pub_year_min, pub_year_max=pub_year_max)
|
|
273
|
+
params = route.calls[0].request.url.params
|
|
274
|
+
assert params["pub_year_min"] == expected_min
|
|
275
|
+
assert params["pub_year_max"] == expected_max
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@pytest.mark.respx(base_url=BASE_URL)
|
|
279
|
+
def test_query_forwards_pub_year_min_only(client: TinyFish, respx_mock: MockRouter):
|
|
280
|
+
route = respx_mock.get(_SEARCH_PATH).mock(return_value=httpx.Response(200, json=_search_response()))
|
|
281
|
+
client.search.query("test", domain_type="research_paper", pub_year_min=2019)
|
|
282
|
+
params = route.calls[0].request.url.params
|
|
283
|
+
assert params["pub_year_min"] == "2019"
|
|
284
|
+
assert "pub_year_max" not in params
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
@pytest.mark.respx(base_url=BASE_URL)
|
|
288
|
+
def test_query_forwards_pub_year_max_only(client: TinyFish, respx_mock: MockRouter):
|
|
289
|
+
route = respx_mock.get(_SEARCH_PATH).mock(return_value=httpx.Response(200, json=_search_response()))
|
|
290
|
+
client.search.query("test", domain_type="research_paper", pub_year_max=2022)
|
|
291
|
+
params = route.calls[0].request.url.params
|
|
292
|
+
assert "pub_year_min" not in params
|
|
293
|
+
assert params["pub_year_max"] == "2022"
|
|
294
|
+
|
|
295
|
+
|
|
241
296
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
242
297
|
# search.query() — async (mirrors sync tests above)
|
|
243
298
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -275,6 +330,8 @@ async def test_async_query_parses_result_fields(async_client: AsyncTinyFish, res
|
|
|
275
330
|
),
|
|
276
331
|
({"location": "United States"}, "location", "United States"),
|
|
277
332
|
({"language": "en"}, "language", "en"),
|
|
333
|
+
({"include_domains": "github.com,arxiv.org"}, "include_domains", "github.com,arxiv.org"),
|
|
334
|
+
({"exclude_domains": "pinterest.com"}, "exclude_domains", "pinterest.com"),
|
|
278
335
|
({"after_date": "2026-06-01"}, "after_date", "2026-06-01"),
|
|
279
336
|
({"before_date": "2026-06-18"}, "before_date", "2026-06-18"),
|
|
280
337
|
({"recency_minutes": 60}, "recency_minutes", "60"),
|
|
@@ -371,6 +428,17 @@ async def test_async_query_rejects_non_integer_page(
|
|
|
371
428
|
{"after_date": "2026-06-18", "before_date": "2026-06-01"},
|
|
372
429
|
"after_date must be on or before before_date",
|
|
373
430
|
),
|
|
431
|
+
({"pub_year_min": True}, "pub_year_min must be an integer"),
|
|
432
|
+
({"pub_year_min": 1.5}, "pub_year_min must be an integer"),
|
|
433
|
+
({"pub_year_min": -1}, "pub_year_min must be between 0 and 9999"),
|
|
434
|
+
({"pub_year_max": True}, "pub_year_max must be an integer"),
|
|
435
|
+
({"pub_year_max": 1.5}, "pub_year_max must be an integer"),
|
|
436
|
+
({"pub_year_max": -1}, "pub_year_max must be between 0 and 9999"),
|
|
437
|
+
({"pub_year_max": 10_000}, "pub_year_max must be between 0 and 9999"),
|
|
438
|
+
(
|
|
439
|
+
{"pub_year_min": 2022, "pub_year_max": 2019},
|
|
440
|
+
"pub_year_min must be less than or equal to pub_year_max",
|
|
441
|
+
),
|
|
374
442
|
],
|
|
375
443
|
)
|
|
376
444
|
async def test_async_query_rejects_invalid_search_filters(
|
|
@@ -407,6 +475,54 @@ async def test_async_query_rejects_invalid_domain_type(async_client: AsyncTinyFi
|
|
|
407
475
|
await _do_query(async_client, "test", domain_type="video")
|
|
408
476
|
|
|
409
477
|
|
|
478
|
+
@pytest.mark.parametrize(
|
|
479
|
+
("pub_year_min", "pub_year_max", "expected_min", "expected_max"),
|
|
480
|
+
[
|
|
481
|
+
(2019, 2022, "2019", "2022"),
|
|
482
|
+
(500, 999, "0500", "0999"),
|
|
483
|
+
(0, 0, "0000", "0000"),
|
|
484
|
+
],
|
|
485
|
+
)
|
|
486
|
+
@pytest.mark.respx(base_url=BASE_URL)
|
|
487
|
+
async def test_async_query_forwards_pub_year_zero_padded(
|
|
488
|
+
pub_year_min: int,
|
|
489
|
+
pub_year_max: int,
|
|
490
|
+
expected_min: str,
|
|
491
|
+
expected_max: str,
|
|
492
|
+
async_client: AsyncTinyFish,
|
|
493
|
+
respx_mock: MockRouter,
|
|
494
|
+
):
|
|
495
|
+
route = respx_mock.get(_SEARCH_PATH).mock(return_value=httpx.Response(200, json=_search_response()))
|
|
496
|
+
await _do_query(
|
|
497
|
+
async_client,
|
|
498
|
+
"test",
|
|
499
|
+
domain_type="research_paper",
|
|
500
|
+
pub_year_min=pub_year_min,
|
|
501
|
+
pub_year_max=pub_year_max,
|
|
502
|
+
)
|
|
503
|
+
params = route.calls[0].request.url.params
|
|
504
|
+
assert params["pub_year_min"] == expected_min
|
|
505
|
+
assert params["pub_year_max"] == expected_max
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
@pytest.mark.respx(base_url=BASE_URL)
|
|
509
|
+
async def test_async_query_forwards_pub_year_min_only(async_client: AsyncTinyFish, respx_mock: MockRouter):
|
|
510
|
+
route = respx_mock.get(_SEARCH_PATH).mock(return_value=httpx.Response(200, json=_search_response()))
|
|
511
|
+
await _do_query(async_client, "test", domain_type="research_paper", pub_year_min=2019)
|
|
512
|
+
params = route.calls[0].request.url.params
|
|
513
|
+
assert params["pub_year_min"] == "2019"
|
|
514
|
+
assert "pub_year_max" not in params
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
@pytest.mark.respx(base_url=BASE_URL)
|
|
518
|
+
async def test_async_query_forwards_pub_year_max_only(async_client: AsyncTinyFish, respx_mock: MockRouter):
|
|
519
|
+
route = respx_mock.get(_SEARCH_PATH).mock(return_value=httpx.Response(200, json=_search_response()))
|
|
520
|
+
await _do_query(async_client, "test", domain_type="research_paper", pub_year_max=2022)
|
|
521
|
+
params = route.calls[0].request.url.params
|
|
522
|
+
assert "pub_year_min" not in params
|
|
523
|
+
assert params["pub_year_max"] == "2022"
|
|
524
|
+
|
|
525
|
+
|
|
410
526
|
@pytest.mark.respx(base_url=BASE_URL)
|
|
411
527
|
async def test_async_query_401(async_client: AsyncTinyFish, respx_mock: MockRouter):
|
|
412
528
|
respx_mock.get(_SEARCH_PATH).mock(return_value=httpx.Response(401, json={"error": {"message": "unauthorized"}}))
|
tinyfish-0.3.0/CHANGELOG.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [0.3.0](https://github.com/tinyfish-io/ux-labs/compare/sdk-py/v0.2.6...sdk-py/v0.3.0) (2026-07-22)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
### Features
|
|
7
|
-
|
|
8
|
-
* **ci:** automate SDK/CLI releases via release-please ([#3632](https://github.com/tinyfish-io/ux-labs/issues/3632)) ([1b311ea](https://github.com/tinyfish-io/ux-labs/commit/1b311ea6d6277fad21b57baf0b7cfdc6619a3b93))
|
|
9
|
-
* **sdk:** add domain_type to search.query() in TypeScript and Python SDKs ([#3432](https://github.com/tinyfish-io/ux-labs/issues/3432)) ([1c2954c](https://github.com/tinyfish-io/ux-labs/commit/1c2954cb192324cdca1ce206515de72df2cd231d))
|
|
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
|
|
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
|