csc-cia-stne 0.1.15__py3-none-any.whl → 0.1.17__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,7 +1,7 @@
1
+ import base64
1
2
  from google.oauth2 import service_account
2
3
  from google.cloud import storage
3
4
  from pydantic import ValidationError
4
-
5
5
  from .utilitarios.validations.gcp_bucket import InitParamsValidator,ListFilesValidator,GetFilesValidator,UploadFilesValidator,DeleteFilesValidator
6
6
 
7
7
 
@@ -112,7 +112,7 @@ class GCPBucket():
112
112
  }
113
113
 
114
114
  # Função para baixar os arquivos de um bucket
115
- def get_file(self, bucket_name:str, filename:str, destination:str=None, chunksize:int=256) -> dict:
115
+ def get_file(self, bucket_name:str, filename:str, destination:str=None, chunksize:int=256, download_as:str='file') -> dict:
116
116
  """
117
117
  Faz o download de um arquivo de um bucket do Google Cloud Storage para um destino local.
118
118
  Args:
@@ -122,6 +122,7 @@ class GCPBucket():
122
122
  Se não for especificado, o arquivo será salvo com o mesmo nome do arquivo no bucket.
123
123
  chunksize (int, opcional): Tamanho do chunk em megabytes para o download do arquivo.
124
124
  O padrão é 256 MB.
125
+ download_as (str, opcional): Define o formato do download.
125
126
  Returns:
126
127
  dict: Um dicionário contendo o status da operação.
127
128
  - 'success' (bool): Indica se a operação foi bem-sucedida.
@@ -133,7 +134,7 @@ class GCPBucket():
133
134
 
134
135
  try:
135
136
 
136
- GetFilesValidator(bucket_name=bucket_name, filename=filename, destination=destination, chunksize=chunksize)
137
+ GetFilesValidator(bucket_name=bucket_name, filename=filename, destination=destination, chunksize=chunksize, download_as=download_as)
137
138
 
138
139
  except ValidationError as e:
139
140
 
@@ -144,7 +145,7 @@ class GCPBucket():
144
145
  destination = filename
145
146
 
146
147
  try:
147
-
148
+
148
149
  bucket = self.client.bucket(bucket_name)
149
150
 
150
151
  except Exception as e:
@@ -161,12 +162,20 @@ class GCPBucket():
161
162
 
162
163
  blob.chunk_size = chunksize * 1024 * 1024 # 256M
163
164
 
164
- blob.download_to_filename(destination)
165
+ if download_as == 'file':
166
+ blob.download_to_filename(destination)
167
+ return {
168
+ 'success':True,
169
+ 'details':f'Arquivo baixado para o diretório: {str(destination)}'
170
+ }
165
171
 
166
- return {
167
- 'success':True,
168
- 'details':f'Arquivo baixado para o diretório: {str(destination)}'
169
- }
172
+ elif download_as == 'bytes':
173
+ b64_str = base64.b64encode(blob.download_as_bytes()).decode()
174
+ return {
175
+ 'success':True,
176
+ 'details':f'Arquivo baixado como bytes em base64',
177
+ 'data': b64_str
178
+ }
170
179
 
171
180
  except Exception as e:
172
181
 
@@ -1,59 +1,145 @@
1
- import os
2
- from googleapiclient.discovery import build
3
- from googleapiclient.http import MediaFileUpload
4
- from googleapiclient.errors import HttpError
5
- from io import BytesIO
6
- from google.oauth2 import service_account
1
+ import os # google_drive.py da lib - Operações do sistema operacional
2
+ import base64 # Codificação/decodificação base64 para manipulação de dados
3
+ from googleapiclient.discovery import build # Construção do cliente da API do Google
4
+ from googleapiclient.http import MediaFileUpload # Upload de arquivos para APIs do Google
5
+ from googleapiclient.http import MediaIoBaseUpload # Upload de streams/buffers para APIs do Google
6
+ from googleapiclient.errors import HttpError # Tratamento de erros HTTP das APIs do Google
7
+ from io import BytesIO # Manipulação de streams de bytes em memória
8
+ from google.oauth2 import service_account # Autenticação com conta de serviço do Google
7
9
  from .utilitarios.validations.GoogleDriveValidator import (
8
10
  InitParamsValidator,
9
11
  CreateFolderValidator,
10
12
  ListFolderValidator,
11
13
  UploadValidator,
12
14
  )
13
- from pydantic import ValidationError
15
+ from pydantic import ValidationError # Exceções de validação do Pydantic
16
+ from typing import Iterable, Optional, Dict, List, Union, Any # Type hints para melhor documentação
14
17
 
15
18
 
16
19
  class GoogleDrive:
17
20
  """
18
- Classe responsável por gerenciar operações no Google Drive, como upload de arquivos, criação de pastas
19
- e listagem de conteúdo. Utiliza a API do Google Drive para realizar essas operações.
20
-
21
- Args:
22
- key (str): Chave de autenticação para acessar a API do Google Drive.
21
+ Classe responsável por gerenciar operações no Google Drive usando padrão Singleton.
22
+
23
+ Esta classe implementa o padrão Singleton, garantindo que apenas uma instância
24
+ seja criada durante a execução da aplicação. Fornece funcionalidades para:
25
+ - Upload de arquivos para o Google Drive
26
+ - Criação e listagem de pastas
27
+ - Autenticação usando conta de serviço do Google
28
+ - Operações de compartilhamento e permissões
29
+
30
+ Note:
31
+ Como implementa Singleton, todas as instâncias criadas retornarão
32
+ a mesma referência de objeto, compartilhando estado e configurações.
33
+
34
+ Attributes:
35
+ _instance (Optional[GoogleDrive]): Instância única da classe (padrão Singleton)
36
+ service: Cliente autenticado da API do Google Drive
37
+ version (str): Versão da API do Google Drive sendo utilizada
38
+ scopes (List[str]): Escopos de permissão para acesso ao Google Drive
39
+ with_subject (str): Email do usuário para delegação de credenciais
40
+ page_size (int): Número máximo de itens retornados por página nas consultas
41
+
42
+ Examples:
43
+ >>> # Primeira instância
44
+ >>> drive1 = GoogleDrive(token=service_account_info, with_subject="user@domain.com")
45
+ >>>
46
+ >>> # Segunda instância (retorna a mesma referência)
47
+ >>> drive2 = GoogleDrive(token=other_token, with_subject="other@domain.com")
48
+ >>> print(drive1 is drive2) # True - mesma instância
23
49
  """
24
50
 
25
- _instance = None # Atributo de classe para armazenar a única instância.
51
+ _instance: Optional['GoogleDrive'] = None # Atributo de classe para armazenar a única instância
26
52
 
27
- def __new__(cls, *args, **kwargs):
28
- # Verifica se já existe uma instância da classe.
53
+ def __new__(cls, *args, **kwargs) -> 'GoogleDrive':
54
+ """
55
+ Implementa o padrão Singleton para garantir instância única.
56
+
57
+ Este método garante que apenas uma instância da classe GoogleDrive
58
+ seja criada durante toda a execução da aplicação, independentemente
59
+ de quantas vezes o construtor seja chamado.
60
+
61
+ Args:
62
+ *args: Argumentos posicionais passados para o construtor
63
+ **kwargs: Argumentos nomeados passados para o construtor
64
+
65
+ Returns:
66
+ GoogleDrive: A única instância da classe GoogleDrive
67
+
68
+ Note:
69
+ Na primeira chamada, uma nova instância é criada e armazenada.
70
+ Nas chamadas subsequentes, a mesma instância é retornada.
71
+ """
72
+ # Verifica se já existe uma instância da classe
29
73
  if cls._instance is None:
30
- # Cria e armazena a instância na primeira chamada.
74
+ # Cria e armazena a instância na primeira chamada
31
75
  cls._instance = super().__new__(cls)
32
76
  return cls._instance
33
77
 
34
78
  def __init__(
35
79
  self,
36
- token: dict,
80
+ token: Dict[str, Any],
37
81
  with_subject: str,
38
- scopes: list = ["https://www.googleapis.com/auth/drive"],
82
+ scopes: List[str] = ["https://www.googleapis.com/auth/drive"],
39
83
  version: str = "v3",
40
- ):
84
+ ) -> None:
41
85
  """
42
- Inicializa uma instância da classe GoogleDrive.
43
- Parâmetros:
44
- - key (str): A chave para acessar o segredo necessário para autenticação.
45
- - with_subject (str): O assunto para o qual a autenticação será realizada.
46
- - scopes (list): Uma lista de escopos de permissão para acesso ao Google Drive. O valor padrão é ["https://www.googleapis.com/auth/drive"].
47
- - version (str): A versão da API do Google Drive a ser utilizada. O valor padrão é "v3".
86
+ Inicializa uma instância da classe GoogleDrive com autenticação de conta de serviço.
87
+
88
+ Configura a autenticação usando uma conta de serviço do Google Cloud e
89
+ estabelece conexão com a API do Google Drive. A autenticação é delegada
90
+ para um usuário específico usando o parâmetro with_subject.
91
+
92
+ Args:
93
+ token (Dict[str, Any]): Dicionário contendo as credenciais da conta de serviço.
94
+ Deve incluir campos como 'type', 'project_id', 'private_key_id',
95
+ 'private_key', 'client_email', 'client_id', 'auth_uri', 'token_uri', etc.
96
+ with_subject (str): Email do usuário para o qual as credenciais serão delegadas.
97
+ Este usuário deve ter permissões adequadas no domínio da organização.
98
+ scopes (List[str], optional): Lista de escopos de permissão para acesso ao Google Drive.
99
+ Padrão: ["https://www.googleapis.com/auth/drive"] (acesso completo).
100
+ Outros exemplos:
101
+ - "https://www.googleapis.com/auth/drive.readonly" (somente leitura)
102
+ - "https://www.googleapis.com/auth/drive.file" (apenas arquivos criados pela app)
103
+ version (str, optional): Versão da API do Google Drive a ser utilizada.
104
+ Padrão: "v3" (versão mais recente estável).
105
+
48
106
  Raises:
49
- - ValueError: Se ocorrer um erro na validação dos dados de input da inicialização da instância.
50
- Exemplo de uso:
51
- ```
52
- google_drive = GoogleDrive(key="chave_secreta", with_subject="assunto", scopes=["https://www.googleapis.com/auth/drive"], version="v3")
53
- ```
107
+ ValueError: Se os dados de entrada falharem na validação do Pydantic.
108
+ Inclui detalhes sobre quais campos são inválidos e por quê.
109
+
110
+ Attributes:
111
+ __token (Dict[str, Any]): Credenciais da conta de serviço (privado)
112
+ version (str): Versão da API sendo utilizada
113
+ scopes (List[str]): Escopos de permissão configurados
114
+ with_subject (str): Email do usuário delegado
115
+ page_size (int): Limite de itens por página (padrão: 1000)
116
+ service: Cliente autenticado da API do Google Drive
117
+
118
+ Examples:
119
+ >>> # Configuração básica
120
+ >>> token = {
121
+ ... "type": "service_account",
122
+ ... "project_id": "my-project",
123
+ ... "private_key": "-----BEGIN PRIVATE KEY-----\n...",
124
+ ... "client_email": "service@my-project.iam.gserviceaccount.com",
125
+ ... # ... outros campos obrigatórios
126
+ ... }
127
+ >>> drive = GoogleDrive(
128
+ ... token=token,
129
+ ... with_subject="user@domain.com"
130
+ ... )
131
+ >>>
132
+ >>> # Configuração com escopos customizados
133
+ >>> drive = GoogleDrive(
134
+ ... token=token,
135
+ ... with_subject="admin@domain.com",
136
+ ... scopes=["https://www.googleapis.com/auth/drive.readonly"],
137
+ ... version="v3"
138
+ ... )
54
139
  """
55
140
 
56
141
  try:
142
+ # Validação dos parâmetros usando Pydantic para garantir tipos e formatos corretos
57
143
  InitParamsValidator(
58
144
  token=token, with_subject=with_subject, scopes=scopes, version=version
59
145
  )
@@ -62,84 +148,186 @@ class GoogleDrive:
62
148
  "Erro na validação dos dados de input da inicialização da instância:",
63
149
  e.errors(),
64
150
  )
65
- self.__token = token
66
- self.version = version
67
- self.scopes = scopes
68
- self.with_subject = with_subject
69
- self.page_size = 1000
151
+
152
+ # Armazenamento das configurações validadas
153
+ self.__token = token # Credenciais privadas da conta de serviço
154
+ self.version = version # Versão da API do Google Drive
155
+ self.scopes = scopes # Escopos de permissão para autenticação
156
+ self.with_subject = with_subject # Email do usuário para delegação
157
+ self.page_size = 1000 # Limite padrão de itens por página nas consultas
158
+
159
+ # Criação do cliente autenticado da API do Google Drive
70
160
  self.service = self.__create_service()
71
161
 
72
- def __create_service(self):
162
+ def __create_service(self) -> Union[Any, bool]:
73
163
  """
74
- Cria um serviço do Google Drive.
164
+ Cria e configura o cliente de serviço do Google Drive.
165
+
166
+ Este método privado estabelece a conexão autenticada com a API do Google Drive
167
+ usando as credenciais da conta de serviço configuradas durante a inicialização.
168
+ O processo inclui autenticação delegada e construção do objeto de serviço.
169
+
75
170
  Returns:
76
- cred: Objeto de credenciais do Google Drive.
77
- False: Caso ocorra algum erro ao criar o serviço.
171
+ Union[Any, bool]:
172
+ - Objeto do serviço Google Drive se a conexão for bem-sucedida
173
+ - False se ocorrer qualquer erro durante o processo de criação
174
+
78
175
  Raises:
79
- Exception: Caso ocorra algum erro ao criar o serviço do Google Drive.
80
- Exemplo de uso:
81
- service = create_service()
82
- if service:
83
- # Fazer algo com o serviço do Google Drive
84
- else:
85
- # Tratar o erro de criação do serviço
176
+ Exception: Capturada internamente e retorna False em caso de erro.
177
+ Possíveis causas de erro incluem:
178
+ - Credenciais inválidas ou malformadas
179
+ - Problemas de conectividade de rede
180
+ - Configurações incorretas de escopo ou versão da API
181
+ - Falhas na delegação de credenciais
182
+
183
+ Note:
184
+ Este é um método privado (prefixo __) e não deve ser chamado diretamente
185
+ fora da classe. É usado automaticamente durante a inicialização.
186
+
187
+ Examples:
188
+ >>> # Uso interno durante __init__
189
+ >>> self.service = self.__create_service()
190
+ >>> if self.service:
191
+ ... print("Conexão com Google Drive estabelecida")
192
+ ... else:
193
+ ... print("Falha na conexão com Google Drive")
86
194
  """
87
195
 
88
196
  try:
197
+ # Autentica usando as credenciais da conta de serviço com delegação de usuário
89
198
  auth = self.__autentica(self.with_subject)
199
+
200
+ # Constrói o cliente da API do Google Drive com as credenciais autenticadas
90
201
  service = build(f"drive", f"{self.version}", credentials=auth)
91
202
  return service
92
203
  except Exception as e:
204
+ # Em caso de erro, retorna False para indicar falha na criação do serviço
205
+ # O erro específico é capturado mas não re-lançado para manter a interface limpa
93
206
  return False
94
207
 
95
- def __autentica(self, with_subject: str):
208
+ def __autentica(self, with_subject: str) -> Union[service_account.Credentials, bool]:
96
209
  """
97
- Autentica o usuário com as credenciais fornecidas e retorna as credenciais delegadas para o assunto especificado.
210
+ Realiza autenticação delegada usando conta de serviço do Google Cloud.
211
+
212
+ Este método privado configura a autenticação OAuth2 usando uma conta de serviço
213
+ e delega as credenciais para um usuário específico. É necessário quando uma
214
+ aplicação precisa acessar recursos do Google Drive em nome de um usuário
215
+ específico da organização.
216
+
98
217
  Args:
99
- with_subject (str): O assunto para o qual as credenciais serão delegadas.
218
+ with_subject (str): Email do usuário para o qual as credenciais serão delegadas.
219
+ Este usuário deve existir no domínio da organização e ter as permissões
220
+ adequadas para acessar os recursos solicitados.
221
+
100
222
  Returns:
101
- google.auth.credentials.Credentials: As credenciais delegadas para o assunto especificado.
223
+ Union[service_account.Credentials, bool]:
224
+ - Objeto de credenciais delegadas se a autenticação for bem-sucedida
225
+ - False se ocorrer qualquer erro durante o processo de autenticação
226
+
102
227
  Raises:
103
- Exception: Se ocorrer um erro durante a autenticação.
104
- Example:
105
- # Autenticar com o assunto "user@example.com"
106
- credentials = self.__autentica("user@example.com")
228
+ Exception: Capturada internamente e retorna False em caso de erro.
229
+ Possíveis causas de erro incluem:
230
+ - Token de conta de serviço inválido ou malformado
231
+ - Usuário especificado não existe no domínio
232
+ - Escopos insuficientes para a delegação
233
+ - Conta de serviço sem permissão de delegação
234
+
235
+ Note:
236
+ - Este é um método privado (prefixo __) usado internamente pela classe
237
+ - Requer que a conta de serviço tenha permissão de delegação configurada
238
+ - O usuário delegado deve fazer parte do mesmo domínio da organização
239
+
240
+ Examples:
241
+ >>> # Uso interno - autentica para um usuário específico
242
+ >>> credentials = self.__autentica("user@company.com")
243
+ >>> if credentials:
244
+ ... print("Autenticação delegada bem-sucedida")
245
+ ... else:
246
+ ... print("Falha na autenticação delegada")
107
247
  """
108
248
 
109
249
  try:
250
+ # Cria credenciais da conta de serviço a partir do token fornecido
110
251
  credentials = service_account.Credentials.from_service_account_info(
111
252
  self.__token, scopes=self.scopes
112
253
  )
254
+
255
+ # Delega as credenciais para o usuário especificado
256
+ # Isso permite que a aplicação aja em nome do usuário
113
257
  delegated_credencial = credentials.with_subject(with_subject)
114
258
  return delegated_credencial
115
259
 
116
260
  except Exception as e:
261
+ # Em caso de erro, retorna False para indicar falha na autenticação
262
+ # O erro específico é capturado mas não re-lançado para manter a interface limpa
117
263
  return False
118
264
 
119
- def upload(self, folder_id: str, name: str, file_path: str, mimetype: str):
265
+ def upload(self, folder_id: str, name: str, file_path: str, mimetype: str) -> Optional[Dict[str, Any]]:
120
266
  """
121
- Faz o upload de um arquivo para o Google Drive em uma pasta especificada.
267
+ Realiza upload de um arquivo para uma pasta específica no Google Drive.
268
+
269
+ Este método faz upload de arquivos locais para o Google Drive, criando uma nova
270
+ entrada na pasta especificada. Suporta todos os tipos de arquivo através da
271
+ especificação do tipo MIME apropriado.
122
272
 
123
273
  Args:
124
- folder_id (str): ID da pasta no Google Drive onde o arquivo será armazenado.
125
- name (str): Nome do arquivo que será carregado.
126
- file_path (str): Caminho completo do arquivo no sistema local.
127
- mimetype (str): Tipo MIME do arquivo a ser carregado.
128
- exemplos: text/plain
129
- text/html
130
- image/jpeg
131
- image/png
132
- audio/mpeg
133
- audio/ogg
134
- audio/*
135
- video/mp4
136
- application/octet-stream
274
+ folder_id (str): ID único da pasta no Google Drive onde o arquivo será armazenado.
275
+ Formato típico: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
276
+ name (str): Nome que o arquivo terá no Google Drive (pode ser diferente do nome local).
277
+ Exemplo: "documento_final.pdf", "relatorio_2025.xlsx"
278
+ file_path (str): Caminho absoluto ou relativo para o arquivo no sistema local.
279
+ Exemplo: "/home/user/documents/file.pdf", "C:\\Users\\user\\file.xlsx"
280
+ mimetype (str): Tipo MIME do arquivo que define como ele será interpretado.
281
+ Exemplos comuns:
282
+ - "text/plain" - Arquivo de texto simples
283
+ - "text/html" - Arquivo HTML
284
+ - "image/jpeg" - Imagem JPEG
285
+ - "image/png" - Imagem PNG
286
+ - "audio/mpeg" - Arquivo de áudio MP3
287
+ - "video/mp4" - Arquivo de vídeo MP4
288
+ - "application/pdf" - Documento PDF
289
+ - "application/vnd.ms-excel" - Planilha Excel
290
+ - "application/octet-stream" - Arquivo binário genérico
137
291
 
138
292
  Returns:
139
- dict: Informações sobre o arquivo carregado, incluindo o ID do arquivo.
140
- None: Caso o caminho do arquivo não seja encontrado.
293
+ Optional[Dict[str, Any]]:
294
+ - Dicionário com informações do arquivo carregado se bem-sucedido:
295
+ {"id": "arquivo_id", "name": "nome_arquivo", "parents": ["pasta_id"], ...}
296
+ - None se o arquivo local não for encontrado
297
+
298
+ Raises:
299
+ ValueError: Se os parâmetros de entrada falharem na validação do Pydantic.
300
+ Inclui detalhes sobre quais campos são inválidos.
301
+ HttpError: Se ocorrer erro na comunicação com a API do Google Drive.
302
+ Pode indicar problemas de permissão, quota ou conectividade.
303
+
304
+ Examples:
305
+ >>> # Upload de um documento PDF
306
+ >>> resultado = drive.upload(
307
+ ... folder_id="1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
308
+ ... name="contrato_assinado.pdf",
309
+ ... file_path="/documents/contrato.pdf",
310
+ ... mimetype="application/pdf"
311
+ ... )
312
+ >>> if resultado:
313
+ ... print(f"Arquivo carregado com ID: {resultado['id']}")
314
+
315
+ >>> # Upload de uma imagem
316
+ >>> resultado = drive.upload(
317
+ ... folder_id="pasta_fotos_id",
318
+ ... name="foto_evento.jpg",
319
+ ... file_path="C:\\fotos\\evento.jpg",
320
+ ... mimetype="image/jpeg"
321
+ ... )
322
+
323
+ Note:
324
+ - O arquivo deve existir no caminho especificado antes do upload
325
+ - O folder_id deve referenciar uma pasta existente e acessível
326
+ - O tipo MIME deve corresponder ao tipo real do arquivo para funcionamento adequado
327
+ - Arquivos com mesmo nome na mesma pasta não são sobrescritos, são duplicados
141
328
  """
142
329
  try:
330
+ # Validação dos parâmetros usando Pydantic para garantir tipos corretos
143
331
  UploadValidator(
144
332
  folder_id=folder_id, name=name, file_path=file_path, mimetype=mimetype
145
333
  )
@@ -149,92 +337,166 @@ class GoogleDrive:
149
337
  e.errors(),
150
338
  )
151
339
 
340
+ # Metadados do arquivo: nome e pasta de destino no Google Drive
152
341
  file_metadata = {"name": name, "parents": [folder_id]}
342
+
343
+ # Verifica se o arquivo existe no sistema local antes de tentar upload
153
344
  if not os.path.exists(file_path):
154
- return {
155
- "success": False,
156
- "result": None,
157
- "error": "Diretório ou arquivo não encontrado",
158
- }
345
+ return None # Retorna None se arquivo não encontrado
159
346
 
160
347
  try:
348
+ # Configura o objeto de mídia para upload com suporte a resumo
161
349
  media = MediaFileUpload(file_path, mimetype=mimetype, resumable=True)
350
+
351
+ # Executa o upload do arquivo para o Google Drive
162
352
  file = (
163
353
  self.service.files()
164
354
  .create(
165
- body=file_metadata,
166
- media_body=media,
167
- fields="id",
168
- supportsAllDrives=True,
355
+ body=file_metadata, # Metadados (nome, pasta pai)
356
+ media_body=media, # Conteúdo do arquivo
357
+ fields="id", # Campos a retornar (apenas ID para eficiência)
358
+ supportsAllDrives=True, # Suporte a drives compartilhados
169
359
  )
170
360
  .execute()
171
361
  )
172
362
 
363
+ # Retorna informações do arquivo carregado em formato padronizado
173
364
  return {"success": True, "result": file}
174
365
  except Exception as e:
175
-
366
+ # Em caso de erro, retorna informações do erro em formato padronizado
176
367
  return {"success": False, "result": None, "error": str(e)}
177
368
 
178
- def _validate_folder_existence(self, folder: str, id_folder: str):
369
+ def _validate_folder_existence(self, folder: str, id_folder: str) -> Optional[Dict[str, Any]]:
179
370
  """
180
- Verifica a existência de uma pasta no Google Drive.
371
+ Verifica se uma pasta específica existe dentro de uma pasta pai no Google Drive.
372
+
373
+ Este método privado busca por uma pasta com nome específico dentro de uma pasta
374
+ pai identificada por seu ID. É usado internamente para evitar duplicação de
375
+ pastas antes de criar novas.
376
+
181
377
  Args:
182
- folder (str): O nome da pasta a ser verificada.
183
- id_folder (str): O ID da pasta pai.
378
+ folder (str): Nome exato da pasta a ser verificada.
379
+ Exemplo: "Documentos 2025", "Relatórios Mensais"
380
+ id_folder (str): ID da pasta pai onde buscar.
381
+ Formato típico: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
382
+
184
383
  Returns:
185
- dict or None: Um dicionário contendo as informações da pasta se ela existir, caso contrário, retorna None.
384
+ Optional[Dict[str, Any]]:
385
+ - Dicionário com informações da pasta se encontrada:
386
+ {"id": "pasta_id", "name": "nome_pasta", "mimeType": "application/vnd.google-apps.folder"}
387
+ - None se a pasta não for encontrada na pasta pai
388
+
186
389
  Raises:
187
- ValueError: Se ocorrer algum erro durante a busca pela pasta.
390
+ ValueError: Se ocorrer erro durante a busca pela pasta.
391
+ Pode indicar problemas de conectividade, permissões ou IDs inválidos.
392
+
393
+ Note:
394
+ - Este é um método privado (prefixo _) usado internamente pela classe
395
+ - A busca é case-sensitive (sensível a maiúsculas/minúsculas)
396
+ - Apenas pastas não movidas para lixeira são consideradas
397
+ - Suporta drives compartilhados da organização
398
+
399
+ Examples:
400
+ >>> # Busca pasta "Relatórios" dentro da pasta pai
401
+ >>> pasta = self._validate_folder_existence("Relatórios", "parent_folder_id")
402
+ >>> if pasta:
403
+ ... print(f"Pasta encontrada: {pasta['id']}")
404
+ ... else:
405
+ ... print("Pasta não existe")
188
406
  """
189
-
407
+
408
+ # Query para buscar itens na pasta pai que não estão na lixeira
190
409
  query = f"'{id_folder}' in parents and trashed=false"
191
410
 
192
411
  try:
193
-
412
+ # Executa busca na API do Google Drive
194
413
  response = (
195
414
  self.service.files()
196
415
  .list(
197
- q=query,
198
- spaces="drive",
199
- fields="nextPageToken, files(id, name, mimeType)",
200
- pageToken=None,
201
- includeItemsFromAllDrives=True,
202
- supportsAllDrives=True,
416
+ q=query, # Query de busca
417
+ spaces="drive", # Espaço de busca (drive principal)
418
+ fields="nextPageToken, files(id, name, mimeType)", # Campos retornados
419
+ pageToken=None, # Token de paginação (primeira página)
420
+ includeItemsFromAllDrives=True, # Incluir drives compartilhados
421
+ supportsAllDrives=True, # Suporte a drives compartilhados
203
422
  )
204
423
  .execute()
205
424
  )
206
425
 
426
+ # Extrai lista de arquivos/pastas da resposta
207
427
  items = response.get("files", [])
208
428
 
429
+ # Procura por pasta com nome específico
209
430
  for item in items:
210
-
431
+ # Verifica se é uma pasta (tipo MIME específico) e nome corresponde
211
432
  if (
212
433
  item["mimeType"] == "application/vnd.google-apps.folder"
213
434
  and item["name"] == folder
214
435
  ):
436
+ return item # Retorna informações da pasta encontrada
215
437
 
216
- return item
217
-
218
- return None
438
+ return None # Pasta não encontrada
219
439
 
220
440
  except Exception as e:
221
-
222
- raise ValueError(f"Erro tentando procurar pela pasta:{e}")
441
+ # Lança erro com contexto específico sobre a falha na busca
442
+ raise ValueError(f"Erro tentando procurar pela pasta: {e}")
223
443
 
224
444
  def create_folder(
225
445
  self, name: str, parent_folder_id: str, validate_existence: bool = False
226
- ):
446
+ ) -> Dict[str, Any]:
227
447
  """
228
- Cria uma pasta no Google Drive dentro de uma pasta existente.
448
+ Cria uma nova pasta no Google Drive dentro de uma pasta pai especificada.
449
+
450
+ Este método permite criar pastas no Google Drive com opção de verificar
451
+ se a pasta já existe antes da criação. É útil para organizar arquivos
452
+ em estruturas hierárquicas de pastas.
229
453
 
230
454
  Args:
231
455
  name (str): Nome da pasta a ser criada.
232
- parent_folder_id (int): ID da pasta pai onde a nova pasta será criada.
233
- validate_existence (bool): Se True, verifica se a pasta existe antes de criá-la. Defaults to False.
456
+ Exemplo: "Relatórios 2025", "Documentos Importantes"
457
+ parent_folder_id (str): ID da pasta pai onde a nova pasta será criada.
458
+ Formato típico: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
459
+ Use "root" para criar na raiz do drive
460
+ validate_existence (bool, optional): Se True, verifica se a pasta já existe
461
+ antes de tentar criar uma nova. Se a pasta existir, retorna suas
462
+ informações ao invés de criar duplicata. Padrão: False.
463
+
234
464
  Returns:
235
- str: ID da pasta criada.
465
+ Dict[str, Any]: Dicionário padronizado com resultado da operação:
466
+ - success (bool): True se operação bem-sucedida, False caso contrário
467
+ - result (Dict[str, Any] | None): Informações da pasta criada/encontrada
468
+ incluindo ID, nome e outros metadados
469
+ - error (str | None): Mensagem de erro se success=False
470
+
471
+ Raises:
472
+ ValueError: Se os parâmetros de entrada falharem na validação do Pydantic.
473
+ Inclui detalhes sobre quais campos são inválidos.
474
+
475
+ Examples:
476
+ >>> # Criar pasta sem verificar existência
477
+ >>> resultado = drive.create_folder(
478
+ ... name="Nova Pasta",
479
+ ... parent_folder_id="1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
480
+ ... )
481
+ >>> if resultado["success"]:
482
+ ... print(f"Pasta criada com ID: {resultado['result']['id']}")
483
+
484
+ >>> # Criar pasta verificando se já existe
485
+ >>> resultado = drive.create_folder(
486
+ ... name="Documentos",
487
+ ... parent_folder_id="root",
488
+ ... validate_existence=True
489
+ ... )
490
+ >>> print(f"Status: {resultado['success']}")
491
+
492
+ Note:
493
+ - Se validate_existence=True e a pasta existir, não será criada duplicata
494
+ - Nomes de pastas são case-sensitive no Google Drive
495
+ - A pasta pai deve existir e ser acessível com as credenciais atuais
496
+ - Suporta drives compartilhados da organização
236
497
  """
237
498
  try:
499
+ # Validação dos parâmetros usando Pydantic
238
500
  CreateFolderValidator(
239
501
  name=name,
240
502
  parent_folder_id=parent_folder_id,
@@ -242,33 +504,41 @@ class GoogleDrive:
242
504
  )
243
505
  except ValidationError as e:
244
506
  raise ValueError(
245
- "Erro na validação dos dados de input da inicialização da instância:",
507
+ "Erro na validação dos dados de input da criação da pasta:",
246
508
  e.errors(),
247
509
  )
248
510
 
249
511
  status_existence = None
250
512
 
513
+ # Verifica existência da pasta se solicitado
251
514
  if validate_existence:
252
-
253
515
  status_existence = self._validate_folder_existence(name, parent_folder_id)
254
516
 
517
+ # Cria pasta apenas se não existir (ou se verificação não foi solicitada)
255
518
  if status_existence is None:
256
-
257
519
  try:
520
+ # Metadados da nova pasta
258
521
  folder_metadata = {
259
522
  "name": name,
260
523
  "parents": [parent_folder_id],
261
- "mimeType": "application/vnd.google-apps.folder",
524
+ "mimeType": "application/vnd.google-apps.folder", # Tipo MIME para pastas
262
525
  }
526
+
527
+ # Executa criação da pasta via API
263
528
  folder = (
264
529
  self.service.files()
265
- .create(body=folder_metadata, fields="id", supportsAllDrives=True)
530
+ .create(
531
+ body=folder_metadata,
532
+ fields="id",
533
+ supportsAllDrives=True # Suporte a drives compartilhados
534
+ )
266
535
  .execute()
267
536
  )
268
537
  return {"success": True, "result": folder}
269
538
  except Exception as e:
270
539
  return {"success": False, "result": None, "error": str(e)}
271
540
 
541
+ # Retorna pasta existente se encontrada
272
542
  return {"success": True, "result": status_existence}
273
543
 
274
544
  def list_items_folder(
@@ -276,46 +546,104 @@ class GoogleDrive:
276
546
  query: str = "",
277
547
  spaces: str = "drive",
278
548
  fields: str = "nextPageToken, files(id, name)",
279
- ):
549
+ ) -> Dict[str, Any]:
280
550
  """
281
- Lista os arquivos e pastas no Google Drive com base nos critérios fornecidos.
551
+ Lista arquivos e pastas no Google Drive com base em critérios de busca especificados.
552
+
553
+ Este método permite buscar e listar conteúdos do Google Drive usando queries
554
+ personalizadas. Suporta busca em drives pessoais e compartilhados, com
555
+ controle sobre quais campos são retornados para otimizar performance.
282
556
 
283
557
  Args:
284
- query (str, optional): Critério de busca para os arquivos ou pastas no Google Drive.
285
- Consulte https://developers.google.com/drive/api/v3/ref-search-terms.
286
- Defaults to "".
287
- exemplo: query = 'ID_DA_PASTA_NO_GOOGLE_DRIVE' in parents and trashed=false"
288
- spaces (str, optional): Especifica os locais de armazenamento a serem consultados. Pode ser 'drive',
289
- 'appDataFolder', ou 'photos'. Defaults to 'drive'.
290
- fields (str, optional): Campos a serem retornados na resposta. Consulte a documentação para os campos disponíveis.
291
- Defaults to "nextPageToken, files(id, name)".
558
+ query (str, optional): Critério de busca para filtrar arquivos e pastas.
559
+ Padrão: "" (lista todos os itens acessíveis).
560
+ Exemplos de queries:
561
+ - "'1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms' in parents and trashed=false"
562
+ (itens em pasta específica, não na lixeira)
563
+ - "name contains 'relatório'" (arquivos com 'relatório' no nome)
564
+ - "mimeType='application/pdf'" (apenas arquivos PDF)
565
+ - "modifiedTime > '2025-01-01T00:00:00'" (modificados após data)
566
+ Consulte: https://developers.google.com/drive/api/v3/ref-search-terms
567
+
568
+ spaces (str, optional): Especifica locais de armazenamento para consulta.
569
+ Padrão: "drive".
570
+ Opções disponíveis:
571
+ - "drive": Drive principal do usuário
572
+ - "appDataFolder": Pasta de dados da aplicação
573
+ - "photos": Google Fotos (se aplicável)
574
+
575
+ fields (str, optional): Campos a serem retornados na resposta da API.
576
+ Padrão: "nextPageToken, files(id, name)".
577
+ Exemplos de campos:
578
+ - "files(id, name, size, modifiedTime)" (informações básicas + tamanho/data)
579
+ - "files(id, name, mimeType, parents)" (inclui tipo MIME e pastas pai)
580
+ - "nextPageToken, files(*)" (todos os campos disponíveis)
581
+ Consulte: https://developers.google.com/drive/api/v3/reference/files
292
582
 
293
583
  Returns:
294
- dict: Dicionário contendo o resultado da busca.
584
+ Dict[str, Any]: Dicionário padronizado com resultado da operação:
585
+ - success (bool): True se operação bem-sucedida, False caso contrário
586
+ - result (Dict[str, Any] | None): Dados retornados da API se success=True:
587
+ * files (List[Dict]): Lista de arquivos/pastas encontrados
588
+ * nextPageToken (str): Token para próxima página (se houver)
589
+ - error (str | None): Mensagem de erro se success=False
590
+
591
+ Raises:
592
+ ValueError: Se os parâmetros de entrada falharem na validação do Pydantic.
593
+
594
+ Examples:
595
+ >>> # Listar todos os itens na raiz do drive
596
+ >>> resultado = drive.list_items_folder()
597
+ >>> if resultado["success"]:
598
+ ... arquivos = resultado["result"]["files"]
599
+ ... for arquivo in arquivos:
600
+ ... print(f"Nome: {arquivo['name']}, ID: {arquivo['id']}")
601
+
602
+ >>> # Listar apenas PDFs em uma pasta específica
603
+ >>> resultado = drive.list_items_folder(
604
+ ... query="'pasta_id' in parents and mimeType='application/pdf'",
605
+ ... fields="files(id, name, size, modifiedTime)"
606
+ ... )
607
+
608
+ >>> # Buscar arquivos por nome
609
+ >>> resultado = drive.list_items_folder(
610
+ ... query="name contains 'contrato' and trashed=false"
611
+ ... )
612
+
613
+ Note:
614
+ - Resultados são limitados pelo page_size configurado na inicialização
615
+ - Use nextPageToken para navegar entre páginas de resultados extensos
616
+ - Queries são case-insensitive para busca por nome
617
+ - Suporta drives compartilhados automaticamente
295
618
  """
296
619
  try:
620
+ # Validação dos parâmetros usando Pydantic
297
621
  ListFolderValidator(query=query, fields=fields, spaces=spaces)
298
622
  except ValidationError as e:
299
623
  raise ValueError(
300
624
  "Erro na validação dos dados de input da lista:", e.errors()
301
625
  )
626
+
302
627
  try:
628
+ # Executa consulta na API do Google Drive
303
629
  results = (
304
630
  self.service.files()
305
631
  .list(
306
- q=query,
307
- spaces=spaces,
308
- pageSize=self.page_size,
309
- fields=fields,
310
- supportsAllDrives=True,
311
- includeItemsFromAllDrives=True,
632
+ q=query, # Query de busca
633
+ spaces=spaces, # Espaços de armazenamento
634
+ pageSize=self.page_size, # Limite de itens por página
635
+ fields=fields, # Campos a retornar
636
+ supportsAllDrives=True, # Suporte a drives compartilhados
637
+ includeItemsFromAllDrives=True, # Incluir itens de drives compartilhados
312
638
  )
313
639
  .execute()
314
640
  )
315
641
  return {"success": True, "result": results}
316
642
  except HttpError as hr:
643
+ # Erro específico da API HTTP (ex: 403 Forbidden, 404 Not Found)
317
644
  return {"success": False, "result": None, "error": str(hr)}
318
645
  except Exception as e:
646
+ # Outros erros gerais (rede, parsing, etc.)
319
647
  return {"success": False, "result": None, "error": str(e)}
320
648
 
321
649
  def download_google_files(self, file: str, mimeType: str, path: str):
@@ -442,4 +770,221 @@ class GoogleDrive:
442
770
  self.service.files().delete(fileId=id_file, supportsAllDrives=True).execute()
443
771
  return {"success": True}
444
772
  except Exception as e:
445
- return {"success": False, "error": str(e)}
773
+ return {"success": False, "error": str(e)}
774
+
775
+ def _find_file_in_folder_by_name(self, parent_folder_id: str, name: str) -> Optional[dict]:
776
+ """
777
+ Retorna o primeiro arquivo (não excluído) com 'name' dentro de 'parent_folder_id',
778
+ ou None se não existir.
779
+ """
780
+ # Escapa aspas simples no nome para a query
781
+ safe_name = name.replace("'", r"\'")
782
+ q = (
783
+ f"'{parent_folder_id}' in parents and "
784
+ f"name = '{safe_name}' and "
785
+ f"trashed = false"
786
+ )
787
+ try:
788
+ resp = (
789
+ self.service.files()
790
+ .list(
791
+ q=q,
792
+ spaces="drive",
793
+ pageSize=1,
794
+ fields="files(id, name, mimeType, size, webViewLink, parents)",
795
+ supportsAllDrives=True,
796
+ includeItemsFromAllDrives=True,
797
+ )
798
+ .execute()
799
+ )
800
+ files = resp.get("files", [])
801
+ return files[0] if files else None
802
+ except Exception as e:
803
+ # Padroniza retorno de erro
804
+ return None
805
+
806
+ def ensure_folder(self, parent_folder_id: str, name: str) -> str:
807
+ """
808
+ Usa o método create_folder(validate_existence=True) para retornar o ID de 'name'
809
+ dentro de 'parent_folder_id', criando se não existir.
810
+ """
811
+ resp = self.create_folder(
812
+ name=name,
813
+ parent_folder_id=parent_folder_id,
814
+ validate_existence=True,
815
+ )
816
+
817
+ if not resp or not resp.get("success"):
818
+ raise RuntimeError(f"Falha ao garantir pasta '{name}': {resp}")
819
+ # A classe retorna em "result" um dict com ao menos "id"
820
+ folder = resp["result"]
821
+ folder_id = folder.get("id")
822
+ if not folder_id:
823
+ # Algumas respostas podem ser {'success': True, 'result': {'id': '...'}} ou já o objeto
824
+ # Se por algum motivo vier diferente, trate aqui
825
+ raise RuntimeError(f"Resposta inesperada ao criar/buscar pasta: {folder}")
826
+ return folder_id
827
+
828
+ def ensure_path(self, path: str, parent_folder_id: str = "root") -> str:
829
+ """
830
+ Percorre/cria cada nível de 'path' dentro de 'parent_folder_id'.
831
+ Retorna o ID da última pasta.
832
+ """
833
+ current_parent = parent_folder_id
834
+ for part in [p for p in path.split("/") if p.strip()]:
835
+ current_parent = self.ensure_folder(current_parent, part)
836
+ return current_parent
837
+
838
+ def upload_pdf_to_drive_path(
839
+ self,
840
+ local_pdf_path: str,
841
+ drive_folder_path: str,
842
+ parent_folder_id: str = "root",
843
+ rename_as: Optional[str] = None,
844
+ ) -> dict:
845
+ """
846
+ - Garante a hierarquia 'drive_folder_path' (ex: "MeusPdfs/2025/09")
847
+ - Sobe o PDF com mimetype application/pdf
848
+ - Se rename_as for fornecido, usa esse nome no Drive (com .pdf); caso contrário, basename do arquivo local.
849
+
850
+ Retorna o dict padronizado da classe: {"success": True/False, "result": {...} | None, "error": str | None}
851
+ """
852
+ if not os.path.exists(local_pdf_path):
853
+ return {"success": False, "result": None, "error": f"Arquivo não encontrado: {local_pdf_path}"}
854
+
855
+ folder_id = self.ensure_path(drive_folder_path, parent_folder_id=parent_folder_id)
856
+
857
+ # nome do arquivo no Drive
858
+ base = os.path.basename(local_pdf_path)
859
+ if rename_as:
860
+ name = rename_as if rename_as.lower().endswith(".pdf") else f"{rename_as}.pdf"
861
+ else:
862
+ name = base
863
+
864
+ # mimetype do PDF
865
+ mimetype = "application/pdf"
866
+
867
+ return self.upload(
868
+ folder_id=folder_id,
869
+ name=name,
870
+ file_path=local_pdf_path,
871
+ mimetype=mimetype,
872
+ )
873
+
874
+ def _gdrive_upload_or_update_media(
875
+ self,
876
+ folder_id: str,
877
+ name: str,
878
+ mimetype: str,
879
+ file_handle: BytesIO,
880
+ overwrite: bool = True,
881
+ ) -> dict:
882
+ """
883
+ Se overwrite=True, procura por (name, folder_id) e:
884
+ - se existir: faz update do conteúdo (mantém o mesmo fileId)
885
+ - se não existir: cria
886
+ Se overwrite=False, sempre cria (comportamento atual).
887
+ """
888
+ try:
889
+ media = MediaIoBaseUpload(
890
+ file_handle,
891
+ mimetype=mimetype,
892
+ resumable=True,
893
+ chunksize=1024 * 1024,
894
+ )
895
+ if overwrite:
896
+ existing = self._find_file_in_folder_by_name(folder_id, name)
897
+ if existing:
898
+ file_id = existing["id"]
899
+ file = (
900
+ self.service.files()
901
+ .update(
902
+ fileId=file_id,
903
+ media_body=media,
904
+ fields="id, name, mimeType, size, webViewLink, parents",
905
+ supportsAllDrives=True,
906
+ )
907
+ .execute()
908
+ )
909
+ return {"success": True, "result": file, "error": None}
910
+
911
+ # cria se não houver existente ou overwrite=False
912
+ file_metadata = {"name": name, "parents": [folder_id]}
913
+ file = (
914
+ self.service.files()
915
+ .create(
916
+ body=file_metadata,
917
+ media_body=media,
918
+ fields="id, name, mimeType, size, webViewLink, parents",
919
+ supportsAllDrives=True,
920
+ )
921
+ .execute()
922
+ )
923
+ return {"success": True, "result": file, "error": None}
924
+ except Exception as e:
925
+ return {"success": False, "result": None, "error": str(e)}
926
+
927
+ def upload_pdf_bytes_to_drive_path(
928
+ self,
929
+ content: bytes,
930
+ drive_folder_path: str,
931
+ parent_folder_id: str = "root",
932
+ name: str | None = None,
933
+ overwrite: bool = True, # << novo parâmetro
934
+ ) -> dict:
935
+ """
936
+ Recebe o conteúdo do PDF em bytes e faz upload para a pasta indicada (criando hierarquia se necessário).
937
+ """
938
+ if not isinstance(content, (bytes, bytearray)) or not content:
939
+ return {"success": False, "result": None, "error": "Parâmetro 'content' vazio ou inválido."}
940
+ folder_id = self.ensure_path(drive_folder_path, parent_folder_id=parent_folder_id)
941
+
942
+ # Nome do arquivo no Drive
943
+ final_name = (name or "arquivo.pdf")
944
+ if not final_name.lower().endswith(".pdf"):
945
+ final_name += ".pdf"
946
+
947
+ fh = BytesIO(content)
948
+ #return self._gdrive_upload_media(folder_id=folder_id, name=final_name, mimetype="application/pdf", file_handle=fh)
949
+ return self._gdrive_upload_or_update_media(
950
+ folder_id=folder_id,
951
+ name=final_name,
952
+ mimetype="application/pdf",
953
+ file_handle=fh,
954
+ overwrite=overwrite,
955
+ )
956
+
957
+ def upload_pdf_base64_to_drive_path(
958
+ self,
959
+ b64_content: str,
960
+ drive_folder_path: str,
961
+ parent_folder_id: str = "root",
962
+ name: str | None = None,
963
+ strict: bool = True,
964
+ overwrite: bool = True, # << novo parâmetro
965
+ ) -> dict:
966
+ """
967
+ Recebe o conteúdo do PDF como string Base64 e faz upload para a pasta indicada (criando hierarquia se necessário).
968
+ - strict=True usa validação estrita no b64 (recomendado).
969
+ - aceita strings com ou sem prefixo data URL (ex.: 'data:application/pdf;base64,...').
970
+ """
971
+ if not isinstance(b64_content, str) or not b64_content.strip():
972
+ return {"success": False, "result": None, "error": "Parâmetro 'b64_content' vazio ou inválido."}
973
+
974
+ # Remove prefixo data URL se existir
975
+ # ex.: data:application/pdf;base64,JVBERi0xLjQKJ...
976
+ if ";base64," in b64_content:
977
+ b64_content = b64_content.split(";base64,", 1)[1]
978
+
979
+ try:
980
+ content = base64.b64decode(b64_content, validate=strict)
981
+ except Exception as e:
982
+ return {"success": False, "result": None, "error": f"Base64 inválido: {e}"}
983
+
984
+ return self.upload_pdf_bytes_to_drive_path(
985
+ content=content,
986
+ drive_folder_path=drive_folder_path,
987
+ parent_folder_id=parent_folder_id,
988
+ name=name,
989
+ overwrite=overwrite,
990
+ )
@@ -52,9 +52,10 @@ class GetFilesValidator(BaseModel):
52
52
  filename: NonEmptyStr
53
53
  destination: NonEmptyStr
54
54
  chunksize: PositiveInt
55
+ download_as: NonEmptyStr = 'file' # 'file' ou 'bytes'
55
56
 
56
57
  # Opcional: se você quiser mensagens personalizadas além das do Field
57
- @field_validator("bucket_name", "filename", "destination")
58
+ @field_validator("bucket_name", "filename", "destination", "download_as")
58
59
  def _not_blank(cls, v, info):
59
60
  if not v.strip():
60
61
  raise ValueError(f"O parametro '{info.field_name}' não pode ser vazio/whitespace.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csc_cia_stne
3
- Version: 0.1.15
3
+ Version: 0.1.17
4
4
  Summary: Biblioteca do time CSC-CIA utilizada no desenvolvimento de RPAs
5
5
  License: MIT
6
6
  Keywords: karavela,csc,cia,stone,rpa,botcity,stne
@@ -4,8 +4,8 @@ csc_cia_stne/bc_sta.py,sha256=sE-aU-ZVSAqryQrT1-nor9eAFM5npNAKF1QSm-ChhGU,28945
4
4
  csc_cia_stne/email.py,sha256=y4xyPAe6_Mga5Wf6qAsDzYgn0f-zf2KshfItlWe58z8,8481
5
5
  csc_cia_stne/ftp.py,sha256=M9WCaq2hm56jGyszNaPinliFaZS0BNrT7VrVPMjkMg4,10988
6
6
  csc_cia_stne/gcp_bigquery.py,sha256=foq8azvvv_f7uikMDslX9RcUIrx7RAS-Sn0AGW0QFQc,7231
7
- csc_cia_stne/gcp_bucket.py,sha256=_Q3LS3Uy9tyi6LFHBedu38S1GS2CrI5iJCxRLu0rNaU,11007
8
- csc_cia_stne/google_drive.py,sha256=j1fvHpgU76_VqCtSEe05JXLOgNwNNfrP6GRKq6eU4b4,17074
7
+ csc_cia_stne/gcp_bucket.py,sha256=vMALWiW7IoBCuJAR8bUCpOV6BuBzI9AhRRk3b72OdMk,11515
8
+ csc_cia_stne/google_drive.py,sha256=sfq2arBYrv8OLIfRJTnj067EPbem2gofwIfpbqJ475o,44500
9
9
  csc_cia_stne/karavela.py,sha256=jJCYX43D49gGuzmwwK6bN9XVnv2dXdp9iHnnV5H1LMQ,4794
10
10
  csc_cia_stne/logger_json.py,sha256=CXxSCOFGMymDi8XE9SKnPKjW4D0wJLqDLnxqePS26i8,3187
11
11
  csc_cia_stne/logger_rich.py,sha256=fklgkBb4rblKQd7YZ3q-eWfhGg9eflO2k2-z4pGh_yo,5201
@@ -31,15 +31,15 @@ csc_cia_stne/utilitarios/validations/GoogleDriveValidator.py,sha256=Q1oZTae4hDJ2
31
31
  csc_cia_stne/utilitarios/validations/ServiceNowValidator.py,sha256=yleKUIo1ZfyloP9fDPNjv3JJXdLcocT81WIgRSYmqEA,14423
32
32
  csc_cia_stne/utilitarios/validations/__init__.py,sha256=O_qyEU2ji3u6LHUXZCXvUFsMpoMWL625qqHTXyXivTA,106
33
33
  csc_cia_stne/utilitarios/validations/ftp.py,sha256=LNYyS2c8eou3ML23bBtn87xJFIKSrb8w-2acG0Zugog,4988
34
- csc_cia_stne/utilitarios/validations/gcp_bucket.py,sha256=sc0xB6IowhKyhH8A2UR0ho3iTYatwsHGbXBsjb25QhY,6905
34
+ csc_cia_stne/utilitarios/validations/gcp_bucket.py,sha256=aDwytjpur6vDKGDMzrqtzDi4bclQ-ahiXuURhmDYZpk,6979
35
35
  csc_cia_stne/utilitarios/validations/waccess.py,sha256=8yfOrmIPUSLzbCt6P0F6vj3FkSgU_RgrJpJlRhlLyV0,7352
36
36
  csc_cia_stne/utilitarios/validations/web_validator.py,sha256=HYKYSpDv1RvRjZIuwTPt-AbEz-9392MxM_O329iYuSA,5722
37
37
  csc_cia_stne/utilitarios/web_screen/__init__.py,sha256=5QcOPXKd95SvP2DoZiHS0gaU68GlyFD9pQ9kae_9D1Q,100
38
38
  csc_cia_stne/utilitarios/web_screen/web_screen_abstract.py,sha256=PjL8Vgfj_JdKidia7RFyCkro3avYLQu4RZRos41sh3w,3241
39
39
  csc_cia_stne/utilitarios/web_screen/web_screen_botcity.py,sha256=Xi5YJjl2pcxlX3OimqcBWRNXZEpAE7asyUjDJ4Oho5U,12297
40
40
  csc_cia_stne/utilitarios/web_screen/web_screen_selenium.py,sha256=JLIcPJE9ZX3Pd6zG6oTRMqqUAY063UzLY3ReRlxmiSM,15581
41
- csc_cia_stne-0.1.15.dist-info/licenses/LICENCE,sha256=LPGMtgKki2C3KEZP7hDhA1HBrlq5JCHkIeStUCLEMx4,1073
42
- csc_cia_stne-0.1.15.dist-info/METADATA,sha256=GoZ9_9FZbKPlj6kTCybVe4coxamwpghFmC2iucPLFuE,1464
43
- csc_cia_stne-0.1.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
- csc_cia_stne-0.1.15.dist-info/top_level.txt,sha256=ldo7GVv3tQx5KJvwBzdZzzQmjPys2NDVVn1rv0BOF2Q,13
45
- csc_cia_stne-0.1.15.dist-info/RECORD,,
41
+ csc_cia_stne-0.1.17.dist-info/licenses/LICENCE,sha256=LPGMtgKki2C3KEZP7hDhA1HBrlq5JCHkIeStUCLEMx4,1073
42
+ csc_cia_stne-0.1.17.dist-info/METADATA,sha256=sJlZR_-JjU01PX7qUYHYGYRFf88JRd0S0mScBwG64vQ,1464
43
+ csc_cia_stne-0.1.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
+ csc_cia_stne-0.1.17.dist-info/top_level.txt,sha256=ldo7GVv3tQx5KJvwBzdZzzQmjPys2NDVVn1rv0BOF2Q,13
45
+ csc_cia_stne-0.1.17.dist-info/RECORD,,