parseapi 0.2.1__py3-none-any.whl → 0.3.2__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.
- parseapi/__init__.py +2 -2
- parseapi/_client.py +134 -28
- parseapi/py.typed +0 -0
- {parseapi-0.2.1.dist-info → parseapi-0.3.2.dist-info}/METADATA +28 -10
- parseapi-0.3.2.dist-info/RECORD +7 -0
- {parseapi-0.2.1.dist-info → parseapi-0.3.2.dist-info}/licenses/LICENSE +1 -1
- parseapi-0.2.1.dist-info/RECORD +0 -6
- {parseapi-0.2.1.dist-info → parseapi-0.3.2.dist-info}/WHEEL +0 -0
parseapi/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"""Official
|
|
1
|
+
"""Official ParseAPI client for Python."""
|
|
2
2
|
|
|
3
3
|
from ._client import AsyncParseAPI, ParseAPI, ParseAPIError
|
|
4
4
|
|
|
5
|
-
__version__ = "0.2
|
|
5
|
+
__version__ = "0.3.2"
|
|
6
6
|
__all__ = ["ParseAPI", "AsyncParseAPI", "ParseAPIError", "__version__"]
|
parseapi/_client.py
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import math
|
|
4
5
|
import random
|
|
5
6
|
import time
|
|
7
|
+
from email.utils import parsedate_to_datetime
|
|
6
8
|
from typing import Any, Dict, Optional
|
|
7
9
|
from urllib.parse import quote
|
|
8
10
|
|
|
9
11
|
import httpx
|
|
10
12
|
|
|
11
|
-
VERSION = "0.2
|
|
13
|
+
VERSION = "0.3.2"
|
|
12
14
|
DEFAULT_BASE_URL = "https://api.parseapi.com"
|
|
13
15
|
DEFAULT_TIMEOUT = 10.0
|
|
14
16
|
DEFAULT_RETRIES = 2
|
|
@@ -37,10 +39,15 @@ def _retry_delay(attempt: int, retry_after: Optional[str]) -> float:
|
|
|
37
39
|
if retry_after:
|
|
38
40
|
try:
|
|
39
41
|
seconds = float(retry_after)
|
|
40
|
-
if seconds >= 0:
|
|
42
|
+
if math.isfinite(seconds) and seconds >= 0:
|
|
41
43
|
return min(seconds, RETRY_AFTER_CAP)
|
|
42
44
|
except ValueError:
|
|
43
|
-
|
|
45
|
+
try:
|
|
46
|
+
parsed = parsedate_to_datetime(retry_after)
|
|
47
|
+
if parsed.tzinfo is not None:
|
|
48
|
+
return min(max(parsed.timestamp() - time.time(), 0), RETRY_AFTER_CAP)
|
|
49
|
+
except (ValueError, TypeError, OverflowError):
|
|
50
|
+
pass
|
|
44
51
|
return random.random() * 0.25 * (2**attempt)
|
|
45
52
|
|
|
46
53
|
|
|
@@ -66,6 +73,13 @@ def _clean(params: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
66
73
|
return {name: value for name, value in params.items() if value is not None and value is not False}
|
|
67
74
|
|
|
68
75
|
|
|
76
|
+
def _default_retries(path: str, params: Optional[Dict[str, Any]]) -> int:
|
|
77
|
+
product = path.split("/")[1]
|
|
78
|
+
metered = product in {"carrier", "caller", "hlr", "litigator", "reassigned"}
|
|
79
|
+
metered = metered or (product in {"email", "vat", "address"} and (params or {}).get("deep") is True)
|
|
80
|
+
return 0 if metered else DEFAULT_RETRIES
|
|
81
|
+
|
|
82
|
+
|
|
69
83
|
class _Config:
|
|
70
84
|
def __init__(
|
|
71
85
|
self,
|
|
@@ -80,7 +94,11 @@ class _Config:
|
|
|
80
94
|
self.api_key = key
|
|
81
95
|
self.base_url = (base_url or os.environ.get("PARSEAPI_BASE_URL") or DEFAULT_BASE_URL).rstrip("/")
|
|
82
96
|
self.timeout = DEFAULT_TIMEOUT if timeout is None else timeout
|
|
83
|
-
self.retries =
|
|
97
|
+
self.retries = retries
|
|
98
|
+
if type(self.timeout) not in (int, float) or not math.isfinite(self.timeout) or self.timeout <= 0:
|
|
99
|
+
raise ValueError("parseapi: timeout must be a finite positive number.")
|
|
100
|
+
if self.retries is not None and (type(self.retries) is not int or self.retries < 0):
|
|
101
|
+
raise ValueError("parseapi: retries must be a non-negative integer.")
|
|
84
102
|
|
|
85
103
|
def headers(self) -> Dict[str, str]:
|
|
86
104
|
return {"X-API-Key": self.api_key, "User-Agent": f"parseapi-python/{VERSION}"}
|
|
@@ -116,6 +134,9 @@ class ParseAPI:
|
|
|
116
134
|
self.holiday = _HolidaySync(self)
|
|
117
135
|
self.emoji = _EmojiSync(self)
|
|
118
136
|
self.tariff = _TariffSync(self)
|
|
137
|
+
self.date = _DateSync(self)
|
|
138
|
+
self.timezone = _TimezoneSync(self)
|
|
139
|
+
self.address = _AddressSync(self)
|
|
119
140
|
|
|
120
141
|
def close(self) -> None:
|
|
121
142
|
self._http.close()
|
|
@@ -127,19 +148,20 @@ class ParseAPI:
|
|
|
127
148
|
self.close()
|
|
128
149
|
|
|
129
150
|
def _get(self, path: str, params: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, str]] = None) -> Json:
|
|
151
|
+
retries = self._config.retries if self._config.retries is not None else _default_retries(path, params)
|
|
130
152
|
attempt = 0
|
|
131
153
|
while True:
|
|
132
154
|
try:
|
|
133
155
|
response = self._http.get(path, params=_clean(params or {}), headers=headers)
|
|
134
156
|
except httpx.HTTPError:
|
|
135
|
-
if attempt <
|
|
157
|
+
if attempt < retries:
|
|
136
158
|
time.sleep(_retry_delay(attempt, None))
|
|
137
159
|
attempt += 1
|
|
138
160
|
continue
|
|
139
161
|
raise
|
|
140
162
|
if response.is_success:
|
|
141
163
|
return response.json()
|
|
142
|
-
if response.status_code in RETRY_STATUS and attempt <
|
|
164
|
+
if response.status_code in RETRY_STATUS and attempt < retries:
|
|
143
165
|
time.sleep(_retry_delay(attempt, response.headers.get("Retry-After")))
|
|
144
166
|
attempt += 1
|
|
145
167
|
continue
|
|
@@ -184,6 +206,12 @@ class ParseAPI:
|
|
|
184
206
|
def domain(self, domain: str, *, deep: bool = False) -> Json:
|
|
185
207
|
return self._get(f"/domain/{_seg(domain)}", {"deep": deep})
|
|
186
208
|
|
|
209
|
+
def asn(self, asn: str) -> Json:
|
|
210
|
+
return self._get(f"/asn/{_seg(asn)}")
|
|
211
|
+
|
|
212
|
+
def mac(self, mac: str) -> Json:
|
|
213
|
+
return self._get(f"/mac/{_seg(mac)}")
|
|
214
|
+
|
|
187
215
|
def mx(self, domain: str) -> Json:
|
|
188
216
|
return self._get(f"/mx/{_seg(domain)}")
|
|
189
217
|
|
|
@@ -193,8 +221,8 @@ class ParseAPI:
|
|
|
193
221
|
def vin(self, vin: str, *, deep: bool = False) -> Json:
|
|
194
222
|
return self._get(f"/vin/{_seg(vin)}", {"deep": deep})
|
|
195
223
|
|
|
196
|
-
def
|
|
197
|
-
return self._get(f"/
|
|
224
|
+
def company(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
|
|
225
|
+
return self._get(f"/company/{_seg(number)}", {"country": country, "deep": deep})
|
|
198
226
|
|
|
199
227
|
def language(self, code: str) -> Json:
|
|
200
228
|
return self._get(f"/language/{_seg(code)}")
|
|
@@ -208,8 +236,8 @@ class ParseAPI:
|
|
|
208
236
|
def point(self, lat: float, lon: float, *, deep: bool = False) -> Json:
|
|
209
237
|
return self._get("/point", {"lat": lat, "lon": lon, "deep": deep})
|
|
210
238
|
|
|
211
|
-
def weather(self, lat: float, lon: float, *, deep: bool = False) -> Json:
|
|
212
|
-
return self._get("/weather", {"lat": lat, "lon": lon, "deep": deep})
|
|
239
|
+
def weather(self, lat: float, lon: float, *, deep: bool = False, date: Optional[str] = None) -> Json:
|
|
240
|
+
return self._get("/weather", {"lat": lat, "lon": lon, "deep": deep, "date": date})
|
|
213
241
|
|
|
214
242
|
|
|
215
243
|
class _IpSync:
|
|
@@ -279,13 +307,13 @@ class _CitySync:
|
|
|
279
307
|
|
|
280
308
|
def search(
|
|
281
309
|
self,
|
|
282
|
-
|
|
310
|
+
query: str,
|
|
283
311
|
*,
|
|
284
312
|
country: Optional[str] = None,
|
|
285
313
|
state: Optional[str] = None,
|
|
286
314
|
limit: Optional[int] = None,
|
|
287
315
|
) -> Json:
|
|
288
|
-
return self._client._get("/city", {"q":
|
|
316
|
+
return self._client._get("/city", {"q": query, "country": country, "state": state, "limit": limit})
|
|
289
317
|
|
|
290
318
|
def nearest(self, lat: float, lon: float) -> Json:
|
|
291
319
|
return self._client._get("/city", {"lat": lat, "lon": lon})
|
|
@@ -360,8 +388,8 @@ class _EmojiSync:
|
|
|
360
388
|
def __call__(self, emoji: str) -> Json:
|
|
361
389
|
return self._client._get(f"/emoji/{_seg(emoji)}")
|
|
362
390
|
|
|
363
|
-
def search(self,
|
|
364
|
-
return self._client._get("/emoji", {"q":
|
|
391
|
+
def search(self, query: str, *, limit: Optional[int] = None) -> Json:
|
|
392
|
+
return self._client._get("/emoji", {"q": query, "limit": limit})
|
|
365
393
|
|
|
366
394
|
|
|
367
395
|
class _TariffSync:
|
|
@@ -371,8 +399,8 @@ class _TariffSync:
|
|
|
371
399
|
def __call__(self, code: str, *, deep: bool = False, origin: Optional[str] = None) -> Json:
|
|
372
400
|
return self._client._get(f"/tariff/{_seg(code)}", {"deep": deep, "origin": origin})
|
|
373
401
|
|
|
374
|
-
def search(self,
|
|
375
|
-
return self._client._get("/tariff", {"q":
|
|
402
|
+
def search(self, query: str) -> Json:
|
|
403
|
+
return self._client._get("/tariff", {"q": query})
|
|
376
404
|
|
|
377
405
|
|
|
378
406
|
class AsyncParseAPI:
|
|
@@ -405,6 +433,9 @@ class AsyncParseAPI:
|
|
|
405
433
|
self.holiday = _HolidayAsync(self)
|
|
406
434
|
self.emoji = _EmojiAsync(self)
|
|
407
435
|
self.tariff = _TariffAsync(self)
|
|
436
|
+
self.date = _DateAsync(self)
|
|
437
|
+
self.timezone = _TimezoneAsync(self)
|
|
438
|
+
self.address = _AddressAsync(self)
|
|
408
439
|
|
|
409
440
|
async def close(self) -> None:
|
|
410
441
|
await self._http.aclose()
|
|
@@ -420,19 +451,20 @@ class AsyncParseAPI:
|
|
|
420
451
|
) -> Json:
|
|
421
452
|
import asyncio
|
|
422
453
|
|
|
454
|
+
retries = self._config.retries if self._config.retries is not None else _default_retries(path, params)
|
|
423
455
|
attempt = 0
|
|
424
456
|
while True:
|
|
425
457
|
try:
|
|
426
458
|
response = await self._http.get(path, params=_clean(params or {}), headers=headers)
|
|
427
459
|
except httpx.HTTPError:
|
|
428
|
-
if attempt <
|
|
460
|
+
if attempt < retries:
|
|
429
461
|
await asyncio.sleep(_retry_delay(attempt, None))
|
|
430
462
|
attempt += 1
|
|
431
463
|
continue
|
|
432
464
|
raise
|
|
433
465
|
if response.is_success:
|
|
434
466
|
return response.json()
|
|
435
|
-
if response.status_code in RETRY_STATUS and attempt <
|
|
467
|
+
if response.status_code in RETRY_STATUS and attempt < retries:
|
|
436
468
|
await asyncio.sleep(_retry_delay(attempt, response.headers.get("Retry-After")))
|
|
437
469
|
attempt += 1
|
|
438
470
|
continue
|
|
@@ -475,6 +507,12 @@ class AsyncParseAPI:
|
|
|
475
507
|
async def domain(self, domain: str, *, deep: bool = False) -> Json:
|
|
476
508
|
return await self._get(f"/domain/{_seg(domain)}", {"deep": deep})
|
|
477
509
|
|
|
510
|
+
async def asn(self, asn: str) -> Json:
|
|
511
|
+
return await self._get(f"/asn/{_seg(asn)}")
|
|
512
|
+
|
|
513
|
+
async def mac(self, mac: str) -> Json:
|
|
514
|
+
return await self._get(f"/mac/{_seg(mac)}")
|
|
515
|
+
|
|
478
516
|
async def mx(self, domain: str) -> Json:
|
|
479
517
|
return await self._get(f"/mx/{_seg(domain)}")
|
|
480
518
|
|
|
@@ -484,8 +522,8 @@ class AsyncParseAPI:
|
|
|
484
522
|
async def vin(self, vin: str, *, deep: bool = False) -> Json:
|
|
485
523
|
return await self._get(f"/vin/{_seg(vin)}", {"deep": deep})
|
|
486
524
|
|
|
487
|
-
async def
|
|
488
|
-
return await self._get(f"/
|
|
525
|
+
async def company(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
|
|
526
|
+
return await self._get(f"/company/{_seg(number)}", {"country": country, "deep": deep})
|
|
489
527
|
|
|
490
528
|
async def language(self, code: str) -> Json:
|
|
491
529
|
return await self._get(f"/language/{_seg(code)}")
|
|
@@ -499,8 +537,8 @@ class AsyncParseAPI:
|
|
|
499
537
|
async def point(self, lat: float, lon: float, *, deep: bool = False) -> Json:
|
|
500
538
|
return await self._get("/point", {"lat": lat, "lon": lon, "deep": deep})
|
|
501
539
|
|
|
502
|
-
async def weather(self, lat: float, lon: float, *, deep: bool = False) -> Json:
|
|
503
|
-
return await self._get("/weather", {"lat": lat, "lon": lon, "deep": deep})
|
|
540
|
+
async def weather(self, lat: float, lon: float, *, deep: bool = False, date: Optional[str] = None) -> Json:
|
|
541
|
+
return await self._get("/weather", {"lat": lat, "lon": lon, "deep": deep, "date": date})
|
|
504
542
|
|
|
505
543
|
|
|
506
544
|
class _IpAsync:
|
|
@@ -570,13 +608,13 @@ class _CityAsync:
|
|
|
570
608
|
|
|
571
609
|
async def search(
|
|
572
610
|
self,
|
|
573
|
-
|
|
611
|
+
query: str,
|
|
574
612
|
*,
|
|
575
613
|
country: Optional[str] = None,
|
|
576
614
|
state: Optional[str] = None,
|
|
577
615
|
limit: Optional[int] = None,
|
|
578
616
|
) -> Json:
|
|
579
|
-
return await self._client._get("/city", {"q":
|
|
617
|
+
return await self._client._get("/city", {"q": query, "country": country, "state": state, "limit": limit})
|
|
580
618
|
|
|
581
619
|
async def nearest(self, lat: float, lon: float) -> Json:
|
|
582
620
|
return await self._client._get("/city", {"lat": lat, "lon": lon})
|
|
@@ -653,8 +691,8 @@ class _EmojiAsync:
|
|
|
653
691
|
async def __call__(self, emoji: str) -> Json:
|
|
654
692
|
return await self._client._get(f"/emoji/{_seg(emoji)}")
|
|
655
693
|
|
|
656
|
-
async def search(self,
|
|
657
|
-
return await self._client._get("/emoji", {"q":
|
|
694
|
+
async def search(self, query: str, *, limit: Optional[int] = None) -> Json:
|
|
695
|
+
return await self._client._get("/emoji", {"q": query, "limit": limit})
|
|
658
696
|
|
|
659
697
|
|
|
660
698
|
class _TariffAsync:
|
|
@@ -664,5 +702,73 @@ class _TariffAsync:
|
|
|
664
702
|
async def __call__(self, code: str, *, deep: bool = False, origin: Optional[str] = None) -> Json:
|
|
665
703
|
return await self._client._get(f"/tariff/{_seg(code)}", {"deep": deep, "origin": origin})
|
|
666
704
|
|
|
667
|
-
async def search(self,
|
|
668
|
-
return await self._client._get("/tariff", {"q":
|
|
705
|
+
async def search(self, query: str) -> Json:
|
|
706
|
+
return await self._client._get("/tariff", {"q": query})
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
class _DateSync:
|
|
710
|
+
def __init__(self, client: ParseAPI):
|
|
711
|
+
self._client = client
|
|
712
|
+
|
|
713
|
+
def __call__(self, date: str, *, format: Optional[str] = None, to: Optional[str] = None) -> Json:
|
|
714
|
+
return self._client._get(f"/date/{_seg(date)}", {"format": format, "to": to})
|
|
715
|
+
|
|
716
|
+
def today(self, *, to: Optional[str] = None) -> Json:
|
|
717
|
+
return self._client._get("/date", {"to": to})
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
class _DateAsync:
|
|
721
|
+
def __init__(self, client: AsyncParseAPI):
|
|
722
|
+
self._client = client
|
|
723
|
+
|
|
724
|
+
async def __call__(self, date: str, *, format: Optional[str] = None, to: Optional[str] = None) -> Json:
|
|
725
|
+
return await self._client._get(f"/date/{_seg(date)}", {"format": format, "to": to})
|
|
726
|
+
|
|
727
|
+
async def today(self, *, to: Optional[str] = None) -> Json:
|
|
728
|
+
return await self._client._get("/date", {"to": to})
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
class _TimezoneSync:
|
|
732
|
+
def __init__(self, client: ParseAPI):
|
|
733
|
+
self._client = client
|
|
734
|
+
|
|
735
|
+
def __call__(self, id: str, *, at: Optional[str] = None, to: Optional[str] = None) -> Json:
|
|
736
|
+
return self._client._get(f"/timezone/{_seg(id)}", {"at": at, "to": to})
|
|
737
|
+
|
|
738
|
+
def at(self, lat: float, lon: float, *, at: Optional[str] = None) -> Json:
|
|
739
|
+
return self._client._get("/timezone", {"lat": lat, "lon": lon, "at": at})
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
class _AddressSync:
|
|
743
|
+
def __init__(self, client: ParseAPI):
|
|
744
|
+
self._client = client
|
|
745
|
+
|
|
746
|
+
def __call__(self, address: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
|
|
747
|
+
return self._client._get(f"/address/{_seg(address)}", {"country": country, "deep": deep})
|
|
748
|
+
|
|
749
|
+
def search(self, query: str, *, country: Optional[str] = None, postal: Optional[str] = None,
|
|
750
|
+
city: Optional[str] = None, state: Optional[str] = None, ip: Optional[str] = None) -> Json:
|
|
751
|
+
return self._client._get("/address", {"q": query, "country": country, "postal": postal, "city": city, "state": state, "ip": ip})
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
class _TimezoneAsync:
|
|
755
|
+
def __init__(self, client: AsyncParseAPI):
|
|
756
|
+
self._client = client
|
|
757
|
+
|
|
758
|
+
async def __call__(self, id: str, *, at: Optional[str] = None, to: Optional[str] = None) -> Json:
|
|
759
|
+
return await self._client._get(f"/timezone/{_seg(id)}", {"at": at, "to": to})
|
|
760
|
+
|
|
761
|
+
async def at(self, lat: float, lon: float, *, at: Optional[str] = None) -> Json:
|
|
762
|
+
return await self._client._get("/timezone", {"lat": lat, "lon": lon, "at": at})
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
class _AddressAsync:
|
|
766
|
+
def __init__(self, client: AsyncParseAPI):
|
|
767
|
+
self._client = client
|
|
768
|
+
|
|
769
|
+
async def __call__(self, address: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
|
|
770
|
+
return await self._client._get(f"/address/{_seg(address)}", {"country": country, "deep": deep})
|
|
771
|
+
|
|
772
|
+
async def search(self, query: str, *, country: Optional[str] = None, postal: Optional[str] = None,
|
|
773
|
+
city: Optional[str] = None, state: Optional[str] = None, ip: Optional[str] = None) -> Json:
|
|
774
|
+
return await self._client._get("/address", {"q": query, "country": country, "postal": postal, "city": city, "state": state, "ip": ip})
|
parseapi/py.typed
ADDED
|
File without changes
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: parseapi
|
|
3
|
-
Version: 0.2
|
|
4
|
-
Summary: Official
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: Official ParseAPI client for Python. One key, minimal JSON, fast.
|
|
5
5
|
Project-URL: Homepage, https://parseapi.com
|
|
6
6
|
Project-URL: Documentation, https://parseapi.com/docs
|
|
7
7
|
Project-URL: Repository, https://github.com/parseapi/python
|
|
8
|
-
Author-email:
|
|
8
|
+
Author-email: ParseAPI <hello@parseapi.com>
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Keywords: currency,email validation,geolocation,ip,parseapi,phone validation,postal,timezone,weather
|
|
@@ -19,7 +19,7 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
|
|
20
20
|
# parseapi
|
|
21
21
|
|
|
22
|
-
Official
|
|
22
|
+
Official ParseAPI client for Python.
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
pip install parseapi
|
|
@@ -53,6 +53,9 @@ parse.postal("SW1A 1AA")
|
|
|
53
53
|
parse.postal("28202", country="US")
|
|
54
54
|
parse.postal.nearby("28202", country="US", radius=40)
|
|
55
55
|
parse.postal.distance("28202", "10001", country="US")
|
|
56
|
+
parse.address("1600 Pennsylvania Ave NW, Washington DC", country="US")
|
|
57
|
+
parse.address.search("1600 Pennsylvania", country="US", postal="20500")
|
|
58
|
+
parse.company("51 824 753 556", country="AU")
|
|
56
59
|
parse.city("charlotte", country="US")
|
|
57
60
|
parse.city.id("city_mb8mbqrkz8zb")
|
|
58
61
|
parse.city.search("char", country="US", limit=10)
|
|
@@ -66,35 +69,45 @@ parse.state.districts("NC", country="US")
|
|
|
66
69
|
parse.district("37081")
|
|
67
70
|
parse.continent("NA")
|
|
68
71
|
parse.continent.countries("NA")
|
|
72
|
+
parse.bloc("EU")
|
|
73
|
+
parse.bloc.countries("EU")
|
|
69
74
|
parse.currency("USD")
|
|
70
75
|
parse.currency.rate("USD", "EUR")
|
|
71
76
|
parse.language("en")
|
|
72
77
|
parse.name("BILLY OSHALL")
|
|
73
78
|
parse.timezone("America/New_York")
|
|
79
|
+
parse.timezone("America/New_York", at="2026-09-05T15:00:00", to="Europe/London")
|
|
80
|
+
parse.timezone.at(39.77, -104.9)
|
|
81
|
+
parse.date("03/04/2026", format="mdy")
|
|
82
|
+
parse.date.today()
|
|
74
83
|
parse.holiday("US", year=2026)
|
|
75
84
|
parse.holiday.date("US", "2026-12-25")
|
|
76
85
|
parse.elevation(35.2271, -80.8431)
|
|
77
86
|
parse.point(36.0726, -79.792)
|
|
78
87
|
parse.weather(40.7128, -74.006)
|
|
79
88
|
parse.domain("example.com")
|
|
89
|
+
parse.asn("AS13335")
|
|
90
|
+
parse.mac("00:1B:63:84:45:E6")
|
|
80
91
|
parse.mx("example.com")
|
|
81
92
|
parse.useragent(ua_string)
|
|
82
93
|
parse.vin("1HGCM82633A004352")
|
|
94
|
+
parse.tariff("8471.30.01.00")
|
|
95
|
+
parse.tariff.search("sunglasses")
|
|
83
96
|
parse.emoji("rocket")
|
|
84
97
|
parse.emoji.search("fire")
|
|
85
98
|
```
|
|
86
99
|
|
|
87
|
-
Responses are plain dicts, exactly the JSON the API returns.
|
|
100
|
+
Responses are plain dicts, exactly the JSON the API returns. `country.states("US")` requests states directly; it does not fetch a country first. Required inputs are positional and optional behavior uses keyword arguments, leaving room for new options without changing existing calls. Reuse a client across calls. Use `with ParseAPI(...) as parse:` or call `parse.close()` when finished.
|
|
88
101
|
|
|
89
102
|
## Async
|
|
90
103
|
|
|
91
|
-
Same
|
|
104
|
+
Same lookup methods and keyword arguments, with `await`. Use a context manager to close the client when the work is done.
|
|
92
105
|
|
|
93
106
|
```python
|
|
94
107
|
from parseapi import AsyncParseAPI
|
|
95
108
|
|
|
96
|
-
|
|
97
|
-
country = await parse.country("US")
|
|
109
|
+
async with AsyncParseAPI("your-api-key") as parse:
|
|
110
|
+
country = await parse.country("US")
|
|
98
111
|
```
|
|
99
112
|
|
|
100
113
|
## Deep
|
|
@@ -120,18 +133,23 @@ except ParseAPIError as err:
|
|
|
120
133
|
... # no such city
|
|
121
134
|
```
|
|
122
135
|
|
|
136
|
+
Network and decoding failures keep their native error types. Responses such as `valid: false` are successful API answers, not exceptions.
|
|
137
|
+
|
|
123
138
|
## Options
|
|
124
139
|
|
|
125
140
|
```python
|
|
126
141
|
parse = ParseAPI(
|
|
127
142
|
"your-api-key",
|
|
128
|
-
timeout=10.0, #
|
|
129
|
-
retries=2, # automatic retries on network errors, 429, and 5xx
|
|
143
|
+
timeout=10.0, # timeout for each connect, read, write, or pool phase
|
|
130
144
|
)
|
|
131
145
|
```
|
|
132
146
|
|
|
133
147
|
Requires Python 3.9 or later. One dependency (httpx).
|
|
134
148
|
|
|
149
|
+
Ordinary lookups retry network failures, 429, and 500/502/503/504 responses twice by default. Carrier, caller, HLR, and email or VAT with `deep=True` make one attempt by default. Address with `deep=True` also uses one attempt, reserving the same behavior for future verification.
|
|
150
|
+
|
|
151
|
+
An explicit client `retries` setting overrides those defaults; `retries=0` always makes one attempt. Another attempt can consume additional usage if the earlier response was lost. Cancelling an async task stops the call and any retry wait. Automatic redirects are disabled.
|
|
152
|
+
|
|
135
153
|
## Docs
|
|
136
154
|
|
|
137
155
|
Full field reference for every endpoint: [parseapi.com/docs](https://parseapi.com/docs)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
parseapi/__init__.py,sha256=K26G0Ln_MpBNehukrxXzNqpfhs6a_ln0UPH5jQut4KQ,199
|
|
2
|
+
parseapi/_client.py,sha256=n6wcmuqP8eOEWaxxWk2p7qBF1OZfye3yWZuFs5DRNWI,28816
|
|
3
|
+
parseapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
parseapi-0.3.2.dist-info/METADATA,sha256=_V4PWtBMcwU-nYgmbigCGrbrA4vjSFFNqPb1Lblx3aU,5108
|
|
5
|
+
parseapi-0.3.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
6
|
+
parseapi-0.3.2.dist-info/licenses/LICENSE,sha256=3IF5YNQQ6vF8sAs9hGRcovgEetJuzSwKqoE1TXLMoRs,1065
|
|
7
|
+
parseapi-0.3.2.dist-info/RECORD,,
|
parseapi-0.2.1.dist-info/RECORD
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
parseapi/__init__.py,sha256=s3dU27Iu4DDpNvvVo5v_7enSx2T6QcOYlYhKSlByV3Q,199
|
|
2
|
-
parseapi/_client.py,sha256=iKVNmgZ-1hFVXOtev18KHiTeRMoY1LiRtJmNHwvmcqo,23770
|
|
3
|
-
parseapi-0.2.1.dist-info/METADATA,sha256=giDF2HjJTXjUvrV5KqhoMK1pACyN05icfQexuVerTnQ,3510
|
|
4
|
-
parseapi-0.2.1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
5
|
-
parseapi-0.2.1.dist-info/licenses/LICENSE,sha256=tdXjNJFfw9PIftBGjZIHyLHbRN6-Y7COFUVuyobBqWY,1065
|
|
6
|
-
parseapi-0.2.1.dist-info/RECORD,,
|
|
File without changes
|