@@ -256,29 +256,40 @@ async def _clone_repo_if_remote(query: IngestionQuery, *, token: str | None) ->
256256 GitHub personal access token (PAT) for accessing private repositories.
257257
258258 """
259+ kwargs = {}
260+ if sys .version_info >= (3 , 12 ):
261+ kwargs ["onexc" ] = _handle_remove_readonly
262+ else :
263+ kwargs ["onerror" ] = _handle_remove_readonly
264+
259265 if query .url :
260266 clone_config = query .extract_clone_config ()
261267 await clone_repo (clone_config , token = token )
262268 try :
263269 yield
264270 finally :
265- shutil .rmtree (query .local_path .parent , onerror = _handle_remove_readonly )
271+ shutil .rmtree (query .local_path .parent , ** kwargs )
266272 else :
267273 yield
268274
269275
270276def _handle_remove_readonly (
271277 func : Callable ,
272278 path : str ,
273- exc_info : tuple [type [BaseException ], BaseException , TracebackType ],
279+ exc_info : BaseException | tuple [type [BaseException ], BaseException , TracebackType ],
274280) -> None :
275281 """Handle permission errors raised by ``shutil.rmtree()``.
276282
277283 * Makes the target writable (removes the read-only attribute).
278284 * Retries the original operation (``func``) once.
279285
280286 """
281- exc = exc_info [1 ]
287+ # 'onerror' passes a (type, value, tb) tuple; 'onexc' passes the exception
288+ if isinstance (exc_info , tuple ): # 'onerror' (Python <3.12)
289+ exc : BaseException = exc_info [1 ]
290+ else : # 'onexc' (Python 3.12+)
291+ exc = exc_info
292+
282293 # Handle only'Permission denied' and 'Operation not permitted'
283294 if not isinstance (exc , OSError ) or exc .errno not in {errno .EACCES , errno .EPERM }:
284295 raise exc
0 commit comments