csc-cia-stne 0.0.30__py3-none-any.whl → 0.0.31__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.
csc_cia_stne/__init__.py CHANGED
@@ -1,36 +1,16 @@
1
1
  import os
2
2
  from dotenv import load_dotenv
3
-
4
- # Carrega .env
5
- load_dotenv()
6
- logger = None # Inicializa como None
7
- #if os.getenv('ambiente_de_execucao') is not None and os.getenv('ambiente_de_execucao') == "karavela":
8
- # from .logger_json import logger
9
- #else:
10
- # from .logger_rich import logger
11
-
12
-
13
- if os.getenv('ambiente_de_execucao') is not None and os.getenv('ambiente_de_execucao') == "karavela":
14
- from .logger_json import get_logger as get_logger_json
15
- def logger():
16
- return get_logger_json()
17
- else:
18
- from .logger_rich import get_logger as get_logger_rich
19
- def logger():
20
- return get_logger_rich()
21
-
22
-
23
-
24
-
3
+ from .logger_json import get_logger as get_logger_json
4
+ from .logger_rich import get_logger as get_logger_rich
25
5
  from .karavela import Karavela
26
- #from .utilitarios.classes import Util
27
6
  from .servicenow import ServiceNow
28
7
  from .stne_admin import StoneAdmin
29
8
  from .bc_sta import BC_STA
30
9
  from .bc_correios import BC_Correios
31
10
  from .gcp_bigquery import BigQuery
32
11
  from .email import Email
33
- #from .utilitarios.functions import titulo
12
+ from .provio import Provio
13
+
34
14
  # Define os itens disponíveis para importação
35
15
  __all__ = [
36
16
  "titulo",
@@ -41,5 +21,49 @@ __all__ = [
41
21
  "ServiceNow",
42
22
  "Util",
43
23
  "logger",
24
+ "Provio",
44
25
  "Email"
45
- ]
26
+ ]
27
+
28
+ diretorio_inicial = os.getcwd()
29
+ caminho_env = os.path.join(diretorio_inicial, ".env")
30
+
31
+ # Carrega .env
32
+ load_dotenv(caminho_env)
33
+ logger = None # Inicializa como None
34
+
35
+ def running_in_container():
36
+
37
+ if os.environ.get("KUBERNETES_SERVICE_HOST") or os.path.exists("/.dockerenv"):
38
+
39
+ return True
40
+
41
+ try:
42
+
43
+ with open("/proc/1/cgroup", "rt") as file:
44
+
45
+ for line in file:
46
+
47
+ if "docker" in line or "kubepods" in line:
48
+
49
+ return True
50
+
51
+ except FileNotFoundError as e:
52
+
53
+ return False
54
+
55
+ return False
56
+
57
+ def logger():
58
+
59
+ if os.getenv('ambiente_de_execucao') is not None and os.getenv('ambiente_de_execucao') == "karavela":
60
+
61
+ return get_logger_json()
62
+
63
+ elif running_in_container():
64
+
65
+ return get_logger_json()
66
+
67
+ else:
68
+
69
+ return get_logger_rich()
@@ -1,99 +1,7 @@
1
1
  from google.cloud import bigquery
2
- import json
3
- import os
4
2
  from google.oauth2 import service_account
5
- from pydantic import BaseModel, ValidationError, field_validator,model_validator
6
-
7
- class InitParamsValidator(BaseModel):
8
- limit:int
9
- id_project:str
10
- creds_dict:dict
11
- creds_file:str
12
-
13
- @field_validator('limit')
14
- def check_input_basic(cls, value, info):
15
- if not isinstance(value, int):
16
- raise ValueError(f"O parametro 'limit' deve ser um inteiro e não um {type(value)}")
17
-
18
- return value
19
-
20
- @field_validator('id_project')
21
- def check_str_input(cls, value, info):
22
- if not isinstance(value, str) or not value.strip():
23
- raise ValueError(f"O parametro 'id_project' deve ser uma string e não um {type(value)} e não vazio")
24
- return value
25
-
26
- @model_validator(mode="after")
27
- def check_others_input(cls, model):
28
- creds_dict = model.creds_dict
29
- creds_file = model.creds_file
30
-
31
- if isinstance(creds_dict, dict):
32
- return model
33
-
34
- elif isinstance(creds_file, str) and creds_file.strip():
35
- return model
36
-
37
- else:
38
- raise ValueError("Pelo menos um dos parâmetros 'creds_dict' ou 'creds_file' deve ser fornecido.")
39
-
40
-
41
- class tryQueryValidator(BaseModel):
42
-
43
- query_to_execute:str
44
- organize:bool
45
- use_legacy:bool
46
- use_cache:bool
47
- query_parameters:list
48
-
49
- @field_validator('query_to_execute')
50
- def check_str_input(cls, value, info):
51
- if not isinstance(value, str) or not value.strip():
52
- raise ValueError(f"O parametro '{info.field_name}' deve ser uma string não vazia")
53
-
54
- return value
55
-
56
- @field_validator('organize','use_legacy','use_cache')
57
- def check_bool_input(cls, value, info):
58
- if not isinstance(value, bool):
59
- raise ValueError(f"O parametro '{info.field_name}' deve ser um boleano")
60
-
61
- return value
62
-
63
- @field_validator('query_parameters')
64
- def check_list_input(cls, value, info):
65
- if not isinstance(value, list):
66
- raise ValueError(f"O parametro '{info.field_name}' deve ser uma lista")
67
-
68
- return value
69
-
70
-
71
- class tryInsertListValidator(BaseModel):
72
-
73
- insert_limit:int
74
- list_to_insert:list
75
- table:str
76
-
77
- @field_validator('list_to_insert')
78
- def check_list_input(cls, value, info):
79
- if not isinstance(value, list) and len(value) > 0:
80
- raise ValueError(f"O parametro '{info.field_name}' deve ser uma lista e não estar vazia")
81
-
82
- return value
83
-
84
- @field_validator('table')
85
- def check_str_input(cls, value, info):
86
- if not isinstance(value, str) or not value.strip():
87
- raise ValueError(f"O parametro '{info.field_name}' deve ser uma string não vazia")
88
-
89
- return value
90
-
91
- @field_validator('insert_limit')
92
- def check_int_input(cls, value, info):
93
- if not isinstance(value, int) or value > 10000:
94
- raise ValueError(f"O parametro '{info.field_name}' deve ser um inteiro não maior que 10000")
95
-
96
- return value
3
+ from pydantic import ValidationError
4
+ from .utilitarios.validations.GcpBigQueryValidator import tryQueryValidator, InitParamsValidator, tryInsertListValidator
97
5
 
98
6
  class BigQuery():
99
7
 
@@ -0,0 +1,238 @@
1
+ import os, time, logging, json
2
+ from .karavela import Karavela
3
+ from googleapiclient.discovery import build
4
+ from googleapiclient.http import MediaFileUpload
5
+ from googleapiclient.errors import HttpError
6
+ from io import BytesIO
7
+ from googleapiclient.discovery import build
8
+ from google.oauth2 import service_account
9
+ from .utilitarios.validations.GoogleDriveValidator import InitParamsValidator, CreateFolderValidator, ListFolderValidator
10
+ from pydantic import ValidationError
11
+
12
+
13
+
14
+ class GoogleDrive():
15
+
16
+ """
17
+ Classe responsável por gerenciar operações no Google Drive, como upload de arquivos, criação de pastas
18
+ e listagem de conteúdo. Utiliza a API do Google Drive para realizar essas operações.
19
+
20
+ Args:
21
+ key (str): Chave de autenticação para acessar a API do Google Drive.
22
+ """
23
+
24
+ def __init__(self, key, with_subject : str, scopes : list = ["https://www.googleapis.com/auth/drive"], version : str = "v3"):
25
+ """
26
+ Inicializa a classe GoogleDrive e autentica o serviço usando a chave fornecida.
27
+
28
+ Args:
29
+ key (str): Chave de autenticação do Google Drive.
30
+ """
31
+ try:
32
+ InitParamsValidator(key=key, with_subject=with_subject, scopes=scopes)
33
+ except ValidationError as e:
34
+ raise ValueError("Erro na validação dos dados de input da inicialização da instância:", e.errors())
35
+
36
+ self.__token = json.loads(Karavela.get_secret(key))
37
+ self.version = version
38
+ self.scopes = scopes
39
+ self.__auth = self.__autentica(with_subject)
40
+ self.page_size = 1000
41
+ self.service = self.create_service()
42
+
43
+ def timer_decorator(func):
44
+ """
45
+ Classe reponsável por calcular qualquer execução que ela seja chamada.
46
+ """
47
+ def wrapper(*args, **kwargs):
48
+ inicio = time.time()
49
+ resultado = func(*args, **kwargs)
50
+ fim = time.time()
51
+ logging.debug(f"Tempo de execução de {func.__name__}: {fim - inicio:.2f} segundos")
52
+ return resultado
53
+ return wrapper
54
+
55
+ def create_service(self):
56
+ """
57
+ Cria um serviço para a plataforma Google especificada.
58
+
59
+ Args:
60
+ platform (str): O nome da plataforma Google para a qual o serviço será criado (por exemplo, 'drive', 'sheets').
61
+
62
+ Returns:
63
+ googleapiclient.discovery.Resource: Serviço do Google para a plataforma especificada.
64
+ bool: Retorna False se houver um erro ao criar o serviço.
65
+ """
66
+ try:
67
+
68
+ cred = build(f"drive", f"{self.version}", credentials=self.__auth)
69
+ logging.debug(f"Serviço do Google drive criado")
70
+ return cred
71
+ except Exception as e:
72
+ logging.debug(f"Erro ao criar o serviço do Google drive: Error: {e}")
73
+ return False
74
+
75
+ def __autentica(self, with_subject : str):
76
+ """
77
+ Autentica o serviço do Google utilizando um token e escopos fornecidos.
78
+
79
+ Args:
80
+ token (dict): As credenciais de autenticação.
81
+ scopes (list): A lista de escopos para o acesso aos serviços do Google.
82
+
83
+ Returns:
84
+ google.oauth2.service_account.Credentials: Objeto de credenciais autenticado.
85
+ bool: Retorna False em caso de erro.
86
+ """
87
+
88
+ try:
89
+ credentials = service_account.Credentials.from_service_account_info(self.__token, scopes=self.scopes)
90
+ delegated_credencial = credentials.with_subject(with_subject)
91
+ return delegated_credencial
92
+
93
+ except Exception as e:
94
+ logging.debug(f"Erro ao tentar autenticar. Verifique o erro: {e}")
95
+ return False
96
+
97
+ @timer_decorator
98
+ def upload(self, folder_id: str, name: str, file_path: str, mimetype: str):
99
+ """
100
+ Faz o upload de um arquivo para o Google Drive em uma pasta especificada.
101
+
102
+ Args:
103
+ folder_id (str): ID da pasta no Google Drive onde o arquivo será armazenado.
104
+ name (str): Nome do arquivo que será carregado.
105
+ file_path (str): Caminho completo do arquivo no sistema local.
106
+ mimetype (str): Tipo MIME do arquivo a ser carregado.
107
+
108
+ Returns:
109
+ dict: Informações sobre o arquivo carregado, incluindo o ID do arquivo.
110
+ None: Caso o caminho do arquivo não seja encontrado.
111
+ """
112
+ file_metadata = {"name": name, "parents": [folder_id]}
113
+ if not os.path.exists(file_path):
114
+ logging.debug(f"Pasta {file_path} não encontrada")
115
+ return {"success" : False, "result" : None, "error" : "Diretório ou arquivo não encontrado"}
116
+
117
+ try:
118
+ logging.debug(f"Realizando o upload do arquivo")
119
+ media = MediaFileUpload(file_path, mimetype=mimetype, resumable=True)
120
+ file = (
121
+ self.service.files()
122
+ .create(body=file_metadata, media_body=media, fields="id", supportsAllDrives=True)
123
+ .execute()
124
+ )
125
+
126
+ logging.debug(f"Upload realizado com sucesso")
127
+ return {"success" : True, "result" : file}
128
+ except Exception as e:
129
+ logging.debug(f"Erro ao realizar o upload do arquivo {name} no google drive. Erro: {e}")
130
+ return {"success" : False, "result" : None, "error" : str(e)}
131
+
132
+ def create_folder(self, name: str, parent_folder_id: str):
133
+ """
134
+ Cria uma pasta no Google Drive dentro de uma pasta existente.
135
+
136
+ Args:
137
+ name (str): Nome da pasta a ser criada.
138
+ parent_folder_id (int): ID da pasta pai onde a nova pasta será criada.
139
+
140
+ Returns:
141
+ str: ID da pasta criada.
142
+ """
143
+ try:
144
+ CreateFolderValidator(name=name, parent_folder_id=parent_folder_id)
145
+ except ValidationError as e:
146
+ raise ValueError("Erro na validação dos dados de input da inicialização da instância:", e.errors())
147
+
148
+ try:
149
+ folder_metadata = {
150
+ "name": name,
151
+ "parents": [parent_folder_id],
152
+ "mimeType": "application/vnd.google-apps.folder",
153
+ }
154
+ folder = (
155
+ self.service.files().create(body=folder_metadata, fields="id", supportsAllDrives=True).execute()
156
+ )
157
+ return {"success" : True, "result": folder}
158
+ except Exception as e:
159
+ logging.debug(f"Não foi possível criar a pasta {name}")
160
+ return {"success" : False, "result": None, "error" : str(e)}
161
+
162
+ def list(self, query: str = "", spaces: str = "drive", fields: str = "nextPageToken, files(id, name)"):
163
+ """
164
+ Lista os arquivos e pastas no Google Drive com base nos critérios fornecidos.
165
+
166
+ Args:
167
+ query (str, optional): Critério de busca para os arquivos ou pastas no Google Drive.
168
+ Consulte https://developers.google.com/drive/api/v3/ref-search-terms.
169
+ Defaults to "".
170
+ spaces (str, optional): Especifica os locais de armazenamento a serem consultados. Pode ser 'drive',
171
+ 'appDataFolder', ou 'photos'. Defaults to 'drive'.
172
+ fields (str, optional): Campos a serem retornados na resposta. Consulte a documentação para os campos disponíveis.
173
+ Defaults to "nextPageToken, files(id, name)".
174
+
175
+ Returns:
176
+ dict: Dicionário contendo o resultado da busca.
177
+ """
178
+ try:
179
+ ListFolderValidator(query=query, fields=fields, spaces=spaces)
180
+ except ValidationError as e:
181
+ raise ValueError("Erro na validação dos dados de input da lista:", e.errors())
182
+ try:
183
+ results = (
184
+ self.service.files()
185
+ .list(q=query,
186
+ spaces=spaces,
187
+ pageSize=self.page_size,
188
+ fields=fields,
189
+ supportsAllDrives=True,
190
+ includeItemsFromAllDrives=True)
191
+ .execute()
192
+ )
193
+ return {"success" : True, "result" : results}
194
+ except HttpError as hr:
195
+ logging.debug(f"Ocorreu um de http. Erro: {hr}")
196
+ return {"success" : False, "result" : None, "error" : str(hr)}
197
+
198
+ @timer_decorator
199
+ def get_file(self, file : str, ):
200
+ """
201
+ Obtém o conteúdo de um arquivo armazenado no Google Drive.
202
+
203
+ Esta função acessa o Google Drive usando a API e lê os dados do arquivo especificado, retornando-os como um objeto binário de memória (`BytesIO`).
204
+
205
+ Parâmetros:
206
+ - file (str): Dicionário contendo informações do arquivo no Google Drive, incluindo as chaves:
207
+ - `"name"`: Nome do arquivo.
208
+ - `"id"`: ID do arquivo.
209
+
210
+ Retorna:
211
+ - BytesIO: Objeto em memória contendo os dados do arquivo.
212
+ - None: Caso ocorra um erro ao tentar abrir ou ler o arquivo.
213
+
214
+ Logs:
215
+ - Registra mensagens indicando o início e o término da leitura do arquivo.
216
+ - Em caso de falha, registra o erro ocorrido.
217
+
218
+ Exceções:
219
+ - Qualquer erro durante o processo será capturado e registrado no log. A função retornará `None` nesses casos.
220
+
221
+ Dependências:
222
+ - A função assume a existência de um atributo `self.service` configurado para interagir com a API do Google Drive.
223
+ """
224
+ try:
225
+ # file_metadata = self.service.files().get(fileId=file_id, fields="name, mimeType").execute()
226
+ logging.debug(f"Lendo o arquivo {file.get("name")}")
227
+ request = self.service.files().get_media(fileId=file.get("id"))
228
+ file_data = BytesIO(request.execute())
229
+ logging.debug("Leitura do arquivo finalizada")
230
+
231
+ return {"success" : True, "result" : file_data}
232
+
233
+ except Exception as e:
234
+ logging.debug(f"Erro ao tentar abrir o arquivo. Erro {e}")
235
+ return {"success" : False, "result" : None}
236
+
237
+
238
+
@@ -2,7 +2,49 @@ import logging
2
2
  from pythonjsonlogger import jsonlogger
3
3
 
4
4
  def setup_json_logger():
5
- logger = logging.getLogger()
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
+ add_log_level("SUCCESS",21)
47
+ logger = logging.getLogger(__name__)
6
48
  logger.setLevel(logging.INFO)
7
49
 
8
50
  # Remove handlers anteriores, se houver
@@ -120,21 +120,30 @@ def get_logger():
120
120
  install()
121
121
 
122
122
  # Definindo o nível de log baseado nas configurações
123
- if os.getenv('log_level') is None:
123
+ if os.getenv('log_level') is None or os.getenv('log_level') == "DEBUG":
124
124
 
125
- log_config_level = logging.DEBUG
126
-
127
- elif os.getenv('log_level') == "DEBUG":
128
-
129
- log_config_level = logging.DEBUG
125
+ log_config_level = logging.INFO
130
126
 
131
127
  elif os.getenv('log_level') == "INFO":
132
128
 
133
129
  log_config_level = logging.INFO
130
+
131
+ elif os.getenv('log_level') == "WARNING" or os.getenv('log_level') == "WARN":
132
+
133
+ log_config_level = logging.WARNING
134
+
135
+ elif os.getenv('log_level') == "ERROR":
136
+
137
+ log_config_level = logging.ERROR
138
+
139
+ elif os.getenv('log_level') == "CRITICAL":
140
+
141
+ log_config_level = logging.CRITICAL
134
142
 
135
143
  else:
136
144
 
137
- log_config_level = logging.WARNING # ou outro nível padrão
145
+ log_config_level = logging.INFO # ou outro nível padrão
146
+ raise ValueError("'log_level' precisa ser 'DEBUG,'INFO','WARNING','ERROR' ou 'CRITICAL'")
138
147
 
139
148
  # Definindo o tema customizado
140
149
  custom_theme = Theme({
@@ -220,6 +229,6 @@ def get_logger():
220
229
 
221
230
  add_log_level("SUCCESS",21)
222
231
 
223
- logger = logging.getLogger()
232
+ logger = logging.getLogger(__name__)
224
233
 
225
234
  return logger
csc_cia_stne/provio.py ADDED
@@ -0,0 +1,66 @@
1
+ import logging
2
+ import requests
3
+ from requests.auth import HTTPBasicAuth
4
+ from pydantic import BaseModel, Field, ValidationError
5
+
6
+ # Validadores
7
+ class ProvioModel(BaseModel):
8
+ username: str = Field(..., strip_whitespace=True, min_length=1)
9
+ password: str = Field(..., strip_whitespace=True, min_length=1)
10
+
11
+ class ExportarRelatorioParams(BaseModel):
12
+ ano: int = Field(..., gt=2015, description="O ano deve ser maior que 2015")
13
+ mes: int = Field(..., ge=1, le=12, description="O mês deve estar entre 1 e 12")
14
+
15
+ # Classe provio
16
+ class Provio:
17
+
18
+ def __init__(self,username:str,password:str):
19
+
20
+ # Validação usando Pydantic
21
+ data = ProvioModel(username=username, password=password)
22
+
23
+ self.api_url = "https://provio.apps.stone.com.br/api/reports"
24
+ self.auth = HTTPBasicAuth(data.username, data.password)
25
+
26
+ def exportar_relatorio_geral(self, ano:int, mes:int):
27
+
28
+ # Validação dos parâmetros
29
+ params = ExportarRelatorioParams(ano=ano, mes=mes)
30
+ periodo = f"{params.ano}-{params.mes:02d}"
31
+ skip = 0
32
+ todos_os_dados = [] # Lista para armazenar todos os resultados
33
+ requisicao = 0
34
+ try:
35
+
36
+ while True:
37
+
38
+ url = f"{self.api_url}/general/{periodo}/{skip}"
39
+ response = requests.get(url=url, auth=self.auth)
40
+
41
+ if response.status_code == 200:
42
+
43
+ dados = response.json()
44
+
45
+ # Verifica se há itens na resposta
46
+ if not dados: # Se a resposta for vazia, interrompa o loop
47
+
48
+ break
49
+
50
+ # Adiciona os dados recebidos à lista total
51
+ todos_os_dados.extend(dados)
52
+
53
+ # Incrementa o skip para buscar a próxima página
54
+ skip += 500
55
+ requisicao += 1
56
+ logging.info(f"Exportando relatório: Requisição #{str(requisicao).zfill(3)} - {len(todos_os_dados)} registros exportados")
57
+
58
+ else:
59
+
60
+ return {"success": False, "error": f"{response.status_code} - {response.text}"}
61
+
62
+ return {"success": True, "error": None, "report": todos_os_dados}
63
+
64
+ except Exception as e:
65
+
66
+ return {"success": False, "error": str(e)}