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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hydrafetch
3
- Version: 0.2.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(domain)` | design system dict | 10 |
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(domain)` | design system dict | 10 |
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.2.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, domain: str) -> dict[str, Any]:
177
- return self._request("GET", "/v1/web/styleguide", params={"domain": domain})
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, domain: str) -> dict[str, Any]:
326
- return await self._request("GET", "/v1/web/styleguide", params={"domain": domain})
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 | None = None
251
+ child: Optional[Node] = None
242
252
 
243
253
 
244
254
  def test_extract_rejects_a_recursive_model_rather_than_sending_a_ref():
@@ -143,7 +143,7 @@ wheels = [
143
143
 
144
144
  [[package]]
145
145
  name = "hydrafetch"
146
- version = "0.2.0"
146
+ version = "0.3.0"
147
147
  source = { editable = "." }
148
148
  dependencies = [
149
149
  { name = "httpx" },
File without changes
File without changes