2626import sys
2727from pathlib import Path
2828
29-
3029def install_and_import (package ):
3130 try :
3231 importlib .import_module (package )
@@ -36,20 +35,13 @@ def install_and_import(package):
3635 finally :
3736 globals ()[package ] = importlib .import_module (package )
3837
39-
40- install_and_import ("tqdm" )
41- install_and_import ("requests" )
42- install_and_import ("tenacity" )
38+ install_and_import ('tqdm' )
39+ install_and_import ('requests' )
40+ install_and_import ('tenacity' )
4341
4442import requests
4543from tqdm import tqdm
46- from tenacity import (
47- retry ,
48- stop_after_attempt ,
49- wait_exponential ,
50- retry_if_exception_type ,
51- )
52-
44+ from tenacity import retry , stop_after_attempt , wait_exponential , retry_if_exception_type
5345
5446def calculate_file_hash (file_path ):
5547 hash_func = hashlib .new ("sha256" )
@@ -58,11 +50,10 @@ def calculate_file_hash(file_path):
5850 hash_func .update (chunk )
5951 return hash_func .hexdigest ()
6052
61-
6253def download_file (url , destination , expected_hash , max_retries = 3 , chunk_size = 1024 ):
6354 """
6455 Download a file with retry and resume support.
65-
56+
6657 Args:
6758 url (str): URL of the file to download.
6859 destination (str): Local path to save the file.
@@ -72,106 +63,94 @@ def download_file(url, destination, expected_hash, max_retries=3, chunk_size=102
7263 """
7364 # Ensure destination directory exists
7465 os .makedirs (os .path .dirname (destination ), exist_ok = True )
75-
66+
7667 # Check if file exists and get its size
7768 current_size = 0
7869 if os .path .exists (destination ):
7970 if calculate_file_hash (destination ) == expected_hash :
80- print (
81- f"File { destination } already exists with the correct hash. Skipping download."
82- )
71+ print (f"File { destination } already exists with the correct hash. Skipping download." )
8372 return True
8473 current_size = os .path .getsize (destination )
8574
8675 @retry (
8776 stop = stop_after_attempt (max_retries ),
8877 wait = wait_exponential (multiplier = 1 , min = 4 , max = 10 ),
89- retry = retry_if_exception_type (
90- (requests .ConnectionError , requests .Timeout , requests .HTTPError )
91- ),
92- reraise = True ,
78+ retry = retry_if_exception_type ((requests .ConnectionError , requests .Timeout , requests .HTTPError )),
79+ reraise = True
9380 )
9481 def download_with_retry ():
9582 nonlocal current_size
96- headers = {" Range" : f" bytes={ current_size } -" } if current_size > 0 else {}
97- mode = "ab" if current_size > 0 else "wb"
98-
83+ headers = {' Range' : f' bytes={ current_size } -' } if current_size > 0 else {}
84+ mode = 'ab' if current_size > 0 else 'wb'
85+
9986 print (f"\n Downloading { destination } (Starting from: { current_size :,} bytes)..." )
100-
87+
10188 response = None
10289 try :
10390 response = requests .get (url , stream = True , headers = headers , timeout = 30 )
10491 response .raise_for_status () # Raise exception for bad status codes
105-
92+
10693 # Determine total_size
10794 total_size = None
108- if " content-length" in response .headers :
109- remaining = int (response .headers [" content-length" ])
95+ if ' content-length' in response .headers :
96+ remaining = int (response .headers [' content-length' ])
11097 else :
11198 remaining = None
112-
99+
113100 # Parse content-range if available
114- if " content-range" in response .headers :
115- cr = response .headers [" content-range" ]
116- total_str = cr .rsplit ("/" , 1 )[- 1 ]
101+ if ' content-range' in response .headers :
102+ cr = response .headers [' content-range' ]
103+ total_str = cr .rsplit ('/' , 1 )[- 1 ]
117104 if total_str .isdigit ():
118105 total_size = int (total_str )
119-
106+
120107 # If content-length available but no total from range, compute it
121108 if remaining is not None and total_size is None :
122109 total_size = current_size + remaining
123-
110+
124111 # Check if server supports range requests
125112 if current_size > 0 and response .status_code != 206 :
126- print (
127- "Server does not support range requests. Restarting download from scratch..."
128- )
113+ print ("Server does not support range requests. Restarting download from scratch..." )
129114 response .close ()
130115 # Truncate the file to zero
131- open (destination , "wb" ).close ()
116+ open (destination , 'wb' ).close ()
132117 current_size = 0
133- raise requests .RequestException (
134- "Restarting due to lack of range support"
135- ) # Trigger retry to restart
136-
118+ raise requests .RequestException ("Restarting due to lack of range support" ) # Trigger retry to restart
119+
137120 # Print total size if known
138121 if total_size is not None :
139122 print (f"Total size detected: { total_size :,} bytes" )
140-
123+
141124 # Now create tqdm with known total or None
142- t = tqdm (total = total_size , initial = current_size , unit = "iB" , unit_scale = True )
143-
125+ t = tqdm (total = total_size , initial = current_size , unit = 'iB' , unit_scale = True )
126+
144127 # Open file and download
145128 with open (destination , mode ) as f :
146129 for chunk in response .iter_content (chunk_size ):
147130 if chunk : # Filter out keep-alive chunks
148131 f .write (chunk )
149132 t .update (len (chunk ))
150-
133+
151134 except requests .RequestException as e :
152135 print (f"Download failed: { e } . Retrying..." )
153136 raise
154137 finally :
155138 if response :
156139 response .close ()
157140 t .close ()
158-
141+
159142 # Verify file size if known
160143 downloaded_size = os .path .getsize (destination )
161144 if total_size is not None and downloaded_size != total_size :
162- print (
163- f"Download incomplete: { downloaded_size :,} of { total_size :,} bytes downloaded."
164- )
145+ print (f"Download incomplete: { downloaded_size :,} of { total_size :,} bytes downloaded." )
165146 raise requests .RequestException ("Incomplete download" )
166-
147+
167148 # Verify hash
168149 downloaded_hash = calculate_file_hash (destination )
169150 if downloaded_hash != expected_hash :
170- print (
171- f"Hash mismatch. Expected: { expected_hash } , Got: { downloaded_hash } . Downloaded file is corrupted."
172- )
151+ print (f"Hash mismatch. Expected: { expected_hash } , Got: { downloaded_hash } . Downloaded file is corrupted." )
173152 raise requests .RequestException ("Hash mismatch" )
174-
153+
175154 print (f"Successfully downloaded { destination } ." )
176155 return True
177156
@@ -181,42 +160,34 @@ def download_with_retry():
181160 print (f"Failed to download { destination } after { max_retries } attempts: { e } " )
182161 return False
183162
184-
185163def extract_archive (archive_path , destination_path ):
186164 import platform
187165
188- is_windows = platform .system () == " Windows"
166+ is_windows = platform .system () == ' Windows'
189167
190168 if is_windows :
191- current_dir_7z = Path ("7z.exe" )
169+ # Check if 7z.exe exists locally
170+ current_dir_7z = Path ("7z.exe" )
192171 if current_dir_7z .exists ():
193172 seven_zip_exe = current_dir_7z
194173 else :
174+ # define the path where 7z.exe should be if not in the current directory
195175 seven_zip_exe = Path ("build_scripts" ) / "7z.exe"
196176 seven_zip_exe = seven_zip_exe .resolve ()
197177 else :
198- seven_zip_exe_path = shutil .which ("7z" )
178+ seven_zip_exe_path = shutil .which ('7z' )
199179 if not seven_zip_exe_path :
200- raise FileNotFoundError (
201- "The 7z executable was not found. Please install p7zip or 7zip."
202- )
180+ raise FileNotFoundError ("The 7z executable was not found. Please install p7zip or 7zip." )
203181 seven_zip_exe = Path (seven_zip_exe_path )
204182
183+ # check if the 7z executable exists
205184 if not os .path .exists (seven_zip_exe ):
206- raise FileNotFoundError (
207- f"The 7z executable was not found at { seven_zip_exe } . Please check the path or installation."
208- )
209-
185+ raise FileNotFoundError (f"The 7z executable was not found at { seven_zip_exe } . Please check the path or installation." )
186+
210187 archive_path_str = str (Path (archive_path ).resolve ())
211188 destination_path_str = str (Path (destination_path ).resolve ())
212189
213- cmd = [
214- str (seven_zip_exe ),
215- "x" ,
216- archive_path_str ,
217- "-o" + destination_path_str ,
218- "-aoa" ,
219- ]
190+ cmd = [str (seven_zip_exe ), 'x' , archive_path_str , '-o' + destination_path_str , '-aoa' ]
220191
221192 print (f"Extracting { archive_path } to { destination_path } using: { seven_zip_exe } " )
222193
@@ -227,8 +198,7 @@ def extract_archive(archive_path, destination_path):
227198 print (f"An error occurred while extracting: { e } " )
228199 print (f"Error output: { e .stderr } " )
229200 raise
230-
231-
201+
232202def copy (source , destination ):
233203 def on_rm_error (func , path , exc_info ):
234204 os .chmod (path , stat .S_IWRITE )
@@ -240,21 +210,17 @@ def on_rm_error(func, path, exc_info):
240210 # check if source is a directory or file
241211 if source_path .is_dir ():
242212 # if source is a directory, ensure destination is a directory too
243- dest_path .mkdir (
244- parents = True , exist_ok = True
245- ) # Create the destination directory if it doesn't exist
246- print (f'Copying directory "{ source_path } " to directory "{ dest_path } "...' )
213+ dest_path .mkdir (parents = True , exist_ok = True ) # Create the destination directory if it doesn't exist
214+ print (f"Copying directory \" { source_path } \" to directory \" { dest_path } \" ..." )
247215 shutil .rmtree (str (dest_path ), onerror = on_rm_error )
248216 shutil .copytree (str (source_path ), str (dest_path ), dirs_exist_ok = True )
249217 elif source_path .is_file ():
250218 # if source is a file, ensure the parent directory of the destination exists
251- dest_path .parent .mkdir (
252- parents = True , exist_ok = True
253- ) # Create parent directory if it doesn't exist
219+ dest_path .parent .mkdir (parents = True , exist_ok = True ) # Create parent directory if it doesn't exist
254220 target = dest_path if dest_path .is_file () else dest_path / source_path .name
255- print (f' Copying file "{ source_path } " to "{ target } "...' )
221+ print (f" Copying file \ "{ source_path } \ " to \ "{ target } \ " ..." )
256222 shutil .copy2 (str (source_path ), str (target ))
257223 else :
258224 print (f"Error: Source '{ source_path } ' is neither a file nor a directory." )
259225 return False
260- return True
226+ return True
0 commit comments