bfocus 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.
- bfocus/__init__.py +45 -0
- bfocus/_client.py +95 -0
- bfocus/_resources.py +862 -0
- bfocus/_transport.py +335 -0
- bfocus/_version.py +3 -0
- bfocus/errors.py +131 -0
- bfocus/py.typed +0 -0
- bfocus/types.py +310 -0
- bfocus/widget.py +36 -0
- bfocus-0.1.0.dist-info/METADATA +384 -0
- bfocus-0.1.0.dist-info/RECORD +13 -0
- bfocus-0.1.0.dist-info/WHEEL +4 -0
- bfocus-0.1.0.dist-info/licenses/LICENSE +21 -0
bfocus/__init__.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""SDK oficial em Python da API pública do bFocus.
|
|
2
|
+
|
|
3
|
+
from bfocus import Bfocus
|
|
4
|
+
|
|
5
|
+
bf = Bfocus("bf_live_...")
|
|
6
|
+
bf.customers.upsert("ERP 1042", name="Padaria Estrela")
|
|
7
|
+
|
|
8
|
+
Zero dependências (só biblioteca padrão). Python 3.9+.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from ._client import Bfocus
|
|
12
|
+
from ._transport import CLIENT_ID, DEFAULT_BASE_URL
|
|
13
|
+
from ._version import __version__
|
|
14
|
+
from .errors import (
|
|
15
|
+
AuthenticationError,
|
|
16
|
+
BfocusError,
|
|
17
|
+
ConflictError,
|
|
18
|
+
NetworkError,
|
|
19
|
+
NotFoundError,
|
|
20
|
+
PermissionDeniedError,
|
|
21
|
+
RateLimitError,
|
|
22
|
+
ServerError,
|
|
23
|
+
ValidationError,
|
|
24
|
+
)
|
|
25
|
+
from .types import UNSET, Page
|
|
26
|
+
from .widget import sign_widget_identity
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"Bfocus",
|
|
30
|
+
"Page",
|
|
31
|
+
"UNSET",
|
|
32
|
+
"sign_widget_identity",
|
|
33
|
+
"BfocusError",
|
|
34
|
+
"AuthenticationError",
|
|
35
|
+
"PermissionDeniedError",
|
|
36
|
+
"NotFoundError",
|
|
37
|
+
"ConflictError",
|
|
38
|
+
"ValidationError",
|
|
39
|
+
"RateLimitError",
|
|
40
|
+
"ServerError",
|
|
41
|
+
"NetworkError",
|
|
42
|
+
"DEFAULT_BASE_URL",
|
|
43
|
+
"CLIENT_ID",
|
|
44
|
+
"__version__",
|
|
45
|
+
]
|
bfocus/_client.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Cliente principal: :class:`Bfocus`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Callable
|
|
6
|
+
|
|
7
|
+
from ._resources import AIAgents, Customers, KnowledgeBase, Products, ReleaseNotes
|
|
8
|
+
from ._transport import DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, Transport
|
|
9
|
+
from .widget import sign_widget_identity
|
|
10
|
+
|
|
11
|
+
__all__ = ["Bfocus"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Bfocus:
|
|
15
|
+
"""Cliente da API pública do bFocus.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
api_key: Chave de API (``Integrações → Chaves de API``). Único argumento
|
|
19
|
+
posicional e obrigatório.
|
|
20
|
+
base_url: URL da API, sem barra final. Padrão: produção
|
|
21
|
+
(``https://api.bfocus.com.br``). Em dev: ``http://localhost:8000``.
|
|
22
|
+
timeout: Segundos por tentativa (padrão 30).
|
|
23
|
+
max_retries: Novas tentativas além da primeira em erro de rede/timeout, 429, 502,
|
|
24
|
+
503 e 504 (padrão 2; ``0`` desliga).
|
|
25
|
+
|
|
26
|
+
Nada é chamado na rede ao construir.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
>>> from bfocus import Bfocus
|
|
30
|
+
>>> bf = Bfocus("bf_live_...")
|
|
31
|
+
>>> bf.customers.upsert("ERP 1042", name="Padaria Estrela") # doctest: +SKIP
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
#: Também disponível como função do pacote: ``from bfocus import sign_widget_identity``.
|
|
35
|
+
sign_widget_identity = staticmethod(sign_widget_identity)
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
api_key: str,
|
|
40
|
+
*,
|
|
41
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
42
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
43
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
44
|
+
) -> None:
|
|
45
|
+
if not isinstance(api_key, str):
|
|
46
|
+
raise TypeError("Bfocus: api_key precisa ser str (ex.: 'bf_live_...').")
|
|
47
|
+
if not api_key.strip():
|
|
48
|
+
raise ValueError("Bfocus: api_key é obrigatória (ex.: 'bf_live_...').")
|
|
49
|
+
if not isinstance(max_retries, int) or isinstance(max_retries, bool) or max_retries < 0:
|
|
50
|
+
raise ValueError("Bfocus: max_retries precisa ser um inteiro >= 0.")
|
|
51
|
+
if timeout is None or timeout <= 0:
|
|
52
|
+
raise ValueError("Bfocus: timeout precisa ser > 0 (segundos).")
|
|
53
|
+
|
|
54
|
+
self._transport = Transport(
|
|
55
|
+
api_key,
|
|
56
|
+
base_url=(base_url or DEFAULT_BASE_URL),
|
|
57
|
+
timeout=float(timeout),
|
|
58
|
+
max_retries=max_retries,
|
|
59
|
+
)
|
|
60
|
+
#: Clientes (empresas), com ``.contacts``, ``.products`` e ``.interactions``.
|
|
61
|
+
self.customers = Customers(self._transport)
|
|
62
|
+
#: Catálogo de produtos.
|
|
63
|
+
self.products = Products(self._transport)
|
|
64
|
+
#: Release notes por produto.
|
|
65
|
+
self.release_notes = ReleaseNotes(self._transport)
|
|
66
|
+
#: Base de conhecimento: ``.articles`` e ``.search(...)``.
|
|
67
|
+
self.kb = KnowledgeBase(self._transport)
|
|
68
|
+
#: Agentes de IA.
|
|
69
|
+
self.ai_agents = AIAgents(self._transport)
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def base_url(self) -> str:
|
|
73
|
+
return self._transport.base_url
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def timeout(self) -> float:
|
|
77
|
+
return self._transport.timeout
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def max_retries(self) -> int:
|
|
81
|
+
return self._transport.max_retries
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def _sleep(self) -> Callable[[float], Any]:
|
|
85
|
+
"""Espera entre novas tentativas (padrão ``time.sleep``). Substitua nos testes."""
|
|
86
|
+
return self._transport.sleep
|
|
87
|
+
|
|
88
|
+
@_sleep.setter
|
|
89
|
+
def _sleep(self, fn: Callable[[float], Any]) -> None:
|
|
90
|
+
self._transport.sleep = fn
|
|
91
|
+
|
|
92
|
+
def __repr__(self) -> str:
|
|
93
|
+
key = self._transport.api_key
|
|
94
|
+
masked = key[:8] + "…" if len(key) > 8 else "…"
|
|
95
|
+
return f"Bfocus(api_key={masked!r}, base_url={self.base_url!r})"
|