nia-etl-utils 0.1.0__py3-none-any.whl → 0.2.1__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.
@@ -0,0 +1,394 @@
1
+ """Exceções customizadas para o pacote nia_etl_utils.
2
+
3
+ Este módulo define a hierarquia de exceções usada em todo o pacote,
4
+ permitindo tratamento granular de erros pelos consumidores da biblioteca.
5
+
6
+ Hierarquia:
7
+ NiaEtlError (base)
8
+ ├── ConfiguracaoError
9
+ │ └── VariavelAmbienteError
10
+ ├── DatabaseError
11
+ │ └── ConexaoError
12
+ ├── ArquivoError
13
+ │ ├── EscritaArquivoError
14
+ │ ├── LeituraArquivoError
15
+ │ └── DiretorioError
16
+ ├── ExtracaoError
17
+ │ └── ExtracaoVaziaError
18
+ ├── EmailError
19
+ │ ├── DestinatarioError
20
+ │ └── SmtpError
21
+ ├── OcrError
22
+ │ ├── OcrSubmissaoError
23
+ │ ├── OcrProcessamentoError
24
+ │ └── OcrTimeoutError
25
+ └── ValidacaoError
26
+
27
+ Examples:
28
+ Capturando erros específicos:
29
+
30
+ >>> from nia_etl_utils.exceptions import ConexaoError, ExtracaoVaziaError
31
+ >>>
32
+ >>> try:
33
+ ... conn = conectar_postgresql(config)
34
+ ... except ConexaoError as e:
35
+ ... logger.error(f"Falha na conexão: {e}")
36
+ ... # tratamento específico
37
+
38
+ Capturando qualquer erro do pacote:
39
+
40
+ >>> from nia_etl_utils.exceptions import NiaEtlError
41
+ >>>
42
+ >>> try:
43
+ ... executar_pipeline()
44
+ ... except NiaEtlError as e:
45
+ ... logger.error(f"Erro no pipeline: {e}")
46
+ ... sys.exit(1) # decisão do CHAMADOR
47
+ """
48
+
49
+
50
+ class NiaEtlError(Exception):
51
+ """Exceção base para todos os erros do pacote nia_etl_utils.
52
+
53
+ Todas as exceções customizadas do pacote herdam desta classe,
54
+ permitindo captura genérica quando necessário.
55
+
56
+ Attributes:
57
+ message: Descrição do erro.
58
+ details: Informações adicionais opcionais sobre o erro.
59
+
60
+ Examples:
61
+ >>> try:
62
+ ... raise NiaEtlError("Algo deu errado", details={"codigo": 123})
63
+ ... except NiaEtlError as e:
64
+ ... print(e.message)
65
+ ... print(e.details)
66
+ Algo deu errado
67
+ {'codigo': 123}
68
+ """
69
+
70
+ def __init__(self, message: str, details: dict | None = None):
71
+ self.message = message
72
+ self.details = details or {}
73
+ super().__init__(self.message)
74
+
75
+ def __str__(self) -> str:
76
+ if self.details:
77
+ return f"{self.message} | Detalhes: {self.details}"
78
+ return self.message
79
+
80
+
81
+ # =============================================================================
82
+ # CONFIGURAÇÃO
83
+ # =============================================================================
84
+
85
+
86
+ class ConfiguracaoError(NiaEtlError):
87
+ """Erro de configuração do sistema.
88
+
89
+ Levantado quando há problemas com configurações necessárias
90
+ para o funcionamento do pacote.
91
+
92
+ Examples:
93
+ >>> raise ConfiguracaoError("Configuração inválida para conexão")
94
+ """
95
+
96
+ pass
97
+
98
+
99
+ class VariavelAmbienteError(ConfiguracaoError):
100
+ """Variável de ambiente ausente ou inválida.
101
+
102
+ Levantado quando uma variável de ambiente obrigatória não está
103
+ definida e nenhum valor padrão foi fornecido.
104
+
105
+ Attributes:
106
+ nome_variavel: Nome da variável de ambiente que causou o erro.
107
+
108
+ Examples:
109
+ >>> raise VariavelAmbienteError("DB_HOST")
110
+ """
111
+
112
+ def __init__(self, nome_variavel: str):
113
+ self.nome_variavel = nome_variavel
114
+ super().__init__(
115
+ f"Variável de ambiente '{nome_variavel}' não encontrada "
116
+ f"e nenhum valor padrão foi fornecido",
117
+ details={"variavel": nome_variavel}
118
+ )
119
+
120
+
121
+ # =============================================================================
122
+ # DATABASE
123
+ # =============================================================================
124
+
125
+
126
+ class DatabaseError(NiaEtlError):
127
+ """Erro base para operações de banco de dados.
128
+
129
+ Examples:
130
+ >>> raise DatabaseError("Falha na operação de banco de dados")
131
+ """
132
+
133
+ pass
134
+
135
+
136
+ class ConexaoError(DatabaseError):
137
+ """Falha ao estabelecer conexão com banco de dados.
138
+
139
+ Levantado quando não é possível conectar ao banco de dados,
140
+ seja por credenciais inválidas, host inacessível ou outros
141
+ problemas de conectividade.
142
+
143
+ Examples:
144
+ >>> raise ConexaoError(
145
+ ... "Timeout ao conectar",
146
+ ... details={"host": "localhost", "port": 5432}
147
+ ... )
148
+ """
149
+
150
+ pass
151
+
152
+
153
+ # =============================================================================
154
+ # ARQUIVOS E DIRETÓRIOS
155
+ # =============================================================================
156
+
157
+
158
+ class ArquivoError(NiaEtlError):
159
+ """Erro base para operações de arquivo e diretório.
160
+
161
+ Examples:
162
+ >>> raise ArquivoError("Operação de arquivo falhou")
163
+ """
164
+
165
+ pass
166
+
167
+
168
+ class EscritaArquivoError(ArquivoError):
169
+ """Falha ao escrever arquivo.
170
+
171
+ Levantado quando não é possível criar ou escrever em um arquivo,
172
+ seja por falta de permissão, disco cheio ou caminho inválido.
173
+
174
+ Examples:
175
+ >>> raise EscritaArquivoError(
176
+ ... "Sem permissão para escrita",
177
+ ... details={"caminho": "/etc/arquivo.csv"}
178
+ ... )
179
+ """
180
+
181
+ pass
182
+
183
+
184
+ class LeituraArquivoError(ArquivoError):
185
+ """Falha ao ler arquivo.
186
+
187
+ Levantado quando não é possível ler um arquivo, seja porque
188
+ ele não existe, não há permissão ou está corrompido.
189
+
190
+ Examples:
191
+ >>> raise LeituraArquivoError(
192
+ ... "Arquivo não encontrado",
193
+ ... details={"caminho": "/tmp/dados.csv"}
194
+ ... )
195
+ """
196
+
197
+ pass
198
+
199
+
200
+ class DiretorioError(ArquivoError):
201
+ """Falha em operação de diretório.
202
+
203
+ Levantado quando não é possível criar, limpar ou remover
204
+ um diretório.
205
+
206
+ Examples:
207
+ >>> raise DiretorioError(
208
+ ... "Sem permissão para criar diretório",
209
+ ... details={"caminho": "/root/dados"}
210
+ ... )
211
+ """
212
+
213
+ pass
214
+
215
+
216
+ # =============================================================================
217
+ # EXTRAÇÃO E PROCESSAMENTO
218
+ # =============================================================================
219
+
220
+
221
+ class ExtracaoError(NiaEtlError):
222
+ """Erro base para operações de extração de dados.
223
+
224
+ Examples:
225
+ >>> raise ExtracaoError("Falha na extração de dados")
226
+ """
227
+
228
+ pass
229
+
230
+
231
+ class ExtracaoVaziaError(ExtracaoError):
232
+ """Extração retornou DataFrame vazio ou None.
233
+
234
+ Levantado quando uma função de extração não retorna dados.
235
+ Pode ser esperado em alguns contextos (extração incremental
236
+ sem novos dados) ou indicar um problema.
237
+
238
+ Attributes:
239
+ nome_extracao: Identificador da extração que falhou.
240
+
241
+ Examples:
242
+ >>> raise ExtracaoVaziaError("clientes_novos")
243
+ """
244
+
245
+ def __init__(self, nome_extracao: str):
246
+ self.nome_extracao = nome_extracao
247
+ super().__init__(
248
+ f"Nenhum dado retornado para extração '{nome_extracao}'",
249
+ details={"extracao": nome_extracao}
250
+ )
251
+
252
+
253
+ class ProcessamentoError(ExtracaoError):
254
+ """Erro durante processamento de dados.
255
+
256
+ Levantado quando há falha durante transformação ou
257
+ processamento de dados.
258
+
259
+ Examples:
260
+ >>> raise ProcessamentoError(
261
+ ... "Falha ao processar chunk",
262
+ ... details={"chunk": 5, "erro": "memória insuficiente"}
263
+ ... )
264
+ """
265
+
266
+ pass
267
+
268
+
269
+ # =============================================================================
270
+ # EMAIL
271
+ # =============================================================================
272
+
273
+
274
+ class EmailError(NiaEtlError):
275
+ """Erro base para operações de email.
276
+
277
+ Examples:
278
+ >>> raise EmailError("Falha no envio de email")
279
+ """
280
+
281
+ pass
282
+
283
+
284
+ class DestinatarioError(EmailError):
285
+ """Erro relacionado a destinatários de email.
286
+
287
+ Levantado quando não há destinatários configurados ou
288
+ quando os destinatários são inválidos.
289
+
290
+ Examples:
291
+ >>> raise DestinatarioError("Nenhum destinatário configurado")
292
+ """
293
+
294
+ pass
295
+
296
+
297
+ class SmtpError(EmailError):
298
+ """Erro de comunicação com servidor SMTP.
299
+
300
+ Levantado quando há falha na conexão ou comunicação
301
+ com o servidor de email.
302
+
303
+ Examples:
304
+ >>> raise SmtpError(
305
+ ... "Conexão recusada",
306
+ ... details={"servidor": "smtp.empresa.com", "porta": 587}
307
+ ... )
308
+ """
309
+
310
+ pass
311
+
312
+
313
+ # =============================================================================
314
+ # OCR
315
+ # =============================================================================
316
+
317
+
318
+ class OcrError(NiaEtlError):
319
+ """Erro base para operações de OCR.
320
+
321
+ Examples:
322
+ >>> raise OcrError("Falha no processamento OCR")
323
+ """
324
+
325
+ pass
326
+
327
+
328
+ class OcrSubmissaoError(OcrError):
329
+ """Falha ao submeter documento para OCR.
330
+
331
+ Levantado quando não é possível enviar o documento para a API,
332
+ seja por problemas de rede, timeout ou resposta inválida.
333
+
334
+ Examples:
335
+ >>> raise OcrSubmissaoError(
336
+ ... "Timeout ao submeter documento",
337
+ ... details={"tentativas": 3, "status": 504}
338
+ ... )
339
+ """
340
+
341
+ pass
342
+
343
+
344
+ class OcrProcessamentoError(OcrError):
345
+ """Falha no processamento do documento pela API.
346
+
347
+ Levantado quando a API retorna status FAILURE ou REVOKED,
348
+ indicando que o documento não pôde ser processado.
349
+
350
+ Examples:
351
+ >>> raise OcrProcessamentoError(
352
+ ... "Documento corrompido",
353
+ ... details={"document_id": "abc-123", "erro_api": "invalid format"}
354
+ ... )
355
+ """
356
+
357
+ pass
358
+
359
+
360
+ class OcrTimeoutError(OcrError):
361
+ """Timeout aguardando resultado do OCR.
362
+
363
+ Levantado quando o tempo máximo de polling é atingido
364
+ sem que a API retorne um resultado final.
365
+
366
+ Examples:
367
+ >>> raise OcrTimeoutError(
368
+ ... "Timeout após 300s",
369
+ ... details={"document_id": "abc-123", "ultimo_status": "PENDING"}
370
+ ... )
371
+ """
372
+
373
+ pass
374
+
375
+
376
+ # =============================================================================
377
+ # VALIDAÇÃO
378
+ # =============================================================================
379
+
380
+
381
+ class ValidacaoError(NiaEtlError):
382
+ """Erro de validação de parâmetros ou dados.
383
+
384
+ Levantado quando parâmetros fornecidos são inválidos
385
+ ou não atendem aos requisitos esperados.
386
+
387
+ Examples:
388
+ >>> raise ValidacaoError(
389
+ ... "Nome do arquivo não pode ser vazio",
390
+ ... details={"parametro": "nome_arquivo", "valor": ""}
391
+ ... )
392
+ """
393
+
394
+ pass