@@ -200,17 +200,81 @@ def unload(name):
200200 except KeyError :
201201 pass
202202
203+ if sys .platform .startswith ("win" ):
204+ def _waitfor (func , pathname , waitall = False ):
205+ # Peform the operation
206+ func (pathname )
207+ # Now setup the wait loop
208+ if waitall :
209+ dirname = pathname
210+ else :
211+ dirname , name = os .path .split (pathname )
212+ dirname = dirname or '.'
213+ # Check for `pathname` to be removed from the filesystem.
214+ # The exponential backoff of the timeout amounts to a total
215+ # of ~1 second after which the deletion is probably an error
216+ # anyway.
217+ # Testing on a [email protected] shows that usually only 1 iteration is 218+ # required when contention occurs.
219+ timeout = 0.001
220+ while timeout < 1.0 :
221+ # Note we are only testing for the existance of the file(s) in
222+ # the contents of the directory regardless of any security or
223+ # access rights. If we have made it this far, we have sufficient
224+ # permissions to do that much using Python's equivalent of the
225+ # Windows API FindFirstFile.
226+ # Other Windows APIs can fail or give incorrect results when
227+ # dealing with files that are pending deletion.
228+ L = os .listdir (dirname )
229+ if not (L if waitall else name in L ):
230+ return
231+ # Increase the timeout and try again
232+ time .sleep (timeout )
233+ timeout *= 2
234+ warnings .warn ('tests may fail, delete still pending for ' + pathname ,
235+ RuntimeWarning , stacklevel = 4 )
236+
237+ def _unlink (filename ):
238+ _waitfor (os .unlink , filename )
239+
240+ def _rmdir (dirname ):
241+ _waitfor (os .rmdir , dirname )
242+
243+ def _rmtree (path ):
244+ def _rmtree_inner (path ):
245+ for name in os .listdir (path ):
246+ fullname = os .path .join (path , name )
247+ if os .path .isdir (fullname ):
248+ _waitfor (_rmtree_inner , fullname , waitall = True )
249+ os .rmdir (fullname )
250+ else :
251+ os .unlink (fullname )
252+ _waitfor (_rmtree_inner , path , waitall = True )
253+ _waitfor (os .rmdir , path )
254+ else :
255+ _unlink = os .unlink
256+ _rmdir = os .rmdir
257+ _rmtree = shutil .rmtree
258+
203259def unlink (filename ):
204260 try :
205- os . unlink (filename )
261+ _unlink (filename )
206262 except OSError as error :
207263 # The filename need not exist.
208264 if error .errno not in (errno .ENOENT , errno .ENOTDIR ):
209265 raise
210266
267+ def rmdir (dirname ):
268+ try :
269+ _rmdir (dirname )
270+ except OSError as error :
271+ # The directory need not exist.
272+ if error .errno != errno .ENOENT :
273+ raise
274+
211275def rmtree (path ):
212276 try :
213- shutil . rmtree (path )
277+ _rmtree (path )
214278 except OSError as error :
215279 # Unix returns ENOENT, Windows returns ESRCH.
216280 if error .errno not in (errno .ENOENT , errno .ESRCH ):
0 commit comments