summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorBrian Curtin <brian@python.org>2012-08-13 22:05:57 (GMT)
committerBrian Curtin <brian@python.org>2012-08-13 22:05:57 (GMT)
commit6f5c5cb75b2fddf31cbb311d2a5508c54f6e21f6 (patch)
tree1cf393061b9bce18c6e0fb84c824fe441c583fbc /Lib
parent59db40166760e270aab5417b5933022349cd35ee (diff)
downloadcpython-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.py68
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):