cpython: 63f0ae6e218a (original) (raw)
Mercurial > cpython
changeset 96163:63f0ae6e218a 2.7
Issue #22107: tempfile.gettempdir() and tempfile.mkdtemp() now try again when a directory with the chosen name already exists on Windows as well as on Unix. tempfile.mkstemp() now fails early if parent directory is not valid (not exists or is a file) on Windows. [#22107]
Serhiy Storchaka storchaka@gmail.com | |
---|---|
date | Wed, 20 May 2015 00:10:56 +0300 |
parents | 6969bac411fa |
children | 56e1d24806b3 |
files | Lib/tempfile.py Lib/test/test_tempfile.py Misc/NEWS |
diffstat | 3 files changed, 64 insertions(+), 10 deletions(-)[+] [-] Lib/tempfile.py 19 Lib/test/test_tempfile.py 50 Misc/NEWS 5 |
line wrap: on
line diff
--- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -205,9 +205,14 @@ def _get_default_tempdir(): _os.unlink(filename) return dir except (OSError, IOError) as e:
if e.args[0] != _errno.EEXIST:[](#l1.7)
break # no point trying more names in this directory[](#l1.8)
pass[](#l1.9)
if e.args[0] == _errno.EEXIST:[](#l1.10)
continue[](#l1.11)
if (_os.name == 'nt' and e.args[0] == _errno.EACCES and[](#l1.12)
_os.path.isdir(dir) and _os.access(dir, _os.W_OK)):[](#l1.13)
# On windows, when a directory with the chosen name already[](#l1.14)
# exists, EACCES error code is returned instead of EEXIST.[](#l1.15)
continue[](#l1.16)
raise IOError, (_errno.ENOENT, ("No usable temporary directory found in %s" % dirlist))break # no point trying more names in this directory[](#l1.17)
@@ -242,7 +247,8 @@ def _mkstemp_inner(dir, pre, suf, flags) except OSError, e: if e.errno == _errno.EEXIST: continue # try again
if _os.name == 'nt' and e.errno == _errno.EACCES:[](#l1.25)
if (_os.name == 'nt' and e.errno == _errno.EACCES and[](#l1.26)
_os.path.isdir(dir) and _os.access(dir, _os.W_OK)):[](#l1.27) # On windows, when a directory with the chosen name already[](#l1.28) # exists, EACCES error code is returned instead of EEXIST.[](#l1.29) continue[](#l1.30)
@@ -335,6 +341,11 @@ def mkdtemp(suffix="", prefix=template, except OSError, e: if e.errno == _errno.EEXIST: continue # try again
if (_os.name == 'nt' and e.errno == _errno.EACCES and[](#l1.35)
_os.path.isdir(dir) and _os.access(dir, _os.W_OK)):[](#l1.36)
# On windows, when a directory with the chosen name already[](#l1.37)
# exists, EACCES error code is returned instead of EEXIST.[](#l1.38)
continue[](#l1.39) raise[](#l1.40)
raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
--- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -287,7 +287,42 @@ def _mock_candidate_names(*names): lambda: iter(names)) -class test__mkstemp_inner(TC): +class TestBadTempdir: +
- def test_read_only_directory(self):
with _inside_empty_temp_dir():[](#l2.11)
oldmode = mode = os.stat(tempfile.tempdir).st_mode[](#l2.12)
mode &= ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)[](#l2.13)
os.chmod(tempfile.tempdir, mode)[](#l2.14)
try:[](#l2.15)
if os.access(tempfile.tempdir, os.W_OK):[](#l2.16)
self.skipTest("can't set the directory read-only")[](#l2.17)
with self.assertRaises(OSError) as cm:[](#l2.18)
self.make_temp()[](#l2.19)
self.assertIn(cm.exception.errno, (errno.EPERM, errno.EACCES))[](#l2.20)
self.assertEqual(os.listdir(tempfile.tempdir), [])[](#l2.21)
finally:[](#l2.22)
os.chmod(tempfile.tempdir, oldmode)[](#l2.23)
- def test_nonexisting_directory(self):
with _inside_empty_temp_dir():[](#l2.26)
tempdir = os.path.join(tempfile.tempdir, 'nonexistent')[](#l2.27)
with support.swap_attr(tempfile, 'tempdir', tempdir):[](#l2.28)
with self.assertRaises(OSError) as cm:[](#l2.29)
self.make_temp()[](#l2.30)
self.assertEqual(cm.exception.errno, errno.ENOENT)[](#l2.31)
- def test_non_directory(self):
with _inside_empty_temp_dir():[](#l2.34)
tempdir = os.path.join(tempfile.tempdir, 'file')[](#l2.35)
open(tempdir, 'wb').close()[](#l2.36)
with support.swap_attr(tempfile, 'tempdir', tempdir):[](#l2.37)
with self.assertRaises(OSError) as cm:[](#l2.38)
self.make_temp()[](#l2.39)
self.assertIn(cm.exception.errno, (errno.ENOTDIR, errno.ENOENT))[](#l2.40)
+ + +class test__mkstemp_inner(TestBadTempdir, TC): """Test the internal function _mkstemp_inner.""" class mkstemped: @@ -400,7 +435,7 @@ class test__mkstemp_inner(TC): self.do_create(bin=0).write("blat\n") # XXX should test that the file really is a text file
@@ -411,11 +446,11 @@ class test__mkstemp_inner(TC): # the chosen name already exists with _inside_empty_temp_dir(), [](#l2.58) _mock_candidate_names('aaa', 'aaa', 'bbb'):
(fd1, name1) = self.default_mkstemp_inner()[](#l2.60)
(fd1, name1) = self.make_temp()[](#l2.61) os.close(fd1)[](#l2.62) self.assertTrue(name1.endswith('aaa'))[](#l2.63)
(fd2, name2) = self.default_mkstemp_inner()[](#l2.65)
(fd2, name2) = self.make_temp()[](#l2.66) os.close(fd2)[](#l2.67) self.assertTrue(name2.endswith('bbb'))[](#l2.68)
@@ -427,7 +462,7 @@ class test__mkstemp_inner(TC): dir = tempfile.mkdtemp() self.assertTrue(dir.endswith('aaa'))
(fd, name) = self.default_mkstemp_inner()[](#l2.74)
(fd, name) = self.make_temp()[](#l2.75) os.close(fd)[](#l2.76) self.assertTrue(name.endswith('bbb'))[](#l2.77)
@@ -542,9 +577,12 @@ class test_mkstemp(TC): test_classes.append(test_mkstemp) -class test_mkdtemp(TC): +class test_mkdtemp(TestBadTempdir, TC): """Test mkdtemp()."""
+ def do_create(self, dir=None, pre="", suf=""): if dir is None: dir = tempfile.gettempdir()
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,11 @@ Core and Builtins Library ------- +- Issue #22107: tempfile.gettempdir() and tempfile.mkdtemp() now try again