diff options
author | Brian Curtin <brian@python.org> | 2012-08-13 22:05:57 (GMT) |
---|---|---|
committer | Brian Curtin <brian@python.org> | 2012-08-13 22:05:57 (GMT) |
commit | 6f5c5cb75b2fddf31cbb311d2a5508c54f6e21f6 (patch) | |
tree | 1cf393061b9bce18c6e0fb84c824fe441c583fbc /Lib | |
parent | 59db40166760e270aab5417b5933022349cd35ee (diff) | |
download | cpython-6f5c5cb75b2fddf31cbb311d2a5508c54f6e21f6.zip cpython-6f5c5cb75b2fddf31cbb311d2a5508c54f6e21f6.tar.gz cpython-6f5c5cb75b2fddf31cbb311d2a5508c54f6e21f6.tar.bz2 |
Fix #15496. Add directory removal helpers to make Windows tests more reliable. Patch by Jeremy Kloth
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/support.py | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/Lib/test/support.py b/Lib/test/support.py index 162805d..d88562e 100644 --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -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 i7@4.3GHz 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): |