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 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})"