hydrafetch 0.2.0__tar.gz → 0.3.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.
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/PKG-INFO +3 -2
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/README.md +2 -1
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/pyproject.toml +7 -1
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/src/hydrafetch/_client.py +12 -4
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/tests/test_client.py +12 -2
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/uv.lock +1 -1
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/.github/workflows/ci.yml +0 -0
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/.github/workflows/publish.yml +0 -0
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/.gitignore +0 -0
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/LICENSE +0 -0
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/src/hydrafetch/__init__.py +0 -0
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/src/hydrafetch/_schema.py +0 -0
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/src/hydrafetch/errors.py +0 -0
- {hydrafetch-0.2.0 → hydrafetch-0.3.0}/src/hydrafetch/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hydrafetch
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Official Python client for the Hydrafetch web data API. Turn any URL into clean Markdown and structured data.
|
|
5
5
|
Project-URL: Homepage, https://hydrafetch.com
|
|
6
6
|
Project-URL: Documentation, https://docs.hydrafetch.com
|
|
@@ -171,6 +171,7 @@ for r in res["results"]:
|
|
|
171
171
|
hf.brand("stripe.com") # logos, colours, fonts, socials
|
|
172
172
|
hf.logo("stripe.com", theme="dark", type="icon") # one asset
|
|
173
173
|
hf.styleguide("stripe.com") # computed design system
|
|
174
|
+
hf.styleguide("https://stripe.com/pricing", maxAge=0) # one page, read fresh
|
|
174
175
|
```
|
|
175
176
|
|
|
176
177
|
For logos in a browser use [`@hydrafetch/client-sdk`](https://github.com/Hydrafetch/client-sdk) with a publishable key. Those bill against logo pulls rather than credits.
|
|
@@ -254,7 +255,7 @@ hf = Hydrafetch(
|
|
|
254
255
|
| `extract(urls, **options)` | dict with `"results"` | 5 per URL |
|
|
255
256
|
| `brand(domain)` | brand dict | 5 |
|
|
256
257
|
| `logo(domain, **options)` | logo dict | 1 |
|
|
257
|
-
| `styleguide(
|
|
258
|
+
| `styleguide(domain_or_url, **options)` | design system dict | 10 |
|
|
258
259
|
| `screenshot(url, **options)` | screenshot dict | 5 |
|
|
259
260
|
| `images(url)`, `links(url)` | page assets | 1 |
|
|
260
261
|
| `crawl(url, **options)` | job dict, polled to completion | 1 per page |
|
|
@@ -148,6 +148,7 @@ for r in res["results"]:
|
|
|
148
148
|
hf.brand("stripe.com") # logos, colours, fonts, socials
|
|
149
149
|
hf.logo("stripe.com", theme="dark", type="icon") # one asset
|
|
150
150
|
hf.styleguide("stripe.com") # computed design system
|
|
151
|
+
hf.styleguide("https://stripe.com/pricing", maxAge=0) # one page, read fresh
|
|
151
152
|
```
|
|
152
153
|
|
|
153
154
|
For logos in a browser use [`@hydrafetch/client-sdk`](https://github.com/Hydrafetch/client-sdk) with a publishable key. Those bill against logo pulls rather than credits.
|
|
@@ -231,7 +232,7 @@ hf = Hydrafetch(
|
|
|
231
232
|
| `extract(urls, **options)` | dict with `"results"` | 5 per URL |
|
|
232
233
|
| `brand(domain)` | brand dict | 5 |
|
|
233
234
|
| `logo(domain, **options)` | logo dict | 1 |
|
|
234
|
-
| `styleguide(
|
|
235
|
+
| `styleguide(domain_or_url, **options)` | design system dict | 10 |
|
|
235
236
|
| `screenshot(url, **options)` | screenshot dict | 5 |
|
|
236
237
|
| `images(url)`, `links(url)` | page assets | 1 |
|
|
237
238
|
| `crawl(url, **options)` | job dict, polled to completion | 1 per page |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hydrafetch"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Official Python client for the Hydrafetch web data API. Turn any URL into clean Markdown and structured data."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -46,3 +46,9 @@ target-version = "py39"
|
|
|
46
46
|
# PYI019 wants typing.Self on the context managers. Self landed in 3.11 and this
|
|
47
47
|
# package supports 3.9, so the bound TypeVars stay until the floor moves.
|
|
48
48
|
ignore = ["PYI019"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint.pyupgrade]
|
|
51
|
+
# `from __future__ import annotations` normally makes `X | None` safe on 3.9, which is why ruff
|
|
52
|
+
# offers to rewrite Optional. Pydantic evaluates annotations at runtime, so on 3.9 the rewrite
|
|
53
|
+
# turns a working model into a TypeError at import. Only the 3.9 CI leg catches it.
|
|
54
|
+
keep-runtime-typing = true
|
|
@@ -92,6 +92,10 @@ class _Base:
|
|
|
92
92
|
def _scrape_body(self, url: str, options: Mapping[str, Any]) -> dict[str, Any]:
|
|
93
93
|
return {"url": url, **_drop_none(options)}
|
|
94
94
|
|
|
95
|
+
def _styleguide_params(self, target: str, options: Mapping[str, Any]) -> dict[str, Any]:
|
|
96
|
+
key = "url" if target.lower().startswith(("http://", "https://")) else "domain"
|
|
97
|
+
return {key: target, **_drop_none(options)}
|
|
98
|
+
|
|
95
99
|
def _extract_body(
|
|
96
100
|
self, urls: str | Iterable[str], options: Mapping[str, Any]
|
|
97
101
|
) -> dict[str, Any]:
|
|
@@ -173,8 +177,10 @@ class Hydrafetch(_Base):
|
|
|
173
177
|
def logo(self, domain: str, **options: Any) -> dict[str, Any]:
|
|
174
178
|
return self._request("GET", "/v1/web/brand/logo", params={"domain": domain, **options})
|
|
175
179
|
|
|
176
|
-
def styleguide(self,
|
|
177
|
-
return self._request(
|
|
180
|
+
def styleguide(self, domain_or_url: str, **options: Any) -> dict[str, Any]:
|
|
181
|
+
return self._request(
|
|
182
|
+
"GET", "/v1/web/styleguide", params=self._styleguide_params(domain_or_url, options)
|
|
183
|
+
)
|
|
178
184
|
|
|
179
185
|
def screenshot(self, url: str, **options: Any) -> dict[str, Any]:
|
|
180
186
|
return self._request("POST", "/v1/web/screenshot", json=self._scrape_body(url, options))
|
|
@@ -322,8 +328,10 @@ class AsyncHydrafetch(_Base):
|
|
|
322
328
|
"GET", "/v1/web/brand/logo", params={"domain": domain, **options}
|
|
323
329
|
)
|
|
324
330
|
|
|
325
|
-
async def styleguide(self,
|
|
326
|
-
return await self._request(
|
|
331
|
+
async def styleguide(self, domain_or_url: str, **options: Any) -> dict[str, Any]:
|
|
332
|
+
return await self._request(
|
|
333
|
+
"GET", "/v1/web/styleguide", params=self._styleguide_params(domain_or_url, options)
|
|
334
|
+
)
|
|
327
335
|
|
|
328
336
|
async def screenshot(self, url: str, **options: Any) -> dict[str, Any]:
|
|
329
337
|
return await self._request(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Optional
|
|
5
5
|
|
|
6
6
|
import httpx
|
|
7
7
|
import pytest
|
|
@@ -102,6 +102,16 @@ class TestRequestShaping:
|
|
|
102
102
|
assert rec.last.url.params["theme"] == "dark"
|
|
103
103
|
assert not rec.last.content
|
|
104
104
|
|
|
105
|
+
def test_styleguide_reads_a_domain_or_one_page(self) -> None:
|
|
106
|
+
rec = Recorder({"success": True, "data": {}})
|
|
107
|
+
hf = make_client(rec)
|
|
108
|
+
hf.styleguide("stripe.com")
|
|
109
|
+
assert rec.last.url.params["domain"] == "stripe.com"
|
|
110
|
+
hf.styleguide("https://stripe.com/pricing", maxAge=0)
|
|
111
|
+
assert rec.last.url.params["url"] == "https://stripe.com/pricing"
|
|
112
|
+
assert rec.last.url.params["maxAge"] == "0"
|
|
113
|
+
assert "domain" not in rec.last.url.params
|
|
114
|
+
|
|
105
115
|
|
|
106
116
|
class TestErrors:
|
|
107
117
|
def test_surfaces_code_status_and_request_id(self) -> None:
|
|
@@ -238,7 +248,7 @@ def test_extract_still_takes_plain_json_schema():
|
|
|
238
248
|
|
|
239
249
|
|
|
240
250
|
class Node(BaseModel):
|
|
241
|
-
child: Node
|
|
251
|
+
child: Optional[Node] = None
|
|
242
252
|
|
|
243
253
|
|
|
244
254
|
def test_extract_rejects_a_recursive_model_rather_than_sending_a_ref():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|