@@ -177,65 +177,64 @@ def _ensure_dirpath_exists(path: Path) -> Path:
177177
178178 return out_path
179179
180- def download_single (
181- self ,
182- guid ,
183- download_path = "." ,
184- filename_format = "original" ,
185- protocol = None ,
186- skip_completed = False ,
187- rename = False ,
188- ):
189- """Download a single file with enhanced options.
180+ def download_single (self , object_id , path ):
181+ """
182+ Download a single file using its GUID.
190183
191184 Args:
192- guid (str): File GUID to download
193- download_path (str): Directory to save file
194- filename_format (str): Format for filename - 'original', 'guid', or 'combined'
195- protocol (str, optional): Protocol preference for download
196- skip_completed (bool): Skip if file already exists
197- rename (bool): Rename file if conflict exists
185+ object_id (str): The file's unique ID
186+ path (str): Path to store the downloaded file at
198187
199188 Returns:
200- Dict: Download result with status and details
189+ bool: True if download successful, False otherwise
201190 """
202- # Create a single-item manifest to reuse async logic
203- manifest_data = [{"guid" : guid }]
204-
205- # Use the async download logic with single process
206- loop = asyncio .new_event_loop ()
207- asyncio .set_event_loop (loop )
208-
209191 try :
210- result = loop .run_until_complete (
211- self .async_download_multiple (
212- manifest_data = manifest_data ,
213- download_path = download_path ,
214- filename_format = filename_format ,
215- protocol = protocol ,
216- max_concurrent_requests = 1 ,
217- num_processes = 1 ,
218- queue_size = 1 ,
219- skip_completed = skip_completed ,
220- rename = rename ,
221- no_progress = True ,
222- )
223- )
192+ url = self .get_presigned_url (object_id )
193+ except Exception as e :
194+ logging .critical (f"Unable to get a presigned URL for download: { e } " )
195+ return False
224196
225- # Extract the single result
226- if result ["succeeded" ]:
227- return {"status" : "downloaded" , "filepath" : result ["succeeded" ][0 ]}
228- elif result ["skipped" ]:
229- return {"status" : "skipped" , "filepath" : result ["skipped" ][0 ]}
230- elif result ["failed" ]:
231- return {"status" : "failed" , "error" : result ["failed" ][0 ]}
197+ response = requests .get (url ["url" ], stream = True )
198+ if response .status_code != 200 :
199+ logging .error (f"Response code: { response .status_code } " )
200+ if response .status_code >= 500 :
201+ for _ in range (MAX_RETRIES ):
202+ logging .info ("Retrying now..." )
203+ # NOTE could be updated with exponential backoff
204+ time .sleep (1 )
205+ response = requests .get (url ["url" ], stream = True )
206+ if response .status_code == 200 :
207+ break
208+ if response .status_code != 200 :
209+ logging .critical ("Response status not 200, try again later" )
210+ return False
232211 else :
233- return { "status" : "failed" , "error" : "Unknown error" }
212+ return False
234213
235- except Exception as e :
236- return {"status" : "failed" , "error" : f"Download failed: { e } " }
237- finally :
238- loop .close ()
214+ response .raise_for_status ()
215+
216+ total_size_in_bytes = int (response .headers .get ("content-length" ))
217+ total_downloaded = 0
218+
219+ index = Gen3Index (self ._auth_provider )
220+ record = index .get_record (object_id )
221+
222+ filename = record ["file_name" ]
223+
224+ out_path = Gen3File ._ensure_dirpath_exists (Path (path ))
225+
226+ with open (os .path .join (out_path , filename ), "wb" ) as f :
227+ for data in response .iter_content (4096 ):
228+ total_downloaded += len (data )
229+ f .write (data )
230+
231+ if total_size_in_bytes == total_downloaded :
232+ logging .info (f"File { filename } downloaded successfully" )
233+ else :
234+ logging .error (f"File { filename } not downloaded successfully" )
235+ return False
236+
237+ return True
239238
240239 def upload_file_to_guid (
241240 self , guid , file_name , protocol = None , expires_in = None , bucket = None
0 commit comments