bb_api 0.5.3__tar.gz → 0.5.4__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.3
3
+ Version: 0.5.4
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.3"
7
+ __version__ = "0.5.4"
8
8
 
9
9
 
10
10
  from .common import Ambiente
@@ -14,6 +14,7 @@ from .accountability import (
14
14
  AccountabilityV3ControleAPI,
15
15
  ExtratoError,
16
16
  IntervaloLongoDemaisError,
17
+ RespostaError,
17
18
  SemLancamentosError,
18
19
  )
19
20
  from .sia import (
@@ -36,6 +37,7 @@ __all__ = [
36
37
  "CredenciaisNecessariasError",
37
38
  "ExtratoError",
38
39
  "IntervaloLongoDemaisError",
40
+ "RespostaError",
39
41
  "SemLancamentosError",
40
42
  "FalhaDownload",
41
43
  "ResultadoDownloads",
@@ -23,23 +23,34 @@ _STATUS_SEM_MOVIMENTO = 404
23
23
  _SEM_MOVIMENTO_PADRAO = "não há movimento no período consultado"
24
24
 
25
25
 
26
- class ExtratoError(Exception):
27
- """Erro devolvido pela API ao consultar o extrato do órgão repassador.
26
+ class RespostaError(Exception):
27
+ """Resposta de erro devolvida pela API do Banco do Brasil.
28
28
 
29
- Carrega o status HTTP e a mensagem originais do Banco do Brasil, porque a
30
- API usa ``400`` tanto para falha de verdade quanto para situações normais.
29
+ Carrega o status HTTP e a mensagem originais junto da ação que falhou. Sem
30
+ eles, um ``404`` de "não o que devolver", um ``403`` de escopo que falta
31
+ e um ``400`` de parâmetro inválido chegam ao chamador iguais.
31
32
  """
32
33
 
33
34
  status_code: int
34
35
  mensagem: str
35
36
 
36
- def __init__(self, status_code: int, mensagem: str) -> None:
37
- detalhe = f"(HTTP {status_code}): {mensagem}"
38
- super().__init__(f"Não foi possível reaver o extrato do órgão repassador {detalhe}")
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}")
39
39
  self.status_code = status_code
40
40
  self.mensagem = mensagem
41
41
 
42
42
 
43
+ class ExtratoError(RespostaError):
44
+ """Erro devolvido pela API ao consultar o extrato do órgão repassador.
45
+
46
+ Carrega o status HTTP e a mensagem originais do Banco do Brasil, porque a
47
+ API usa ``400`` tanto para falha de verdade quanto para situações normais.
48
+ """
49
+
50
+ def __init__(self, status_code: int, mensagem: str) -> None:
51
+ super().__init__("reaver o extrato do órgão repassador", status_code, mensagem)
52
+
53
+
43
54
  class SemLancamentosError(ExtratoError):
44
55
  """A conta não tem lançamento nenhum no período consultado.
45
56
 
@@ -99,6 +110,11 @@ def _mensagem_da_lista_de_erros(campos: dict[str, object]) -> str:
99
110
  return ""
100
111
 
101
112
 
113
+ def _erro(acao: str, res: requests.Response) -> RespostaError:
114
+ """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))
116
+
117
+
102
118
  def _erro_extrato(res: requests.Response) -> ExtratoError:
103
119
  mensagem = _mensagem_de_erro(res)
104
120
  normalizada = mensagem.casefold()
@@ -235,7 +251,7 @@ class _AccountabilityV3BaseAPI:
235
251
  )
236
252
 
237
253
  if res.status_code != 200:
238
- raise Exception("Não foi possível adquirir as novas credenciais de acesso.")
254
+ raise _erro("adquirir as novas credenciais de acesso", res)
239
255
 
240
256
  data = common.parse_json_object(res)
241
257
  self._access_token = cast("str", data["access_token"])
@@ -266,9 +282,7 @@ class _AccountabilityV3BaseAPI:
266
282
  )
267
283
 
268
284
  if res.status_code != 200:
269
- raise Exception(
270
- "Não foi possível listar as categorias do programa de governo."
271
- )
285
+ raise _erro("listar as agências próximas", res)
272
286
 
273
287
  res = common.parse_json_object(res)
274
288
  return common.handle_results(
@@ -411,7 +425,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
411
425
  )
412
426
 
413
427
  if res.status_code != 200:
414
- raise Exception("Não foi possível reaver o extrato do órgão repassador.")
428
+ raise _erro("reaver o documento de despesa do programa de governo", res)
415
429
 
416
430
  res = common.parse_json_object(res)
417
431
 
@@ -542,7 +556,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
542
556
  )
543
557
 
544
558
  if res.status_code != 200:
545
- raise Exception("Não foi possível reaver o extrato do órgão repassador.")
559
+ raise _erro("reaver o documento de despesa da prestação de contas", res)
546
560
 
547
561
  res = common.parse_json_object(res)
548
562
 
@@ -674,7 +688,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
674
688
  )
675
689
 
676
690
  if res.status_code != 200:
677
- raise Exception("Não foi possível reaver o extrato do órgão repassador.")
691
+ raise _erro("reaver o extrato de subtransações do programa de governo", res)
678
692
 
679
693
  res = common.parse_json_object(res)
680
694
 
@@ -974,9 +988,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
974
988
  )
975
989
 
976
990
  if res.status_code != 200:
977
- raise Exception(
978
- "Não foi possível listar as categorias do programa de governo."
979
- )
991
+ raise _erro("listar os lançamentos atualizados do programa de governo", res)
980
992
 
981
993
  res = common.parse_json_object(res)
982
994
  return common.handle_results(
@@ -1017,9 +1029,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1017
1029
  )
1018
1030
 
1019
1031
  if res.status_code != 200:
1020
- raise Exception(
1021
- "Não foi possível listar as categorias do programa de governo."
1022
- )
1032
+ raise _erro("listar os sublançamentos atualizados do programa de governo", res)
1023
1033
 
1024
1034
  res = common.parse_json_object(res)
1025
1035
  return common.handle_results(
@@ -1053,9 +1063,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1053
1063
  )
1054
1064
 
1055
1065
  if res.status_code != 200:
1056
- raise Exception(
1057
- "Não foi possível listar as categorias do programa de governo."
1058
- )
1066
+ raise _erro("listar as categorias do programa de governo", res)
1059
1067
 
1060
1068
  res = common.parse_json_object(res)
1061
1069
  return common.handle_results(
@@ -1086,9 +1094,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1086
1094
  )
1087
1095
 
1088
1096
  if res.status_code != 200:
1089
- raise Exception(
1090
- "Não foi possível listar as categorias do programa de governo."
1091
- )
1097
+ raise _erro("reaver o saldo das aplicações financeiras", res)
1092
1098
 
1093
1099
  res = common.parse_json_object(res)
1094
1100
  return common.handle_results(
@@ -1125,9 +1131,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1125
1131
  )
1126
1132
 
1127
1133
  if res.status_code != 200:
1128
- raise Exception(
1129
- "Não foi possível listar as categorias do programa de governo."
1130
- )
1134
+ raise _erro("reaver o saldo da conta corrente", res)
1131
1135
 
1132
1136
  res = common.parse_json_object(res)
1133
1137
 
@@ -1173,9 +1177,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1173
1177
  )
1174
1178
 
1175
1179
  if res.status_code not in [200, 201]:
1176
- raise Exception(
1177
- "Não foi possível listar as categorias do programa de governo."
1178
- )
1180
+ raise _erro("categorizar a despesa do lançamento a crédito", res)
1179
1181
 
1180
1182
  res = common.parse_json_object(res)
1181
1183
  return common.handle_results(
@@ -1222,9 +1224,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1222
1224
  )
1223
1225
 
1224
1226
  if res.status_code not in [200, 201]:
1225
- raise Exception(
1226
- "Não foi possível listar as categorias do programa de governo."
1227
- )
1227
+ raise _erro("identificar o lançamento a crédito", res)
1228
1228
 
1229
1229
  res = common.parse_json_object(res)
1230
1230
  return common.handle_results(
@@ -1255,9 +1255,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1255
1255
  )
1256
1256
 
1257
1257
  if res.status_code not in [200, 201]:
1258
- raise Exception(
1259
- "Não foi possível listar as categorias do programa de governo."
1260
- )
1258
+ raise _erro("excluir a identificação do lançamento a crédito", res)
1261
1259
 
1262
1260
  res = common.parse_json_object(res)
1263
1261
  return common.handle_results(
@@ -1286,9 +1284,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
1286
1284
  )
1287
1285
 
1288
1286
  if res.status_code != 200:
1289
- raise Exception(
1290
- "Não foi possível listar as categorias do programa de governo."
1291
- )
1287
+ raise _erro("listar as identificações dos lançamentos a débito", res)
1292
1288
 
1293
1289
  res = common.parse_json_object(res)
1294
1290
  return common.handle_results(
@@ -1431,7 +1427,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
1431
1427
  )
1432
1428
 
1433
1429
  if res.status_code != 200:
1434
- raise Exception("Não foi possível reaver o extrato do órgão repassador.")
1430
+ raise _erro("reaver o documento de despesa do programa de governo", res)
1435
1431
 
1436
1432
  res = common.parse_json_object(res)
1437
1433
 
@@ -1562,7 +1558,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
1562
1558
  )
1563
1559
 
1564
1560
  if res.status_code != 200:
1565
- raise Exception("Não foi possível reaver o extrato do órgão repassador.")
1561
+ raise _erro("reaver o documento de despesa da prestação de contas", res)
1566
1562
 
1567
1563
  res = common.parse_json_object(res)
1568
1564
 
@@ -1688,9 +1684,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
1688
1684
  )
1689
1685
 
1690
1686
  if res.status_code != 200:
1691
- raise Exception(
1692
- "Não foi possível listar as categorias do programa de governo."
1693
- )
1687
+ raise _erro("reaver o extrato de subtransações do programa de governo", res)
1694
1688
 
1695
1689
  res = common.parse_json_object(res)
1696
1690
  return common.handle_results(
@@ -1978,9 +1972,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
1978
1972
  )
1979
1973
 
1980
1974
  if res.status_code != 200:
1981
- raise Exception(
1982
- "Não foi possível listar as categorias do programa de governo."
1983
- )
1975
+ raise _erro("listar as contas correntes do órgão de controle", res)
1984
1976
 
1985
1977
  res = common.parse_json_object(res)
1986
1978
  return common.handle_results(
@@ -60,9 +60,27 @@ def handle_numeric_string_with_symbols(v: str) -> str:
60
60
  return re.sub(r"\D", "", v)
61
61
 
62
62
 
63
+ def _data_de_texto(texto: str) -> datetime:
64
+ """Interpreta uma data em ISO ou em dd/mm/aaaa.
65
+
66
+ A API devolve os dois formatos, e o valor de uma resposta costuma virar
67
+ parâmetro da consulta seguinte: o ``bookingDate`` do extrato chega em
68
+ dd/mm/aaaa e é o que identifica o documento de despesa daquela transação.
69
+ """
70
+ formatos = ("%Y-%m-%d", "%d/%m/%Y")
71
+ for formato in formatos:
72
+ try:
73
+ return datetime.strptime(texto, formato)
74
+ except ValueError:
75
+ continue
76
+
77
+ aceitos = " ou ".join(formatos)
78
+ raise ValueError(f"A data '{texto}' não está em {aceitos}.")
79
+
80
+
63
81
  def handle_dates(v: DateLike) -> str:
64
82
  if isinstance(v, str):
65
- dt = datetime.strptime(v, "%Y-%m-%d")
83
+ dt = _data_de_texto(v)
66
84
  elif isinstance(v, datetime):
67
85
  dt = v
68
86
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bb_api
3
- Version: 0.5.3
3
+ Version: 0.5.4
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.3"
3
+ version = "0.5.4"
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