@@ -252,29 +252,40 @@ async def _clone_repo_if_remote(query: IngestionQuery, *, token: str | None) ->
252252 GitHub personal access token (PAT) for accessing private repositories.
253253
254254 """
255+ kwargs = {}
256+ if sys .version_info >= (3 , 12 ):
257+ kwargs ["onexc" ] = _handle_remove_readonly
258+ else :
259+ kwargs ["onerror" ] = _handle_remove_readonly
260+
255261 if query .url :
256262 clone_config = query .extract_clone_config ()
257263 await clone_repo (clone_config , token = token )
258264 try :
259265 yield
260266 finally :
261- shutil .rmtree (query .local_path .parent , onerror = _handle_remove_readonly )
267+ shutil .rmtree (query .local_path .parent , ** kwargs )
262268 else :
263269 yield
264270
265271
266272def _handle_remove_readonly (
267273 func : Callable ,
268274 path : str ,
269- exc_info : tuple [type [BaseException ], BaseException , TracebackType ],
275+ exc_info : BaseException | tuple [type [BaseException ], BaseException , TracebackType ],
270276) -> None :
271277 """Handle permission errors raised by ``shutil.rmtree()``.
272278
273279 * Makes the target writable (removes the read-only attribute).
274280 * Retries the original operation (``func``) once.
275281
276282 """
277- exc = exc_info [1 ]
283+ # 'onerror' passes a (type, value, tb) tuple; 'onexc' passes the exception
284+ if isinstance (exc_info , tuple ): # 'onerror' (Python <3.12)
285+ exc : BaseException = exc_info [1 ]
286+ else : # 'onexc' (Python 3.12+)
287+ exc = exc_info
288+
278289 # Handle only'Permission denied' and 'Operation not permitted'
279290 if not isinstance (exc , OSError ) or exc .errno not in {errno .EACCES , errno .EPERM }:
280291 raise exc
0 commit comments