@@ -202,24 +202,36 @@ def cmd_output_p(
202202 cmd_output_p = cmd_output_b
203203
204204
205- def rmtree (path : str ) -> None :
206- """On windows, rmtree fails for readonly dirs."""
207- def handle_remove_readonly (
208- func : Callable [..., Any ],
209- path : str ,
210- exc : tuple [type [OSError ], OSError , TracebackType ],
205+ def _handle_readonly (
206+ func : Callable [[str ], object ],
207+ path : str ,
208+ exc : OSError ,
209+ ) -> None :
210+ if (
211+ func in (os .rmdir , os .remove , os .unlink ) and
212+ exc .errno in {errno .EACCES , errno .EPERM }
213+ ):
214+ for p in (path , os .path .dirname (path )):
215+ os .chmod (p , os .stat (p ).st_mode | stat .S_IWUSR )
216+ func (path )
217+ else :
218+ raise
219+
220+
221+ if sys .version_info < (3 , 12 ): # pragma: <3.12 cover
222+ def _handle_readonly_old (
223+ func : Callable [[str ], object ],
224+ path : str ,
225+ excinfo : tuple [type [OSError ], OSError , TracebackType ],
211226 ) -> None :
212- excvalue = exc [1 ]
213- if (
214- func in (os .rmdir , os .remove , os .unlink ) and
215- excvalue .errno in {errno .EACCES , errno .EPERM }
216- ):
217- for p in (path , os .path .dirname (path )):
218- os .chmod (p , os .stat (p ).st_mode | stat .S_IWUSR )
219- func (path )
220- else :
221- raise
222- shutil .rmtree (path , ignore_errors = False , onerror = handle_remove_readonly )
227+ return _handle_readonly (func , path , excinfo [1 ])
228+
229+ def rmtree (path : str ) -> None :
230+ shutil .rmtree (path , ignore_errors = False , onerror = _handle_readonly_old )
231+ else : # pragma: >=3.12 cover
232+ def rmtree (path : str ) -> None :
233+ """On windows, rmtree fails for readonly dirs."""
234+ shutil .rmtree (path , ignore_errors = False , onexc = _handle_readonly )
223235
224236
225237def win_exe (s : str ) -> str :
0 commit comments