summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/tempfile.py77
-rw-r--r--Lib/test/test_tempfile.py61
2 files changed, 41 insertions, 97 deletions
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index 900222f..692bea5 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -80,33 +80,6 @@ tempdir = None
_once_lock = _allocate_lock()
-def _once(var, initializer):
- """Wrapper to execute an initialization operation just once,
- even if multiple threads reach the same point at the same time.
-
- var is the name (as a string) of the variable to be entered into
- the current global namespace.
-
- initializer is a callable which will return the appropriate initial
- value for variable. It will be called only if variable is not
- present in the global namespace, or its current value is None.
-
- Do not call _once from inside an initializer routine, it will deadlock.
- """
-
- vars = globals()
- # Check first outside the lock.
- if vars.get(var) is not None:
- return
- try:
- _once_lock.acquire()
- # Check again inside the lock.
- if vars.get(var) is not None:
- return
- vars[var] = initializer()
- finally:
- _once_lock.release()
-
class _RandomNameSequence:
"""An instance of _RandomNameSequence generates an endless
sequence of unpredictable strings which can safely be incorporated
@@ -178,8 +151,7 @@ def _candidate_tempdir_list():
def _get_default_tempdir():
"""Calculate the default directory to use for temporary files.
- This routine should be called through '_once' (see above) as we
- do not want multiple threads attempting this calculation simultaneously.
+ This routine should be called exactly once.
We determine whether or not a candidate temp dir is usable by
trying to create and write to a file in that directory. If this
@@ -212,10 +184,19 @@ def _get_default_tempdir():
raise IOError, (_errno.ENOENT,
("No usable temporary directory found in %s" % dirlist))
+_name_sequence = None
+
def _get_candidate_names():
"""Common setup sequence for all user-callable interfaces."""
- _once('_name_sequence', _RandomNameSequence)
+ global _name_sequence
+ if _name_sequence is None:
+ _once_lock.acquire()
+ try:
+ if _name_sequence is None:
+ _name_sequence = _RandomNameSequence()
+ finally:
+ _once_lock.release()
return _name_sequence
@@ -245,12 +226,21 @@ def gettempprefix():
"""Accessor for tempdir.template."""
return template
+tempdir = None
+
def gettempdir():
"""Accessor for tempdir.tempdir."""
- _once('tempdir', _get_default_tempdir)
+ global tempdir
+ if tempdir is None:
+ _once_lock.acquire()
+ try:
+ if tempdir is None:
+ tempdir = _get_default_tempdir()
+ finally:
+ _once_lock.release()
return tempdir
-def mkstemp(suffix="", prefix=template, dir=gettempdir(), text=False):
+def mkstemp(suffix="", prefix=template, dir=None, text=False):
"""mkstemp([suffix, [prefix, [dir, [text]]]])
User-callable function to create and return a unique temporary
file. The return value is a pair (fd, name) where fd is the
@@ -277,6 +267,9 @@ def mkstemp(suffix="", prefix=template, dir=gettempdir(), text=False):
Caller is responsible for deleting the file when done with it.
"""
+ if dir is None:
+ dir = gettempdir()
+
if text:
flags = _text_openflags
else:
@@ -285,7 +278,7 @@ def mkstemp(suffix="", prefix=template, dir=gettempdir(), text=False):
return _mkstemp_inner(dir, prefix, suffix, flags)
-def mkdtemp(suffix="", prefix=template, dir=gettempdir()):
+def mkdtemp(suffix="", prefix=template, dir=None):
"""mkdtemp([suffix, [prefix, [dir]]])
User-callable function to create and return a unique temporary
directory. The return value is the pathname of the directory.
@@ -299,6 +292,9 @@ def mkdtemp(suffix="", prefix=template, dir=gettempdir()):
Caller is responsible for deleting the directory when done with it.
"""
+ if dir is None:
+ dir = gettempdir()
+
names = _get_candidate_names()
for seq in xrange(TMP_MAX):
@@ -314,7 +310,7 @@ def mkdtemp(suffix="", prefix=template, dir=gettempdir()):
raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
-def mktemp(suffix="", prefix=template, dir=gettempdir()):
+def mktemp(suffix="", prefix=template, dir=None):
"""mktemp([suffix, [prefix, [dir]]])
User-callable function to return a unique temporary file name. The
file is not created.
@@ -332,6 +328,9 @@ def mktemp(suffix="", prefix=template, dir=gettempdir()):
_warn("mktemp is a potential security risk to your program",
RuntimeWarning, stacklevel=2)
+ if dir is None:
+ dir = gettempdir()
+
names = _get_candidate_names()
for seq in xrange(TMP_MAX):
name = names.next()
@@ -383,7 +382,7 @@ class _TemporaryFileWrapper:
self.close()
def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
- prefix=template, dir=gettempdir()):
+ prefix=template, dir=None):
"""Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
@@ -396,6 +395,9 @@ def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
closed.
"""
+ if dir is None:
+ dir = gettempdir()
+
if 'b' in mode:
flags = _bin_openflags
else:
@@ -417,7 +419,7 @@ if _os.name != 'posix' or _os.sys.platform == 'cygwin':
else:
def TemporaryFile(mode='w+b', bufsize=-1, suffix="",
- prefix=template, dir=gettempdir()):
+ prefix=template, dir=None):
"""Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'directory' -- as for mkstemp.
@@ -429,6 +431,9 @@ else:
exist when it is closed.
"""
+ if dir is None:
+ dir = gettempdir()
+
if 'b' in mode:
flags = _bin_openflags
else:
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 575986f..10426b3 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -84,67 +84,6 @@ class test_exports(TC):
test_classes.append(test_exports)
-class test__once(TC):
- """Test the internal function _once."""
-
- def setUp(self):
- tempfile.once_var = None
- self.already_called = 0
-
- def tearDown(self):
- del tempfile.once_var
-
- def callMeOnce(self):
- self.failIf(self.already_called, "callMeOnce called twice")
- self.already_called = 1
- return 24
-
- def do_once(self):
- tempfile._once('once_var', self.callMeOnce)
-
- def test_once_initializes(self):
- """_once initializes its argument"""
-
- self.do_once()
-
- self.assertEqual(tempfile.once_var, 24,
- "once_var=%d, not 24" % tempfile.once_var)
- self.assertEqual(self.already_called, 1,
- "already_called=%d, not 1" % self.already_called)
-
- def test_once_means_once(self):
- """_once calls the callback just once"""
-
- self.do_once()
- self.do_once()
- self.do_once()
- self.do_once()
-
- def test_once_namespace_safe(self):
- """_once does not modify anything but its argument"""
-
- env_copy = tempfile.__dict__.copy()
-
- self.do_once()
-
- env = tempfile.__dict__
-
- a = env.keys()
- a.sort()
- b = env_copy.keys()
- b.sort()
-
- self.failIf(len(a) != len(b))
- for i in xrange(len(a)):
- self.failIf(a[i] != b[i])
-
- key = a[i]
- if key != 'once_var':
- self.failIf(env[key] != env_copy[key])
-
-test_classes.append(test__once)
-
-
class test__RandomNameSequence(TC):
"""Test the internal iterator object _RandomNameSequence."""