wbapi-async 0.7.2__tar.gz → 0.7.4__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.4
2
2
  Name: wbapi-async
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: Asynchronous client for Wildberries API
5
5
  Project-URL: Documentation, https://serdukow.github.io/wbapi-async/
6
6
  Project-URL: Repository, https://github.com/serdukow/wbapi-async
@@ -42,7 +42,7 @@ Requires-Dist: python-dotenv<2.0.0,>=1.2.1; extra == 'test'
42
42
  Description-Content-Type: text/markdown
43
43
 
44
44
  <p align="center">
45
- <a href="https://dev.wildberries.ru/"><img src="docs/assets/logo.svg" alt="WbAPI" width="200"></a>
45
+ <a href="https://dev.wildberries.ru/"><img src="https://dev.wildberries.ru/images/open-graph.png" alt="WbAPI" width="600"></a>
46
46
  </p>
47
47
 
48
48
  <div align="center">
@@ -62,9 +62,9 @@ Just pass the path from the docs and get data back.
62
62
  ## Features
63
63
 
64
64
  - **Zero boilerplate** — WB API changes constantly; typed models break on every schema update. Instead, responses are plain attribute-accessible dicts — `result.fieldName` just works, no models to maintain
65
- - **Auto-pagination** — `get_all()` fetches all page. Auto-detect for all known strategies
65
+ - **Auto-pagination** — `get_all()` fetches all pages. Auto-detects all known strategies; you can easily add your own via a custom paginator — [see docs](https://serdukow.github.io/wbapi-async/advanced/pagination/)
66
66
  - **Rate limiting** — per-endpoint limits from the spec, powered by `aiolimiter`
67
- - **Auto-retry** — automatic retry on HTTP 429 with `X-Ratelimit-Retry` backoff
67
+ - **Auto-retry** — automatic retry on HTTP 429
68
68
  - **Always up to date** — path registry is [auto-generated](https://github.com/serdukow/wbapi-codegen) from WB OpenAPI specs daily
69
69
  - **Fully async** — built on `httpx` + `asyncio`
70
70
 
@@ -83,12 +83,6 @@ async with WbAPI(token="...") as api:
83
83
 
84
84
  supplies = await api.get_all("/api/v3/supplies")
85
85
  print(f"supplies: {supplies!r}")
86
-
87
- result = await api.post("/adv/v0/rename", body={"advertId": 2233344, "name": "newname"})
88
- print(f"rename: {result!r}")
89
-
90
- await api.put("/api/v3/stocks/507", body={"stocks": [{"sku": "WB007", "amount": 10}]})
91
- await api.delete("/content/v2/tag/99")
92
86
  ```
93
87
 
94
88
  Just copy the path straight from the [WB API](https://dev.wildberries.ru) — the correct base URL and subdomain are resolved automatically.
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <a href="https://dev.wildberries.ru/"><img src="docs/assets/logo.svg" alt="WbAPI" width="200"></a>
2
+ <a href="https://dev.wildberries.ru/"><img src="https://dev.wildberries.ru/images/open-graph.png" alt="WbAPI" width="600"></a>
3
3
  </p>
4
4
 
5
5
  <div align="center">
@@ -19,9 +19,9 @@ Just pass the path from the docs and get data back.
19
19
  ## Features
20
20
 
21
21
  - **Zero boilerplate** — WB API changes constantly; typed models break on every schema update. Instead, responses are plain attribute-accessible dicts — `result.fieldName` just works, no models to maintain
22
- - **Auto-pagination** — `get_all()` fetches all page. Auto-detect for all known strategies
22
+ - **Auto-pagination** — `get_all()` fetches all pages. Auto-detects all known strategies; you can easily add your own via a custom paginator — [see docs](https://serdukow.github.io/wbapi-async/advanced/pagination/)
23
23
  - **Rate limiting** — per-endpoint limits from the spec, powered by `aiolimiter`
24
- - **Auto-retry** — automatic retry on HTTP 429 with `X-Ratelimit-Retry` backoff
24
+ - **Auto-retry** — automatic retry on HTTP 429
25
25
  - **Always up to date** — path registry is [auto-generated](https://github.com/serdukow/wbapi-codegen) from WB OpenAPI specs daily
26
26
  - **Fully async** — built on `httpx` + `asyncio`
27
27
 
@@ -40,12 +40,6 @@ async with WbAPI(token="...") as api:
40
40
 
41
41
  supplies = await api.get_all("/api/v3/supplies")
42
42
  print(f"supplies: {supplies!r}")
43
-
44
- result = await api.post("/adv/v0/rename", body={"advertId": 2233344, "name": "newname"})
45
- print(f"rename: {result!r}")
46
-
47
- await api.put("/api/v3/stocks/507", body={"stocks": [{"sku": "WB007", "amount": 10}]})
48
- await api.delete("/content/v2/tag/99")
49
43
  ```
50
44
 
51
45
  Just copy the path straight from the [WB API](https://dev.wildberries.ru) — the correct base URL and subdomain are resolved automatically.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wbapi-async"
7
- version = "0.7.2"
7
+ version = "0.7.4"
8
8
  description = "Asynchronous client for Wildberries API"
9
9
  authors = [
10
10
  { name = "Andrei Serdiukov", email = "asyncdf@gmail.com" },
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ from datetime import datetime, timedelta
2
3
  import logging
3
4
  from typing import Any
4
5
 
@@ -10,6 +11,7 @@ from ...exceptions import WbAPIError
10
11
  from .headers import Headers
11
12
 
12
13
 
14
+ log = logging.getLogger("wbapi.session")
13
15
  logging.getLogger("httpx").setLevel(logging.WARNING)
14
16
  logging.getLogger("httpcore").setLevel(logging.WARNING)
15
17
 
@@ -57,9 +59,13 @@ class BaseSession:
57
59
 
58
60
  if response.status_code == 429:
59
61
  retry_after = int(response.headers.get("X-Ratelimit-Retry", "1"))
60
- log = logging.getLogger("wbapi.session")
61
62
  if retry_after > 60:
62
- log.warning("Rate limit exceeded. Retrying in %s seconds", retry_after)
63
+ retry_at = datetime.now() + timedelta(seconds=retry_after)
64
+ log.warning(
65
+ "Rate limit exceeded. Retrying in %s seconds (at %s)",
66
+ retry_after,
67
+ retry_at,
68
+ )
63
69
  await asyncio.sleep(retry_after)
64
70
  return await self._request(method, url, params=params, json=json, limit=limit)
65
71
 
@@ -543,9 +543,16 @@ class MethodDispatcher:
543
543
  *,
544
544
  params: dict[str, Any] | None = None,
545
545
  json: Any | None = None,
546
- unofficial: bool = False,
546
+ no_auth: bool = False,
547
547
  ) -> Any:
548
- if not unofficial:
548
+ from urllib.parse import urlparse
549
+
550
+ if not no_auth and path.startswith(("https://", "http://")):
551
+ no_auth = urlparse(path).netloc in _EXTRA_ALLOWED_HOSTS
552
+
553
+ if no_auth:
554
+ self._session.headers.authorization = None
555
+ else:
549
556
  self._session.headers.set_token(self._token)
550
557
  url = resolve_url(path)
551
558
  limiter = _get_limiter(path)
File without changes
File without changes