parseapi 0.3.2__py3-none-any.whl → 0.4.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.
parseapi/__init__.py CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  from ._client import AsyncParseAPI, ParseAPI, ParseAPIError
4
4
 
5
- __version__ = "0.3.2"
5
+ __version__ = "0.4.0"
6
6
  __all__ = ["ParseAPI", "AsyncParseAPI", "ParseAPIError", "__version__"]
parseapi/_client.py CHANGED
@@ -10,7 +10,7 @@ from urllib.parse import quote
10
10
 
11
11
  import httpx
12
12
 
13
- VERSION = "0.3.2"
13
+ VERSION = "0.4.0"
14
14
  DEFAULT_BASE_URL = "https://api.parseapi.com"
15
15
  DEFAULT_TIMEOUT = 10.0
16
16
  DEFAULT_RETRIES = 2
@@ -88,6 +88,7 @@ class _Config:
88
88
  timeout: Optional[float],
89
89
  retries: Optional[int],
90
90
  ):
91
+ # You found Dev. https://parseapi.com/dev
91
92
  key = api_key or os.environ.get("PARSEAPI_KEY")
92
93
  if not key:
93
94
  raise ValueError("parseapi: missing API key. Pass one or set PARSEAPI_KEY.")
@@ -133,8 +134,11 @@ class ParseAPI:
133
134
  self.currency = _CurrencySync(self)
134
135
  self.holiday = _HolidaySync(self)
135
136
  self.emoji = _EmojiSync(self)
137
+ self.naics = _NaicsSync(self)
136
138
  self.tariff = _TariffSync(self)
137
139
  self.date = _DateSync(self)
140
+ self.measure = _MeasureSync(self)
141
+ self.time = _TimeSync(self)
138
142
  self.timezone = _TimezoneSync(self)
139
143
  self.address = _AddressSync(self)
140
144
 
@@ -169,10 +173,14 @@ class ParseAPI:
169
173
 
170
174
  # Plain methods (no subresources)
171
175
 
172
- def district(self, code: str, *, country: Optional[str] = None, state: Optional[str] = None) -> Json:
173
- return self._get(f"/district/{_seg(code)}", {"country": country, "state": state})
176
+ def district(self, code: str, *, country: Optional[str] = None, state: Optional[str] = None, deep: bool = False) -> Json:
177
+ return self._get(f"/district/{_seg(code)}", {"country": country, "state": state, "deep": deep})
174
178
 
175
179
  def email(self, email: str, *, deep: bool = False) -> Json:
180
+ """Parse an email and check its format and domain. Deep explicitly requests a metered
181
+ deliverability check. Deep checks use one attempt by default. An explicit retry
182
+ count can repeat paid usage.
183
+ """
176
184
  return self._get(f"/email/{_seg(email)}", {"deep": deep})
177
185
 
178
186
  def vat(
@@ -183,27 +191,46 @@ class ParseAPI:
183
191
  deep: bool = False,
184
192
  from_vat: Optional[str] = None,
185
193
  ) -> Json:
194
+ """Check VAT format and checksum. Deep requests a metered registry check where supported. Deep
195
+ checks use one attempt by default. Supply your own VAT number for a consultation
196
+ reference when supported.
197
+ """
186
198
  return self._get(f"/vat/{_seg(number)}", {"country": country, "deep": deep, "from": from_vat})
187
199
 
188
- def iban(self, iban: str, *, country: Optional[str] = None) -> Json:
189
- return self._get(f"/iban/{_seg(iban)}", {"country": country})
200
+ def iban(self, iban: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
201
+ return self._get(f"/iban/{_seg(iban)}", {"country": country, "deep": deep})
202
+
203
+ def bin(self, bin: str, *, deep: bool = False) -> Json:
204
+ """Look up a 6-11 digit card prefix, preserving leading zeros."""
205
+ return self._get(f"/bin/{_seg(bin)}", {"deep": deep})
190
206
 
191
207
  def npi(self, npi: str, *, deep: bool = False) -> Json:
192
208
  return self._get(f"/npi/{_seg(npi)}", {"deep": deep})
193
209
 
194
210
  def phone(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
211
+ """Parse a phone number and its formats. Pass country for national numbers when needed. Deep
212
+ adds numbering-plan geography on every plan. Carrier, caller, and HLR are separate metered lookups.
213
+ """
195
214
  return self._get(f"/phone/{_seg(number)}", {"country": country, "deep": deep})
196
215
 
197
- def carrier(self, number: str, *, country: Optional[str] = None) -> Json:
198
- return self._get(f"/carrier/{_seg(number)}", {"country": country})
216
+ def carrier(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
217
+ """Request a metered carrier lookup. No automatic retries by default.
218
+ """
219
+ return self._get(f"/carrier/{_seg(number)}", {"country": country, "deep": deep})
199
220
 
200
221
  def caller(self, number: str, *, country: Optional[str] = None) -> Json:
222
+ """Request a metered caller-name lookup for a NANP number. No automatic retries by default.
223
+ """
201
224
  return self._get(f"/caller/{_seg(number)}", {"country": country})
202
225
 
203
- def hlr(self, number: str, *, country: Optional[str] = None) -> Json:
204
- return self._get(f"/hlr/{_seg(number)}", {"country": country})
226
+ def hlr(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
227
+ """Look up phone status at the last check. Live means assigned and connected means reachable
228
+ at that check. Cached results may be returned. Null means unconfirmed. Deep adds network
229
+ diagnostics within the same metered lookup. No automatic retries by default."""
230
+ return self._get(f"/hlr/{_seg(number)}", {"country": country, "deep": deep})
205
231
 
206
232
  def domain(self, domain: str, *, deep: bool = False) -> Json:
233
+ """Check whether a domain is registered. Deep adds registration dates, registrar, status and DNSSEC on paid plans."""
207
234
  return self._get(f"/domain/{_seg(domain)}", {"deep": deep})
208
235
 
209
236
  def asn(self, asn: str) -> Json:
@@ -212,6 +239,14 @@ class ParseAPI:
212
239
  def mac(self, mac: str) -> Json:
213
240
  return self._get(f"/mac/{_seg(mac)}")
214
241
 
242
+ def dns(self, domain: str, *, type: str | None = None) -> Json:
243
+ """Published DNS records with TTLs. Omit type to check all supported types.
244
+
245
+ Type selects the question and may include its CNAME chain. Values retain
246
+ DNS presentation syntax, including TXT quoting. Pooled on every plan.
247
+ """
248
+ return self._get(f"/dns/{_seg(domain)}", {"type": type})
249
+
215
250
  def mx(self, domain: str) -> Json:
216
251
  return self._get(f"/mx/{_seg(domain)}")
217
252
 
@@ -224,19 +259,26 @@ class ParseAPI:
224
259
  def company(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
225
260
  return self._get(f"/company/{_seg(number)}", {"country": country, "deep": deep})
226
261
 
227
- def language(self, code: str) -> Json:
228
- return self._get(f"/language/{_seg(code)}")
262
+ def language(self, code: str, *, deep: bool = False) -> Json:
263
+ return self._get(f"/language/{_seg(code)}", {"deep": deep})
229
264
 
230
- def name(self, name: str) -> Json:
231
- return self._get(f"/name/{_seg(name)}")
265
+ def name(self, name: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
266
+ """Parse a name. Country is an ISO2 gender context, not nationality."""
267
+ return self._get(f"/name/{_seg(name)}", {"country": country, "deep": deep})
232
268
 
233
269
  def elevation(self, lat: float, lon: float) -> Json:
234
270
  return self._get("/elevation", {"lat": lat, "lon": lon})
235
271
 
236
272
  def point(self, lat: float, lon: float, *, deep: bool = False) -> Json:
273
+ """Resolve the country, state, district and timezone at coordinates. Deep adds terrain and
274
+ compact nearest-city context on every plan. The timezone ID stays in core. The nearest
275
+ city is null when none is within 200 km."""
237
276
  return self._get("/point", {"lat": lat, "lon": lon, "deep": deep})
238
277
 
239
278
  def weather(self, lat: float, lon: float, *, deep: bool = False, date: Optional[str] = None) -> Json:
279
+ """Get current conditions in metric and imperial units. Paid deep adds specialist current
280
+ measurements, forecasts and related detail. With deep, date selects a past UTC day (YYYY-
281
+ MM-DD) in deep.history alongside current conditions. Date alone does not request history."""
240
282
  return self._get("/weather", {"lat": lat, "lon": lon, "deep": deep, "date": date})
241
283
 
242
284
 
@@ -245,9 +287,13 @@ class _IpSync:
245
287
  self._client = client
246
288
 
247
289
  def __call__(self, ip: str, *, deep: bool = False) -> Json:
290
+ """Look up an IP. Deep enrichment is included with a paid plan, without a separate check meter.
291
+ """
248
292
  return self._client._get(f"/ip/{_seg(ip)}", {"deep": deep})
249
293
 
250
294
  def self(self, *, deep: bool = False) -> Json:
295
+ """Look up the public IP making this request. On a server, this is the server's IP.
296
+ """
251
297
  return self._client._get("/ip", {"deep": deep})
252
298
 
253
299
 
@@ -277,8 +323,8 @@ class _CountrySync:
277
323
  def __init__(self, client: ParseAPI):
278
324
  self._client = client
279
325
 
280
- def __call__(self, code: str) -> Json:
281
- return self._client._get(f"/country/{_seg(code)}")
326
+ def __call__(self, code: str, *, deep: bool = False) -> Json:
327
+ return self._client._get(f"/country/{_seg(code)}", {"deep": deep})
282
328
 
283
329
  def states(self, code: str) -> Json:
284
330
  return self._client._get(f"/country/{_seg(code)}/states")
@@ -288,22 +334,22 @@ class _StateSync:
288
334
  def __init__(self, client: ParseAPI):
289
335
  self._client = client
290
336
 
291
- def __call__(self, code: str, *, country: Optional[str] = None) -> Json:
292
- return self._client._get(f"/state/{_seg(code)}", {"country": country})
337
+ def __call__(self, code: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
338
+ return self._client._get(f"/state/{_seg(code)}", {"country": country, "deep": deep})
293
339
 
294
- def districts(self, code: str, *, country: Optional[str] = None) -> Json:
295
- return self._client._get(f"/state/{_seg(code)}/districts", {"country": country})
340
+ def districts(self, code: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
341
+ return self._client._get(f"/state/{_seg(code)}/districts", {"country": country, "deep": deep})
296
342
 
297
343
 
298
344
  class _CitySync:
299
345
  def __init__(self, client: ParseAPI):
300
346
  self._client = client
301
347
 
302
- def __call__(self, name: str, *, country: Optional[str] = None, state: Optional[str] = None) -> Json:
303
- return self._client._get(f"/city/{_seg(name)}", {"country": country, "state": state})
348
+ def __call__(self, name: str, *, country: Optional[str] = None, state: Optional[str] = None, deep: bool = False) -> Json:
349
+ return self._client._get(f"/city/{_seg(name)}", {"country": country, "state": state, "deep": deep})
304
350
 
305
- def id(self, id: str) -> Json:
306
- return self._client._get(f"/city/id/{_seg(id)}")
351
+ def id(self, id: str, *, deep: bool = False) -> Json:
352
+ return self._client._get(f"/city/id/{_seg(id)}", {"deep": deep})
307
353
 
308
354
  def search(
309
355
  self,
@@ -312,11 +358,12 @@ class _CitySync:
312
358
  country: Optional[str] = None,
313
359
  state: Optional[str] = None,
314
360
  limit: Optional[int] = None,
361
+ deep: bool = False,
315
362
  ) -> Json:
316
- return self._client._get("/city", {"q": query, "country": country, "state": state, "limit": limit})
363
+ return self._client._get("/city", {"q": query, "country": country, "state": state, "limit": limit, "deep": deep})
317
364
 
318
- def nearest(self, lat: float, lon: float) -> Json:
319
- return self._client._get("/city", {"lat": lat, "lon": lon})
365
+ def nearest(self, lat: float, lon: float, *, deep: bool = False) -> Json:
366
+ return self._client._get("/city", {"lat": lat, "lon": lon, "deep": deep})
320
367
 
321
368
  def nearby(
322
369
  self,
@@ -327,10 +374,11 @@ class _CitySync:
327
374
  country: Optional[str] = None,
328
375
  state: Optional[str] = None,
329
376
  limit: Optional[int] = None,
377
+ deep: bool = False,
330
378
  ) -> Json:
331
379
  return self._client._get(
332
380
  f"/city/{_seg(name)}/nearby",
333
- {"radius": radius, "unit": unit, "country": country, "state": state, "limit": limit},
381
+ {"radius": radius, "unit": unit, "country": country, "state": state, "limit": limit, "deep": deep},
334
382
  )
335
383
 
336
384
 
@@ -338,8 +386,11 @@ class _PostalSync:
338
386
  def __init__(self, client: ParseAPI):
339
387
  self._client = client
340
388
 
341
- def __call__(self, code: str, *, country: Optional[str] = None) -> Json:
342
- return self._client._get(f"/postal/{_seg(code)}", {"country": country})
389
+ def __call__(self, code: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
390
+ """Look up a postal area. Pass country when known. Check nullable coordinates before another
391
+ location lookup.
392
+ """
393
+ return self._client._get(f"/postal/{_seg(code)}", {"country": country, "deep": deep})
343
394
 
344
395
  def nearby(
345
396
  self,
@@ -348,19 +399,20 @@ class _PostalSync:
348
399
  country: Optional[str] = None,
349
400
  radius: Optional[float] = None,
350
401
  unit: Optional[str] = None,
402
+ deep: bool = False,
351
403
  ) -> Json:
352
- return self._client._get(f"/postal/{_seg(code)}/nearby", {"country": country, "radius": radius, "unit": unit})
404
+ return self._client._get(f"/postal/{_seg(code)}/nearby", {"country": country, "radius": radius, "unit": unit, "deep": deep})
353
405
 
354
- def distance(self, from_postal: str, to_postal: str, *, country: Optional[str] = None) -> Json:
355
- return self._client._get(f"/postal/{_seg(from_postal)}/distance/{_seg(to_postal)}", {"country": country})
406
+ def distance(self, from_postal: str, to_postal: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
407
+ return self._client._get(f"/postal/{_seg(from_postal)}/distance/{_seg(to_postal)}", {"country": country, "deep": deep})
356
408
 
357
409
 
358
410
  class _CurrencySync:
359
411
  def __init__(self, client: ParseAPI):
360
412
  self._client = client
361
413
 
362
- def __call__(self, code: str) -> Json:
363
- return self._client._get(f"/currency/{_seg(code)}")
414
+ def __call__(self, code: str, *, deep: bool = False) -> Json:
415
+ return self._client._get(f"/currency/{_seg(code)}", {"deep": deep})
364
416
 
365
417
  def rate(
366
418
  self, base: str, quote_currency: str, *, date: Optional[str] = None, amount: Optional[float] = None
@@ -385,11 +437,24 @@ class _EmojiSync:
385
437
  def __init__(self, client: ParseAPI):
386
438
  self._client = client
387
439
 
388
- def __call__(self, emoji: str) -> Json:
389
- return self._client._get(f"/emoji/{_seg(emoji)}")
440
+ def __call__(self, emoji: str, *, deep: bool = False) -> Json:
441
+ return self._client._get(f"/emoji/{_seg(emoji)}", {"deep": deep})
442
+
443
+ def search(self, query: str, *, limit: Optional[int] = None, deep: bool = False) -> Json:
444
+ return self._client._get("/emoji", {"q": query, "limit": limit, "deep": deep})
445
+
446
+
447
+ class _NaicsSync:
448
+ def __init__(self, client: ParseAPI):
449
+ self._client = client
450
+
451
+ def __call__(self, code: str, *, deep: bool = False) -> Json:
452
+ """Look up a US NAICS 2022 code and its hierarchy."""
453
+ return self._client._get(f"/naics/{_seg(code)}", {"deep": deep})
390
454
 
391
- def search(self, query: str, *, limit: Optional[int] = None) -> Json:
392
- return self._client._get("/emoji", {"q": query, "limit": limit})
455
+ def search(self, query: str, *, limit: Optional[int] = None, deep: bool = False) -> Json:
456
+ """Search industry keywords. Limit defaults to 10 and accepts 1-50."""
457
+ return self._client._get("/naics", {"q": query, "limit": limit, "deep": deep})
393
458
 
394
459
 
395
460
  class _TariffSync:
@@ -397,6 +462,10 @@ class _TariffSync:
397
462
  self._client = client
398
463
 
399
464
  def __call__(self, code: str, *, deep: bool = False, origin: Optional[str] = None) -> Json:
465
+ """Look up the general US duty schedule line. Paid deep adds units and the special and other
466
+ schedule columns. Add origin with deep to resolve country-specific measures. Without
467
+ origin, schedule detail remains available and origin-dependent fields are null. A null
468
+ effective rate is not a zero rate."""
400
469
  return self._client._get(f"/tariff/{_seg(code)}", {"deep": deep, "origin": origin})
401
470
 
402
471
  def search(self, query: str) -> Json:
@@ -432,8 +501,11 @@ class AsyncParseAPI:
432
501
  self.currency = _CurrencyAsync(self)
433
502
  self.holiday = _HolidayAsync(self)
434
503
  self.emoji = _EmojiAsync(self)
504
+ self.naics = _NaicsAsync(self)
435
505
  self.tariff = _TariffAsync(self)
436
506
  self.date = _DateAsync(self)
507
+ self.measure = _MeasureAsync(self)
508
+ self.time = _TimeAsync(self)
437
509
  self.timezone = _TimezoneAsync(self)
438
510
  self.address = _AddressAsync(self)
439
511
 
@@ -470,10 +542,14 @@ class AsyncParseAPI:
470
542
  continue
471
543
  raise _error_from(response)
472
544
 
473
- async def district(self, code: str, *, country: Optional[str] = None, state: Optional[str] = None) -> Json:
474
- return await self._get(f"/district/{_seg(code)}", {"country": country, "state": state})
545
+ async def district(self, code: str, *, country: Optional[str] = None, state: Optional[str] = None, deep: bool = False) -> Json:
546
+ return await self._get(f"/district/{_seg(code)}", {"country": country, "state": state, "deep": deep})
475
547
 
476
548
  async def email(self, email: str, *, deep: bool = False) -> Json:
549
+ """Parse an email and check its format and domain. Deep explicitly requests a metered
550
+ deliverability check. Deep checks use one attempt by default. An explicit retry
551
+ count can repeat paid usage.
552
+ """
477
553
  return await self._get(f"/email/{_seg(email)}", {"deep": deep})
478
554
 
479
555
  async def vat(
@@ -484,27 +560,46 @@ class AsyncParseAPI:
484
560
  deep: bool = False,
485
561
  from_vat: Optional[str] = None,
486
562
  ) -> Json:
563
+ """Check VAT format and checksum. Deep requests a metered registry check where supported. Deep
564
+ checks use one attempt by default. Supply your own VAT number for a consultation
565
+ reference when supported.
566
+ """
487
567
  return await self._get(f"/vat/{_seg(number)}", {"country": country, "deep": deep, "from": from_vat})
488
568
 
489
- async def iban(self, iban: str, *, country: Optional[str] = None) -> Json:
490
- return await self._get(f"/iban/{_seg(iban)}", {"country": country})
569
+ async def iban(self, iban: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
570
+ return await self._get(f"/iban/{_seg(iban)}", {"country": country, "deep": deep})
571
+
572
+ async def bin(self, bin: str, *, deep: bool = False) -> Json:
573
+ """Look up a 6-11 digit card prefix, preserving leading zeros."""
574
+ return await self._get(f"/bin/{_seg(bin)}", {"deep": deep})
491
575
 
492
576
  async def npi(self, npi: str, *, deep: bool = False) -> Json:
493
577
  return await self._get(f"/npi/{_seg(npi)}", {"deep": deep})
494
578
 
495
579
  async def phone(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
580
+ """Parse a phone number and its formats. Pass country for national numbers when needed. Deep
581
+ adds numbering-plan geography on every plan. Carrier, caller, and HLR are separate metered lookups.
582
+ """
496
583
  return await self._get(f"/phone/{_seg(number)}", {"country": country, "deep": deep})
497
584
 
498
- async def carrier(self, number: str, *, country: Optional[str] = None) -> Json:
499
- return await self._get(f"/carrier/{_seg(number)}", {"country": country})
585
+ async def carrier(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
586
+ """Request a metered carrier lookup. No automatic retries by default.
587
+ """
588
+ return await self._get(f"/carrier/{_seg(number)}", {"country": country, "deep": deep})
500
589
 
501
590
  async def caller(self, number: str, *, country: Optional[str] = None) -> Json:
591
+ """Request a metered caller-name lookup for a NANP number. No automatic retries by default.
592
+ """
502
593
  return await self._get(f"/caller/{_seg(number)}", {"country": country})
503
594
 
504
- async def hlr(self, number: str, *, country: Optional[str] = None) -> Json:
505
- return await self._get(f"/hlr/{_seg(number)}", {"country": country})
595
+ async def hlr(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
596
+ """Look up phone status at the last check. Live means assigned and connected means reachable
597
+ at that check. Cached results may be returned. Null means unconfirmed. Deep adds network
598
+ diagnostics within the same metered lookup. No automatic retries by default."""
599
+ return await self._get(f"/hlr/{_seg(number)}", {"country": country, "deep": deep})
506
600
 
507
601
  async def domain(self, domain: str, *, deep: bool = False) -> Json:
602
+ """Check whether a domain is registered. Deep adds registration dates, registrar, status and DNSSEC on paid plans."""
508
603
  return await self._get(f"/domain/{_seg(domain)}", {"deep": deep})
509
604
 
510
605
  async def asn(self, asn: str) -> Json:
@@ -513,6 +608,14 @@ class AsyncParseAPI:
513
608
  async def mac(self, mac: str) -> Json:
514
609
  return await self._get(f"/mac/{_seg(mac)}")
515
610
 
611
+ async def dns(self, domain: str, *, type: str | None = None) -> Json:
612
+ """Published DNS records with TTLs. Omit type to check all supported types.
613
+
614
+ Type selects the question and may include its CNAME chain. Values retain
615
+ DNS presentation syntax, including TXT quoting. Pooled on every plan.
616
+ """
617
+ return await self._get(f"/dns/{_seg(domain)}", {"type": type})
618
+
516
619
  async def mx(self, domain: str) -> Json:
517
620
  return await self._get(f"/mx/{_seg(domain)}")
518
621
 
@@ -525,19 +628,26 @@ class AsyncParseAPI:
525
628
  async def company(self, number: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
526
629
  return await self._get(f"/company/{_seg(number)}", {"country": country, "deep": deep})
527
630
 
528
- async def language(self, code: str) -> Json:
529
- return await self._get(f"/language/{_seg(code)}")
631
+ async def language(self, code: str, *, deep: bool = False) -> Json:
632
+ return await self._get(f"/language/{_seg(code)}", {"deep": deep})
530
633
 
531
- async def name(self, name: str) -> Json:
532
- return await self._get(f"/name/{_seg(name)}")
634
+ async def name(self, name: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
635
+ """Parse a name. Country is an ISO2 gender context, not nationality."""
636
+ return await self._get(f"/name/{_seg(name)}", {"country": country, "deep": deep})
533
637
 
534
638
  async def elevation(self, lat: float, lon: float) -> Json:
535
639
  return await self._get("/elevation", {"lat": lat, "lon": lon})
536
640
 
537
641
  async def point(self, lat: float, lon: float, *, deep: bool = False) -> Json:
642
+ """Resolve the country, state, district and timezone at coordinates. Deep adds terrain and
643
+ compact nearest-city context on every plan. The timezone ID stays in core. The nearest
644
+ city is null when none is within 200 km."""
538
645
  return await self._get("/point", {"lat": lat, "lon": lon, "deep": deep})
539
646
 
540
647
  async def weather(self, lat: float, lon: float, *, deep: bool = False, date: Optional[str] = None) -> Json:
648
+ """Get current conditions in metric and imperial units. Paid deep adds specialist current
649
+ measurements, forecasts and related detail. With deep, date selects a past UTC day (YYYY-
650
+ MM-DD) in deep.history alongside current conditions. Date alone does not request history."""
541
651
  return await self._get("/weather", {"lat": lat, "lon": lon, "deep": deep, "date": date})
542
652
 
543
653
 
@@ -546,9 +656,13 @@ class _IpAsync:
546
656
  self._client = client
547
657
 
548
658
  async def __call__(self, ip: str, *, deep: bool = False) -> Json:
659
+ """Look up an IP. Deep enrichment is included with a paid plan, without a separate check meter.
660
+ """
549
661
  return await self._client._get(f"/ip/{_seg(ip)}", {"deep": deep})
550
662
 
551
663
  async def self(self, *, deep: bool = False) -> Json:
664
+ """Look up the public IP making this request. On a server, this is the server's IP.
665
+ """
552
666
  return await self._client._get("/ip", {"deep": deep})
553
667
 
554
668
 
@@ -578,8 +692,8 @@ class _CountryAsync:
578
692
  def __init__(self, client: AsyncParseAPI):
579
693
  self._client = client
580
694
 
581
- async def __call__(self, code: str) -> Json:
582
- return await self._client._get(f"/country/{_seg(code)}")
695
+ async def __call__(self, code: str, *, deep: bool = False) -> Json:
696
+ return await self._client._get(f"/country/{_seg(code)}", {"deep": deep})
583
697
 
584
698
  async def states(self, code: str) -> Json:
585
699
  return await self._client._get(f"/country/{_seg(code)}/states")
@@ -589,22 +703,22 @@ class _StateAsync:
589
703
  def __init__(self, client: AsyncParseAPI):
590
704
  self._client = client
591
705
 
592
- async def __call__(self, code: str, *, country: Optional[str] = None) -> Json:
593
- return await self._client._get(f"/state/{_seg(code)}", {"country": country})
706
+ async def __call__(self, code: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
707
+ return await self._client._get(f"/state/{_seg(code)}", {"country": country, "deep": deep})
594
708
 
595
- async def districts(self, code: str, *, country: Optional[str] = None) -> Json:
596
- return await self._client._get(f"/state/{_seg(code)}/districts", {"country": country})
709
+ async def districts(self, code: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
710
+ return await self._client._get(f"/state/{_seg(code)}/districts", {"country": country, "deep": deep})
597
711
 
598
712
 
599
713
  class _CityAsync:
600
714
  def __init__(self, client: AsyncParseAPI):
601
715
  self._client = client
602
716
 
603
- async def __call__(self, name: str, *, country: Optional[str] = None, state: Optional[str] = None) -> Json:
604
- return await self._client._get(f"/city/{_seg(name)}", {"country": country, "state": state})
717
+ async def __call__(self, name: str, *, country: Optional[str] = None, state: Optional[str] = None, deep: bool = False) -> Json:
718
+ return await self._client._get(f"/city/{_seg(name)}", {"country": country, "state": state, "deep": deep})
605
719
 
606
- async def id(self, id: str) -> Json:
607
- return await self._client._get(f"/city/id/{_seg(id)}")
720
+ async def id(self, id: str, *, deep: bool = False) -> Json:
721
+ return await self._client._get(f"/city/id/{_seg(id)}", {"deep": deep})
608
722
 
609
723
  async def search(
610
724
  self,
@@ -613,11 +727,12 @@ class _CityAsync:
613
727
  country: Optional[str] = None,
614
728
  state: Optional[str] = None,
615
729
  limit: Optional[int] = None,
730
+ deep: bool = False,
616
731
  ) -> Json:
617
- return await self._client._get("/city", {"q": query, "country": country, "state": state, "limit": limit})
732
+ return await self._client._get("/city", {"q": query, "country": country, "state": state, "limit": limit, "deep": deep})
618
733
 
619
- async def nearest(self, lat: float, lon: float) -> Json:
620
- return await self._client._get("/city", {"lat": lat, "lon": lon})
734
+ async def nearest(self, lat: float, lon: float, *, deep: bool = False) -> Json:
735
+ return await self._client._get("/city", {"lat": lat, "lon": lon, "deep": deep})
621
736
 
622
737
  async def nearby(
623
738
  self,
@@ -628,10 +743,11 @@ class _CityAsync:
628
743
  country: Optional[str] = None,
629
744
  state: Optional[str] = None,
630
745
  limit: Optional[int] = None,
746
+ deep: bool = False,
631
747
  ) -> Json:
632
748
  return await self._client._get(
633
749
  f"/city/{_seg(name)}/nearby",
634
- {"radius": radius, "unit": unit, "country": country, "state": state, "limit": limit},
750
+ {"radius": radius, "unit": unit, "country": country, "state": state, "limit": limit, "deep": deep},
635
751
  )
636
752
 
637
753
 
@@ -639,8 +755,11 @@ class _PostalAsync:
639
755
  def __init__(self, client: AsyncParseAPI):
640
756
  self._client = client
641
757
 
642
- async def __call__(self, code: str, *, country: Optional[str] = None) -> Json:
643
- return await self._client._get(f"/postal/{_seg(code)}", {"country": country})
758
+ async def __call__(self, code: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
759
+ """Look up a postal area. Pass country when known. Check nullable coordinates before another
760
+ location lookup.
761
+ """
762
+ return await self._client._get(f"/postal/{_seg(code)}", {"country": country, "deep": deep})
644
763
 
645
764
  async def nearby(
646
765
  self,
@@ -649,21 +768,22 @@ class _PostalAsync:
649
768
  country: Optional[str] = None,
650
769
  radius: Optional[float] = None,
651
770
  unit: Optional[str] = None,
771
+ deep: bool = False,
652
772
  ) -> Json:
653
773
  return await self._client._get(
654
- f"/postal/{_seg(code)}/nearby", {"country": country, "radius": radius, "unit": unit}
774
+ f"/postal/{_seg(code)}/nearby", {"country": country, "radius": radius, "unit": unit, "deep": deep}
655
775
  )
656
776
 
657
- async def distance(self, from_postal: str, to_postal: str, *, country: Optional[str] = None) -> Json:
658
- return await self._client._get(f"/postal/{_seg(from_postal)}/distance/{_seg(to_postal)}", {"country": country})
777
+ async def distance(self, from_postal: str, to_postal: str, *, country: Optional[str] = None, deep: bool = False) -> Json:
778
+ return await self._client._get(f"/postal/{_seg(from_postal)}/distance/{_seg(to_postal)}", {"country": country, "deep": deep})
659
779
 
660
780
 
661
781
  class _CurrencyAsync:
662
782
  def __init__(self, client: AsyncParseAPI):
663
783
  self._client = client
664
784
 
665
- async def __call__(self, code: str) -> Json:
666
- return await self._client._get(f"/currency/{_seg(code)}")
785
+ async def __call__(self, code: str, *, deep: bool = False) -> Json:
786
+ return await self._client._get(f"/currency/{_seg(code)}", {"deep": deep})
667
787
 
668
788
  async def rate(
669
789
  self, base: str, quote_currency: str, *, date: Optional[str] = None, amount: Optional[float] = None
@@ -688,11 +808,24 @@ class _EmojiAsync:
688
808
  def __init__(self, client: AsyncParseAPI):
689
809
  self._client = client
690
810
 
691
- async def __call__(self, emoji: str) -> Json:
692
- return await self._client._get(f"/emoji/{_seg(emoji)}")
811
+ async def __call__(self, emoji: str, *, deep: bool = False) -> Json:
812
+ return await self._client._get(f"/emoji/{_seg(emoji)}", {"deep": deep})
813
+
814
+ async def search(self, query: str, *, limit: Optional[int] = None, deep: bool = False) -> Json:
815
+ return await self._client._get("/emoji", {"q": query, "limit": limit, "deep": deep})
816
+
817
+
818
+ class _NaicsAsync:
819
+ def __init__(self, client: AsyncParseAPI):
820
+ self._client = client
821
+
822
+ async def __call__(self, code: str, *, deep: bool = False) -> Json:
823
+ """Look up a US NAICS 2022 code and its hierarchy."""
824
+ return await self._client._get(f"/naics/{_seg(code)}", {"deep": deep})
693
825
 
694
- async def search(self, query: str, *, limit: Optional[int] = None) -> Json:
695
- return await self._client._get("/emoji", {"q": query, "limit": limit})
826
+ async def search(self, query: str, *, limit: Optional[int] = None, deep: bool = False) -> Json:
827
+ """Search industry keywords. Limit defaults to 10 and accepts 1-50."""
828
+ return await self._client._get("/naics", {"q": query, "limit": limit, "deep": deep})
696
829
 
697
830
 
698
831
  class _TariffAsync:
@@ -700,6 +833,10 @@ class _TariffAsync:
700
833
  self._client = client
701
834
 
702
835
  async def __call__(self, code: str, *, deep: bool = False, origin: Optional[str] = None) -> Json:
836
+ """Look up the general US duty schedule line. Paid deep adds units and the special and other
837
+ schedule columns. Add origin with deep to resolve country-specific measures. Without
838
+ origin, schedule detail remains available and origin-dependent fields are null. A null
839
+ effective rate is not a zero rate."""
703
840
  return await self._client._get(f"/tariff/{_seg(code)}", {"deep": deep, "origin": origin})
704
841
 
705
842
  async def search(self, query: str) -> Json:
@@ -710,33 +847,46 @@ class _DateSync:
710
847
  def __init__(self, client: ParseAPI):
711
848
  self._client = client
712
849
 
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})
850
+ def __call__(self, date: str, *, format: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
851
+ return self._client._get(f"/date/{_seg(date)}", {"format": format, "to": to, "deep": deep})
715
852
 
716
- def today(self, *, to: Optional[str] = None) -> Json:
717
- return self._client._get("/date", {"to": to})
853
+ def today(self, *, to: Optional[str] = None, deep: bool = False) -> Json:
854
+ return self._client._get("/date", {"to": to, "deep": deep})
718
855
 
719
856
 
720
857
  class _DateAsync:
721
858
  def __init__(self, client: AsyncParseAPI):
722
859
  self._client = client
723
860
 
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})
861
+ async def __call__(self, date: str, *, format: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
862
+ return await self._client._get(f"/date/{_seg(date)}", {"format": format, "to": to, "deep": deep})
863
+
864
+ async def today(self, *, to: Optional[str] = None, deep: bool = False) -> Json:
865
+ return await self._client._get("/date", {"to": to, "deep": deep})
866
+
867
+
868
+ class _TimeSync:
869
+ def __init__(self, client: ParseAPI):
870
+ self._client = client
726
871
 
727
- async def today(self, *, to: Optional[str] = None) -> Json:
728
- return await self._client._get("/date", {"to": to})
872
+ def __call__(self, timezone: Optional[str] = None, *, at: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
873
+ """Current local time, UTC by default. With to, offsetless at is source wall time."""
874
+ path = "/time" if timezone is None else f"/time/{_seg(timezone)}"
875
+ return self._client._get(path, {"at": at, "to": to, "deep": deep})
876
+
877
+ def at(self, lat: float, lon: float, *, at: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
878
+ return self._client._get("/time", {"lat": lat, "lon": lon, "at": at, "to": to, "deep": deep})
729
879
 
730
880
 
731
881
  class _TimezoneSync:
732
882
  def __init__(self, client: ParseAPI):
733
883
  self._client = client
734
884
 
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})
885
+ def __call__(self, id: str, *, at: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
886
+ return self._client._get(f"/timezone/{_seg(id)}", {"at": at, "to": to, "deep": deep})
737
887
 
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})
888
+ def at(self, lat: float, lon: float, *, at: Optional[str] = None, deep: bool = False) -> Json:
889
+ return self._client._get("/timezone", {"lat": lat, "lon": lon, "at": at, "deep": deep})
740
890
 
741
891
 
742
892
  class _AddressSync:
@@ -748,18 +898,35 @@ class _AddressSync:
748
898
 
749
899
  def search(self, query: str, *, country: Optional[str] = None, postal: Optional[str] = None,
750
900
  city: Optional[str] = None, state: Optional[str] = None, ip: Optional[str] = None) -> Json:
901
+ """Find address suggestions using the context supplied. Prefer postal, or city and state,
902
+ from the form. ip is an optional end-user locality hint for server-side calls. An empty
903
+ result has reason more_input, missing_context or no_matches. Suggestions have reason null.
904
+ Operational failures are errors."""
751
905
  return self._client._get("/address", {"q": query, "country": country, "postal": postal, "city": city, "state": state, "ip": ip})
752
906
 
753
907
 
908
+ class _TimeAsync:
909
+ def __init__(self, client: AsyncParseAPI):
910
+ self._client = client
911
+
912
+ async def __call__(self, timezone: Optional[str] = None, *, at: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
913
+ """Current local time, UTC by default. With to, offsetless at is source wall time."""
914
+ path = "/time" if timezone is None else f"/time/{_seg(timezone)}"
915
+ return await self._client._get(path, {"at": at, "to": to, "deep": deep})
916
+
917
+ async def at(self, lat: float, lon: float, *, at: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
918
+ return await self._client._get("/time", {"lat": lat, "lon": lon, "at": at, "to": to, "deep": deep})
919
+
920
+
754
921
  class _TimezoneAsync:
755
922
  def __init__(self, client: AsyncParseAPI):
756
923
  self._client = client
757
924
 
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})
925
+ async def __call__(self, id: str, *, at: Optional[str] = None, to: Optional[str] = None, deep: bool = False) -> Json:
926
+ return await self._client._get(f"/timezone/{_seg(id)}", {"at": at, "to": to, "deep": deep})
760
927
 
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})
928
+ async def at(self, lat: float, lon: float, *, at: Optional[str] = None, deep: bool = False) -> Json:
929
+ return await self._client._get("/timezone", {"lat": lat, "lon": lon, "at": at, "deep": deep})
763
930
 
764
931
 
765
932
  class _AddressAsync:
@@ -771,4 +938,40 @@ class _AddressAsync:
771
938
 
772
939
  async def search(self, query: str, *, country: Optional[str] = None, postal: Optional[str] = None,
773
940
  city: Optional[str] = None, state: Optional[str] = None, ip: Optional[str] = None) -> Json:
941
+ """Find address suggestions using the context supplied. Prefer postal, or city and state,
942
+ from the form. ip is an optional end-user locality hint for server-side calls. An empty
943
+ result has reason more_input, missing_context or no_matches. Suggestions have reason null.
944
+ Operational failures are errors."""
774
945
  return await self._client._get("/address", {"q": query, "country": country, "postal": postal, "city": city, "state": state, "ip": ip})
946
+
947
+
948
+ class _MeasureSync:
949
+ def __init__(self, client: ParseAPI):
950
+ self._client = client
951
+
952
+ def __call__(self, measure: str, *, to: Optional[str] = None, locale: Optional[str] = None, system: Optional[str] = None) -> Json:
953
+ """Parse or convert a measurement. Amount is a decimal string. Without to, use the
954
+ type's canonical unit. Locale and system (us or imperial) resolve explicit ambiguity.
955
+ Invalid measurements return valid=False and a reason. Invalid targets raise an API error.
956
+ """
957
+ return self._client._get(f"/measure/{_seg(measure)}", {"to": to, "locale": locale, "system": system})
958
+
959
+ def units(self, *, query: Optional[str] = None, type: Optional[str] = None, unit: Optional[str] = None) -> Json:
960
+ """Discover reviewed units. unit filters compatible conversion targets."""
961
+ return self._client._get("/measure/units", {"q": query, "type": type, "unit": unit})
962
+
963
+
964
+ class _MeasureAsync:
965
+ def __init__(self, client: AsyncParseAPI):
966
+ self._client = client
967
+
968
+ async def __call__(self, measure: str, *, to: Optional[str] = None, locale: Optional[str] = None, system: Optional[str] = None) -> Json:
969
+ """Parse or convert a measurement. Amount is a decimal string. Without to, use the
970
+ type's canonical unit. Locale and system (us or imperial) resolve explicit ambiguity.
971
+ Invalid measurements return valid=False and a reason. Invalid targets raise an API error.
972
+ """
973
+ return await self._client._get(f"/measure/{_seg(measure)}", {"to": to, "locale": locale, "system": system})
974
+
975
+ async def units(self, *, query: Optional[str] = None, type: Optional[str] = None, unit: Optional[str] = None) -> Json:
976
+ """Discover reviewed units. unit filters compatible conversion targets."""
977
+ return await self._client._get("/measure/units", {"q": query, "type": type, "unit": unit})
@@ -0,0 +1,272 @@
1
+ Metadata-Version: 2.5
2
+ Name: parseapi
3
+ Version: 0.4.0
4
+ Summary: Official ParseAPI client for Python. One key, minimal JSON, fast.
5
+ Project-URL: Homepage, https://parseapi.com
6
+ Project-URL: Documentation, https://parseapi.com/docs
7
+ Project-URL: Repository, https://github.com/parseapi/python
8
+ Author-email: ParseAPI <hello@parseapi.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: currency,email validation,geolocation,ip,parseapi,phone validation,postal,timezone,weather
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Libraries
16
+ Requires-Python: >=3.9
17
+ Requires-Dist: httpx>=0.24
18
+ Description-Content-Type: text/markdown
19
+
20
+ # parseapi
21
+
22
+ Official ParseAPI client for Python.
23
+
24
+ ```bash
25
+ pip install parseapi
26
+ ```
27
+
28
+ ```python
29
+ from parseapi import ParseAPI
30
+
31
+ parse = ParseAPI("your-api-key")
32
+ country = parse.country("US")
33
+ ```
34
+
35
+ Get a key at [parseapi.com](https://parseapi.com). The client also reads `PARSEAPI_KEY` from the environment.
36
+
37
+ ## API versions
38
+
39
+ Choose your team's API version in [Dashboard → API version](https://parseapi.com/dashboard/versions). One setting applies to every key, including new and replacement keys. Existing teams keep `1.0.0`; new teams start on `2.0.0`. Keep the same keys and lookup URLs. Installing or upgrading the package does not change the team's setting.
40
+
41
+ Published SDK `0.3.2` matches API `1.0.0`. The examples and response types in this source tree target API `2.0.0`, including changes that are not in `0.3.2`. Use a package release documented for your team's version. These types do not model every historical response; moving to `2.0.0` may require updating code that reads renamed, moved or removed fields.
42
+
43
+ Test the target contract in a separate development team before changing your production team's version. A change applies to every integration in that team. See [API versions and migration](https://parseapi.com/docs/versioning).
44
+
45
+ ## Weather from a postal code
46
+
47
+ Start with the postal code, then pass its coordinates to weather. Reuse the client from the example above.
48
+
49
+ ```python
50
+ place = parse.postal("28202", country="US")
51
+ lat, lon = place["latitude"], place["longitude"]
52
+ if lat is not None and lon is not None:
53
+ weather = parse.weather(lat, lon)
54
+ print(weather)
55
+ ```
56
+
57
+ The coordinates represent the postal area. Weather is for that point. Missing coordinates skip the weather lookup. This composition performs two ordinary lookups when coordinates are available, with the retry policy below.
58
+
59
+ ## Supply the context you know
60
+
61
+ Pass `country` when a postal code or national phone number needs disambiguation. A complete international phone number already carries its country context. For a numeric date such as `03/04/2026`, supply the intended `format`. Defaults resolve what the input establishes. Ambiguous input needs your context.
62
+
63
+ Results are plain data. Pass a returned code or coordinate to another operation when the task needs it. Check nullable values before composing the next call.
64
+
65
+ Use `parse.postal("28202", country="US", deep=True)` for US ZIP tax references. `deep.tax` names the levy and `deep.tax_rate` is a percentage, so `7.9` means 7.9%. The state, county, city and special components explain that combined rate. An exact address can differ. Country and state lookups provide their own geographic reference rates, which should not be added to the ZIP rate. `None` means unknown and `0` means known zero. Country `deep.tax_id_format` and `deep.tax_id_regex` describe registration-number format only. Use `vat` for a metered registration check with `deep` explicitly enabled.
66
+
67
+ ## Calls
68
+
69
+ One method per endpoint, named after the route.
70
+
71
+ ```python
72
+ parse.ip("8.8.8.8")
73
+ parse.ip.self()
74
+ parse.email("hello@gmail.com")
75
+ parse.vat("DE136695976")
76
+ parse.iban("DE89370400440532013000")
77
+ parse.bin("424242")
78
+ parse.npi("1881018208")
79
+ parse.phone("+14155552671")
80
+ parse.carrier("+14155552671")
81
+ parse.caller("+14155552671")
82
+ parse.hlr("+14155552671")
83
+ parse.postal("SW1A 1AA")
84
+ parse.postal("28202", country="US")
85
+ parse.postal.nearby("28202", country="US", radius=40)
86
+ parse.postal.distance("28202", "10001", country="US")
87
+ parse.address("1600 Pennsylvania Ave NW, Washington DC", country="US")
88
+ parse.address.search("1600 Pennsylvania", country="US", postal="20500")
89
+ parse.company("51 824 753 556", country="AU")
90
+ parse.city("charlotte", country="US")
91
+ parse.city.id("city_mb8mbqrkz8zb")
92
+ parse.city.search("char", country="US", limit=10)
93
+ parse.city.nearest(35.2271, -80.8431)
94
+ parse.city.nearby("denver", radius=8, unit="mi")
95
+ parse.country("US")
96
+ parse.country.states("US")
97
+ parse.state("colorado")
98
+ parse.state("NC", country="US")
99
+ parse.state.districts("NC", country="US")
100
+ parse.district("37081")
101
+ parse.continent("NA")
102
+ parse.continent.countries("NA")
103
+ parse.bloc("EU")
104
+ parse.bloc.countries("EU")
105
+ parse.currency("USD")
106
+ parse.currency.rate("USD", "EUR")
107
+ parse.language("en")
108
+ parse.name("BILLY OSHALL")
109
+ parse.name("Andrea", country="IT", deep=True)
110
+ parse.time() # UTC now
111
+ parse.time("America/New_York")
112
+ parse.time("America/New_York", at="2026-09-05T15:00:00", to="Europe/London")
113
+ parse.time.at(39.77, -104.9)
114
+ parse.date("03/04/2026", format="mdy")
115
+ parse.date.today()
116
+ parse.holiday("US", year=2026)
117
+ parse.holiday.date("US", "2026-12-25")
118
+ parse.elevation(35.2271, -80.8431)
119
+ parse.point(36.0726, -79.792)
120
+ parse.weather(40.7128, -74.006)
121
+ parse.domain("example.com")
122
+ parse.asn("AS13335")
123
+ parse.mac("00:1B:63:84:45:E6")
124
+ parse.mx("example.com")
125
+ parse.dns("example.com")
126
+ parse.dns("_dmarc.example.com", type="TXT")
127
+ parse.useragent(ua_string)
128
+ parse.vin("1HGCM82633A004352")
129
+ parse.naics("541511")
130
+ parse.naics.search("coffee shop", limit=5)
131
+ parse.tariff("8471.30.01.00")
132
+ parse.tariff.search("sunglasses")
133
+ parse.emoji("rocket")
134
+ parse.emoji.search("fire")
135
+ ```
136
+
137
+ NAICS paid deep records include classification `deep.exclusions`, each with a description and linked codes. Generic exclusions can have no linked codes. Omitted or null exclusions in older responses remain unknown. Search results also include `match`: the matched `field` (`name`, `term` or `naics`) and `text`, plus `corrections` with `from` and `to` tokens for typo fallback. Corrections are empty for exact, plural and prefix matches. Direct code lookups omit `match`. Older responses may omit it.
138
+
139
+ 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.
140
+
141
+ DNS uses pooled requests on every plan. Omit `type` to check A, AAAA, CNAME, MX, NS, TXT, SOA, CAA, SRV and PTR. Records contain `name`, `type`, `ttl` in seconds and a DNS presentation `value`. TXT values retain quoting and chunk boundaries. A selected question can include its CNAME chain. Empty records mean no records. Lookup failures remain errors.
142
+
143
+ ## Async
144
+
145
+ Same lookup methods and keyword arguments, with `await`. Use a context manager to close the client when the work is done.
146
+
147
+ ```python
148
+ from parseapi import AsyncParseAPI
149
+
150
+ async with AsyncParseAPI("your-api-key") as parse:
151
+ country = await parse.country("US")
152
+ ```
153
+
154
+ ## Time
155
+
156
+ `time` returns local ISO `at` with its UTC offset and integer Unix seconds in `unix`. The core `offset` preserves exact precision. Optional `deep.offset_seconds` gives the numeric offset, while `deep.offset_minutes` gives whole minutes. Historical offsets and ISO times can include offset seconds. Omitted `at` means now. With `to`, an offsetless `at` is source wall time. Otherwise it is UTC. Include an offset for repeated local times around a clock change. Current time and conversion use pooled requests on every plan. Coordinate clock fields can be null when the timezone is unknown. Existing `timezone` methods remain supported.
157
+
158
+ ## Measurements
159
+
160
+ ```python
161
+ result = parse.measure("5 ft 11 in", to="cm")
162
+ units = parse.measure.units(unit="m")
163
+ ```
164
+
165
+ `amount` is a decimal string, such as `"180.34"`. Without `to`, the API returns the canonical unit for the measurement type. Pass `locale` for number formatting and `system` (`us` or `imperial`) when a customary unit needs context. Ambiguous input returns `valid: false`, a `reason`, and available `choices`. Invalid or incompatible target units use the normal API error.
166
+
167
+ Unit discovery accepts optional `query`, `type`, and `unit` filters. `unit` selects compatible targets. Omit the filters for the reviewed catalog. Both operations use pooled requests.
168
+
169
+ ## Place statistics and optional detail
170
+
171
+ Postal and District paid profiles include `deep.property_tax` where supported. It contains `annual_median`, `currency` and `period`: median annual property tax payable on owner-occupied homes in the statistical area. The amount is adjusted to the final year of the reporting period (`YYYY-YYYY`). This is an area statistic, not a rate or an individual property bill. Unsupported, missing and censored estimates are null.
172
+
173
+ ```python
174
+ place = parse.postal("28202", country="US", deep=True)
175
+ property_tax = (place.get("deep") or {}).get("property_tax")
176
+ ```
177
+
178
+ Read `population_period` alongside `population`: a reporting year (`YYYY`) or period (`YYYY-YYYY`), null when unknown or unverifiable. Keep missing or null values unknown and preserve a known zero. These fields belong to full place profiles. State district lists include each district's population and period. Postal nearby and distance detail remains metropolitan associations only. Continent population and its period remain in core.
179
+
180
+ Point returns the timezone ID with the core location. Its optional deep detail adds terrain and compact nearest-city context on every plan. A nearest city is null when none is within 200 km.
181
+
182
+ Weather returns current conditions by default. Paid deep adds specialist current measurements, forecasts and related detail. A past `date` is a UTC day and requires deep: it adds `deep.history` alongside current conditions. Date alone does not request history.
183
+
184
+ ```python
185
+ parse.weather(40.7128, -74.006, deep=True, date="2026-08-15")
186
+ ```
187
+
188
+ Tariff starts with the general schedule line. Paid deep adds units and the special and other schedule columns. An optional origin then resolves country-specific measures. The three calls below show those successive choices. Without origin, schedule detail is still returned and origin-dependent fields are null. A null effective rate is not a zero rate.
189
+
190
+ ```python
191
+ parse.tariff("8471.30.01.00")
192
+ parse.tariff("8471.30.01.00", deep=True)
193
+ parse.tariff("8471.30.01.00", deep=True, origin="CN")
194
+ ```
195
+
196
+ Address search uses context from the form: prefer postal, or city and state. An optional end-user `ip` is a locality hint for server-side calls. An empty result explains itself with `reason`: `more_input`, `missing_context` or `no_matches`. With suggestions, reason is null. Older responses may omit it, and future reasons remain strings. Catalog and lookup failures use the existing API errors.
197
+
198
+ HLR reports status at the last check. `live` means assigned and `connected` means reachable at that check. Cached results may be returned. Null means unconfirmed. Deep diagnostics stay within the same metered lookup.
199
+
200
+ ## Deep
201
+
202
+ Choose enrichment for the question you need answered.
203
+
204
+ | Operation | What `deep` requests |
205
+ |---|---|
206
+ | IP | Richer IP fields included with a paid plan. No separate check meter. |
207
+ | Domain | Registration dates, registrar, status and DNSSEC, included with a paid plan. Use `dns` for DNS records and `mx` for mail routing. |
208
+ | Email | A metered deliverability check, using included email checks or enabled on-demand usage. |
209
+ | VAT | A metered registry check where supported, using included VAT checks or enabled on-demand usage. |
210
+ | Phone, Time, Date, Currency, Language, Emoji, IBAN, Point | Optional detail in the same pooled request on every plan. |
211
+ | Country, State, District, City, Postal | The place profile on paid plans, including demographic and tax facts where held. |
212
+ | Name, NAICS | Name evidence or the industry definition profile on paid plans. |
213
+ | VIN, NPI, Tariff, Company | The complete product detail bag on paid plans. |
214
+ | Weather | Specialist current measurements and the existing forecast, alert, air and history bag on paid plans. |
215
+ | Carrier, HLR | Optional diagnostic detail within the same metered core unit, including Free allowance units. No second gate or additional check. |
216
+
217
+ Carrier, caller, and HLR are separate metered operations. Choose them explicitly when you need their answers. Ordinary lookups retry twice by default. Metered checks use one attempt by default. Setting retries explicitly can repeat paid usage.
218
+
219
+ Without `deep`, the response omits that key. When requested, it is an empty object if access is locked or the operation has no deep fields. Otherwise it contains the available fields. A missing or null field means unknown.
220
+
221
+ ```python
222
+ ip = parse.ip("52.94.76.10", deep=True)
223
+ ip.get("deep", {}).get("datacenter") # True, False, or None
224
+ ```
225
+
226
+ ## Errors
227
+
228
+ Every non-2xx response raises `ParseAPIError` with `status`, `code`, `docs`, and `request_id`. Branch on `code`.
229
+
230
+ ```python
231
+ from parseapi import ParseAPIError
232
+
233
+ try:
234
+ parse.city("atlantis")
235
+ except ParseAPIError as err:
236
+ if err.code == "not_found":
237
+ ... # no such city
238
+ ```
239
+
240
+ Network and decoding failures keep their native error types. Responses such as `valid: false` are successful API answers, not exceptions.
241
+
242
+ ## Options
243
+
244
+ ```python
245
+ parse = ParseAPI(
246
+ "your-api-key",
247
+ timeout=10.0, # timeout for each connect, read, write, or pool phase
248
+ )
249
+ ```
250
+
251
+ Requires Python 3.9 or later. One dependency (httpx).
252
+
253
+ 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.
254
+
255
+ 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.
256
+
257
+ ## Docs
258
+
259
+ Full field reference for every endpoint: [parseapi.com/docs](https://parseapi.com/docs)
260
+
261
+ BIN lookup accepts 6-11 digits as a string, including leading zeros. Spaces and hyphens are accepted. `prefix` is the actual longest match and can be shorter than the input. Unknown reference fields are null. `deep` adds an empty object on every plan.
262
+
263
+
264
+ ## Optional detail
265
+
266
+ The default response answers the common task. Ask for `deep` when you need more detail about that same result. Core fields stay equal. City, NAICS and Emoji searches put detail inside each result. Postal nearby and distance put metropolitan detail beside the entity it describes. Time conversion keeps target detail in `to.deep`; only the source has `deep.next_dst`.
267
+
268
+ ```python
269
+ basic = parse.time("America/New_York")
270
+ detail = parse.time("America/New_York", deep=True)
271
+ print(basic["at"], detail.get("deep", {}).get("next_dst"))
272
+ ```
@@ -0,0 +1,7 @@
1
+ parseapi/__init__.py,sha256=SId1i8NW8kO5uuh4j-UeLcd2Smo6luEYiOdYWPiioZQ,199
2
+ parseapi/_client.py,sha256=yfQCvENzLFIQ2WJjOPZHUeSSC6D7jaL_HtOYCtXAxVU,42523
3
+ parseapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ parseapi-0.4.0.dist-info/METADATA,sha256=GlA4b9aLP-83ZIFtqQmD93LHUX1xy8PawCkdmw2kVeM,15212
5
+ parseapi-0.4.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
6
+ parseapi-0.4.0.dist-info/licenses/LICENSE,sha256=3IF5YNQQ6vF8sAs9hGRcovgEetJuzSwKqoE1TXLMoRs,1065
7
+ parseapi-0.4.0.dist-info/RECORD,,
@@ -1,155 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: parseapi
3
- Version: 0.3.2
4
- Summary: Official ParseAPI client for Python. One key, minimal JSON, fast.
5
- Project-URL: Homepage, https://parseapi.com
6
- Project-URL: Documentation, https://parseapi.com/docs
7
- Project-URL: Repository, https://github.com/parseapi/python
8
- Author-email: ParseAPI <hello@parseapi.com>
9
- License-Expression: MIT
10
- License-File: LICENSE
11
- Keywords: currency,email validation,geolocation,ip,parseapi,phone validation,postal,timezone,weather
12
- Classifier: Development Status :: 4 - Beta
13
- Classifier: Intended Audience :: Developers
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Topic :: Software Development :: Libraries
16
- Requires-Python: >=3.9
17
- Requires-Dist: httpx>=0.24
18
- Description-Content-Type: text/markdown
19
-
20
- # parseapi
21
-
22
- Official ParseAPI client for Python.
23
-
24
- ```bash
25
- pip install parseapi
26
- ```
27
-
28
- ```python
29
- from parseapi import ParseAPI
30
-
31
- parse = ParseAPI("your-api-key")
32
- country = parse.country("US")
33
- ```
34
-
35
- Get a key at [parseapi.com](https://parseapi.com). The client also reads `PARSEAPI_KEY` from the environment.
36
-
37
- ## Calls
38
-
39
- One method per endpoint, named after the route.
40
-
41
- ```python
42
- parse.ip("8.8.8.8")
43
- parse.ip.self()
44
- parse.email("hello@gmail.com")
45
- parse.vat("DE136695976")
46
- parse.iban("DE89370400440532013000")
47
- parse.npi("1881018208")
48
- parse.phone("+14155552671")
49
- parse.carrier("+14155552671")
50
- parse.caller("+14155552671")
51
- parse.hlr("+14155552671")
52
- parse.postal("SW1A 1AA")
53
- parse.postal("28202", country="US")
54
- parse.postal.nearby("28202", country="US", radius=40)
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")
59
- parse.city("charlotte", country="US")
60
- parse.city.id("city_mb8mbqrkz8zb")
61
- parse.city.search("char", country="US", limit=10)
62
- parse.city.nearest(35.2271, -80.8431)
63
- parse.city.nearby("denver", radius=8, unit="mi")
64
- parse.country("US")
65
- parse.country.states("US")
66
- parse.state("colorado")
67
- parse.state("NC", country="US")
68
- parse.state.districts("NC", country="US")
69
- parse.district("37081")
70
- parse.continent("NA")
71
- parse.continent.countries("NA")
72
- parse.bloc("EU")
73
- parse.bloc.countries("EU")
74
- parse.currency("USD")
75
- parse.currency.rate("USD", "EUR")
76
- parse.language("en")
77
- parse.name("BILLY OSHALL")
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()
83
- parse.holiday("US", year=2026)
84
- parse.holiday.date("US", "2026-12-25")
85
- parse.elevation(35.2271, -80.8431)
86
- parse.point(36.0726, -79.792)
87
- parse.weather(40.7128, -74.006)
88
- parse.domain("example.com")
89
- parse.asn("AS13335")
90
- parse.mac("00:1B:63:84:45:E6")
91
- parse.mx("example.com")
92
- parse.useragent(ua_string)
93
- parse.vin("1HGCM82633A004352")
94
- parse.tariff("8471.30.01.00")
95
- parse.tariff.search("sunglasses")
96
- parse.emoji("rocket")
97
- parse.emoji.search("fire")
98
- ```
99
-
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.
101
-
102
- ## Async
103
-
104
- Same lookup methods and keyword arguments, with `await`. Use a context manager to close the client when the work is done.
105
-
106
- ```python
107
- from parseapi import AsyncParseAPI
108
-
109
- async with AsyncParseAPI("your-api-key") as parse:
110
- country = await parse.country("US")
111
- ```
112
-
113
- ## Deep
114
-
115
- Pass `deep=True` to include the nested `deep` object with richer fields.
116
-
117
- ```python
118
- ip = parse.ip("52.94.76.10", deep=True)
119
- ip["deep"]["datacenter"] # True
120
- ```
121
-
122
- ## Errors
123
-
124
- Every non-2xx response raises `ParseAPIError` with `status`, `code`, `docs`, and `request_id`. Branch on `code`.
125
-
126
- ```python
127
- from parseapi import ParseAPIError
128
-
129
- try:
130
- parse.city("atlantis")
131
- except ParseAPIError as err:
132
- if err.code == "not_found":
133
- ... # no such city
134
- ```
135
-
136
- Network and decoding failures keep their native error types. Responses such as `valid: false` are successful API answers, not exceptions.
137
-
138
- ## Options
139
-
140
- ```python
141
- parse = ParseAPI(
142
- "your-api-key",
143
- timeout=10.0, # timeout for each connect, read, write, or pool phase
144
- )
145
- ```
146
-
147
- Requires Python 3.9 or later. One dependency (httpx).
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
-
153
- ## Docs
154
-
155
- Full field reference for every endpoint: [parseapi.com/docs](https://parseapi.com/docs)
@@ -1,7 +0,0 @@
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,,