-
-
Notifications
You must be signed in to change notification settings - Fork 30.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix #15496. Add directory removal helpers to make Windows tests more …
…reliable. Patch by Jeremy Kloth
- Loading branch information
1 parent
59db401
commit 6f5c5cb
Showing
2 changed files
with
69 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -200,17 +200,81 @@ def unload(name): | |
except KeyError: | ||
pass | ||
|
||
if sys.platform.startswith("win"): | ||
def _waitfor(func, pathname, waitall=False): | ||
# Peform the operation | ||
func(pathname) | ||
# Now setup the wait loop | ||
if waitall: | ||
dirname = pathname | ||
else: | ||
dirname, name = os.path.split(pathname) | ||
dirname = dirname or '.' | ||
# Check for `pathname` to be removed from the filesystem. | ||
# The exponential backoff of the timeout amounts to a total | ||
# of ~1 second after which the deletion is probably an error | ||
# anyway. | ||
# Testing on a [email protected] shows that usually only 1 iteration is | ||
# required when contention occurs. | ||
timeout = 0.001 | ||
while timeout < 1.0: | ||
# Note we are only testing for the existance of the file(s) in | ||
# the contents of the directory regardless of any security or | ||
# access rights. If we have made it this far, we have sufficient | ||
# permissions to do that much using Python's equivalent of the | ||
# Windows API FindFirstFile. | ||
# Other Windows APIs can fail or give incorrect results when | ||
# dealing with files that are pending deletion. | ||
L = os.listdir(dirname) | ||
if not (L if waitall else name in L): | ||
return | ||
# Increase the timeout and try again | ||
time.sleep(timeout) | ||
timeout *= 2 | ||
warnings.warn('tests may fail, delete still pending for ' + pathname, | ||
RuntimeWarning, stacklevel=4) | ||
|
||
def _unlink(filename): | ||
_waitfor(os.unlink, filename) | ||
|
||
def _rmdir(dirname): | ||
_waitfor(os.rmdir, dirname) | ||
|
||
def _rmtree(path): | ||
def _rmtree_inner(path): | ||
for name in os.listdir(path): | ||
fullname = os.path.join(path, name) | ||
if os.path.isdir(fullname): | ||
_waitfor(_rmtree_inner, fullname, waitall=True) | ||
os.rmdir(fullname) | ||
else: | ||
os.unlink(fullname) | ||
_waitfor(_rmtree_inner, path, waitall=True) | ||
_waitfor(os.rmdir, path) | ||
else: | ||
_unlink = os.unlink | ||
_rmdir = os.rmdir | ||
_rmtree = shutil.rmtree | ||
|
||
def unlink(filename): | ||
try: | ||
os.unlink(filename) | ||
_unlink(filename) | ||
except OSError as error: | ||
# The filename need not exist. | ||
if error.errno not in (errno.ENOENT, errno.ENOTDIR): | ||
raise | ||
|
||
def rmdir(dirname): | ||
try: | ||
_rmdir(dirname) | ||
except OSError as error: | ||
# The directory need not exist. | ||
if error.errno != errno.ENOENT: | ||
raise | ||
|
||
def rmtree(path): | ||
try: | ||
shutil.rmtree(path) | ||
_rmtree(path) | ||
except OSError as error: | ||
# Unix returns ENOENT, Windows returns ESRCH. | ||
if error.errno not in (errno.ENOENT, errno.ESRCH): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters