csc-cia-stne 0.0.43__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+ import logging
2
+ from pythonjsonlogger import jsonlogger
3
+
4
+ def setup_json_logger():
5
+
6
+ def add_log_level(level_name, level_num, method_name=None):
7
+ """
8
+ Adiciona um log level
9
+
10
+ Parâmetros:
11
+ level_name (str): Nome do level
12
+ level_num (int): Número do level
13
+ """
14
+ if not method_name:
15
+
16
+ method_name = level_name.lower()
17
+
18
+ if hasattr(logging, level_name):
19
+
20
+ raise AttributeError('{} already defined in logging module'.format(level_name))
21
+
22
+ if hasattr(logging, method_name):
23
+
24
+ raise AttributeError('{} already defined in logging module'.format(method_name))
25
+
26
+ if hasattr(logging.getLoggerClass(), method_name):
27
+
28
+ raise AttributeError('{} already defined in logger class'.format(method_name))
29
+
30
+ def log_for_level(self, message, *args, **kwargs):
31
+
32
+ if self.isEnabledFor(level_num):
33
+
34
+ #self._log(level_num, message, args, **kwargs)
35
+ self._log(level_num, message, args, **{**kwargs, "stacklevel": 2})
36
+
37
+ def log_to_root(message, *args, **kwargs):
38
+
39
+ logging.log(level_num, message, *args, **kwargs)
40
+
41
+ logging.addLevelName(level_num, level_name)
42
+ setattr(logging, level_name, level_num)
43
+ setattr(logging.getLoggerClass(), method_name, log_for_level)
44
+ setattr(logging, method_name, log_to_root)
45
+
46
+ if not 'SUCCESS' in logging._nameToLevel:
47
+ add_log_level("SUCCESS",21)
48
+ logger = logging.getLogger(__name__)
49
+ logger.setLevel(logging.INFO)
50
+
51
+ # Remove handlers anteriores, se houver
52
+ if logger.hasHandlers():
53
+ logger.handlers.clear()
54
+
55
+ log_handler = logging.StreamHandler()
56
+ formatter = jsonlogger.JsonFormatter(
57
+ fmt='%(asctime)s %(levelname)s %(name)s %(message)s %(pathname)s %(lineno)d %(exc_info)s %(stack_info)s %(funcName)s %(module)s',
58
+ json_ensure_ascii=False
59
+ )
60
+ log_handler.setFormatter(formatter)
61
+ logger.addHandler(log_handler)
62
+
63
+ # Capturando logs da biblioteca FastAPI/Uvicorn
64
+ #uvicorn_logger = logging.getLogger("uvicorn")
65
+ #uvicorn_logger.handlers = logger.handlers
66
+ #uvicorn_logger.setLevel(logging.INFO)
67
+
68
+ #uvicorn_error_logger = logging.getLogger("uvicorn.error")
69
+ #uvicorn_error_logger.handlers = logger.handlers
70
+ #uvicorn_error_logger.setLevel(logging.INFO)
71
+
72
+ #uvicorn_access_logger = logging.getLogger("uvicorn.access")
73
+ #uvicorn_access_logger.handlers = logger.handlers
74
+ #uvicorn_access_logger.setLevel(logging.INFO)
75
+
76
+ return logger
77
+
78
+ # Chama a função para configurar o logger
79
+ #logger = setup_json_logger()
80
+
81
+ def get_logger():
82
+ """
83
+ logger = logging.getLogger("my_json_logger")
84
+ if not logger.hasHandlers(): # Evita configurar múltiplas vezes
85
+ handler = logging.StreamHandler()
86
+ formatter = logging.Formatter(json.dumps({"level": "%(levelname)s", "message": "%(message)s"}))
87
+ handler.setFormatter(formatter)
88
+ logger.setLevel(logging.DEBUG)
89
+ logger.addHandler(handler)
90
+ """
91
+ logger = setup_json_logger()
92
+ return logger
@@ -0,0 +1,249 @@
1
+ import logging
2
+ from rich.logging import RichHandler
3
+ from rich.theme import Theme
4
+ from rich.console import Console
5
+ from rich.traceback import install
6
+ import re
7
+ import traceback
8
+ import os
9
+ """
10
+ # Instala formatações de exception da biblioteca Rich
11
+ install()
12
+
13
+ # Definindo o nível de log baseado nas configurações
14
+ if os.getenv('log_level') is None:
15
+
16
+ log_config_level = logging.DEBUG
17
+
18
+ elif os.getenv('log_level') == "DEBUG":
19
+
20
+ log_config_level = logging.DEBUG
21
+
22
+ elif os.getenv('log_level') == "INFO":
23
+
24
+ log_config_level = logging.INFO
25
+
26
+ else:
27
+
28
+ log_config_level = logging.WARNING # ou outro nível padrão
29
+
30
+ # Definindo o tema customizado
31
+ custom_theme = Theme({
32
+ # python -m rich.color - cores
33
+ # python -m rich.default_styles - item + cor padrão
34
+ "logging.level.debug": "bold bright_cyan",
35
+ "logging.level.info": "bold bright_white",
36
+ "logging.level.warning": "bold orange1",
37
+ "logging.level.error": "bold red blink",
38
+ "logging.level.critical": "bold white on red blink",
39
+ "logging.level.success": "bold bright_green",
40
+ "log.time":"bold white",
41
+ "log.message":"bold gray70",
42
+ "repr.str":"dark_olive_green3",
43
+ "inspect.value.border":"blue",
44
+ })
45
+
46
+ console = Console(theme=custom_theme)
47
+
48
+ class CustomRichHandler(RichHandler):
49
+ def __init__(self, *args, rich_tracebacks=True, show_time=True, show_level=True, show_path=True, console=console, omit_repeated_times=True, **kwargs):
50
+ super().__init__(rich_tracebacks=rich_tracebacks, show_time=show_time, show_level=show_level, show_path=show_path, console=console, omit_repeated_times=omit_repeated_times, *args, **kwargs)
51
+ self.show_time = show_time
52
+
53
+
54
+ def format(self, record: logging.LogRecord) -> str:
55
+ try:
56
+ msg = f"| {record.getMessage()}"
57
+ #msg = f"{record.getMessage()}"
58
+
59
+ return(str(msg))
60
+ except Exception as e:
61
+ print("FALHA AO FORMATAR O LOG")
62
+ print(e)
63
+
64
+ # Configurando o logging com o CustomRichHandler
65
+ logging.basicConfig(
66
+ level=log_config_level,
67
+ handlers=[CustomRichHandler()],
68
+ datefmt="%d/%m/%Y %H:%M:%S |",
69
+ format="| %(message)s"
70
+ )
71
+
72
+ def add_log_level(level_name, level_num, method_name=None):
73
+ #""
74
+ #Adiciona um log level
75
+ #
76
+ #Parâmetros:
77
+ # level_name (str): Nome do level
78
+ # level_num (int): Número do level
79
+ #""
80
+ if not method_name:
81
+
82
+ method_name = level_name.lower()
83
+
84
+ if hasattr(logging, level_name):
85
+
86
+ raise AttributeError('{} already defined in logging module'.format(level_name))
87
+
88
+ if hasattr(logging, method_name):
89
+
90
+ raise AttributeError('{} already defined in logging module'.format(method_name))
91
+
92
+ if hasattr(logging.getLoggerClass(), method_name):
93
+
94
+ raise AttributeError('{} already defined in logger class'.format(method_name))
95
+
96
+ def log_for_level(self, message, *args, **kwargs):
97
+
98
+ if self.isEnabledFor(level_num):
99
+
100
+ #self._log(level_num, message, args, **kwargs)
101
+ self._log(level_num, message, args, **{**kwargs, "stacklevel": 2})
102
+
103
+ def log_to_root(message, *args, **kwargs):
104
+
105
+ logging.log(level_num, message, *args, **kwargs)
106
+
107
+ logging.addLevelName(level_num, level_name)
108
+ setattr(logging, level_name, level_num)
109
+ setattr(logging.getLoggerClass(), method_name, log_for_level)
110
+ setattr(logging, method_name, log_to_root)
111
+
112
+ add_log_level("SUCCESS",21)
113
+
114
+ logger = logging.getLogger()
115
+
116
+ """
117
+
118
+ def get_logger():
119
+ """
120
+ Retorna um objeto logger configurado com base nas variáveis de ambiente.
121
+ Returns:
122
+ logging.Logger: Objeto logger configurado.
123
+ Raises:
124
+ ValueError: Se o valor da variável de ambiente 'log_level' não for 'DEBUG', 'INFO', 'WARNING', 'ERROR' ou 'CRITICAL'.
125
+ """
126
+ # Instala formatações de exception da biblioteca Rich
127
+ install()
128
+
129
+ # Definindo o nível de log baseado nas configurações
130
+ if os.getenv('log_level') is None or os.getenv('log_level') == "DEBUG":
131
+
132
+ log_config_level = logging.DEBUG
133
+
134
+ elif os.getenv('log_level') == "INFO":
135
+
136
+ log_config_level = logging.INFO
137
+
138
+ elif os.getenv('log_level') == "WARNING" or os.getenv('log_level') == "WARN":
139
+
140
+ log_config_level = logging.WARNING
141
+
142
+ elif os.getenv('log_level') == "ERROR":
143
+
144
+ log_config_level = logging.ERROR
145
+
146
+ elif os.getenv('log_level') == "CRITICAL":
147
+
148
+ log_config_level = logging.CRITICAL
149
+
150
+ else:
151
+
152
+ log_config_level = logging.INFO # ou outro nível padrão
153
+ raise ValueError("'log_level' precisa ser 'DEBUG,'INFO','WARNING','ERROR' ou 'CRITICAL'")
154
+
155
+ # Definindo o tema customizado
156
+ custom_theme = Theme({
157
+ # python -m rich.color - cores
158
+ # python -m rich.default_styles - item + cor padrão
159
+ "logging.level.debug": "bold bright_cyan",
160
+ "logging.level.info": "bold bright_white",
161
+ "logging.level.warning": "bold orange1",
162
+ "logging.level.error": "bold red blink",
163
+ "logging.level.critical": "bold white on red blink",
164
+ "logging.level.success": "bold bright_green",
165
+ "log.time":"bold white",
166
+ "log.message":"bold gray70",
167
+ "repr.str":"dark_olive_green3",
168
+ "inspect.value.border":"blue",
169
+ })
170
+
171
+ console = Console(theme=custom_theme)
172
+
173
+ class CustomRichHandler(RichHandler):
174
+ def __init__(self, *args, rich_tracebacks=True, show_time=True, show_level=True, show_path=True, console=console, omit_repeated_times=True, **kwargs):
175
+ super().__init__(rich_tracebacks=rich_tracebacks, show_time=show_time, show_level=show_level, show_path=show_path, console=console, omit_repeated_times=omit_repeated_times, *args, **kwargs)
176
+ self.show_time = show_time
177
+
178
+
179
+ def format(self, record: logging.LogRecord) -> str:
180
+ try:
181
+ msg = f"| {record.getMessage()}"
182
+ #msg = f"{record.getMessage()}"
183
+
184
+ return(str(msg))
185
+ except Exception as e:
186
+ print("FALHA AO FORMATAR O LOG")
187
+ print(e)
188
+
189
+ # Configurando o logging com o CustomRichHandler
190
+ # Comentado pois estava gerando logs de libs como slack_sdk e big query
191
+ # logging.basicConfig(
192
+ # level=log_config_level,
193
+ # handlers=[CustomRichHandler()],
194
+ # datefmt="%d/%m/%Y %H:%M:%S |",
195
+ # format="| %(message)s"
196
+ # )
197
+
198
+ def add_log_level(level_name, level_num, method_name=None):
199
+ """
200
+ Adiciona um log level
201
+
202
+ Parâmetros:
203
+ level_name (str): Nome do level
204
+ level_num (int): Número do level
205
+ """
206
+ if not method_name:
207
+
208
+ method_name = level_name.lower()
209
+
210
+ if hasattr(logging, level_name):
211
+
212
+ raise AttributeError('{} already defined in logging module'.format(level_name))
213
+
214
+ if hasattr(logging, method_name):
215
+
216
+ raise AttributeError('{} already defined in logging module'.format(method_name))
217
+
218
+ if hasattr(logging.getLoggerClass(), method_name):
219
+
220
+ raise AttributeError('{} already defined in logger class'.format(method_name))
221
+
222
+ def log_for_level(self, message, *args, **kwargs):
223
+
224
+ if self.isEnabledFor(level_num):
225
+
226
+ #self._log(level_num, message, args, **kwargs)
227
+ self._log(level_num, message, args, **{**kwargs, "stacklevel": 2})
228
+
229
+ def log_to_root(message, *args, **kwargs):
230
+
231
+ logging.log(level_num, message, *args, **kwargs)
232
+
233
+ logging.addLevelName(level_num, level_name)
234
+ setattr(logging, level_name, level_num)
235
+ setattr(logging.getLoggerClass(), method_name, log_for_level)
236
+ setattr(logging, method_name, log_to_root)
237
+
238
+ if not 'SUCCESS' in logging._nameToLevel:
239
+ add_log_level("SUCCESS",21)
240
+
241
+ logger = logging.getLogger(__name__)
242
+
243
+ # Sendo setado aqui pois no basicConfig estava gerando logs para as libs do slack_sdk e big query
244
+
245
+ logger.addHandler(CustomRichHandler())
246
+
247
+ logger.setLevel(log_config_level)
248
+
249
+ return logger
csc_cia_stne/provio.py ADDED
@@ -0,0 +1,103 @@
1
+ import logging
2
+ import requests
3
+ from requests.auth import HTTPBasicAuth
4
+ from pydantic import BaseModel, Field, ValidationError
5
+ from typing import List, Dict, Union
6
+
7
+ # Validadores
8
+ class ProvioModel(BaseModel):
9
+ """
10
+ Modelo para validação das credenciais de autenticação.
11
+ """
12
+ username: str = Field(..., strip_whitespace=True, min_length=1)
13
+ password: str = Field(..., strip_whitespace=True, min_length=1)
14
+
15
+ class ExportarRelatorioParams(BaseModel):
16
+ """
17
+ Modelo para validação dos parâmetros do relatório.
18
+ """
19
+ ano: int = Field(..., gt=2015, description="O ano deve ser maior que 2015")
20
+ mes: int = Field(..., ge=1, le=12, description="O mês deve estar entre 1 e 12")
21
+ verbose: bool = Field(False, description="Indica se as mensagens detalhadas devem ser exibidas")
22
+
23
+ # Classe provio
24
+ class Provio:
25
+ """
26
+ Classe para interagir com a API do Provio.
27
+ """
28
+
29
+ def __init__(self, username: str, password: str):
30
+ """
31
+ Inicializa a classe com as credenciais de autenticação.
32
+
33
+ Args:
34
+ username (str): Nome de usuário para autenticação.
35
+ password (str): Senha para autenticação.
36
+
37
+ Raises:
38
+ ValidationError: Se as credenciais forem inválidas de acordo com o modelo `ProvioModel`.
39
+ """
40
+ # Validação usando Pydantic
41
+ data = ProvioModel(username=username, password=password)
42
+
43
+ self.api_url = "https://provio.apps.stone.com.br/api/reports"
44
+ self.auth = HTTPBasicAuth(data.username, data.password)
45
+
46
+ def exportar_relatorio_geral(self, ano: int, mes: int, verbose: bool=False) -> Dict[str, Union[bool, str, List[Dict]]]:
47
+ """
48
+ Exporta o relatório geral para o período especificado.
49
+
50
+ Args:
51
+ ano (int): Ano do relatório (deve ser maior que 2015).
52
+ mes (int): Mês do relatório (deve estar entre 1 e 12).
53
+ verbose (bool): informa se as requisições devem ser expostas na console
54
+
55
+ Returns:
56
+ Dict[str, Union[bool, str, List[Dict]]]: Um dicionário contendo:
57
+ - `success` (bool): Indica se a exportação foi bem-sucedida.
58
+ - `error` (str): Mensagem de erro, se houver.
59
+ - `report` (List[Dict]): Lista de registros exportados, se `success` for `True`.
60
+
61
+ Raises:
62
+ ValidationError: Se os parâmetros `ano` e `mes` forem inválidos.
63
+ """
64
+ # Validação dos parâmetros
65
+ params = ExportarRelatorioParams(ano=ano, mes=mes, verbose=verbose)
66
+ periodo = f"{params.ano}-{params.mes:02d}"
67
+ skip = 0
68
+ todos_os_dados = [] # Lista para armazenar todos os resultados
69
+ requisicao = 0
70
+ try:
71
+
72
+ while True:
73
+
74
+ url = f"{self.api_url}/general/{periodo}/{skip}"
75
+ response = requests.get(url=url, auth=self.auth)
76
+
77
+ if response.status_code == 200:
78
+
79
+ dados = response.json()
80
+
81
+ # Verifica se há itens na resposta
82
+ if not dados: # Se a resposta for vazia, interrompa o loop
83
+
84
+ break
85
+
86
+ # Adiciona os dados recebidos à lista total
87
+ todos_os_dados.extend(dados)
88
+
89
+ # Incrementa o skip para buscar a próxima página
90
+ skip += 500
91
+ requisicao += 1
92
+ if verbose:
93
+ logging.info(f"Exportando relatório: Requisição #{str(requisicao).zfill(3)} - {len(todos_os_dados)} registros no total")
94
+
95
+ else:
96
+
97
+ return {"success": False, "error": f"{response.status_code} - {response.text}"}
98
+
99
+ return {"success": True, "error": None, "report": todos_os_dados}
100
+
101
+ except Exception as e:
102
+
103
+ return {"success": False, "error": str(e)}