Skip to content

Commit f23489f

Browse files
committed
bump version to 0.2.4 and enhance file download with integrity check and retry logic
1 parent 39b4cbd commit f23489f

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "office365-service"
3-
version = "0.2.3"
3+
version = "0.2.4"
44
description = "Add your description here"
55
readme = "README.md"
66
authors = [

src/office365_service/sharepoint_service.py

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,61 @@ def criar_pasta(self, pasta_pai: Folder | str, nome_pasta: str):
203203
pasta.execute_query()
204204
return pasta
205205

206-
@handle_sharepoint_errors()
207-
def baixar_arquivo(self, arquivo_sp: File | str, caminho_download: str):
208-
"""Baixa um arquivo do SharePoint para um caminho local."""
206+
def baixar_arquivo(self, arquivo_sp: File | str, caminho_download: str, max_tentativas: int = 3):
207+
"""
208+
Baixa um arquivo do SharePoint para um caminho local, com verificação de integridade e novas tentativas.
209+
"""
209210
if isinstance(arquivo_sp, str):
210-
file_to_download = self.ctx.web.get_file_by_server_relative_url(arquivo_sp)
211+
file_to_download = self.obter_arquivo(arquivo_sp)
212+
if file_to_download is None:
213+
raise FileNotFoundError(f"Arquivo remoto '{arquivo_sp}' não encontrado.")
211214
else:
212215
file_to_download = arquivo_sp
216+
# Garante que os metadados do arquivo (como o tamanho) estão carregados
217+
file_to_download.get().execute_query()
218+
219+
# O decorador @handle_sharepoint_errors em obter_arquivo já tratou erros de API aqui.
220+
tamanho_remoto = file_to_download.length
221+
222+
for tentativa in range(max_tentativas):
223+
print(f"Iniciando download de '{file_to_download.name}' (Tentativa {tentativa + 1}/{max_tentativas})...")
224+
225+
try:
226+
with open(caminho_download, "wb") as local_file:
227+
file_to_download.download_session(local_file).execute_query()
228+
229+
# Verificação do tamanho do arquivo
230+
tamanho_local = os.path.getsize(caminho_download)
231+
232+
if tamanho_local == tamanho_remoto:
233+
print(
234+
f"Download de '{file_to_download.name}' concluído e verificado com sucesso. Tamanho: {tamanho_local} bytes.")
235+
return # Sucesso, sai da função
236+
else:
237+
print(f"Falha na verificação de tamanho para '{file_to_download.name}'.")
238+
print(f" -> Tamanho esperado: {tamanho_remoto} bytes")
239+
print(f" -> Tamanho baixado: {tamanho_local} bytes")
240+
241+
except Exception as e:
242+
print(f"Ocorreu um erro durante o download na tentativa {tentativa + 1}/{max_tentativas}: {e}")
243+
244+
if tentativa < max_tentativas - 1:
245+
print("Aguardando 5 segundos para tentar novamente...")
246+
time.sleep(5)
247+
248+
# Se o loop terminar, todas as tentativas falharam.
249+
print(f"Falha ao baixar o arquivo '{file_to_download.name}' após {max_tentativas} tentativas.")
250+
251+
# Tenta remover o arquivo parcial/corrompido
252+
try:
253+
if os.path.exists(caminho_download):
254+
os.remove(caminho_download)
255+
print(f"Arquivo parcial '{caminho_download}' removido.")
256+
except OSError as e:
257+
print(f"Não foi possível remover o arquivo parcial '{caminho_download}': {e}")
213258

214-
with open(caminho_download, "wb") as local_file:
215-
file_to_download.download_session(local_file).execute_query()
259+
raise IOError(
260+
f"Não foi possível baixar o arquivo '{file_to_download.name}' com o tamanho correto após {max_tentativas} tentativas.")
216261

217262
@handle_sharepoint_errors()
218263
def enviar_arquivo(self, pasta_destino: Folder | str, arquivo_local: str, nome_arquivo_sp: str = None):
@@ -279,4 +324,4 @@ def obter_pasta_por_nome(self, pasta_raiz: Folder, nome):
279324
def obter_arquivo_por_nome(self, pasta: Folder, nome):
280325
arquivos = list(self.listar_arquivos(pasta))
281326
arquivo_encontrado = next((arquivo for arquivo in arquivos if nome in arquivo.name), None)
282-
return arquivo_encontrado
327+
return arquivo_encontrado

0 commit comments

Comments
 (0)