prismadata 0.7.0__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {prismadata-0.7.0 → prismadata-0.8.0}/PKG-INFO +1 -1
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/__init__.py +10 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_constants.py +3 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_types.py +87 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_validation.py +41 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/async_client.py +158 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/client.py +164 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/pyproject.toml +1 -1
- {prismadata-0.7.0 → prismadata-0.8.0}/LICENSE +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/README.md +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_async_auth.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_async_http.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_auth.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_batch.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_cache.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_columns.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_enrich.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_http.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_prepare.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/_progress.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/exceptions.py +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/py.typed +0 -0
- {prismadata-0.7.0 → prismadata-0.8.0}/prismadata/sklearn.py +0 -0
|
@@ -17,6 +17,11 @@ Async usage::
|
|
|
17
17
|
|
|
18
18
|
from ._types import (
|
|
19
19
|
BorderResult,
|
|
20
|
+
CnpjEnrichedResult,
|
|
21
|
+
CnpjMetadataRawResult,
|
|
22
|
+
CnpjMetadataResult,
|
|
23
|
+
CnpjRawResult,
|
|
24
|
+
CnpjResult,
|
|
20
25
|
CommercialClusterResult,
|
|
21
26
|
GeocodeResult,
|
|
22
27
|
IncomePdfResult,
|
|
@@ -77,6 +82,11 @@ __all__ = [
|
|
|
77
82
|
"RateLimitError",
|
|
78
83
|
"ValidationError",
|
|
79
84
|
"BorderResult",
|
|
85
|
+
"CnpjEnrichedResult",
|
|
86
|
+
"CnpjMetadataRawResult",
|
|
87
|
+
"CnpjMetadataResult",
|
|
88
|
+
"CnpjRawResult",
|
|
89
|
+
"CnpjResult",
|
|
80
90
|
"CommercialClusterResult",
|
|
81
91
|
"GeocodeResult",
|
|
82
92
|
"IncomePdfResult",
|
|
@@ -138,6 +138,93 @@ class QuotaInfo(TypedDict, total=False):
|
|
|
138
138
|
reset: int
|
|
139
139
|
|
|
140
140
|
|
|
141
|
+
class CnpjResult(TypedDict, total=False):
|
|
142
|
+
"""Response from ``cnpj()`` — flat shape (49 scalar keys).
|
|
143
|
+
|
|
144
|
+
Full field list at https://docs.prismadata.io/cnpj. Categoria prefix is
|
|
145
|
+
``pessoa_juridica`` (to avoid ``prismadata__cnpj__cnpj`` collisions).
|
|
146
|
+
"""
|
|
147
|
+
prismadata__pessoa_juridica__cnpj: str
|
|
148
|
+
prismadata__pessoa_juridica__cnpj_basico: str
|
|
149
|
+
prismadata__pessoa_juridica__razao_social: str
|
|
150
|
+
prismadata__pessoa_juridica__nome_fantasia: str
|
|
151
|
+
prismadata__pessoa_juridica__situacao_cadastral: str
|
|
152
|
+
prismadata__pessoa_juridica__data_abertura: str
|
|
153
|
+
prismadata__pessoa_juridica__natureza_juridica_codigo: str
|
|
154
|
+
prismadata__pessoa_juridica__natureza_juridica_descricao: str
|
|
155
|
+
prismadata__pessoa_juridica__porte: str
|
|
156
|
+
prismadata__pessoa_juridica__capital_social: str
|
|
157
|
+
prismadata__pessoa_juridica__cnae_principal_codigo: str
|
|
158
|
+
prismadata__pessoa_juridica__cnae_principal_descricao: str
|
|
159
|
+
prismadata__pessoa_juridica__cnae_secundario_1: str
|
|
160
|
+
prismadata__pessoa_juridica__cnae_secundario_2: str
|
|
161
|
+
prismadata__pessoa_juridica__cnae_secundario_3: str
|
|
162
|
+
prismadata__pessoa_juridica__total_cnaes_secundarios: int
|
|
163
|
+
prismadata__pessoa_juridica__logradouro: str
|
|
164
|
+
prismadata__pessoa_juridica__numero: str
|
|
165
|
+
prismadata__pessoa_juridica__bairro: str
|
|
166
|
+
prismadata__pessoa_juridica__municipio_nome: str
|
|
167
|
+
prismadata__pessoa_juridica__uf: str
|
|
168
|
+
prismadata__pessoa_juridica__cep: str
|
|
169
|
+
prismadata__pessoa_juridica__latitude: str
|
|
170
|
+
prismadata__pessoa_juridica__longitude: str
|
|
171
|
+
prismadata__pessoa_juridica__qualidade_geocodificacao_score: int
|
|
172
|
+
prismadata__pessoa_juridica__qualidade_geocodificacao_classificacao: str
|
|
173
|
+
prismadata__pessoa_juridica__total_socios: int
|
|
174
|
+
prismadata__pessoa_juridica__total_socios_pf: int
|
|
175
|
+
prismadata__pessoa_juridica__total_socios_pj: int
|
|
176
|
+
prismadata__pessoa_juridica__data_publicacao_rfb: str
|
|
177
|
+
prismadata__pessoa_juridica__data_processamento: str
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class CnpjRawResult(TypedDict, total=False):
|
|
181
|
+
"""Response from ``cnpj_raw()`` — F1 schema with nested ``socios`` list.
|
|
182
|
+
|
|
183
|
+
See https://docs.prismadata.io/cnpj.
|
|
184
|
+
"""
|
|
185
|
+
prismadata__pessoa_juridica__cnpj: str
|
|
186
|
+
prismadata__pessoa_juridica__razao_social: str
|
|
187
|
+
prismadata__pessoa_juridica__cnaes_secundarios: list[str]
|
|
188
|
+
prismadata__pessoa_juridica__socios: list[dict[str, Any]]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class CnpjMetadataResult(TypedDict, total=False):
|
|
192
|
+
"""Response from ``cnpj_metadata()`` — flat coverage buckets.
|
|
193
|
+
|
|
194
|
+
See https://docs.prismadata.io/cnpj.
|
|
195
|
+
"""
|
|
196
|
+
prismadata__pessoa_juridica__versao_dados: str
|
|
197
|
+
prismadata__pessoa_juridica__data_publicacao_rfb: str
|
|
198
|
+
prismadata__pessoa_juridica__data_processamento: str
|
|
199
|
+
prismadata__pessoa_juridica__total_cnpjs_carregados: int
|
|
200
|
+
prismadata__pessoa_juridica__cobertura_geo_muito_alta: int
|
|
201
|
+
prismadata__pessoa_juridica__cobertura_geo_alta: int
|
|
202
|
+
prismadata__pessoa_juridica__cobertura_geo_media: int
|
|
203
|
+
prismadata__pessoa_juridica__cobertura_geo_baixa: int
|
|
204
|
+
prismadata__pessoa_juridica__cobertura_geo_muito_baixa: int
|
|
205
|
+
prismadata__pessoa_juridica__cobertura_geo_falha: int
|
|
206
|
+
prismadata__pessoa_juridica__cobertura_geo_sem_geo: int
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class CnpjMetadataRawResult(TypedDict, total=False):
|
|
210
|
+
"""Response from ``cnpj_raw_metadata()`` — nested coverage dict."""
|
|
211
|
+
prismadata__pessoa_juridica__versao_dados: str
|
|
212
|
+
prismadata__pessoa_juridica__data_publicacao_rfb: str
|
|
213
|
+
prismadata__pessoa_juridica__data_processamento: str
|
|
214
|
+
prismadata__pessoa_juridica__total_cnpjs_carregados: int
|
|
215
|
+
prismadata__pessoa_juridica__cobertura_geo: dict[str, int]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class CnpjEnrichedResult(CnpjResult, total=False):
|
|
219
|
+
"""Response from ``cnpj_enriched()`` / values of ``cnpj_batch_enriched()``.
|
|
220
|
+
|
|
221
|
+
Extends :class:`CnpjResult` with keys from each active geo flag
|
|
222
|
+
(``prismadata__slum__*``, ``prismadata__border__*`` etc.). When the CNPJ
|
|
223
|
+
has no lat/lng the geo pillars are silently skipped — only the 49
|
|
224
|
+
``pessoa_juridica`` keys are returned. See https://docs.prismadata.io/cnpj.
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
|
|
141
228
|
class TipologiaResult(TypedDict, total=False):
|
|
142
229
|
"""Response from ``tipologia()`` (coordinate-based lookup).
|
|
143
230
|
|
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import re
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
7
8
|
_VALID_PROFILES = {"car", "foot", "bike"}
|
|
8
9
|
|
|
10
|
+
_CNPJ_NON_ALNUM = re.compile(r"[^A-Za-z0-9]")
|
|
11
|
+
_CNPJ_BODY_PATTERN = re.compile(r"^[A-Z0-9]{12}$")
|
|
12
|
+
_CNPJ_DV_WEIGHTS_1 = (5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
|
|
13
|
+
_CNPJ_DV_WEIGHTS_2 = (6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
|
|
14
|
+
|
|
9
15
|
_RANKING_SCOPE = {"national": "nacional", "state": "uf", "city": "municipio"}
|
|
10
16
|
_RANKING_CRITERION = {"score": "score", "pdvs": "pdvs", "density": "densidade"}
|
|
11
17
|
_SEARCH_FILTER_KEYS = {
|
|
@@ -46,6 +52,41 @@ def validate_route_points(points: list) -> None:
|
|
|
46
52
|
)
|
|
47
53
|
|
|
48
54
|
|
|
55
|
+
def _cnpj_char_value(c: str) -> int:
|
|
56
|
+
return ord(c) - ord("0")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _cnpj_dv(body: str, weights: tuple[int, ...]) -> str:
|
|
60
|
+
total = sum(_cnpj_char_value(c) * w for c, w in zip(body, weights))
|
|
61
|
+
resto = total % 11
|
|
62
|
+
return "0" if resto < 2 else str(11 - resto)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def validate_cnpj(cnpj: str) -> str:
|
|
66
|
+
"""Normalize and validate a CNPJ (supports alphanumeric NT COCAD/SUARA 49/2024).
|
|
67
|
+
|
|
68
|
+
Accepts masked input (e.g. ``12.345.678/0001-95``) and lowercase letters.
|
|
69
|
+
Returns the normalized 14-char CNPJ. Raises ``ValueError`` if invalid.
|
|
70
|
+
"""
|
|
71
|
+
if not isinstance(cnpj, str):
|
|
72
|
+
raise ValueError(f"cnpj must be a string, got {type(cnpj).__name__}")
|
|
73
|
+
normalized = _CNPJ_NON_ALNUM.sub("", cnpj).upper()
|
|
74
|
+
if len(normalized) != 14:
|
|
75
|
+
raise ValueError(f"cnpj must have 14 alphanumeric chars, got {len(normalized)}")
|
|
76
|
+
if len(set(normalized)) == 1:
|
|
77
|
+
raise ValueError("cnpj cannot have all identical characters")
|
|
78
|
+
body, dv = normalized[:12], normalized[12:]
|
|
79
|
+
if not _CNPJ_BODY_PATTERN.match(body):
|
|
80
|
+
raise ValueError("cnpj body (positions 1-12) must be A-Z or 0-9")
|
|
81
|
+
if not dv.isdigit():
|
|
82
|
+
raise ValueError("cnpj check digits (positions 13-14) must be digits")
|
|
83
|
+
if _cnpj_dv(body, _CNPJ_DV_WEIGHTS_1) != dv[0]:
|
|
84
|
+
raise ValueError("cnpj first check digit is invalid")
|
|
85
|
+
if _cnpj_dv(body + dv[0], _CNPJ_DV_WEIGHTS_2) != dv[1]:
|
|
86
|
+
raise ValueError("cnpj second check digit is invalid")
|
|
87
|
+
return normalized
|
|
88
|
+
|
|
89
|
+
|
|
49
90
|
def validate_address_fields(**fields: Any) -> None:
|
|
50
91
|
"""Raise ValueError if no address field is provided."""
|
|
51
92
|
if not any(v is not None for v in fields.values()):
|
|
@@ -19,6 +19,8 @@ from ._constants import (
|
|
|
19
19
|
DEFAULT_TIMEOUT,
|
|
20
20
|
DIRECTION_MAP,
|
|
21
21
|
MAX_BATCH_SIZE,
|
|
22
|
+
MAX_CNPJ_BATCH_FLAT,
|
|
23
|
+
MAX_CNPJ_BATCH_RAW,
|
|
22
24
|
MAX_ROUTING_BATCH,
|
|
23
25
|
)
|
|
24
26
|
from ._prepare import async_batch_complete, async_batch_prepare, async_wait_until_ready
|
|
@@ -28,6 +30,7 @@ from ._validation import (
|
|
|
28
30
|
translate_ranking_scope,
|
|
29
31
|
translate_search_filters,
|
|
30
32
|
validate_address_fields,
|
|
33
|
+
validate_cnpj,
|
|
31
34
|
validate_lat_lng,
|
|
32
35
|
validate_profile,
|
|
33
36
|
validate_route_points,
|
|
@@ -39,6 +42,11 @@ if TYPE_CHECKING:
|
|
|
39
42
|
|
|
40
43
|
from ._types import (
|
|
41
44
|
BorderResult,
|
|
45
|
+
CnpjEnrichedResult,
|
|
46
|
+
CnpjMetadataRawResult,
|
|
47
|
+
CnpjMetadataResult,
|
|
48
|
+
CnpjRawResult,
|
|
49
|
+
CnpjResult,
|
|
42
50
|
CommercialClusterResult,
|
|
43
51
|
GeocodeResult,
|
|
44
52
|
IncomePdfResult,
|
|
@@ -717,6 +725,156 @@ class AsyncClient:
|
|
|
717
725
|
return [clean_columns(item) for item in items]
|
|
718
726
|
return items
|
|
719
727
|
|
|
728
|
+
# ------------------------------------------------------------------
|
|
729
|
+
# CNPJ (pessoa juridica)
|
|
730
|
+
# ------------------------------------------------------------------
|
|
731
|
+
|
|
732
|
+
async def cnpj(self, cnpj: str) -> CnpjResult:
|
|
733
|
+
"""Individual CNPJ lookup, flat shape.
|
|
734
|
+
|
|
735
|
+
See :meth:`Client.cnpj` for full docs.
|
|
736
|
+
"""
|
|
737
|
+
normalized = validate_cnpj(cnpj)
|
|
738
|
+
return self._maybe_clean(await self._get(f"/cnpj/{normalized}"))
|
|
739
|
+
|
|
740
|
+
async def cnpj_raw(self, cnpj: str) -> CnpjRawResult:
|
|
741
|
+
"""Individual CNPJ lookup with F1 schema.
|
|
742
|
+
|
|
743
|
+
See :meth:`Client.cnpj_raw` for full docs.
|
|
744
|
+
"""
|
|
745
|
+
normalized = validate_cnpj(cnpj)
|
|
746
|
+
return self._maybe_clean(await self._get(f"/cnpj/raw/{normalized}"))
|
|
747
|
+
|
|
748
|
+
async def cnpj_batch(
|
|
749
|
+
self,
|
|
750
|
+
cnpjs: list[str],
|
|
751
|
+
*,
|
|
752
|
+
timeout: int | None = None,
|
|
753
|
+
) -> dict[str, CnpjResult | None]:
|
|
754
|
+
"""Batch CNPJ lookup, flat shape. Server caps at 1024.
|
|
755
|
+
|
|
756
|
+
See :meth:`Client.cnpj_batch` for full docs.
|
|
757
|
+
"""
|
|
758
|
+
if len(cnpjs) > MAX_CNPJ_BATCH_FLAT:
|
|
759
|
+
raise ValueError(
|
|
760
|
+
f"Batch limit is {MAX_CNPJ_BATCH_FLAT} CNPJs per call, got {len(cnpjs)}"
|
|
761
|
+
)
|
|
762
|
+
normalized = [validate_cnpj(c) for c in cnpjs]
|
|
763
|
+
result = await self._post("/cnpj/batch", {"cnpjs": normalized}, timeout=timeout)
|
|
764
|
+
if self._clean:
|
|
765
|
+
return {k: clean_columns(v) if isinstance(v, dict) else v for k, v in result.items()}
|
|
766
|
+
return result
|
|
767
|
+
|
|
768
|
+
async def cnpj_raw_batch(
|
|
769
|
+
self,
|
|
770
|
+
cnpjs: list[str],
|
|
771
|
+
*,
|
|
772
|
+
timeout: int | None = None,
|
|
773
|
+
) -> dict[str, CnpjRawResult | None]:
|
|
774
|
+
"""Batch CNPJ lookup with F1 schema. Server caps at 256.
|
|
775
|
+
|
|
776
|
+
See :meth:`Client.cnpj_raw_batch` for full docs.
|
|
777
|
+
"""
|
|
778
|
+
if len(cnpjs) > MAX_CNPJ_BATCH_RAW:
|
|
779
|
+
raise ValueError(
|
|
780
|
+
f"Batch limit is {MAX_CNPJ_BATCH_RAW} CNPJs per call, got {len(cnpjs)}"
|
|
781
|
+
)
|
|
782
|
+
normalized = [validate_cnpj(c) for c in cnpjs]
|
|
783
|
+
result = await self._post("/cnpj/raw/batch", {"cnpjs": normalized}, timeout=timeout)
|
|
784
|
+
if self._clean:
|
|
785
|
+
return {k: clean_columns(v) if isinstance(v, dict) else v for k, v in result.items()}
|
|
786
|
+
return result
|
|
787
|
+
|
|
788
|
+
async def cnpj_metadata(self) -> CnpjMetadataResult:
|
|
789
|
+
"""Dataset metadata (flat).
|
|
790
|
+
|
|
791
|
+
See :meth:`Client.cnpj_metadata` for full docs.
|
|
792
|
+
"""
|
|
793
|
+
return self._maybe_clean(await self._get("/cnpj/metadata"))
|
|
794
|
+
|
|
795
|
+
async def cnpj_raw_metadata(self) -> CnpjMetadataRawResult:
|
|
796
|
+
"""Dataset metadata with ``cobertura_geo`` as nested dict.
|
|
797
|
+
|
|
798
|
+
See :meth:`Client.cnpj_raw_metadata` for full docs.
|
|
799
|
+
"""
|
|
800
|
+
return self._maybe_clean(await self._get("/cnpj/raw/metadata"))
|
|
801
|
+
|
|
802
|
+
async def cnpj_enriched(
|
|
803
|
+
self,
|
|
804
|
+
cnpj: str,
|
|
805
|
+
*,
|
|
806
|
+
slum: bool = False,
|
|
807
|
+
prison: bool = False,
|
|
808
|
+
border: bool = False,
|
|
809
|
+
personal_income_static: bool = False,
|
|
810
|
+
personal_income_pdf: bool = False,
|
|
811
|
+
commercial_cluster: bool = False,
|
|
812
|
+
infosc: bool = False,
|
|
813
|
+
tipologia: bool = False,
|
|
814
|
+
sandbox: bool = False,
|
|
815
|
+
) -> CnpjEnrichedResult:
|
|
816
|
+
"""CNPJ lookup with geo fan-out.
|
|
817
|
+
|
|
818
|
+
See :meth:`Client.cnpj_enriched` for full docs.
|
|
819
|
+
"""
|
|
820
|
+
normalized = validate_cnpj(cnpj)
|
|
821
|
+
flags = {
|
|
822
|
+
"slum": slum,
|
|
823
|
+
"prison": prison,
|
|
824
|
+
"border": border,
|
|
825
|
+
"personal_income_static": personal_income_static,
|
|
826
|
+
"personal_income_pdf": personal_income_pdf,
|
|
827
|
+
"commercial_cluster": commercial_cluster,
|
|
828
|
+
"infosc": infosc,
|
|
829
|
+
"tipologia": tipologia,
|
|
830
|
+
"sandbox": sandbox,
|
|
831
|
+
}
|
|
832
|
+
params = {k: "true" for k, v in flags.items() if v}
|
|
833
|
+
return self._maybe_clean(
|
|
834
|
+
await self._get(f"/cnpj/{normalized}/enriched", params)
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
async def cnpj_batch_enriched(
|
|
838
|
+
self,
|
|
839
|
+
cnpjs: list[str],
|
|
840
|
+
*,
|
|
841
|
+
slum: bool = False,
|
|
842
|
+
prison: bool = False,
|
|
843
|
+
border: bool = False,
|
|
844
|
+
personal_income_static: bool = False,
|
|
845
|
+
personal_income_pdf: bool = False,
|
|
846
|
+
commercial_cluster: bool = False,
|
|
847
|
+
infosc: bool = False,
|
|
848
|
+
tipologia: bool = False,
|
|
849
|
+
timeout: int | None = None,
|
|
850
|
+
) -> dict[str, CnpjEnrichedResult | None]:
|
|
851
|
+
"""Batch CNPJ lookup with geo fan-out. Server caps at 256.
|
|
852
|
+
|
|
853
|
+
See :meth:`Client.cnpj_batch_enriched` for full docs.
|
|
854
|
+
"""
|
|
855
|
+
if len(cnpjs) > MAX_CNPJ_BATCH_RAW:
|
|
856
|
+
raise ValueError(
|
|
857
|
+
f"Batch limit is {MAX_CNPJ_BATCH_RAW} CNPJs per call, got {len(cnpjs)}"
|
|
858
|
+
)
|
|
859
|
+
normalized = [validate_cnpj(c) for c in cnpjs]
|
|
860
|
+
body = {
|
|
861
|
+
"cnpjs": normalized,
|
|
862
|
+
"flags": {
|
|
863
|
+
"slum": slum,
|
|
864
|
+
"prison": prison,
|
|
865
|
+
"border": border,
|
|
866
|
+
"personal_income_static": personal_income_static,
|
|
867
|
+
"personal_income_pdf": personal_income_pdf,
|
|
868
|
+
"commercial_cluster": commercial_cluster,
|
|
869
|
+
"infosc": infosc,
|
|
870
|
+
"tipologia": tipologia,
|
|
871
|
+
},
|
|
872
|
+
}
|
|
873
|
+
result = await self._post("/cnpj/batch/enriched", body, timeout=timeout)
|
|
874
|
+
if self._clean:
|
|
875
|
+
return {k: clean_columns(v) if isinstance(v, dict) else v for k, v in result.items()}
|
|
876
|
+
return result
|
|
877
|
+
|
|
720
878
|
# ------------------------------------------------------------------
|
|
721
879
|
# Batch operations
|
|
722
880
|
# ------------------------------------------------------------------
|
|
@@ -22,6 +22,8 @@ from ._constants import (
|
|
|
22
22
|
ENV_PASSWORD,
|
|
23
23
|
ENV_USERNAME,
|
|
24
24
|
MAX_BATCH_SIZE,
|
|
25
|
+
MAX_CNPJ_BATCH_FLAT,
|
|
26
|
+
MAX_CNPJ_BATCH_RAW,
|
|
25
27
|
MAX_ROUTING_BATCH,
|
|
26
28
|
)
|
|
27
29
|
from ._http import HttpClient, _handle_response
|
|
@@ -32,6 +34,7 @@ from ._validation import (
|
|
|
32
34
|
translate_ranking_scope,
|
|
33
35
|
translate_search_filters,
|
|
34
36
|
validate_address_fields,
|
|
37
|
+
validate_cnpj,
|
|
35
38
|
validate_lat_lng,
|
|
36
39
|
validate_profile,
|
|
37
40
|
validate_route_points,
|
|
@@ -43,6 +46,11 @@ if TYPE_CHECKING:
|
|
|
43
46
|
|
|
44
47
|
from ._types import (
|
|
45
48
|
BorderResult,
|
|
49
|
+
CnpjEnrichedResult,
|
|
50
|
+
CnpjMetadataRawResult,
|
|
51
|
+
CnpjMetadataResult,
|
|
52
|
+
CnpjRawResult,
|
|
53
|
+
CnpjResult,
|
|
46
54
|
CommercialClusterResult,
|
|
47
55
|
GeocodeResult,
|
|
48
56
|
IncomePdfResult,
|
|
@@ -923,6 +931,162 @@ class Client:
|
|
|
923
931
|
return [clean_columns(item) for item in items]
|
|
924
932
|
return items
|
|
925
933
|
|
|
934
|
+
# ------------------------------------------------------------------
|
|
935
|
+
# CNPJ (pessoa juridica)
|
|
936
|
+
# ------------------------------------------------------------------
|
|
937
|
+
|
|
938
|
+
def cnpj(self, cnpj: str) -> CnpjResult:
|
|
939
|
+
"""Individual CNPJ lookup, flat shape (49 scalar keys, no nested lists).
|
|
940
|
+
|
|
941
|
+
Accepts masked or alphanumeric input; the SDK normalizes and validates
|
|
942
|
+
the check digits locally before hitting the server.
|
|
943
|
+
See https://docs.prismadata.io/cnpj.
|
|
944
|
+
"""
|
|
945
|
+
normalized = validate_cnpj(cnpj)
|
|
946
|
+
return self._maybe_clean(self._get(f"/cnpj/{normalized}"))
|
|
947
|
+
|
|
948
|
+
def cnpj_raw(self, cnpj: str) -> CnpjRawResult:
|
|
949
|
+
"""Individual CNPJ lookup with F1 schema (``socios`` and ``cnaes`` as lists).
|
|
950
|
+
|
|
951
|
+
See https://docs.prismadata.io/cnpj.
|
|
952
|
+
"""
|
|
953
|
+
normalized = validate_cnpj(cnpj)
|
|
954
|
+
return self._maybe_clean(self._get(f"/cnpj/raw/{normalized}"))
|
|
955
|
+
|
|
956
|
+
def cnpj_batch(
|
|
957
|
+
self,
|
|
958
|
+
cnpjs: list[str],
|
|
959
|
+
*,
|
|
960
|
+
timeout: int | None = None,
|
|
961
|
+
) -> dict[str, CnpjResult | None]:
|
|
962
|
+
"""Batch CNPJ lookup, flat shape. Server caps at 1024 per call.
|
|
963
|
+
|
|
964
|
+
Returns a dict indexed by the normalized CNPJ, with ``None`` for
|
|
965
|
+
CNPJs not found by the server. See https://docs.prismadata.io/cnpj.
|
|
966
|
+
"""
|
|
967
|
+
if len(cnpjs) > MAX_CNPJ_BATCH_FLAT:
|
|
968
|
+
raise ValueError(
|
|
969
|
+
f"Batch limit is {MAX_CNPJ_BATCH_FLAT} CNPJs per call, got {len(cnpjs)}"
|
|
970
|
+
)
|
|
971
|
+
normalized = [validate_cnpj(c) for c in cnpjs]
|
|
972
|
+
result = self._post("/cnpj/batch", {"cnpjs": normalized}, timeout=timeout)
|
|
973
|
+
if self._clean:
|
|
974
|
+
return {k: clean_columns(v) if isinstance(v, dict) else v for k, v in result.items()}
|
|
975
|
+
return result
|
|
976
|
+
|
|
977
|
+
def cnpj_raw_batch(
|
|
978
|
+
self,
|
|
979
|
+
cnpjs: list[str],
|
|
980
|
+
*,
|
|
981
|
+
timeout: int | None = None,
|
|
982
|
+
) -> dict[str, CnpjRawResult | None]:
|
|
983
|
+
"""Batch CNPJ lookup with F1 schema. Server caps at 256 per call
|
|
984
|
+
(raw payload is larger than flat).
|
|
985
|
+
|
|
986
|
+
See https://docs.prismadata.io/cnpj.
|
|
987
|
+
"""
|
|
988
|
+
if len(cnpjs) > MAX_CNPJ_BATCH_RAW:
|
|
989
|
+
raise ValueError(
|
|
990
|
+
f"Batch limit is {MAX_CNPJ_BATCH_RAW} CNPJs per call, got {len(cnpjs)}"
|
|
991
|
+
)
|
|
992
|
+
normalized = [validate_cnpj(c) for c in cnpjs]
|
|
993
|
+
result = self._post("/cnpj/raw/batch", {"cnpjs": normalized}, timeout=timeout)
|
|
994
|
+
if self._clean:
|
|
995
|
+
return {k: clean_columns(v) if isinstance(v, dict) else v for k, v in result.items()}
|
|
996
|
+
return result
|
|
997
|
+
|
|
998
|
+
def cnpj_metadata(self) -> CnpjMetadataResult:
|
|
999
|
+
"""Dataset metadata (version + geo coverage buckets, flat).
|
|
1000
|
+
|
|
1001
|
+
See https://docs.prismadata.io/cnpj.
|
|
1002
|
+
"""
|
|
1003
|
+
return self._maybe_clean(self._get("/cnpj/metadata"))
|
|
1004
|
+
|
|
1005
|
+
def cnpj_raw_metadata(self) -> CnpjMetadataRawResult:
|
|
1006
|
+
"""Dataset metadata with ``cobertura_geo`` as a nested dict.
|
|
1007
|
+
|
|
1008
|
+
See https://docs.prismadata.io/cnpj.
|
|
1009
|
+
"""
|
|
1010
|
+
return self._maybe_clean(self._get("/cnpj/raw/metadata"))
|
|
1011
|
+
|
|
1012
|
+
def cnpj_enriched(
|
|
1013
|
+
self,
|
|
1014
|
+
cnpj: str,
|
|
1015
|
+
*,
|
|
1016
|
+
slum: bool = False,
|
|
1017
|
+
prison: bool = False,
|
|
1018
|
+
border: bool = False,
|
|
1019
|
+
personal_income_static: bool = False,
|
|
1020
|
+
personal_income_pdf: bool = False,
|
|
1021
|
+
commercial_cluster: bool = False,
|
|
1022
|
+
infosc: bool = False,
|
|
1023
|
+
tipologia: bool = False,
|
|
1024
|
+
sandbox: bool = False,
|
|
1025
|
+
) -> CnpjEnrichedResult:
|
|
1026
|
+
"""CNPJ lookup with optional fan-out to geo pillars.
|
|
1027
|
+
|
|
1028
|
+
When a flag is set, the server appends ``prismadata__<flag>__*`` keys
|
|
1029
|
+
to the flat response. When the CNPJ has no lat/lng, geo flags are
|
|
1030
|
+
silently skipped and only the 49 ``pessoa_juridica`` keys come back
|
|
1031
|
+
(``qualidade_geocodificacao_classificacao`` will be ``"FALHA"`` or
|
|
1032
|
+
``null``). See https://docs.prismadata.io/cnpj.
|
|
1033
|
+
"""
|
|
1034
|
+
normalized = validate_cnpj(cnpj)
|
|
1035
|
+
flags = {
|
|
1036
|
+
"slum": slum,
|
|
1037
|
+
"prison": prison,
|
|
1038
|
+
"border": border,
|
|
1039
|
+
"personal_income_static": personal_income_static,
|
|
1040
|
+
"personal_income_pdf": personal_income_pdf,
|
|
1041
|
+
"commercial_cluster": commercial_cluster,
|
|
1042
|
+
"infosc": infosc,
|
|
1043
|
+
"tipologia": tipologia,
|
|
1044
|
+
"sandbox": sandbox,
|
|
1045
|
+
}
|
|
1046
|
+
params = {k: "true" for k, v in flags.items() if v}
|
|
1047
|
+
return self._maybe_clean(self._get(f"/cnpj/{normalized}/enriched", params))
|
|
1048
|
+
|
|
1049
|
+
def cnpj_batch_enriched(
|
|
1050
|
+
self,
|
|
1051
|
+
cnpjs: list[str],
|
|
1052
|
+
*,
|
|
1053
|
+
slum: bool = False,
|
|
1054
|
+
prison: bool = False,
|
|
1055
|
+
border: bool = False,
|
|
1056
|
+
personal_income_static: bool = False,
|
|
1057
|
+
personal_income_pdf: bool = False,
|
|
1058
|
+
commercial_cluster: bool = False,
|
|
1059
|
+
infosc: bool = False,
|
|
1060
|
+
tipologia: bool = False,
|
|
1061
|
+
timeout: int | None = None,
|
|
1062
|
+
) -> dict[str, CnpjEnrichedResult | None]:
|
|
1063
|
+
"""Batch CNPJ lookup with optional geo fan-out. Server caps at 256 per call.
|
|
1064
|
+
|
|
1065
|
+
See https://docs.prismadata.io/cnpj.
|
|
1066
|
+
"""
|
|
1067
|
+
if len(cnpjs) > MAX_CNPJ_BATCH_RAW:
|
|
1068
|
+
raise ValueError(
|
|
1069
|
+
f"Batch limit is {MAX_CNPJ_BATCH_RAW} CNPJs per call, got {len(cnpjs)}"
|
|
1070
|
+
)
|
|
1071
|
+
normalized = [validate_cnpj(c) for c in cnpjs]
|
|
1072
|
+
body = {
|
|
1073
|
+
"cnpjs": normalized,
|
|
1074
|
+
"flags": {
|
|
1075
|
+
"slum": slum,
|
|
1076
|
+
"prison": prison,
|
|
1077
|
+
"border": border,
|
|
1078
|
+
"personal_income_static": personal_income_static,
|
|
1079
|
+
"personal_income_pdf": personal_income_pdf,
|
|
1080
|
+
"commercial_cluster": commercial_cluster,
|
|
1081
|
+
"infosc": infosc,
|
|
1082
|
+
"tipologia": tipologia,
|
|
1083
|
+
},
|
|
1084
|
+
}
|
|
1085
|
+
result = self._post("/cnpj/batch/enriched", body, timeout=timeout)
|
|
1086
|
+
if self._clean:
|
|
1087
|
+
return {k: clean_columns(v) if isinstance(v, dict) else v for k, v in result.items()}
|
|
1088
|
+
return result
|
|
1089
|
+
|
|
926
1090
|
# ------------------------------------------------------------------
|
|
927
1091
|
# Batch operations
|
|
928
1092
|
# ------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|