repsapi 0.1.0__py3-none-any.whl
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.
- repsapi/__init__.py +39 -0
- repsapi/_client.py +769 -0
- repsapi/_errors.py +117 -0
- repsapi/_version.py +1 -0
- repsapi/py.typed +0 -0
- repsapi/types.py +509 -0
- repsapi-0.1.0.dist-info/METADATA +162 -0
- repsapi-0.1.0.dist-info/RECORD +10 -0
- repsapi-0.1.0.dist-info/WHEEL +4 -0
- repsapi-0.1.0.dist-info/licenses/LICENSE +21 -0
repsapi/_errors.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"RepsApiError",
|
|
8
|
+
"APIError",
|
|
9
|
+
"BadRequestError",
|
|
10
|
+
"AuthenticationError",
|
|
11
|
+
"PermissionDeniedError",
|
|
12
|
+
"NotFoundError",
|
|
13
|
+
"UnprocessableEntityError",
|
|
14
|
+
"RateLimitError",
|
|
15
|
+
"InternalServerError",
|
|
16
|
+
"APIConnectionError",
|
|
17
|
+
"APITimeoutError",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class RepsApiError(Exception):
|
|
22
|
+
"""Base class of every error this client raises."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, message: str) -> None:
|
|
25
|
+
super().__init__(message)
|
|
26
|
+
self.message = message
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class APIError(RepsApiError):
|
|
30
|
+
"""The API answered with an error status."""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
status: int,
|
|
35
|
+
type: str,
|
|
36
|
+
message: str,
|
|
37
|
+
details: Optional[Dict[str, Any]] = None,
|
|
38
|
+
body: Any = None,
|
|
39
|
+
) -> None:
|
|
40
|
+
super().__init__(message)
|
|
41
|
+
#: HTTP status
|
|
42
|
+
self.status = status
|
|
43
|
+
#: the API's error type, e.g. "bad_request", "unauthorized", "rate_limited"
|
|
44
|
+
self.type = type
|
|
45
|
+
#: extra fields of the error, e.g. ``allowed``, ``fields``, ``reset_at``
|
|
46
|
+
self.details: Dict[str, Any] = details or {}
|
|
47
|
+
#: the parsed response body (or the raw text when it isn't JSON)
|
|
48
|
+
self.body = body
|
|
49
|
+
|
|
50
|
+
def __repr__(self) -> str:
|
|
51
|
+
return f"{self.__class__.__name__}(status={self.status}, type={self.type!r}, message={self.message!r})"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class BadRequestError(APIError):
|
|
55
|
+
"""400, 413, 415 and other 4xx: the request itself is wrong."""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class AuthenticationError(APIError):
|
|
59
|
+
"""401: missing, malformed, invalid or revoked API key."""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class PermissionDeniedError(APIError):
|
|
63
|
+
"""403: the key lacks this API's scope, or the IP isn't whitelisted."""
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class NotFoundError(APIError):
|
|
67
|
+
"""404"""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class UnprocessableEntityError(APIError):
|
|
71
|
+
"""422: no platform and product id could be read from the link."""
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class RateLimitError(APIError):
|
|
75
|
+
"""429: per-minute rate limit or daily quota."""
|
|
76
|
+
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
status: int,
|
|
80
|
+
type: str,
|
|
81
|
+
message: str,
|
|
82
|
+
details: Optional[Dict[str, Any]] = None,
|
|
83
|
+
body: Any = None,
|
|
84
|
+
retry_after: Optional[float] = None,
|
|
85
|
+
) -> None:
|
|
86
|
+
super().__init__(status, type, message, details, body)
|
|
87
|
+
d = self.details
|
|
88
|
+
#: seconds to wait, from Retry-After
|
|
89
|
+
self.retry_after = retry_after
|
|
90
|
+
#: when the exhausted limit resets
|
|
91
|
+
self.reset_at: Optional[datetime] = _parse_time(d.get("reset_at"))
|
|
92
|
+
#: "org" = the workspace quota, "key" = the project's own daily cap
|
|
93
|
+
self.scope: Optional[str] = d.get("scope") if isinstance(d.get("scope"), str) else None
|
|
94
|
+
self.limit: Optional[int] = d.get("limit") if isinstance(d.get("limit"), int) else None
|
|
95
|
+
self.used: Optional[int] = d.get("used") if isinstance(d.get("used"), int) else None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class InternalServerError(APIError):
|
|
99
|
+
"""5xx: something failed on our side (already retried)."""
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class APIConnectionError(RepsApiError):
|
|
103
|
+
"""The request never got an answer (DNS, TLS, connection reset ...)."""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class APITimeoutError(APIConnectionError):
|
|
107
|
+
"""No answer within the timeout."""
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _parse_time(value: Any) -> Optional[datetime]:
|
|
111
|
+
if not isinstance(value, str):
|
|
112
|
+
return None
|
|
113
|
+
try:
|
|
114
|
+
# fromisoformat before 3.11 doesn't take a trailing "Z"
|
|
115
|
+
return datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
116
|
+
except ValueError:
|
|
117
|
+
return None
|
repsapi/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
repsapi/py.typed
ADDED
|
File without changes
|
repsapi/types.py
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
"""Response types of the RepsApi.pl API.
|
|
2
|
+
|
|
3
|
+
Every method returns the API's JSON as plain dicts; these TypedDicts only
|
|
4
|
+
describe them for editors and type checkers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Dict, List, Literal, Optional, TypedDict
|
|
10
|
+
|
|
11
|
+
Platform = Literal["weidian", "taobao", "1688", "tmall"]
|
|
12
|
+
|
|
13
|
+
Agent = Literal[
|
|
14
|
+
"kakobuy", "cnfans", "acbuy", "mulebuy", "hoobuy", "oopbuy", "cnshopper", "ootdbuy",
|
|
15
|
+
"ponybuy", "superbuy", "sugargoo", "loongbuy", "cssbuy", "usfans", "litbuy",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
TrackingStage = Literal[
|
|
19
|
+
"info_received", "received", "in_transit", "export_customs", "awaiting_flight",
|
|
20
|
+
"flight_departed", "flight_arrived", "import_customs", "last_mile", "out_for_delivery",
|
|
21
|
+
"ready_for_pickup", "delivered", "delayed", "exception", "returned",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
ServiceName = Literal["api", "tracking", "qc", "lookup", "convert"]
|
|
25
|
+
ServiceStatus = Literal["operational", "degraded", "down"]
|
|
26
|
+
ChangeTag = Literal["new", "improved", "fixed", "removed"]
|
|
27
|
+
|
|
28
|
+
# "from" is a keyword, hence the functional syntax
|
|
29
|
+
Exchange = TypedDict(
|
|
30
|
+
"Exchange",
|
|
31
|
+
{"from": str, "to": str, "rate": float, "date": str, "source": Literal["NBP", "ECB"]},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Dimensions(TypedDict):
|
|
36
|
+
length: float
|
|
37
|
+
width: float
|
|
38
|
+
height: float
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Country(TypedDict):
|
|
42
|
+
code: str
|
|
43
|
+
name: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ------------------------------- tracking -------------------------------
|
|
47
|
+
|
|
48
|
+
class TrackingUpdate(TypedDict):
|
|
49
|
+
date: str
|
|
50
|
+
hour: str
|
|
51
|
+
status: str
|
|
52
|
+
status_en: str
|
|
53
|
+
status_original: str
|
|
54
|
+
stage: TrackingStage
|
|
55
|
+
location: str
|
|
56
|
+
country: Optional[str]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
EstimatedDelivery = TypedDict(
|
|
60
|
+
"EstimatedDelivery",
|
|
61
|
+
{"from": str, "to": str, "based_on": int, "from_stage": TrackingStage, "slower_than_usual": bool},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TrackingSummary(TypedDict):
|
|
66
|
+
stage: TrackingStage
|
|
67
|
+
status: str
|
|
68
|
+
status_en: str
|
|
69
|
+
delivered: bool
|
|
70
|
+
last_update: str
|
|
71
|
+
origin_country: Optional[str]
|
|
72
|
+
destination_country: Optional[str]
|
|
73
|
+
carrier: Optional[str]
|
|
74
|
+
carrier_tracking_number: Optional[str]
|
|
75
|
+
estimated_delivery: Optional[EstimatedDelivery]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class TrackingResponse(TypedDict):
|
|
79
|
+
tracking_number: str
|
|
80
|
+
count: int
|
|
81
|
+
summary: Optional[TrackingSummary]
|
|
82
|
+
updates: List[TrackingUpdate]
|
|
83
|
+
source: str
|
|
84
|
+
attribution: str
|
|
85
|
+
docs: str
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# ---------------------------------- QC ----------------------------------
|
|
89
|
+
|
|
90
|
+
class _QcBatchBase(TypedDict):
|
|
91
|
+
date: Optional[str]
|
|
92
|
+
photos: List[str]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class QcBatch(_QcBatchBase, total=False):
|
|
96
|
+
sku: str
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class _QcResponseBase(TypedDict):
|
|
100
|
+
platform: Platform
|
|
101
|
+
product_id: str
|
|
102
|
+
canonical: Optional[str]
|
|
103
|
+
provider: Optional[str]
|
|
104
|
+
total_photos: int
|
|
105
|
+
batch_count: int
|
|
106
|
+
batches: List[QcBatch]
|
|
107
|
+
listing_photos: List[str]
|
|
108
|
+
source: str
|
|
109
|
+
docs: str
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class QcResponse(_QcResponseBase, total=False):
|
|
113
|
+
note: str
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# -------------------------------- lookup --------------------------------
|
|
117
|
+
|
|
118
|
+
class PriceRange(TypedDict):
|
|
119
|
+
low: Optional[float]
|
|
120
|
+
high: Optional[float]
|
|
121
|
+
discount_low: Optional[float]
|
|
122
|
+
discount_high: Optional[float]
|
|
123
|
+
currency: str
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class _VariantOptionBase(TypedDict):
|
|
127
|
+
name: str
|
|
128
|
+
values: List[str]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class VariantOption(_VariantOptionBase, total=False):
|
|
132
|
+
name_cn: str
|
|
133
|
+
values_en: List[str]
|
|
134
|
+
values_pl: List[str]
|
|
135
|
+
images: Dict[str, str]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class _VariantSkuBase(TypedDict):
|
|
139
|
+
attrs: Dict[str, str]
|
|
140
|
+
stock: Optional[int]
|
|
141
|
+
price: Optional[float]
|
|
142
|
+
image: Optional[str]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class VariantSku(_VariantSkuBase, total=False):
|
|
146
|
+
price_local: Optional[float]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class Variants(TypedDict):
|
|
150
|
+
options: List[VariantOption]
|
|
151
|
+
skus: List[VariantSku]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class Labeled(TypedDict):
|
|
155
|
+
label: str
|
|
156
|
+
value: str
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class WarehouseStats(TypedDict):
|
|
160
|
+
storage_time: Optional[Labeled]
|
|
161
|
+
turnover: Optional[Labeled]
|
|
162
|
+
weight_g: Optional[float]
|
|
163
|
+
volume_cm3: Optional[float]
|
|
164
|
+
dimensions_cm: Optional[str]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class WeightEstimate(TypedDict):
|
|
168
|
+
grams: int
|
|
169
|
+
category: str
|
|
170
|
+
source: Literal["similar_items", "typical"]
|
|
171
|
+
based_on: Optional[int]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class PricePoint(TypedDict):
|
|
175
|
+
date: str
|
|
176
|
+
low: Optional[float]
|
|
177
|
+
high: Optional[float]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class Seller(TypedDict):
|
|
181
|
+
id: Optional[str]
|
|
182
|
+
name: str
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class Availability(TypedDict):
|
|
186
|
+
in_stock: Optional[bool]
|
|
187
|
+
total_stock: Optional[int]
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class Money(TypedDict):
|
|
191
|
+
price: Optional[float]
|
|
192
|
+
currency: str
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class QcCount(TypedDict):
|
|
196
|
+
batches: int
|
|
197
|
+
photos: int
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class _LookupResponseBase(TypedDict):
|
|
201
|
+
platform: Platform
|
|
202
|
+
product_id: str
|
|
203
|
+
canonical: Optional[str]
|
|
204
|
+
source_agent: Optional[Agent]
|
|
205
|
+
title: Optional[str]
|
|
206
|
+
title_en: Optional[str]
|
|
207
|
+
title_pl: Optional[str]
|
|
208
|
+
main_image: Optional[str]
|
|
209
|
+
images: List[str]
|
|
210
|
+
price: Optional[PriceRange]
|
|
211
|
+
domestic_shipping: Optional[Money]
|
|
212
|
+
min_order: Optional[int]
|
|
213
|
+
seller: Optional[Seller]
|
|
214
|
+
availability: Availability
|
|
215
|
+
variant_source: Optional[Platform]
|
|
216
|
+
sizes: List[str]
|
|
217
|
+
versions: List[str]
|
|
218
|
+
variants: Variants
|
|
219
|
+
warehouse: Optional[WarehouseStats]
|
|
220
|
+
category: Optional[str]
|
|
221
|
+
weight_estimate: Optional[WeightEstimate]
|
|
222
|
+
qc: Optional[QcCount]
|
|
223
|
+
price_history: List[PricePoint]
|
|
224
|
+
source: str
|
|
225
|
+
docs: str
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class LookupResponse(_LookupResponseBase, total=False):
|
|
229
|
+
# only with currency=...
|
|
230
|
+
exchange: Optional[Exchange]
|
|
231
|
+
price_local: Optional[PriceRange]
|
|
232
|
+
domestic_shipping_local: Optional[Money]
|
|
233
|
+
note: str
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
# -------------------------------- convert -------------------------------
|
|
237
|
+
|
|
238
|
+
class ConvertResponse(TypedDict):
|
|
239
|
+
platform: Platform
|
|
240
|
+
id: str
|
|
241
|
+
canonical: str
|
|
242
|
+
agents: Dict[str, str]
|
|
243
|
+
source: str
|
|
244
|
+
docs: str
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# ------------------------------- shipping -------------------------------
|
|
248
|
+
|
|
249
|
+
class LineDays(TypedDict):
|
|
250
|
+
min: Optional[int]
|
|
251
|
+
max: Optional[int]
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class LineFees(TypedDict):
|
|
255
|
+
first: Optional[float]
|
|
256
|
+
additional: Optional[float]
|
|
257
|
+
service: Optional[float]
|
|
258
|
+
fuel: Optional[float]
|
|
259
|
+
handling: Optional[float]
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class WeightLimits(TypedDict):
|
|
263
|
+
min: Optional[int]
|
|
264
|
+
max: Optional[int]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class LineAccepts(TypedDict):
|
|
268
|
+
brands: bool
|
|
269
|
+
battery: bool
|
|
270
|
+
liquids: bool
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class _ShippingLineBase(TypedDict):
|
|
274
|
+
id: str
|
|
275
|
+
name: str
|
|
276
|
+
days: LineDays
|
|
277
|
+
price: float
|
|
278
|
+
currency: Literal["CNY"]
|
|
279
|
+
fees: LineFees
|
|
280
|
+
chargeable_weight_g: Optional[int]
|
|
281
|
+
volumetric_divisor: Optional[int]
|
|
282
|
+
weight_limits_g: WeightLimits
|
|
283
|
+
accepts: LineAccepts
|
|
284
|
+
restrictions: Optional[str]
|
|
285
|
+
features: Optional[str]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class ShippingLine(_ShippingLineBase, total=False):
|
|
289
|
+
price_local: Optional[float]
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class _HaulItemBase(TypedDict):
|
|
293
|
+
url: str
|
|
294
|
+
platform: Optional[str]
|
|
295
|
+
product_id: Optional[str]
|
|
296
|
+
title: Optional[str]
|
|
297
|
+
title_pl: Optional[str]
|
|
298
|
+
image: Optional[str]
|
|
299
|
+
seller: Optional[str]
|
|
300
|
+
quantity: int
|
|
301
|
+
unit_price: Optional[float]
|
|
302
|
+
domestic_shipping: Optional[float]
|
|
303
|
+
weight_g: Optional[float]
|
|
304
|
+
weight_source: Optional[Literal["measured", "estimate"]]
|
|
305
|
+
dimensions_cm: Optional[Dimensions]
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class HaulItem(_HaulItemBase, total=False):
|
|
309
|
+
unit_price_local: Optional[float]
|
|
310
|
+
error: Literal["unsupported_link", "not_found"]
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class ParcelInfo(TypedDict):
|
|
314
|
+
weight_g: int
|
|
315
|
+
dimensions_cm: Optional[Dimensions]
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
class _ShippingEstimateBase(TypedDict):
|
|
319
|
+
country: Country
|
|
320
|
+
parcel: ParcelInfo
|
|
321
|
+
currency: Literal["CNY"]
|
|
322
|
+
lines: List[ShippingLine]
|
|
323
|
+
cheapest: Optional[str]
|
|
324
|
+
fastest: Optional[str]
|
|
325
|
+
note: str
|
|
326
|
+
source: str
|
|
327
|
+
docs: str
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class ShippingEstimateResponse(_ShippingEstimateBase, total=False):
|
|
331
|
+
items: List[HaulItem]
|
|
332
|
+
exchange: Optional[Exchange]
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
class ShippingCountriesResponse(TypedDict):
|
|
336
|
+
countries: List[Country]
|
|
337
|
+
count: int
|
|
338
|
+
source: str
|
|
339
|
+
docs: str
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
# --------------------------------- haul ---------------------------------
|
|
343
|
+
|
|
344
|
+
class _HaulItemInputBase(TypedDict):
|
|
345
|
+
url: str
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class HaulItemInput(_HaulItemInputBase, total=False):
|
|
349
|
+
quantity: int
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class LocalTotals(TypedDict):
|
|
353
|
+
goods: Optional[float]
|
|
354
|
+
domestic_shipping: Optional[float]
|
|
355
|
+
shipping: Optional[float]
|
|
356
|
+
total: Optional[float]
|
|
357
|
+
currency: str
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class _HaulTotalsBase(TypedDict):
|
|
361
|
+
goods: float
|
|
362
|
+
domestic_shipping: float
|
|
363
|
+
shipping: Optional[float]
|
|
364
|
+
total: Optional[float]
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class HaulTotals(_HaulTotalsBase, total=False):
|
|
368
|
+
local: LocalTotals
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class HaulParcel(TypedDict):
|
|
372
|
+
weight_g: int
|
|
373
|
+
dimensions_cm: Optional[Dimensions]
|
|
374
|
+
weight_complete: bool
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
class HaulShipping(TypedDict):
|
|
378
|
+
lines: List[ShippingLine]
|
|
379
|
+
cheapest: Optional[str]
|
|
380
|
+
fastest: Optional[str]
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
class _HaulResponseBase(TypedDict):
|
|
384
|
+
country: Country
|
|
385
|
+
currency: Literal["CNY"]
|
|
386
|
+
items: List[HaulItem]
|
|
387
|
+
totals: HaulTotals
|
|
388
|
+
parcel: HaulParcel
|
|
389
|
+
shipping: Optional[HaulShipping]
|
|
390
|
+
notes: List[str]
|
|
391
|
+
source: str
|
|
392
|
+
docs: str
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
class HaulResponse(_HaulResponseBase, total=False):
|
|
396
|
+
exchange: Exchange
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
# ----------------------------- account / misc ---------------------------
|
|
400
|
+
|
|
401
|
+
class UsageProject(TypedDict):
|
|
402
|
+
name: str
|
|
403
|
+
today: int
|
|
404
|
+
daily_cap: Optional[int]
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class UsageWorkspace(TypedDict):
|
|
408
|
+
used_today: int
|
|
409
|
+
limit_per_day: Optional[int]
|
|
410
|
+
remaining: Optional[int]
|
|
411
|
+
rate_per_min: Optional[int]
|
|
412
|
+
reset_at: str
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class UsageResponse(TypedDict):
|
|
416
|
+
plan: Literal["free", "pro", "enterprise"]
|
|
417
|
+
project: UsageProject
|
|
418
|
+
workspace: UsageWorkspace
|
|
419
|
+
source: str
|
|
420
|
+
docs: str
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class RatesResponse(TypedDict):
|
|
424
|
+
base: str
|
|
425
|
+
date: str
|
|
426
|
+
source: Literal["NBP", "ECB"]
|
|
427
|
+
rates: Dict[str, float]
|
|
428
|
+
source_site: str
|
|
429
|
+
docs: str
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class ServiceSources(TypedDict):
|
|
433
|
+
up: int
|
|
434
|
+
total: int
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class ServiceHealth(TypedDict):
|
|
438
|
+
status: ServiceStatus
|
|
439
|
+
latency_ms: int
|
|
440
|
+
sources: ServiceSources
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
class DayService(TypedDict):
|
|
444
|
+
status: ServiceStatus
|
|
445
|
+
uptime: float
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
class DayHistory(TypedDict):
|
|
449
|
+
date: str
|
|
450
|
+
services: Dict[str, DayService]
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
class _HealthResponseBase(TypedDict):
|
|
454
|
+
status: ServiceStatus
|
|
455
|
+
checked_at: str
|
|
456
|
+
services: Dict[str, ServiceHealth]
|
|
457
|
+
uptime_30d: Dict[str, Optional[float]]
|
|
458
|
+
source: str
|
|
459
|
+
docs: str
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
class HealthResponse(_HealthResponseBase, total=False):
|
|
463
|
+
history: List[DayHistory]
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class Bilingual(TypedDict):
|
|
467
|
+
en: str
|
|
468
|
+
pl: str
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
class ChangeItem(TypedDict):
|
|
472
|
+
tag: ChangeTag
|
|
473
|
+
en: str
|
|
474
|
+
pl: str
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
class Release(TypedDict):
|
|
478
|
+
version: str
|
|
479
|
+
date: str
|
|
480
|
+
url: str
|
|
481
|
+
title: Bilingual
|
|
482
|
+
items: List[ChangeItem]
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
class ChangelogResponse(TypedDict):
|
|
486
|
+
latest: Optional[str]
|
|
487
|
+
releases: List[Release]
|
|
488
|
+
rss: str
|
|
489
|
+
source: str
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class LocalizedChangeItem(TypedDict):
|
|
493
|
+
tag: ChangeTag
|
|
494
|
+
text: str
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
class LocalizedRelease(TypedDict):
|
|
498
|
+
version: str
|
|
499
|
+
date: str
|
|
500
|
+
url: str
|
|
501
|
+
title: str
|
|
502
|
+
items: List[LocalizedChangeItem]
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
class LocalizedChangelogResponse(TypedDict):
|
|
506
|
+
latest: Optional[str]
|
|
507
|
+
releases: List[LocalizedRelease]
|
|
508
|
+
rss: str
|
|
509
|
+
source: str
|