bb_api 0.5.4__tar.gz → 0.5.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bb_api
3
- Version: 0.5.4
3
+ Version: 0.5.5
4
4
  Summary: Wrapper da API do Banco do Brasil.
5
5
  Requires-Python: >=3.13
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ from importlib.metadata import PackageNotFoundError, version
4
4
  try:
5
5
  __version__ = version("bb_api")
6
6
  except PackageNotFoundError:
7
- __version__ = "0.5.4"
7
+ __version__ = "0.5.5"
8
8
 
9
9
 
10
10
  from .common import Ambiente
@@ -22,6 +22,8 @@ _ERRO_INTERVALO_LONGO = "maior do que 31 dias"
22
22
  _STATUS_SEM_MOVIMENTO = 404
23
23
  _SEM_MOVIMENTO_PADRAO = "não há movimento no período consultado"
24
24
 
25
+ _LIMITE_DO_CORPO = 500
26
+
25
27
 
26
28
  class RespostaError(Exception):
27
29
  """Resposta de erro devolvida pela API do Banco do Brasil.
@@ -29,15 +31,45 @@ class RespostaError(Exception):
29
31
  Carrega o status HTTP e a mensagem originais junto da ação que falhou. Sem
30
32
  eles, um ``404`` de "não há o que devolver", um ``403`` de escopo que falta
31
33
  e um ``400`` de parâmetro inválido chegam ao chamador iguais.
34
+
35
+ Quando recebe a ``resposta``, guarda também o corpo cru e o
36
+ ``x-request-id``: o corpo traz o ``codigo`` e a ``ocorrencia`` do BB, que a
37
+ mensagem sozinha perde, e é com eles que o suporte do banco rastreia a falha.
32
38
  """
33
39
 
34
40
  status_code: int
35
41
  mensagem: str
42
+ corpo: str
43
+ request_id: str | None
36
44
 
37
- def __init__(self, acao: str, status_code: int, mensagem: str) -> None:
38
- super().__init__(f"Não foi possível {acao} (HTTP {status_code}): {mensagem}")
45
+ def __init__(
46
+ self,
47
+ acao: str,
48
+ status_code: int,
49
+ mensagem: str,
50
+ *,
51
+ resposta: requests.Response | None = None,
52
+ ) -> None:
39
53
  self.status_code = status_code
40
54
  self.mensagem = mensagem
55
+ self.corpo = ""
56
+ self.request_id = None
57
+ if resposta is not None:
58
+ self.corpo = resposta.text.strip()
59
+ self.request_id = resposta.headers.get("x-request-id")
60
+ super().__init__(_descreve(acao, status_code, mensagem, self.corpo, self.request_id))
61
+
62
+
63
+ def _descreve(
64
+ acao: str, status_code: int, mensagem: str, corpo: str, request_id: str | None
65
+ ) -> str:
66
+ partes = [f"Não foi possível {acao} (HTTP {status_code}): {mensagem}"]
67
+ if corpo and corpo != mensagem:
68
+ encurtado = corpo[:_LIMITE_DO_CORPO] + ("…" if len(corpo) > _LIMITE_DO_CORPO else "")
69
+ partes.append(f"resposta do BB: {encurtado}")
70
+ if request_id:
71
+ partes.append(f"x-request-id: {request_id}")
72
+ return " | ".join(partes)
41
73
 
42
74
 
43
75
  class ExtratoError(RespostaError):
@@ -47,8 +79,16 @@ class ExtratoError(RespostaError):
47
79
  API usa ``400`` tanto para falha de verdade quanto para situações normais.
48
80
  """
49
81
 
50
- def __init__(self, status_code: int, mensagem: str) -> None:
51
- super().__init__("reaver o extrato do órgão repassador", status_code, mensagem)
82
+ def __init__(
83
+ self,
84
+ status_code: int,
85
+ mensagem: str,
86
+ *,
87
+ resposta: requests.Response | None = None,
88
+ ) -> None:
89
+ super().__init__(
90
+ "reaver o extrato do órgão repassador", status_code, mensagem, resposta=resposta
91
+ )
52
92
 
53
93
 
54
94
  class SemLancamentosError(ExtratoError):
@@ -112,17 +152,17 @@ def _mensagem_da_lista_de_erros(campos: dict[str, object]) -> str:
112
152
 
113
153
  def _erro(acao: str, res: requests.Response) -> RespostaError:
114
154
  """Erro de uma resposta não-200, com a ação que falhou e o que o BB disse."""
115
- return RespostaError(acao, res.status_code, _mensagem_de_erro(res))
155
+ return RespostaError(acao, res.status_code, _mensagem_de_erro(res), resposta=res)
116
156
 
117
157
 
118
158
  def _erro_extrato(res: requests.Response) -> ExtratoError:
119
159
  mensagem = _mensagem_de_erro(res)
120
160
  normalizada = mensagem.casefold()
121
161
  if _ERRO_SEM_LANCAMENTOS in normalizada:
122
- return SemLancamentosError(res.status_code, mensagem)
162
+ return SemLancamentosError(res.status_code, mensagem, resposta=res)
123
163
  if _ERRO_INTERVALO_LONGO in normalizada:
124
- return IntervaloLongoDemaisError(res.status_code, mensagem)
125
- return ExtratoError(res.status_code, mensagem)
164
+ return IntervaloLongoDemaisError(res.status_code, mensagem, resposta=res)
165
+ return ExtratoError(res.status_code, mensagem, resposta=res)
126
166
 
127
167
 
128
168
  def _erro_extrato_aplicacao(res: requests.Response) -> ExtratoError:
@@ -134,7 +174,7 @@ def _erro_extrato_aplicacao(res: requests.Response) -> ExtratoError:
134
174
  """
135
175
  if res.status_code == _STATUS_SEM_MOVIMENTO:
136
176
  mensagem = _mensagem_de_erro(res) or _SEM_MOVIMENTO_PADRAO
137
- return SemLancamentosError(res.status_code, mensagem)
177
+ return SemLancamentosError(res.status_code, mensagem, resposta=res)
138
178
  return _erro_extrato(res)
139
179
 
140
180
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bb_api
3
- Version: 0.5.4
3
+ Version: 0.5.5
4
4
  Summary: Wrapper da API do Banco do Brasil.
5
5
  Requires-Python: >=3.13
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bb_api"
3
- version = "0.5.4"
3
+ version = "0.5.5"
4
4
  description = "Wrapper da API do Banco do Brasil."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes