csc-cia-stne 0.0.43__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,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)}