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.
@@ -1,12 +1,35 @@
1
- """Funções utilitárias para manipulação de arquivos e diretórios."""
2
- import sys
1
+ """Funções utilitárias para manipulação de arquivos e diretórios.
2
+
3
+ Fornece operações comuns de sistema de arquivos com logging
4
+ apropriado e tratamento de erros consistente.
5
+
6
+ Examples:
7
+ Limpar pasta antes de processamento:
8
+
9
+ >>> from nia_etl_utils import limpar_pasta
10
+ >>> limpar_pasta("/tmp/meu_pipeline")
11
+
12
+ Criar estrutura de diretórios:
13
+
14
+ >>> from nia_etl_utils import criar_pasta_se_nao_existir
15
+ >>> criar_pasta_se_nao_existir("/dados/processados/2025/01")
16
+
17
+ Remover pasta temporária:
18
+
19
+ >>> from nia_etl_utils import remover_pasta_recursivamente
20
+ >>> remover_pasta_recursivamente("/tmp/pasta_temporaria")
21
+ """
22
+
3
23
  import shutil
4
24
  from pathlib import Path
25
+
5
26
  from loguru import logger
6
27
 
28
+ from .exceptions import DiretorioError
29
+
7
30
 
8
- def limpar_pasta(pasta: str, log: bool = True) -> None:
9
- """Remove todos os arquivos de uma pasta, recriando-a se necessário.
31
+ def limpar_pasta(pasta: str, log: bool = True) -> int:
32
+ """Remove todos os arquivos de uma pasta, preservando subdiretórios.
10
33
 
11
34
  Se a pasta não existir, ela será criada. Se existir, todos os arquivos
12
35
  dentro dela serão removidos (subdiretórios são preservados).
@@ -15,13 +38,22 @@ def limpar_pasta(pasta: str, log: bool = True) -> None:
15
38
  pasta: Caminho da pasta que será limpa.
16
39
  log: Se True, emite logs com Loguru. Defaults to True.
17
40
 
41
+ Returns:
42
+ Número de arquivos removidos.
43
+
18
44
  Raises:
19
- SystemExit: Se houver erro ao criar ou limpar a pasta.
45
+ DiretorioError: Se houver erro ao criar ou limpar a pasta.
20
46
 
21
47
  Examples:
22
- >>> from nia_etl_utils.limpeza_pastas import limpar_pasta
23
- >>> limpar_pasta("/tmp/meu_pipeline")
24
- >>> # Pasta criada ou limpa com sucesso
48
+ Limpar pasta de saída antes de processamento:
49
+
50
+ >>> from nia_etl_utils import limpar_pasta
51
+ >>> removidos = limpar_pasta("/tmp/meu_pipeline")
52
+ >>> print(f"{removidos} arquivo(s) removido(s)")
53
+
54
+ Limpar sem logging:
55
+
56
+ >>> limpar_pasta("/tmp/dados", log=False)
25
57
  """
26
58
  try:
27
59
  pasta_path = Path(pasta)
@@ -30,46 +62,66 @@ def limpar_pasta(pasta: str, log: bool = True) -> None:
30
62
  pasta_path.mkdir(parents=True, exist_ok=True)
31
63
  if log:
32
64
  logger.info(f"Pasta criada: {pasta}")
33
- else:
34
- arquivos_removidos = 0
65
+ return 0
35
66
 
36
- for item in pasta_path.iterdir():
37
- if item.is_file():
38
- item.unlink()
39
- arquivos_removidos += 1
40
- if log:
41
- logger.debug(f"Arquivo removido: {item}")
67
+ arquivos_removidos = 0
42
68
 
43
- if log:
44
- logger.info(f"Pasta '{pasta}' limpa com sucesso. {arquivos_removidos} arquivo(s) removido(s).")
69
+ for item in pasta_path.iterdir():
70
+ if item.is_file():
71
+ item.unlink()
72
+ arquivos_removidos += 1
73
+ if log:
74
+ logger.debug(f"Arquivo removido: {item}")
45
75
 
46
- except PermissionError as error:
47
- logger.error(f"Sem permissão para acessar/modificar a pasta '{pasta}': {error}")
48
- sys.exit(1)
49
- except OSError as error:
50
- logger.error(f"Erro do sistema ao manipular a pasta '{pasta}': {error}")
51
- sys.exit(1)
52
- except Exception as error:
53
- logger.error(f"Erro inesperado ao limpar a pasta '{pasta}': {error}")
54
- sys.exit(1)
76
+ if log:
77
+ logger.info(
78
+ f"Pasta '{pasta}' limpa com sucesso. "
79
+ f"{arquivos_removidos} arquivo(s) removido(s)."
80
+ )
55
81
 
82
+ return arquivos_removidos
56
83
 
57
- def remover_pasta_recursivamente(pasta: str, log: bool = True) -> None:
84
+ except PermissionError as e:
85
+ raise DiretorioError(
86
+ f"Sem permissão para acessar/modificar a pasta '{pasta}'",
87
+ details={"pasta": pasta, "erro": str(e)}
88
+ ) from e
89
+ except OSError as e:
90
+ raise DiretorioError(
91
+ f"Erro do sistema ao manipular a pasta '{pasta}'",
92
+ details={"pasta": pasta, "erro": str(e)}
93
+ ) from e
94
+
95
+
96
+ def remover_pasta_recursivamente(pasta: str, log: bool = True) -> bool:
58
97
  """Remove uma pasta e todo seu conteúdo (arquivos e subpastas).
59
98
 
60
- ATENÇÃO: Esta função remove TUDO dentro da pasta, incluindo subdiretórios.
61
- Use com cautela.
99
+ ATENÇÃO: Esta função remove TUDO dentro da pasta, incluindo
100
+ subdiretórios. Use com cautela.
62
101
 
63
102
  Args:
64
103
  pasta: Caminho da pasta que será removida completamente.
65
104
  log: Se True, emite logs com Loguru. Defaults to True.
66
105
 
106
+ Returns:
107
+ True se a pasta foi removida, False se não existia.
108
+
67
109
  Raises:
68
- SystemExit: Se houver erro ao remover a pasta.
110
+ DiretorioError: Se o caminho não for um diretório ou
111
+ houver erro ao remover.
69
112
 
70
113
  Examples:
71
- >>> from nia_etl_utils.limpeza_pastas import remover_pasta_recursivamente
72
- >>> remover_pasta_recursivamente("/tmp/pasta_temporaria")
114
+ Remover pasta temporária:
115
+
116
+ >>> from nia_etl_utils import remover_pasta_recursivamente
117
+ >>> if remover_pasta_recursivamente("/tmp/pasta_temporaria"):
118
+ ... print("Pasta removida")
119
+ ... else:
120
+ ... print("Pasta não existia")
121
+
122
+ Remover sem logging:
123
+
124
+ >>> remover_pasta_recursivamente("/tmp/dados", log=False)
73
125
  """
74
126
  try:
75
127
  pasta_path = Path(pasta)
@@ -77,41 +129,58 @@ def remover_pasta_recursivamente(pasta: str, log: bool = True) -> None:
77
129
  if not pasta_path.exists():
78
130
  if log:
79
131
  logger.warning(f"Pasta '{pasta}' não existe. Nada a remover.")
80
- return
132
+ return False
81
133
 
82
134
  if not pasta_path.is_dir():
83
- logger.error(f"'{pasta}' não é um diretório.")
84
- sys.exit(1)
135
+ raise DiretorioError(
136
+ f"'{pasta}' não é um diretório",
137
+ details={"pasta": pasta, "tipo": "arquivo"}
138
+ )
85
139
 
86
140
  shutil.rmtree(pasta_path)
87
141
 
88
142
  if log:
89
143
  logger.info(f"Pasta '{pasta}' removida completamente (incluindo subpastas).")
90
144
 
91
- except PermissionError as error:
92
- logger.error(f"Sem permissão para remover a pasta '{pasta}': {error}")
93
- sys.exit(1)
94
- except OSError as error:
95
- logger.error(f"Erro do sistema ao remover a pasta '{pasta}': {error}")
96
- sys.exit(1)
97
- except Exception as error:
98
- logger.error(f"Erro inesperado ao remover a pasta '{pasta}': {error}")
99
- sys.exit(1)
145
+ return True
100
146
 
147
+ except PermissionError as e:
148
+ raise DiretorioError(
149
+ f"Sem permissão para remover a pasta '{pasta}'",
150
+ details={"pasta": pasta, "erro": str(e)}
151
+ ) from e
152
+ except OSError as e:
153
+ raise DiretorioError(
154
+ f"Erro do sistema ao remover a pasta '{pasta}'",
155
+ details={"pasta": pasta, "erro": str(e)}
156
+ ) from e
101
157
 
102
- def criar_pasta_se_nao_existir(pasta: str, log: bool = True) -> None:
158
+
159
+ def criar_pasta_se_nao_existir(pasta: str, log: bool = True) -> bool:
103
160
  """Cria uma pasta se ela não existir (incluindo pastas pai).
104
161
 
105
162
  Args:
106
163
  pasta: Caminho da pasta que será criada.
107
164
  log: Se True, emite logs com Loguru. Defaults to True.
108
165
 
166
+ Returns:
167
+ True se a pasta foi criada, False se já existia.
168
+
109
169
  Raises:
110
- SystemExit: Se houver erro ao criar a pasta.
170
+ DiretorioError: Se houver erro ao criar a pasta.
111
171
 
112
172
  Examples:
113
- >>> from nia_etl_utils.limpeza_pastas import criar_pasta_se_nao_existir
114
- >>> criar_pasta_se_nao_existir("/tmp/dados/processados/2025")
173
+ Criar estrutura de diretórios:
174
+
175
+ >>> from nia_etl_utils import criar_pasta_se_nao_existir
176
+ >>> if criar_pasta_se_nao_existir("/tmp/dados/processados/2025"):
177
+ ... print("Estrutura criada")
178
+ ... else:
179
+ ... print("Já existia")
180
+
181
+ Criar sem logging:
182
+
183
+ >>> criar_pasta_se_nao_existir("/tmp/dados", log=False)
115
184
  """
116
185
  try:
117
186
  pasta_path = Path(pasta)
@@ -119,19 +188,83 @@ def criar_pasta_se_nao_existir(pasta: str, log: bool = True) -> None:
119
188
  if pasta_path.exists():
120
189
  if log:
121
190
  logger.debug(f"Pasta '{pasta}' já existe.")
122
- return
191
+ return False
123
192
 
124
193
  pasta_path.mkdir(parents=True, exist_ok=True)
125
194
 
126
195
  if log:
127
196
  logger.info(f"Pasta criada: {pasta}")
128
197
 
129
- except PermissionError as error:
130
- logger.error(f"Sem permissão para criar a pasta '{pasta}': {error}")
131
- sys.exit(1)
132
- except OSError as error:
133
- logger.error(f"Erro do sistema ao criar a pasta '{pasta}': {error}")
134
- sys.exit(1)
135
- except Exception as error:
136
- logger.error(f"Erro inesperado ao criar a pasta '{pasta}': {error}")
137
- sys.exit(1)
198
+ return True
199
+
200
+ except PermissionError as e:
201
+ raise DiretorioError(
202
+ f"Sem permissão para criar a pasta '{pasta}'",
203
+ details={"pasta": pasta, "erro": str(e)}
204
+ ) from e
205
+ except OSError as e:
206
+ raise DiretorioError(
207
+ f"Erro do sistema ao criar a pasta '{pasta}'",
208
+ details={"pasta": pasta, "erro": str(e)}
209
+ ) from e
210
+
211
+
212
+ def listar_arquivos(
213
+ pasta: str,
214
+ extensao: str | None = None,
215
+ recursivo: bool = False
216
+ ) -> list[Path]:
217
+ """Lista arquivos em uma pasta.
218
+
219
+ Args:
220
+ pasta: Caminho da pasta a ser listada.
221
+ extensao: Filtrar por extensão (ex: ".csv", ".json").
222
+ Se None, lista todos os arquivos.
223
+ recursivo: Se True, inclui arquivos em subpastas.
224
+
225
+ Returns:
226
+ Lista de objetos Path para cada arquivo encontrado.
227
+
228
+ Raises:
229
+ DiretorioError: Se a pasta não existir ou não for acessível.
230
+
231
+ Examples:
232
+ Listar todos os CSVs:
233
+
234
+ >>> arquivos = listar_arquivos("/tmp/dados", extensao=".csv")
235
+ >>> for arq in arquivos:
236
+ ... print(arq.name)
237
+
238
+ Listar recursivamente:
239
+
240
+ >>> arquivos = listar_arquivos("/tmp/dados", recursivo=True)
241
+ """
242
+ try:
243
+ pasta_path = Path(pasta)
244
+
245
+ if not pasta_path.exists():
246
+ raise DiretorioError(
247
+ f"Pasta '{pasta}' não existe",
248
+ details={"pasta": pasta}
249
+ )
250
+
251
+ if not pasta_path.is_dir():
252
+ raise DiretorioError(
253
+ f"'{pasta}' não é um diretório",
254
+ details={"pasta": pasta}
255
+ )
256
+
257
+ if recursivo:
258
+ pattern = "**/*" if extensao is None else f"**/*{extensao}"
259
+ arquivos = [p for p in pasta_path.glob(pattern) if p.is_file()]
260
+ else:
261
+ pattern = "*" if extensao is None else f"*{extensao}"
262
+ arquivos = [p for p in pasta_path.glob(pattern) if p.is_file()]
263
+
264
+ return sorted(arquivos)
265
+
266
+ except PermissionError as e:
267
+ raise DiretorioError(
268
+ f"Sem permissão para acessar a pasta '{pasta}'",
269
+ details={"pasta": pasta, "erro": str(e)}
270
+ ) from e
@@ -1,8 +1,39 @@
1
- """Módulo utilitário para configuração de logging com Loguru."""
2
- import sys
1
+ """Módulo utilitário para configuração de logging com Loguru.
2
+
3
+ Fornece funções para configurar o logger com rotação automática,
4
+ retenção configurável e estrutura de diretórios organizada.
5
+
6
+ Examples:
7
+ Configuração básica:
8
+
9
+ >>> from nia_etl_utils import configurar_logger
10
+ >>> caminho = configurar_logger("extract", "2025_01_20")
11
+ >>> logger.info("Pipeline iniciado")
12
+
13
+ Configuração com padrões NIA:
14
+
15
+ >>> from nia_etl_utils import configurar_logger_padrao_nia
16
+ >>> caminho = configurar_logger_padrao_nia("ouvidorias_etl")
17
+
18
+ Configuração customizada:
19
+
20
+ >>> caminho = configurar_logger(
21
+ ... prefixo="etl_vendas",
22
+ ... data_extracao="2025_01_20",
23
+ ... pasta_logs="/var/log/nia",
24
+ ... rotation="50 MB",
25
+ ... retention="30 days",
26
+ ... level="INFO"
27
+ ... )
28
+ """
29
+
30
+ from datetime import datetime
3
31
  from pathlib import Path
32
+
4
33
  from loguru import logger
5
34
 
35
+ from .exceptions import DiretorioError, ValidacaoError
36
+
6
37
 
7
38
  def configurar_logger(
8
39
  prefixo: str,
@@ -14,32 +45,43 @@ def configurar_logger(
14
45
  ) -> str:
15
46
  """Configura o logger da aplicação com Loguru.
16
47
 
17
- Cria um handler de arquivo para o logger com rotação automática e retenção
18
- configurável. O arquivo de log é criado em uma estrutura de diretórios
19
- organizada por prefixo.
48
+ Cria um handler de arquivo para o logger com rotação automática
49
+ e retenção configurável. O arquivo de log é criado em uma estrutura
50
+ de diretórios organizada por prefixo.
20
51
 
21
52
  Args:
22
53
  prefixo: Nome do módulo/pipeline (ex: 'extract', 'transform', 'load').
54
+ Usado para criar subdiretório e nomear arquivo.
23
55
  data_extracao: Data usada no nome do arquivo de log (ex: '2025_01_19').
24
- pasta_logs: Diretório raiz onde os logs serão armazenados. Defaults to "logs".
25
- rotation: Critério de rotação do arquivo (tamanho ou tempo). Defaults to "10 MB".
26
- retention: Tempo de retenção dos logs antigos. Defaults to "7 days".
27
- level: Nível mínimo de log a ser registrado. Defaults to "DEBUG".
56
+ pasta_logs: Diretório raiz onde os logs serão armazenados.
57
+ Defaults to "logs".
58
+ rotation: Critério de rotação do arquivo. Pode ser tamanho
59
+ ("10 MB", "500 KB") ou tempo ("1 day", "1 week").
60
+ Defaults to "10 MB".
61
+ retention: Tempo de retenção dos logs antigos antes de serem
62
+ removidos. Defaults to "7 days".
63
+ level: Nível mínimo de log a ser registrado. Opções: DEBUG,
64
+ INFO, WARNING, ERROR, CRITICAL. Defaults to "DEBUG".
28
65
 
29
66
  Returns:
30
- str: Caminho completo do arquivo de log criado.
67
+ Caminho completo do arquivo de log criado.
31
68
 
32
69
  Raises:
33
- SystemExit: Se houver erro ao criar diretórios ou configurar o logger.
70
+ ValidacaoError: Se prefixo ou data_extracao forem vazios.
71
+ DiretorioError: Se houver erro ao criar diretórios de log.
34
72
 
35
73
  Examples:
36
- >>> from nia_etl_utils.logger_config import configurar_logger
37
- >>> caminho_log = configurar_logger("extract", "2025_01_19")
74
+ Configuração básica:
75
+
76
+ >>> from nia_etl_utils import configurar_logger
77
+ >>> from loguru import logger
78
+ >>> caminho = configurar_logger("extract", "2025_01_19")
38
79
  >>> logger.info("Pipeline iniciado")
39
80
  >>> # Log salvo em: logs/extract/extract_2025_01_19.log
40
81
 
41
- >>> # Com configurações customizadas
42
- >>> caminho_log = configurar_logger(
82
+ Com configurações customizadas:
83
+
84
+ >>> caminho = configurar_logger(
43
85
  ... prefixo="etl_ouvidorias",
44
86
  ... data_extracao="2025_01_19",
45
87
  ... pasta_logs="/var/logs/nia",
@@ -48,16 +90,20 @@ def configurar_logger(
48
90
  ... level="INFO"
49
91
  ... )
50
92
  """
51
- try:
52
- # Valida inputs
53
- if not prefixo or not prefixo.strip():
54
- logger.error("Prefixo não pode ser vazio.")
55
- sys.exit(1)
93
+ # Validações
94
+ if not prefixo or not prefixo.strip():
95
+ raise ValidacaoError(
96
+ "Prefixo não pode ser vazio",
97
+ details={"parametro": "prefixo", "valor": prefixo}
98
+ )
56
99
 
57
- if not data_extracao or not data_extracao.strip():
58
- logger.error("Data de extração não pode ser vazia.")
59
- sys.exit(1)
100
+ if not data_extracao or not data_extracao.strip():
101
+ raise ValidacaoError(
102
+ "Data de extração não pode ser vazia",
103
+ details={"parametro": "data_extracao", "valor": data_extracao}
104
+ )
60
105
 
106
+ try:
61
107
  # Cria estrutura de diretórios
62
108
  diretorio_log = Path(pasta_logs) / prefixo
63
109
  diretorio_log.mkdir(parents=True, exist_ok=True)
@@ -79,15 +125,16 @@ def configurar_logger(
79
125
 
80
126
  return str(caminho_log)
81
127
 
82
- except PermissionError as error:
83
- logger.error(f"Sem permissão para criar diretório de logs '{pasta_logs}': {error}")
84
- sys.exit(1)
85
- except OSError as error:
86
- logger.error(f"Erro do sistema ao configurar logger em '{pasta_logs}': {error}")
87
- sys.exit(1)
88
- except Exception as error:
89
- logger.error(f"Erro inesperado ao configurar logger: {error}")
90
- sys.exit(1)
128
+ except PermissionError as e:
129
+ raise DiretorioError(
130
+ f"Sem permissão para criar diretório de logs '{pasta_logs}'",
131
+ details={"pasta": pasta_logs, "erro": str(e)}
132
+ ) from e
133
+ except OSError as e:
134
+ raise DiretorioError(
135
+ f"Erro do sistema ao configurar logger em '{pasta_logs}'",
136
+ details={"pasta": pasta_logs, "erro": str(e)}
137
+ ) from e
91
138
 
92
139
 
93
140
  def configurar_logger_padrao_nia(nome_pipeline: str) -> str:
@@ -104,17 +151,19 @@ def configurar_logger_padrao_nia(nome_pipeline: str) -> str:
104
151
  nome_pipeline: Nome do pipeline (será usado como prefixo e na data).
105
152
 
106
153
  Returns:
107
- str: Caminho completo do arquivo de log criado.
154
+ Caminho completo do arquivo de log criado.
155
+
156
+ Raises:
157
+ ValidacaoError: Se nome_pipeline for vazio.
158
+ DiretorioError: Se houver erro ao criar diretórios.
108
159
 
109
160
  Examples:
110
- >>> from nia_etl_utils.logger_config import configurar_logger_padrao_nia
111
- >>> from datetime import datetime
161
+ >>> from nia_etl_utils import configurar_logger_padrao_nia
162
+ >>> from loguru import logger
112
163
  >>>
113
- >>> caminho_log = configurar_logger_padrao_nia("ouvidorias_etl")
164
+ >>> caminho = configurar_logger_padrao_nia("ouvidorias_etl")
114
165
  >>> logger.info("Pipeline iniciado com configurações padrão NIA")
115
166
  """
116
- from datetime import datetime
117
-
118
167
  data_hoje = datetime.now().strftime("%Y_%m_%d")
119
168
 
120
169
  return configurar_logger(
@@ -133,8 +182,12 @@ def remover_handlers_existentes() -> None:
133
182
  Útil quando você precisa reconfigurar o logger do zero ou quando está
134
183
  rodando múltiplos scripts em sequência que configuram o logger.
135
184
 
185
+ Note:
186
+ Após chamar esta função, apenas o handler padrão (stderr) estará
187
+ ativo. Chame configurar_logger() para adicionar novos handlers.
188
+
136
189
  Examples:
137
- >>> from nia_etl_utils.logger_config import remover_handlers_existentes, configurar_logger
190
+ >>> from nia_etl_utils import remover_handlers_existentes, configurar_logger
138
191
  >>>
139
192
  >>> # Remove handlers anteriores
140
193
  >>> remover_handlers_existentes()
@@ -143,4 +196,9 @@ def remover_handlers_existentes() -> None:
143
196
  >>> configurar_logger("novo_pipeline", "2025_01_19")
144
197
  """
145
198
  logger.remove()
146
- logger.info("Todos os handlers do logger foram removidos.")
199
+ logger.add(
200
+ sink=lambda msg: print(msg, end=""),
201
+ level="DEBUG",
202
+ format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}"
203
+ )
204
+ logger.debug("Handlers do logger foram resetados.")