33import base64
44import json
55import os
6+ import time
67from tempfile import NamedTemporaryFile
78from typing import Any
89
@@ -202,6 +203,19 @@ def check_file_exists(file_path: str) -> bool:
202203 except Exception :
203204 return False
204205
206+
207+ def _replace_with_retry (self , src : str , dst : str , retries : int = 8 , delay : float = 0.05 ) -> None :
208+ last_error = None
209+ for _ in range (retries ):
210+ try :
211+ os .replace (src , dst )
212+ return
213+ except PermissionError as error :
214+ last_error = error
215+ time .sleep (delay )
216+ if last_error is not None :
217+ raise last_error
218+
205219 def _save_data (self ) -> None :
206220 if self ._file is None or self ._file_path is None :
207221 return
@@ -219,7 +233,7 @@ def _save_data(self) -> None:
219233 if self ._file and not self ._file .closed :
220234 self ._file .close ()
221235
222- os . replace (tmp_path , self ._file_path )
236+ self . _replace_with_retry (tmp_path , self ._file_path )
223237 object .__setattr__ (self , '_file' , open (self ._file_path , 'r+' , encoding = 'utf-8' ))
224238 except Exception as error :
225239 self ._log (f"{ get_message ('save_data_error' )} : { str (error )} " , 'ERROR' )
@@ -235,9 +249,11 @@ def _save_data(self) -> None:
235249 pass
236250
237251 def close (self ) -> None :
238- self ._save_data ()
252+ if self ._file is not None :
253+ self ._save_data ()
239254 if self ._file and not self ._file .closed :
240255 self ._file .close ()
256+ object .__setattr__ (self , '_file' , None )
241257 if self ._is_temp and self ._auto_cleanup_temp and self ._file_path :
242258 try :
243259 if os .path .exists (self ._file_path ):
0 commit comments