kodebar 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kodebar/__init__.py ADDED
@@ -0,0 +1,245 @@
1
+ """
2
+ Kodebar SDK — consulta de produtos por código de barras (GTIN/EAN)
3
+ https://kodebar.korvensistemas.com.br
4
+ """
5
+
6
+ import re
7
+ import time
8
+ import requests
9
+
10
+ __version__ = "0.1.0"
11
+
12
+ DEFAULT_BASE_URL = "https://kodebar.korvensistemas.com.br"
13
+ GTIN_RE = re.compile(r"^\d{8,14}$")
14
+
15
+
16
+ class KodebarError(Exception):
17
+ """Erro genérico da API Kodebar."""
18
+ def __init__(self, message, status=None, code=None):
19
+ super().__init__(message)
20
+ self.status = status
21
+ self.code = code
22
+
23
+
24
+ class KodebarNotFoundError(KodebarError):
25
+ """Produto não encontrado (404)."""
26
+ def __init__(self, gtin):
27
+ super().__init__(f"Produto não encontrado: {gtin}", 404, "NOT_FOUND")
28
+ self.gtin = gtin
29
+
30
+
31
+ class KodebarRateLimitError(KodebarError):
32
+ """Rate limit excedido (429)."""
33
+ def __init__(self, message="Rate limit excedido", retry_after=60):
34
+ super().__init__(message, 429, "RATE_LIMITED")
35
+ self.retry_after = retry_after
36
+
37
+
38
+ class Kodebar:
39
+ """
40
+ Cliente da API Kodebar.
41
+
42
+ Args:
43
+ api_key: Sua API key do Kodebar.
44
+ base_url: URL base da API (default: https://kodebar.korvensistemas.com.br).
45
+ timeout: Timeout em segundos (default: 10).
46
+ max_retries: Retries em caso de 429/5xx (default: 2).
47
+ """
48
+
49
+ def __init__(self, api_key, *, base_url=None, timeout=10, max_retries=2):
50
+ if not api_key or not isinstance(api_key, str):
51
+ raise ValueError("API key é obrigatória")
52
+ self.api_key = api_key
53
+ self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
54
+ self.timeout = timeout
55
+ self.max_retries = max_retries
56
+ self._session = requests.Session()
57
+ self._session.headers.update({
58
+ "X-API-Key": self.api_key,
59
+ "User-Agent": f"kodebar-python/{__version__}",
60
+ })
61
+
62
+ def _request(self, method, path, *, params=None, json=None):
63
+ url = f"{self.base_url}{path}"
64
+ if params:
65
+ params = {k: v for k, v in params.items() if v is not None}
66
+
67
+ last_error = None
68
+ for attempt in range(self.max_retries + 1):
69
+ try:
70
+ resp = self._session.request(
71
+ method, url,
72
+ params=params, json=json,
73
+ timeout=self.timeout,
74
+ )
75
+ try:
76
+ data = resp.json()
77
+ except Exception:
78
+ data = {}
79
+
80
+ if resp.ok:
81
+ return data
82
+
83
+ if resp.status_code == 404:
84
+ gtin = (params or {}).get("gtin", path)
85
+ raise KodebarNotFoundError(gtin)
86
+
87
+ if resp.status_code == 429:
88
+ retry_after = int(resp.headers.get("Retry-After", "60"))
89
+ err = KodebarRateLimitError(
90
+ data.get("erro", "Rate limit excedido"),
91
+ retry_after,
92
+ )
93
+ if attempt < self.max_retries:
94
+ time.sleep(min(retry_after, 5))
95
+ continue
96
+ raise err
97
+
98
+ if resp.status_code >= 500 and attempt < self.max_retries:
99
+ time.sleep(1 * (attempt + 1))
100
+ continue
101
+
102
+ raise KodebarError(
103
+ data.get("erro", f"Erro HTTP {resp.status_code}"),
104
+ resp.status_code,
105
+ )
106
+
107
+ except KodebarError:
108
+ raise
109
+ except Exception as e:
110
+ last_error = e
111
+ if attempt < self.max_retries:
112
+ time.sleep(1 * (attempt + 1))
113
+ continue
114
+
115
+ raise last_error or KodebarError("Falha na requisição")
116
+
117
+ @staticmethod
118
+ def _validate_gtin(gtin):
119
+ g = str(gtin).strip()
120
+ if not GTIN_RE.match(g):
121
+ raise ValueError(f'GTIN inválido: "{gtin}" (deve ter 8-14 dígitos)')
122
+ return g
123
+
124
+ # ── Endpoints públicos ──
125
+
126
+ def lookup(self, gtin):
127
+ """
128
+ Consulta um produto pelo GTIN/EAN.
129
+
130
+ Args:
131
+ gtin: Código de barras (8-14 dígitos).
132
+
133
+ Returns:
134
+ dict com gtin, nome, thumbnail, ncm, cached, source.
135
+
136
+ Raises:
137
+ KodebarNotFoundError: Produto não encontrado.
138
+ """
139
+ g = self._validate_gtin(gtin)
140
+ return self._request("GET", "/gtin/lookup", params={"gtin": g})
141
+
142
+ def search(self, query, *, limit=None, offset=None):
143
+ """
144
+ Busca produtos por nome.
145
+
146
+ Args:
147
+ query: Termo de busca.
148
+ limit: Máximo de resultados.
149
+ offset: Offset para paginação.
150
+
151
+ Returns:
152
+ dict com results, total, limit, offset.
153
+ """
154
+ if not query or not query.strip():
155
+ raise ValueError("Termo de busca é obrigatório")
156
+ return self._request("GET", "/gtin/search", params={
157
+ "q": query.strip(), "limit": limit, "offset": offset,
158
+ })
159
+
160
+ def autocomplete(self, query, *, limit=None):
161
+ """
162
+ Autocomplete rápido por nome.
163
+
164
+ Args:
165
+ query: Termo parcial.
166
+ limit: Máximo de resultados (max 10).
167
+
168
+ Returns:
169
+ dict com results.
170
+ """
171
+ if not query or not query.strip():
172
+ raise ValueError("Termo de busca é obrigatório")
173
+ return self._request("GET", "/gtin/autocomplete", params={
174
+ "q": query.strip(), "limit": limit,
175
+ })
176
+
177
+ def bulk(self, gtins):
178
+ """
179
+ Consulta em lote.
180
+
181
+ Args:
182
+ gtins: Lista de GTINs.
183
+
184
+ Returns:
185
+ dict com results, found, missed.
186
+ """
187
+ if not gtins or not isinstance(gtins, (list, tuple)):
188
+ raise ValueError("Lista de GTINs é obrigatória")
189
+ validated = [self._validate_gtin(g) for g in gtins]
190
+ return self._request("POST", "/gtin/bulk", json={"gtins": validated})
191
+
192
+ # ── Conta ──
193
+
194
+ def me(self):
195
+ """Info da sua conta (tier, uso, limite)."""
196
+ return self._request("GET", "/account/me")
197
+
198
+ def usage(self, days=30):
199
+ """
200
+ Histórico de uso diário.
201
+
202
+ Args:
203
+ days: Quantidade de dias (default: 30).
204
+ """
205
+ return self._request("GET", "/account/usage", params={"days": days})
206
+
207
+ def logs(self, limit=50):
208
+ """
209
+ Últimas consultas realizadas.
210
+
211
+ Args:
212
+ limit: Máximo de registros (default: 50).
213
+ """
214
+ return self._request("GET", "/account/logs", params={"limit": limit})
215
+
216
+ def resolved_misses(self, *, days=None, limit=None):
217
+ """GTINs que eram miss e agora estão encontrados."""
218
+ return self._request("GET", "/account/resolved-misses", params={
219
+ "days": days, "limit": limit,
220
+ })
221
+
222
+ # ── Webhooks ──
223
+
224
+ def list_webhooks(self):
225
+ """Lista webhooks registrados."""
226
+ return self._request("GET", "/webhooks")
227
+
228
+ def create_webhook(self, url, event=None):
229
+ """
230
+ Registra um webhook.
231
+
232
+ Args:
233
+ url: URL de callback.
234
+ event: Evento (gtin.updated, gtin.created, miss.resolved).
235
+ """
236
+ if not url:
237
+ raise ValueError("URL do webhook é obrigatória")
238
+ body = {"url": url}
239
+ if event:
240
+ body["event"] = event
241
+ return self._request("POST", "/webhooks/subscribe", json=body)
242
+
243
+ def delete_webhook(self, webhook_id):
244
+ """Remove um webhook."""
245
+ return self._request("DELETE", f"/webhooks/{webhook_id}")
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: kodebar
3
+ Version: 0.1.0
4
+ Summary: SDK oficial da API Kodebar — consulta de produtos por código de barras (GTIN/EAN)
5
+ Author-email: Kodebar <contato@korvensistemas.com.br>
6
+ License: MIT
7
+ Project-URL: Homepage, https://kodebar.korvensistemas.com.br
8
+ Project-URL: Documentation, https://kodebar.korvensistemas.com.br/docs
9
+ Project-URL: Repository, https://github.com/kodebar/kodebar-python
10
+ Keywords: kodebar,gtin,ean,barcode,produto,api,brasil
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Libraries
16
+ Requires-Python: >=3.7
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: requests>=2.20
19
+
20
+ # kodebar
21
+
22
+ SDK oficial da [API Kodebar](https://kodebar.korvensistemas.com.br) — consulta de produtos brasileiros por código de barras (GTIN/EAN).
23
+
24
+ ## Instalação
25
+
26
+ ```bash
27
+ pip install kodebar
28
+ ```
29
+
30
+ ## Uso rápido
31
+
32
+ ```python
33
+ from kodebar import Kodebar
34
+
35
+ kb = Kodebar("sua-api-key")
36
+
37
+ # Consultar um produto
38
+ produto = kb.lookup("7891234567890")
39
+ print(produto["nome"]) # "Produto Exemplo 500ml"
40
+ print(produto["thumbnail"]) # URL da imagem
41
+
42
+ # Buscar por nome
43
+ busca = kb.search("arroz integral")
44
+ for p in busca["results"]:
45
+ print(p["gtin"], p["nome"])
46
+
47
+ # Autocomplete
48
+ sugestoes = kb.autocomplete("coca")
49
+
50
+ # Consulta em lote
51
+ lote = kb.bulk(["7891234567890", "7898765432100"])
52
+ print(f'{lote["found"]} encontrados, {lote["missed"]} não encontrados')
53
+ ```
54
+
55
+ ## Configuração
56
+
57
+ ```python
58
+ kb = Kodebar("sua-api-key",
59
+ timeout=15, # timeout em segundos (default: 10)
60
+ max_retries=3, # retries em 429/5xx (default: 2)
61
+ )
62
+ ```
63
+
64
+ ## Métodos
65
+
66
+ | Método | Descrição | Tier mínimo |
67
+ |--------|-----------|-------------|
68
+ | `lookup(gtin)` | Consulta por GTIN/EAN | Teste (grátis) |
69
+ | `search(query, limit=, offset=)` | Busca por nome | Básico |
70
+ | `autocomplete(query, limit=)` | Autocomplete rápido | Básico |
71
+ | `bulk(gtins)` | Consulta em lote | Básico |
72
+ | `me()` | Info da conta | Teste |
73
+ | `usage(days=30)` | Histórico de uso | Teste |
74
+ | `logs(limit=50)` | Últimas consultas | Teste |
75
+ | `resolved_misses(days=, limit=)` | Misses resolvidos | Básico |
76
+ | `list_webhooks()` | Lista webhooks | Básico |
77
+ | `create_webhook(url, event=)` | Cria webhook | Básico |
78
+ | `delete_webhook(id)` | Remove webhook | Básico |
79
+
80
+ ## Tratamento de erros
81
+
82
+ ```python
83
+ from kodebar import Kodebar, KodebarNotFoundError, KodebarRateLimitError
84
+
85
+ kb = Kodebar("sua-api-key")
86
+
87
+ try:
88
+ produto = kb.lookup("0000000000000")
89
+ except KodebarNotFoundError as e:
90
+ print(f"Produto não encontrado: {e.gtin}")
91
+ except KodebarRateLimitError as e:
92
+ print(f"Rate limit! Tente novamente em {e.retry_after} segundos")
93
+ except KodebarError as e:
94
+ print(f"Erro: {e} (status: {e.status})")
95
+ ```
96
+
97
+ ## Crie sua conta grátis
98
+
99
+ [kodebar.korvensistemas.com.br/painel](https://kodebar.korvensistemas.com.br/painel)
100
+
101
+ ## Licença
102
+
103
+ MIT
@@ -0,0 +1,5 @@
1
+ kodebar/__init__.py,sha256=owUJJDdFVtuUPfiG-DX0PnZFKj08jodqjL-1cdnn73E,7559
2
+ kodebar-0.1.0.dist-info/METADATA,sha256=bV_5U0zqCJ5HLewg_f7kYv6mJJDFBK6Awl5wKE_gfjE,3110
3
+ kodebar-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
4
+ kodebar-0.1.0.dist-info/top_level.txt,sha256=m7JsV4Gt0swuIqtu01aswcemkKfwIfyplC0bXr4nWqE,8
5
+ kodebar-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ kodebar