=================================================================== Index: dist/src/Demo/pdist/rcslib.py --- dist/src/Demo/pdist/rcslib.py 20 Jul 2001 19:00:52 -0000 1.8 +++ dist/src/Demo/pdist/rcslib.py 3 Aug 2002 06:32:23 -0000 @@ -143,22 +143,17 @@ class RCS: if message and message[-1] != '\n': message = message + '\n' lockflag = "-u" - textfile = None - try: - if new: - textfile = tempfile.mktemp() - f = open(textfile, 'w') - f.write(message) - f.close() - cmd = 'ci %s%s -t%s %s %s' % \ - (lockflag, rev, textfile, otherflags, name) - else: - message = regsub.gsub('\([\\"$`]\)', '\\\\\\1', message) - cmd = 'ci %s%s -m"%s" %s %s' % \ - (lockflag, rev, message, otherflags, name) - return self._system(cmd) - finally: - if textfile: self._remove(textfile) + if new: + f = tempfile.NamedTemporaryFile() + f.write(message) + f.flush() + cmd = 'ci %s%s -t%s %s %s' % \ + (lockflag, rev, f.name, otherflags, name) + else: + message = regsub.gsub('\([\\"$`]\)', '\\\\\\1', message) + cmd = 'ci %s%s -m"%s" %s %s' % \ + (lockflag, rev, message, otherflags, name) + return self._system(cmd) # --- Exported support methods --- =================================================================== Index: dist/src/Demo/pdist/rcvs.py --- dist/src/Demo/pdist/rcvs.py 27 Nov 1996 19:49:24 -0000 1.21 +++ dist/src/Demo/pdist/rcvs.py 3 Aug 2002 06:32:23 -0000 @@ -172,17 +172,13 @@ class MyFile(File): if self.lsum == sum: return import tempfile - tfn = tempfile.mktemp() - try: - tf = open(tfn, 'w') - tf.write(data) - tf.close() - print 'diff %s -r%s %s' % (flags, rev, fn) - sts = os.system('diff %s %s %s' % (flags, tfn, fn)) - if sts: - print '='*70 - finally: - remove(tfn) + tf = tempfile.NamedTemporaryFile() + tf.write(data) + tf.flush() + print 'diff %s -r%s %s' % (flags, rev, fn) + sts = os.system('diff %s %s %s' % (flags, tf.name, fn)) + if sts: + print '='*70 def commitcheck(self): return self.action() != 'C' =================================================================== Index: dist/src/Demo/pdist/rrcs.py --- dist/src/Demo/pdist/rrcs.py 27 Nov 1996 19:49:26 -0000 1.6 +++ dist/src/Demo/pdist/rrcs.py 3 Aug 2002 06:32:23 -0000 @@ -102,17 +102,13 @@ def diff(x, copts, fn): flags = flags + ' ' + o + a flags = flags[1:] data = x.get(fn) - tfn = tempfile.mktemp() - try: - tf = open(tfn, 'w') - tf.write(data) - tf.close() - print 'diff %s -r%s %s' % (flags, x.head(fn), fn) - sts = os.system('diff %s %s %s' % (flags, tfn, fn)) - if sts: - print '='*70 - finally: - remove(tfn) + tf = tempfile.NamedTemporaryFile() + tf.write(data) + tf.flush() + print 'diff %s -r%s %s' % (flags, x.head(fn), fn) + sts = os.system('diff %s %s %s' % (flags, tf.name, fn)) + if sts: + print '='*70 def same(x, copts, fn, data = None): if data is None: =================================================================== Index: dist/src/Demo/scripts/pp.py --- dist/src/Demo/scripts/pp.py 27 Nov 1996 19:47:06 -0000 1.4 +++ dist/src/Demo/scripts/pp.py 3 Aug 2002 06:32:23 -0000 @@ -120,19 +120,11 @@ for line in SCRIPT: program = program + (string.joinfields(epilogue, '\n') + '\n') import tempfile -tfn = tempfile.mktemp() -try: - fp = open(tfn, 'w') - fp.write(program) - fp.close() - if DFLAG: - import pdb - pdb.run('execfile(' + `tfn` + ')') - else: - execfile(tfn) -finally: - import os - try: - os.unlink(tfn) - except: - pass +fp = tempfile.NamedTemporaryFile() +fp.write(program) +fp.flush() +if DFLAG: + import pdb + pdb.run('execfile(' + `tfn` + ')') +else: + execfile(tfn) =================================================================== Index: dist/src/Doc/lib/libtempfile.tex --- dist/src/Doc/lib/libtempfile.tex 28 Nov 2001 07:26:15 -0000 1.17 +++ dist/src/Doc/lib/libtempfile.tex 3 Aug 2002 06:32:23 -0000 @@ -1,78 +1,197 @@ \section{\module{tempfile} --- - Generate temporary file names} + Generate temporary files and directories} +\sectionauthor{Zack Weinberg}{zack@codesourcery.com} \declaremodule{standard}{tempfile} -\modulesynopsis{Generate temporary file names.} +\modulesynopsis{Generate temporary files and directories.} \indexii{temporary}{file name} \indexii{temporary}{file} +This module generates temporary files and directories. It works on +all supported platforms. -This module generates temporary file names. It is not \UNIX{} specific, -but it may require some help on non-\UNIX{} systems. +In version 2.3 of Python, this module was overhauled for enhanced +security. It now provides three new functions, +\function{NamedTemporaryFile}, \function{mkstemp}, and +\function{mkdtemp}, which should eliminate all remaining need to use +the insecure \function{mktemp} function. Temporary file names created +by this module no longer contain the process ID; instead a string of +six random characters is used. + +Also, all the user-callable functions now take additional arguments +which allow direct control over the location and name of temporary +files. It is no longer necessary to use the global \var{tempdir} and +\var{template} variables. To maintain backward compatibility, the +argument order is somewhat odd; it is recommended to use keyword +arguments for clarity. The module defines the following user-callable functions: -\begin{funcdesc}{mktemp}{\optional{suffix}} -Return a unique temporary filename. This is an absolute pathname of a -file that does not exist at the time the call is made. No two calls -will return the same filename. \var{suffix}, if provided, is used as -the last part of the generated file name. This can be used to provide -a filename extension or other identifying information that may be -useful on some platforms. -\end{funcdesc} - -\begin{funcdesc}{TemporaryFile}{\optional{mode\optional{, - bufsize\optional{, suffix}}}} +\begin{funcdesc}{TemporaryFile}{\optional{mode='w+b'} + \optional{, bufsize=-1} + \optional{, suffix} + \optional{, prefix} + \optional{, dir}} Return a file (or file-like) object that can be used as a temporary -storage area. The file is created in the most secure manner available -in the appropriate temporary directory for the host platform. Under -\UNIX, the directory entry to the file is removed so that it is secure -against attacks which involve creating symbolic links to the file or -replacing the file with a symbolic link to some other file. For other -platforms, which don't allow removing the directory entry while the -file is in use, the file is automatically deleted as soon as it is -closed (including an implicit close when it is garbage-collected). +storage area. The file is created using \function{mkstemp}. It will +be destroyed as soon as it is closed (including an implicit close when +the object is garbage collected). Under \UNIX, the directory entry +for the file is removed immediately after the file is created. Other +platforms do not support this; your code should not rely on a +\class{TemporaryFile} having or not having a visible name in the file +system. The \var{mode} parameter defaults to \code{'w+b'} so that the file created can be read and written without being closed. Binary mode is used so that it behaves consistently on all platforms without regard for the data that is stored. \var{bufsize} defaults to \code{-1}, -meaning that the operating system default is used. \var{suffix} is -passed to \function{mktemp()}. +meaning that the operating system default is used. + +The \var{dir}, \var{prefix} and \var{suffix} parameters are passed to +\function{mkstemp}. +\end{funcdesc} + +\begin{funcdesc}{NamedTemporaryFile}{\optional{mode='w+b'} + \optional{, bufsize=-1} + \optional{, suffix} + \optional{, prefix} + \optional{, dir}} +This function operates exactly as \function{TemporaryFile} does, +except that the file is guaranteed to have a visible name in the file +system. That name can be retrieved from the \member{name} member of +the file object. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{mkstemp}{\optional{suffix} + \optional{, prefix} + \optional{, dir} + \optional{, binary=1}} +Creates a temporary file in the most secure manner possible. There +are no race conditions in the file's creation, assuming that the +platform properly implements the \constant{O_EXCL} flag for +\function{os.open}. The file is readable and writable only by the +creating user ID. If the platform uses permission bits to indicate +whether a file is executable, the file is executable by no one. The +file descriptor is not inherited by child processes. + +Unlike \function{TemporaryFile}, the user of \function{mkstemp} is +responsible for deleting the temporary file when done with it. + +If \var{suffix} is specified, the file name will end with that suffix, +otherwise there will be no suffix. \function{mkstemp} does not put a +dot between the file name and the suffix; if you need one, put it at +the beginning of \var{suffix}. + +If \var{prefix} is specified, the file name will begin with that +prefix; otherwise, a default prefix is used. + +If \var{dir} is specified, the file will be created in that directory; +otherwise, a default directory is used. + +If \var{binary} is specified, it indicates whether to open the file in +binary mode (the default) or text mode. On some platforms, this makes +no difference. + +\function{mkstemp} returns a tuple containing an OS-level handle to +an open file (as would be returned by \function{os.open}) and the +absolute pathname of that file, in that order. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{mkdtemp}{\optional{suffix} + \optional{, prefix} + \optional{, dir}} +Creates a temporary directory in the most secure manner possible. +There are no race conditions in the directory's creation. The +directory is readable, writable, and searchable only by the +creating user ID. + +The user of \function{mkdtemp} is responsible for deleting the +temporary directory and its contents when done with it. + +The \var{prefix}, \var{suffix}, and \var{dir} arguments are the same +as for \function{mkstemp}. + +\function{mkdtemp} returns the absolute pathname of the new directory. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{mktemp}{\optional{suffix} + \optional{, prefix} + \optional{, dir}} +\deprecated{2.3}{Use \function{mkstemp()} instead.} +Return an absolute pathname of a file that did not exist at the time +the call is made. The \var{prefix}, \var{suffix}, and \var{dir} +arguments are the same as for \function{mkstemp}. + +\warning{Use of this function may introduce a security hole in your +program. By the time you get around to doing anything with the file +name it returns, someone else may have beaten you to the punch.} \end{funcdesc} The module uses two global variables that tell it how to construct a -temporary name. The caller may assign values to them; by default they -are initialized at the first call to \function{mktemp()}. +temporary name. They are initialized at the first call to any of the +functions above. The caller may change them, but this is discouraged; +use the appropriate function arguments, instead. \begin{datadesc}{tempdir} When set to a value other than \code{None}, this variable defines the -directory in which filenames returned by \function{mktemp()} reside. -The default is taken from the environment variable \envvar{TMPDIR}; if -this is not set, either \file{/usr/tmp} is used (on \UNIX), or the -current working directory (all other systems). No check is made to -see whether its value is valid. +default value for the \var{dir} argument to all the functions defined +in this module. + +If \var{tempdir} is unset or \code{None} at any call to any of the +above functions, Python searches a standard list of directories and +sets \var{tempdir} to the first one which the calling user can create +files in. The list is: + +\begin{enumerate} +\item The directory named by the \envvar{TMPDIR} environment variable. +\item The directory named by the \envvar{TEMP} environment variable. +\item The directory named by the \envvar{TMP} environment variable. +\item A platform-specific location: + \begin{itemize} + \item On Macintosh, the \file{Temporary Items} folder. + \item On RiscOS, the directory named by the + \envvar{Wimp\$ScrapDir} environment variable. + \item On Windows, the directories + \file{C:$\backslash$TEMP}, + \file{C:$\backslash$TMP}, + \file{$\backslash$TEMP}, and + \file{$\backslash$TMP}, in that order. + \item On all other platforms, the directories + \file{/tmp}, \file{/var/tmp}, and \file{/usr/tmp}, in that order. + \end{itemize} +\item As a last resort, the current working directory. +\end{enumerate} \end{datadesc} -\begin{funcdesc}{gettempprefix}{} -Return the filename prefix used to create temporary files. This does -not contain the directory component. Using this function is preferred -over using the \code{template} variable directly. -\versionadded{1.5.2} -\end{funcdesc} +\begin{funcdesc}{gettempdir}{} +Return the directory currently selected to create temporary files in. +If \var{tempdir} is not None, this simply returns its contents; +otherwise, the search described above is performed, and the result +returned. +\end{funcdesc} \begin{datadesc}{template} \deprecated{2.0}{Use \function{gettempprefix()} instead.} When set to a value other than \code{None}, this variable defines the prefix of the final component of the filenames returned by -\function{mktemp()}. A string of decimal digits is added to generate -unique filenames. The default is either \file{@\var{pid}.} where -\var{pid} is the current process ID (on \UNIX), -\file{\textasciitilde\var{pid}-} on Windows NT, \file{Python-Tmp-} on -MacOS, or \file{tmp} (all other systems). +\function{mktemp()}. A string of six random letters and digits is +appended to the prefix to make the filename unique. On Windows, +the default prefix is \file{\textasciitilde{}T}; on all other systems +it is \file{tmp}. Older versions of this module used to require that \code{template} be set to \code{None} after a call to \function{os.fork()}; this has not been necessary since version 1.5.2. \end{datadesc} + +\begin{funcdesc}{gettempprefix}{} +Return the filename prefix used to create temporary files. This does +not contain the directory component. Using this function is preferred +over reading the \var{template} variable directly. +\versionadded{1.5.2} +\end{funcdesc} + =================================================================== Index: dist/src/Lib/cgitb.py --- dist/src/Lib/cgitb.py 26 Jun 2002 07:10:56 -0000 1.5 +++ dist/src/Lib/cgitb.py 3 Aug 2002 06:32:24 -0000 @@ -193,10 +193,10 @@ class Hook: if self.logdir is not None: import os, tempfile - name = tempfile.mktemp(['.html', '.txt'][text]) - path = os.path.join(self.logdir, os.path.basename(name)) + (fd, name) = tempfile.mkstemp(suffix=['.html', '.txt'][text], + dir=self.logdir) try: - file = open(path, 'w') + file = os.fdopen(fd, 'w') file.write(doc) file.close() msg = '

%s contains the description of this error.' % path =================================================================== Index: dist/src/Lib/mimetools.py --- dist/src/Lib/mimetools.py 1 Jun 2002 14:18:46 -0000 1.26 +++ dist/src/Lib/mimetools.py 3 Aug 2002 06:32:24 -0000 @@ -202,8 +202,8 @@ def pipeto(input, command): pipe.close() def pipethrough(input, command, output): - tempname = tempfile.mktemp() - temp = open(tempname, 'w') + (fd, tempname) = tempfile.mkstemp() + temp = os.fdopen(fd, 'w') copyliteral(input, temp) temp.close() pipe = os.popen(command + ' <' + tempname, 'r') =================================================================== Index: dist/src/Lib/pipes.py --- dist/src/Lib/pipes.py 2 Aug 2001 07:15:29 -0000 1.11 +++ dist/src/Lib/pipes.py 3 Aug 2002 06:32:24 -0000 @@ -225,7 +225,8 @@ def makepipeline(infile, steps, outfile) lkind = list[i-1][2] rkind = list[i][2] if lkind[1] == 'f' or rkind[0] == 'f': - temp = tempfile.mktemp() + (fd, temp) = tempfile.mkstemp() + os.close(fd) garbage.append(temp) list[i-1][-1] = list[i][0] = temp # =================================================================== Index: dist/src/Lib/pydoc.py --- dist/src/Lib/pydoc.py 1 Jun 2002 19:51:15 -0000 1.65 +++ dist/src/Lib/pydoc.py 3 Aug 2002 06:32:24 -0000 @@ -1202,8 +1202,8 @@ def getpager(): return lambda text: pipepager(text, 'less') import tempfile - filename = tempfile.mktemp() - open(filename, 'w').close() + (fd, filename) = tempfile.mkstemp() + os.close(fd) try: if hasattr(os, 'system') and os.system('more %s' % filename) == 0: return lambda text: pipepager(text, 'more') @@ -1228,8 +1228,8 @@ def pipepager(text, cmd): def tempfilepager(text, cmd): """Page through text by invoking a program on a temporary file.""" import tempfile - filename = tempfile.mktemp() - file = open(filename, 'w') + (fd, filename) = tempfile.mkstemp() + file = os.fdopen(fd, 'w') file.write(text) file.close() try: =================================================================== Index: dist/src/Lib/tempfile.py --- dist/src/Lib/tempfile.py 1 Jun 2002 14:18:46 -0000 1.39 +++ dist/src/Lib/tempfile.py 3 Aug 2002 06:32:25 -0000 @@ -1,178 +1,361 @@ -"""Temporary files and filenames.""" +"""Temporary files. -# XXX This tries to be not UNIX specific, but I don't know beans about -# how to choose a temp directory or filename on MS-DOS or other -# systems so it may have to be changed... +This module provides generic, low- and high-level interfaces for +creating temporary files and directories. The interfaces listed +as "safe" just below can be used without fear of race conditions. +Those listed as "unsafe" cannot, and are provided for backward +compatibility only. + +This module also provides some data items to the user: + + TMP_MAX - maximum number of names that will be tried before + giving up. + template - the default prefix for all temporary names. + You may change this to control the default prefix. + tempdir - If this is set to a string before the first use of + any routine from this module, it will be considered as + another candidate location to store temporary files. +""" + +__all__ = [ + "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces + "mkstemp", "mkdtemp", # low level safe interfaces + "mktemp", # deprecated unsafe interface + "TMP_MAX", "gettempprefix", # constants + "tempdir", "gettempdir" + ] + + +# Imports. + +import os as _os +import errno as _errno +from random import Random as _Random + +if _os.name == 'mac': + import macfs as _macfs + import MACFS as _MACFS -import os +try: + import fcntl as _fcntl + def _set_cloexec(fd): + flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) + if flags >= 0: + # flags read successfully, modify + flags |= _fcntl.FD_CLOEXEC + _fcntl.fcntl(fd, _fcntl.F_SETFD, flags) +except (ImportError, AttributeError): + def _set_cloexec(fd): + pass + +try: + import thread as _thread + _allocate_lock = _thread.allocate_lock +except (ImportError, AttributeError): + class _allocate_lock: + def acquire(self): + pass + release = acquire + +_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL +if hasattr(_os, 'O_NOINHERIT'): _text_openflags |= _os.O_NOINHERIT +if hasattr(_os, 'O_NOFOLLOW'): _text_openflags |= _os.O_NOFOLLOW + +_bin_openflags = _text_openflags +if hasattr(_os, 'O_BINARY'): _bin_openflags |= _os.O_BINARY -__all__ = ["mktemp", "TemporaryFile", "tempdir", "gettempprefix"] +if hasattr(_os, 'TMP_MAX'): + TMP_MAX = _os.TMP_MAX +else: + TMP_MAX = 10000 + +if _os.name == 'nt': + template = '~t' # cater to eight-letter limit +else: + template = "tmp" -# Parameters that the caller may set to override the defaults tempdir = None -template = None -def gettempdir(): - """Function to calculate the directory to use.""" - global tempdir - if tempdir is not None: - return tempdir - - # _gettempdir_inner deduces whether a candidate temp dir is usable by - # trying to create a file in it, and write to it. If that succeeds, - # great, it closes the file and unlinks it. There's a race, though: - # the *name* of the test file it tries is the same across all threads - # under most OSes (Linux is an exception), and letting multiple threads - # all try to open, write to, close, and unlink a single file can cause - # a variety of bogus errors (e.g., you cannot unlink a file under - # Windows if anyone has it open, and two threads cannot create the - # same file in O_EXCL mode under Unix). The simplest cure is to serialize - # calls to _gettempdir_inner. This isn't a real expense, because the - # first thread to succeed sets the global tempdir, and all subsequent - # calls to gettempdir() reuse that without trying _gettempdir_inner. - _tempdir_lock.acquire() +# Internal routines. + +_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() + lock = _once_lock + + # Check first outside the lock. + if var in vars and vars[var] is not None: + return try: - return _gettempdir_inner() + lock.acquire() + # Check again inside the lock. + if var in vars and vars[var] is not None: + return + vars[var] = initializer() finally: - _tempdir_lock.release() + lock.release() + +class _RandomNameSequence: + """An instance of _RandomNameSequence generates an endless + sequence of unpredictable strings which can safely be incorporated + into file names. Each string is six characters long. Multiple + threads can safely use the same instance at the same time. + + _RandomNameSequence is an iterator.""" + + characters = ( "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "0123456789-_") + + def __init__(self): + self.mutex = _allocate_lock() + self.rng = _Random() + self.normcase = _os.path.normcase + def __iter__(self): + return self + + def next(self): + m = self.mutex + c = self.characters + r = self.rng -def _gettempdir_inner(): - """Function to calculate the directory to use.""" - global tempdir - if tempdir is not None: - return tempdir - try: - pwd = os.getcwd() - except (AttributeError, os.error): - pwd = os.curdir - attempdirs = ['/tmp', '/var/tmp', '/usr/tmp', pwd] - if os.name == 'nt': - attempdirs.insert(0, 'C:\\TEMP') - attempdirs.insert(0, '\\TEMP') - elif os.name == 'mac': - import macfs, MACFS try: - refnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk, - MACFS.kTemporaryFolderType, 1) - dirname = macfs.FSSpec((refnum, dirid, '')).as_pathname() - attempdirs.insert(0, dirname) - except macfs.error: - pass - elif os.name == 'riscos': - scrapdir = os.getenv('Wimp$ScrapDir') - if scrapdir: - attempdirs.insert(0, scrapdir) + m.acquire() + letters = ''.join([r.choice(c), r.choice(c), r.choice(c), + r.choice(c), r.choice(c), r.choice(c)]) + finally: + m.release() + + return self.normcase(letters) + +def _candidate_tempdir_list(): + """Generate a list of candidate temporary directories which + _get_default_tempdir will try.""" + + dirlist = [] + + # First, try the environment. for envname in 'TMPDIR', 'TEMP', 'TMP': - if envname in os.environ: - attempdirs.insert(0, os.environ[envname]) - testfile = gettempprefix() + 'test' - for dir in attempdirs: + dirname = _os.getenv(envname) + if dirname: dirlist.append(dirname) + + # Failing that, try OS-specific locations. + if _os.name == 'mac': try: - filename = os.path.join(dir, testfile) - if os.name == 'posix': - try: - fd = os.open(filename, - os.O_RDWR | os.O_CREAT | os.O_EXCL, 0700) - except OSError: - pass - else: - fp = os.fdopen(fd, 'w') - fp.write('blat') - fp.close() - os.unlink(filename) - del fp, fd - tempdir = dir - break - else: - fp = open(filename, 'w') + refnum, dirid = _macfs.FindFolder(_MACFS.kOnSystemDisk, + _MACFS.kTemporaryFolderType, 1) + dirname = _macfs.FSSpec((refnum, dirid, '')).as_pathname() + dirlist.append(dirname) + except _macfs.error: + pass + elif _os.name == 'riscos': + dirname = _os.getenv('Wimp$ScrapDir') + if dirname: dirlist.append(dirname) + elif _os.name == 'nt': + dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) + else: + dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) + + # As a last resort, the current directory. + try: + dirlist.append(_os.getcwd()) + except (AttributeError, _os.error): + dirlist.append(_os.curdir) + + return dirlist + +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. + + 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 + is successful, the test file is deleted. To prevent denial of + service, the name of the test file must be randomized.""" + + namer = _RandomNameSequence() + dirlist = _candidate_tempdir_list() + flags = _text_openflags + + for dir in dirlist: + if dir != _os.curdir: + dir = _os.path.normcase(_os.path.abspath(dir)) + # Try only a few names per directory. + for seq in xrange(100): + name = namer.next() + filename = _os.path.join(dir, name) + try: + fd = _os.open(filename, flags, 0600) + fp = _os.fdopen(fd, 'w') fp.write('blat') fp.close() - os.unlink(filename) - tempdir = dir - break - except IOError: - pass - if tempdir is None: - msg = "Can't find a usable temporary directory amongst " + `attempdirs` - raise IOError, msg - return tempdir + _os.unlink(filename) + del fp, fd + return dir + except (OSError, IOError), e: + if e[0] != _errno.EEXIST: + break # no point trying more names in this directory + pass + raise IOError, (_errno.ENOENT, + ("No usable temporary directory found in %s" % dirlist)) + +def _get_candidate_names(): + """Common setup sequence for all user-callable interfaces.""" + + _once('_name_sequence', _RandomNameSequence) + return _name_sequence + + +def _mkstemp_inner(dir, pre, suf, flags): + """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile.""" + + names = _get_candidate_names() + + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, pre + name + suf) + try: + fd = _os.open(file, flags, 0600) + _set_cloexec(fd) + return (fd, file) + except OSError, e: + if e.errno == _errno.EEXIST: + continue # try again + raise + raise IOError, (_errno.EEXIST, "No usable temporary file name found") + -# template caches the result of gettempprefix, for speed, when possible. -# XXX unclear why this isn't "_template"; left it "template" for backward -# compatibility. -if os.name == "posix": - # We don't try to cache the template on posix: the pid may change on us - # between calls due to a fork, and on Linux the pid changes even for - # another thread in the same process. Since any attempt to keep the - # cache in synch would have to call os.getpid() anyway in order to make - # sure the pid hasn't changed between calls, a cache wouldn't save any - # time. In addition, a cache is difficult to keep correct with the pid - # changing willy-nilly, and earlier attempts proved buggy (races). - template = None - -# Else the pid never changes, so gettempprefix always returns the same -# string. -elif os.name == "nt": - template = '~' + `os.getpid()` + '-' -elif os.name in ('mac', 'riscos'): - template = 'Python-Tmp-' -else: - template = 'tmp' # XXX might choose a better one +# User visible interfaces. def gettempprefix(): - """Function to calculate a prefix of the filename to use. + """Accessor for tempdir.template.""" + return template - This incorporates the current process id on systems that support such a - notion, so that concurrent processes don't generate the same prefix. +def gettempdir(): + """Accessor for tempdir.tempdir.""" + _once('tempdir', _get_default_tempdir) + return tempdir + +def mkstemp(suffix="", prefix=template, dir=gettempdir(), binary=1): + """mkstemp([suffix, [prefix, [dir, [binary]]]]) + User-callable function to create and return a unique temporary + file. The return value is a pair (fd, name) where fd is the + file descriptor returned by os.open, and name is the filename. + + If 'suffix' is specified, the file name will end with that suffix, + otherwise there will be no suffix. + + If 'prefix' is specified, the file name will begin with that prefix, + otherwise a default prefix is used. + + If 'dir' is specified, the file will be created in that directory, + otherwise a default directory is used. + + If 'binary' is specified and false, the file is opened in binary + mode. Otherwise, the file is opened in text mode. On some + operating systems, this makes no difference. + + The file is readable and writable only by the creating user ID. + If the operating system uses permission bits to indicate whether a + file is executable, the file is executable by no one. The file + descriptor is not inherited by children of this process. + + Caller is responsible for deleting the file when done with it. """ - global template - if template is None: - return '@' + `os.getpid()` + '.' + if binary: + flags = _bin_openflags else: - return template + flags = _text_openflags + + return _mkstemp_inner(dir, prefix, suffix, flags) + +def mkdtemp(suffix="", prefix=template, dir=gettempdir()): + """mkdtemp([suffix, [prefix, [dir]]]) + User-callable function to create and return a unique temporary + directory. The return value is the pathname of the directory. -def mktemp(suffix=""): - """User-callable function to return a unique temporary file name.""" - dir = gettempdir() - pre = gettempprefix() - while 1: - i = _counter.get_next() - file = os.path.join(dir, pre + str(i) + suffix) - if not os.path.exists(file): + Arguments are as for mkstemp, except that the 'binary' argument is + not accepted. + + The directory is readable, writable, and searchable only by the + creating user. + + Caller is responsible for deleting the directory when done with it. + """ + + names = _get_candidate_names() + + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, prefix + name + suffix) + try: + _os.mkdir(file, 0700) return file + except OSError, e: + if e.errno == _errno.EEXIST: + continue # try again + raise + raise IOError, (_errno.EEXIST, "No usable temporary directory name found") -class TemporaryFileWrapper: +def mktemp(suffix="", prefix=template, dir=gettempdir()): + """mktemp([suffix, [prefix, [dir]]]) + User-callable function to return a unique temporary file name. The + file is not created. + + Arguments are as for mkstemp, except that the 'binary' argument is + not accepted. + + This function is unsafe and should not be used. The file name + refers to a file that did not exist at some point, but by the time + you get around to creating it, someone else may have beaten you to + the punch. + """ + + from warnings import warn as _warn + _warn("mktemp is a potential security risk to your program", + RuntimeWarning, stacklevel=2) + + names = _get_candidate_names() + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, prefix + name + suffix) + if not _os.path.exists(file): + return file + + raise IOError, (_errno.EEXIST, "No usable temporary filename found") + +class _TemporaryFileWrapper: """Temporary file wrapper - This class provides a wrapper around files opened for temporary use. - In particular, it seeks to automatically remove the file when it is - no longer needed. + This class provides a wrapper around files opened for + temporary use. In particular, it seeks to automatically + remove the file when it is no longer needed. """ - # Cache the unlinker so we don't get spurious errors at shutdown - # when the module-level "os" is None'd out. Note that this must - # be referenced as self.unlink, because the name TemporaryFileWrapper - # may also get None'd out before __del__ is called. - unlink = os.unlink - - def __init__(self, file, path): + def __init__(self, file, name): self.file = file - self.path = path + self.name = name self.close_called = 0 - def close(self): - if not self.close_called: - self.close_called = 1 - self.file.close() - self.unlink(self.path) - - def __del__(self): - self.close() - def __getattr__(self, name): file = self.__dict__['file'] a = getattr(file, name) @@ -180,93 +363,81 @@ class TemporaryFileWrapper: setattr(self, name, a) return a -try: - import fcntl as _fcntl - def _set_cloexec(fd, flag=_fcntl.FD_CLOEXEC): - flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) - if flags >= 0: - # flags read successfully, modify - flags |= flag - _fcntl.fcntl(fd, _fcntl.F_SETFD, flags) -except (ImportError, AttributeError): - def _set_cloexec(fd): - pass - -def TemporaryFile(mode='w+b', bufsize=-1, suffix=""): - """Create and return a temporary file (opened read-write by default).""" - name = mktemp(suffix) - if os.name == 'posix': - # Unix -- be very careful - fd = os.open(name, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700) - _set_cloexec(fd) - try: - os.unlink(name) - return os.fdopen(fd, mode, bufsize) - except: - os.close(fd) - raise - elif os.name == 'nt': - # Windows -- can't unlink an open file, but O_TEMPORARY creates a - # file that "deletes itself" when the last handle is closed. - # O_NOINHERIT ensures processes created via spawn() don't get a - # handle to this too. That would be a security hole, and, on my - # Win98SE box, when an O_TEMPORARY file is inherited by a spawned - # process, the fd in the spawned process seems to lack the - # O_TEMPORARY flag, so the file doesn't go away by magic then if the - # spawning process closes it first. - flags = (os.O_RDWR | os.O_CREAT | os.O_EXCL | - os.O_TEMPORARY | os.O_NOINHERIT) - if 'b' in mode: - flags |= os.O_BINARY - fd = os.open(name, flags, 0700) - return os.fdopen(fd, mode, bufsize) - else: - # Assume we can't unlink a file that's still open, or arrange for - # an automagically self-deleting file -- use wrapper. - file = open(name, mode, bufsize) - return TemporaryFileWrapper(file, name) - -# In order to generate unique names, mktemp() uses _counter.get_next(). -# This returns a unique integer on each call, in a threadsafe way (i.e., -# multiple threads will never see the same integer). The integer will -# usually be a Python int, but if _counter.get_next() is called often -# enough, it will become a Python long. -# Note that the only names that survive this next block of code -# are "_counter" and "_tempdir_lock". - -class _ThreadSafeCounter: - def __init__(self, mutex, initialvalue=0): - self.mutex = mutex - self.i = initialvalue - - def get_next(self): - self.mutex.acquire() - result = self.i - try: - newi = result + 1 - except OverflowError: - newi = long(result) + 1 - self.i = newi - self.mutex.release() - return result - -try: - import thread - -except ImportError: - class _DummyMutex: - def acquire(self): - pass - - release = acquire + # NT provides delete-on-close as a primitive, so we don't need + # the wrapper to do anything special. We still use it so that + # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. + if _os.name != 'nt': + + # Cache the unlinker so we don't get spurious errors at + # shutdown when the module-level "os" is None'd out. Note + # that this must be referenced as self.unlink, because the + # name TemporaryFileWrapper may also get None'd out before + # __del__ is called. + unlink = _os.unlink + + def close(self): + if not self.close_called: + self.close_called = 1 + self.file.close() + self.unlink(self.name) + + def __del__(self): + self.close() + +def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="", + prefix=template, dir=gettempdir()): + """Create and return a temporary file. + Arguments: + 'prefix', 'suffix', 'dir' -- as for mkstemp. + 'mode' -- the mode argument to os.fdopen (default "w+b"). + 'bufsize' -- the buffer size argument to os.fdopen (default -1). + The file is created as mkstemp() would do it. + + Returns a file object; the name of the file is accessible as + file.name. The file will be automatically deleted when it is + closed. + """ - _counter = _ThreadSafeCounter(_DummyMutex()) - _tempdir_lock = _DummyMutex() - del _DummyMutex + bin = 'b' in mode + if bin: flags = _bin_openflags + else: flags = _text_openflags + + # Setting O_TEMPORARY in the flags causes the OS to delete + # the file when it is closed. This is only supported by Windows. + if _os.name == 'nt': + flags |= _os.O_TEMPORARY + + (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) + file = _os.fdopen(fd, mode, bufsize) + return _TemporaryFileWrapper(file, name) + +if _os.name != 'posix': + # On non-POSIX systems, assume that we cannot unlink a file while + # it is open. + TemporaryFile = NamedTemporaryFile else: - _counter = _ThreadSafeCounter(thread.allocate_lock()) - _tempdir_lock = thread.allocate_lock() - del thread + def TemporaryFile(mode='w+b', bufsize=-1, suffix="", + prefix=template, dir=gettempdir()): + """Create and return a temporary file. + Arguments: + 'prefix', 'suffix', 'directory' -- as for mkstemp. + 'mode' -- the mode argument to os.fdopen (default "w+b"). + 'bufsize' -- the buffer size argument to os.fdopen (default -1). + The file is created as mkstemp() would do it. + + Returns a file object. The file has no name, and will cease to + exist when it is closed. + """ + + bin = 'b' in mode + if bin: flags = _bin_openflags + else: flags = _text_openflags -del _ThreadSafeCounter + (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) + try: + _os.unlink(name) + return _os.fdopen(fd, mode, bufsize) + except: + _os.close(fd) + raise =================================================================== Index: dist/src/Lib/toaiff.py --- dist/src/Lib/toaiff.py 1 Jun 2002 14:18:47 -0000 1.12 +++ dist/src/Lib/toaiff.py 3 Aug 2002 06:32:25 -0000 @@ -75,7 +75,8 @@ def toaiff(filename): def _toaiff(filename, temps): if filename[-2:] == '.Z': - fname = tempfile.mktemp() + (fd, fname) = tempfile.mkstemp() + os.close(fd) temps.append(fname) sts = uncompress.copy(filename, fname) if sts: @@ -98,7 +99,8 @@ def _toaiff(filename, temps): if ftype is None or not ftype in table: raise error, \ filename + ': unsupported audio file type ' + `ftype` - temp = tempfile.mktemp() + (fd, temp) = tempfile.mktemp() + os.close(fd) temps.append(temp) sts = table[ftype].copy(fname, temp) if sts: =================================================================== Index: dist/src/Lib/urllib.py --- dist/src/Lib/urllib.py 11 Jun 2002 13:38:51 -0000 1.148 +++ dist/src/Lib/urllib.py 3 Aug 2002 06:32:26 -0000 @@ -212,19 +212,21 @@ class URLopener: pass fp = self.open(url, data) headers = fp.info() - if not filename: + if filename: + tfp = open(filename, 'wb') + else: import tempfile garbage, path = splittype(url) garbage, path = splithost(path or "") path, garbage = splitquery(path or "") path, garbage = splitattr(path or "") suffix = os.path.splitext(path)[1] - filename = tempfile.mktemp(suffix) + (fd, filename) = tempfile.mkstemp(suffix) self.__tempfiles.append(filename) + tfp = os.open(fd, 'wb') result = filename, headers if self.tempcache is not None: self.tempcache[url] = result - tfp = open(filename, 'wb') bs = 1024*8 size = -1 blocknum = 1 =================================================================== Index: dist/src/Lib/distutils/util.py --- dist/src/Lib/distutils/util.py 4 Jun 2002 20:14:42 -0000 1.68 +++ dist/src/Lib/distutils/util.py 3 Aug 2002 06:32:26 -0000 @@ -359,11 +359,11 @@ def byte_compile (py_files, # "Indirect" byte-compilation: write a temporary script and then # run it with the appropriate flags. if not direct: - from tempfile import mktemp - script_name = mktemp(".py") + from tempfile import mkstemp + (script_fd, script_name) = mkstemp(".py") log.info("writing byte-compilation script '%s'", script_name) if not dry_run: - script = open(script_name, "w") + script = os.fdopen(script_fd, "w") script.write("""\ from distutils.util import byte_compile =================================================================== Index: dist/src/Lib/distutils/command/bdist_wininst.py --- dist/src/Lib/distutils/command/bdist_wininst.py 29 Jul 2002 12:11:18 -0000 1.34 +++ dist/src/Lib/distutils/command/bdist_wininst.py 3 Aug 2002 06:32:26 -0000 @@ -130,8 +130,9 @@ class bdist_wininst (Command): # And make an archive relative to the root of the # pseudo-installation tree. - from tempfile import mktemp - archive_basename = mktemp() + from tempfile import NamedTemporaryFile + arc = NamedTemporaryFile(".zip") + archive_basename = arc.name[:-4] fullname = self.distribution.get_fullname() arcname = self.make_archive(archive_basename, "zip", root_dir=self.bdist_dir) @@ -139,7 +140,7 @@ class bdist_wininst (Command): self.create_exe(arcname, fullname, self.bitmap) # remove the zip-file again log.debug("removing temporary file '%s'", arcname) - os.remove(arcname) + arc.close() if not self.keep_temp: remove_tree(self.bdist_dir, dry_run=self.dry_run) =================================================================== Index: dist/src/Lib/hotshot/stones.py --- dist/src/Lib/hotshot/stones.py 18 Jul 2002 19:47:05 -0000 1.1 +++ dist/src/Lib/hotshot/stones.py 3 Aug 2002 06:32:26 -0000 @@ -8,12 +8,10 @@ import test.pystone if sys.argv[1:]: logfile = sys.argv[1] - cleanup = 0 else: import tempfile - logfile = tempfile.mktemp() - cleanup = 1 - + logf = tempfile.NamedTemporaryFile() + logfile = logf.name p = hotshot.Profile(logfile) benchtime, stones = p.runcall(test.pystone.pystones) @@ -24,8 +22,6 @@ print "Pystone(%s) time for %d passes = print "This machine benchmarks at %g pystones/second" % stones stats = hotshot.stats.load(logfile) -if cleanup: - os.unlink(logfile) stats.strip_dirs() stats.sort_stats('time', 'calls') try: =================================================================== Index: dist/src/Lib/plat-irix5/torgb.py --- dist/src/Lib/plat-irix5/torgb.py 12 Dec 2000 23:11:42 -0000 1.6 +++ dist/src/Lib/plat-irix5/torgb.py 3 Aug 2002 06:32:26 -0000 @@ -70,7 +70,8 @@ def torgb(filename): def _torgb(filename, temps): if filename[-2:] == '.Z': - fname = tempfile.mktemp() + (fd, fname) = tempfile.mkstemp() + os.close(fd) temps.append(fname) sts = uncompress.copy(filename, fname) if sts: @@ -91,7 +92,8 @@ def _torgb(filename, temps): if ftype is None or not table.has_key(ftype): raise error, \ filename + ': unsupported image file type ' + `ftype` - temp = tempfile.mktemp() + (fd, temp) = tempfile.mktemp() + os.close(fd) sts = table[ftype].copy(fname, temp) if sts: raise error, filename + ': conversion to rgb failed' =================================================================== Index: dist/src/Lib/plat-irix6/torgb.py --- dist/src/Lib/plat-irix6/torgb.py 12 Dec 2000 23:11:42 -0000 1.3 +++ dist/src/Lib/plat-irix6/torgb.py 3 Aug 2002 06:32:26 -0000 @@ -70,7 +70,8 @@ def torgb(filename): def _torgb(filename, temps): if filename[-2:] == '.Z': - fname = tempfile.mktemp() + (fd, fname) = tempfile.mkstemp() + os.close(fd) temps.append(fname) sts = uncompress.copy(filename, fname) if sts: @@ -91,7 +92,8 @@ def _torgb(filename, temps): if ftype is None or not table.has_key(ftype): raise error, \ filename + ': unsupported image file type ' + `ftype` - temp = tempfile.mktemp() + (fd, temp) = tempfile.mktemp() + os.close(fd) sts = table[ftype].copy(fname, temp) if sts: raise error, filename + ': conversion to rgb failed' =================================================================== Index: dist/src/Lib/test/pickletester.py --- dist/src/Lib/test/pickletester.py 30 Jul 2002 23:26:00 -0000 1.16 +++ dist/src/Lib/test/pickletester.py 3 Aug 2002 06:32:26 -0000 @@ -1,5 +1,5 @@ import unittest -from test.test_support import TestFailed, have_unicode +from test.test_support import TestFailed, have_unicode, TESTFN class C: def __cmp__(self, other): @@ -269,17 +269,19 @@ class AbstractPickleTests(unittest.TestC class AbstractPickleModuleTests(unittest.TestCase): def test_dump_closed_file(self): - import tempfile, os - fn = tempfile.mktemp() - f = open(fn, "w") - f.close() - self.assertRaises(ValueError, self.module.dump, 123, f) - os.remove(fn) + import os + f = open(TESTFN, "w") + try: + f.close() + self.assertRaises(ValueError, self.module.dump, 123, f) + finally: + os.remove(TESTFN) def test_load_closed_file(self): - import tempfile, os - fn = tempfile.mktemp() - f = open(fn, "w") - f.close() - self.assertRaises(ValueError, self.module.dump, 123, f) - os.remove(fn) + import os + f = open(TESTFN, "w") + try: + f.close() + self.assertRaises(ValueError, self.module.dump, 123, f) + finally: + os.remove(TESTFN) =================================================================== Index: dist/src/Lib/test/test_anydbm.py --- dist/src/Lib/test/test_anydbm.py 23 Jul 2002 19:03:43 -0000 1.2 +++ dist/src/Lib/test/test_anydbm.py 3 Aug 2002 06:32:26 -0000 @@ -6,11 +6,10 @@ import os import unittest import anydbm -import tempfile import glob from test import test_support -_fname = tempfile.mktemp() +_fname = test_support.TESTFN def _delete_files(): # we don't know the precise name the underlying database uses =================================================================== Index: dist/src/Lib/test/test_binhex.py --- dist/src/Lib/test/test_binhex.py 23 Jul 2002 19:03:45 -0000 1.13 +++ dist/src/Lib/test/test_binhex.py 3 Aug 2002 06:32:26 -0000 @@ -6,7 +6,6 @@ """ import binhex import os -import tempfile import unittest from test import test_support @@ -14,8 +13,8 @@ from test import test_support class BinHexTestCase(unittest.TestCase): def setUp(self): - self.fname1 = tempfile.mktemp() - self.fname2 = tempfile.mktemp() + self.fname1 = test_support.TESTFN + "1" + self.fname2 = test_support.TESTFN + "2" def tearDown(self): try: os.unlink(self.fname1) =================================================================== Index: dist/src/Lib/test/test_bsddb.py --- dist/src/Lib/test/test_bsddb.py 23 Jul 2002 19:23:22 -0000 1.11 +++ dist/src/Lib/test/test_bsddb.py 3 Aug 2002 06:32:26 -0000 @@ -5,8 +5,7 @@ import os import bsddb import dbhash # Just so we know it's imported -import tempfile -from test.test_support import verbose, verify +from test.test_support import verbose, verify, TESTFN def test(openmethod, what, ondisk=1): @@ -14,7 +13,7 @@ def test(openmethod, what, ondisk=1): print '\nTesting: ', what, (ondisk and "on disk" or "in memory") if ondisk: - fname = tempfile.mktemp() + fname = TESTFN else: fname = None f = openmethod(fname, 'c') =================================================================== Index: dist/src/Lib/test/test_commands.py --- dist/src/Lib/test/test_commands.py 23 Jul 2002 19:03:46 -0000 1.6 +++ dist/src/Lib/test/test_commands.py 3 Aug 2002 06:32:26 -0000 @@ -24,10 +24,17 @@ class CommandTests(unittest.TestCase): self.assertEquals(getoutput('echo xyzzy'), 'xyzzy') self.assertEquals(getstatusoutput('echo xyzzy'), (0, 'xyzzy')) - # we use mktemp in the next line to get a filename which we - # _know_ won't exist. This is guaranteed to fail. - status, output = getstatusoutput('cat ' + tempfile.mktemp()) - self.assertNotEquals(status, 0) + # we use mkdtemp in the next line to create an empty directory + # under our exclusive control; from that, we can invent a pathname + # that we _know_ won't exist. This is guaranteed to fail. + try: + dir = tempfile.mkdtemp() + name = os.path.join(dir, "foo") + + status, output = getstatusoutput('cat ' + name) + self.assertNotEquals(status, 0) + finally: + os.rmdir(dir) def test_getstatus(self): # This pattern should match 'ls -ld /.' on any posix =================================================================== Index: dist/src/Lib/test/test_dumbdbm.py --- dist/src/Lib/test/test_dumbdbm.py 23 Jul 2002 19:03:50 -0000 1.7 +++ dist/src/Lib/test/test_dumbdbm.py 3 Aug 2002 06:32:26 -0000 @@ -6,10 +6,9 @@ import os import unittest import dumbdbm -import tempfile from test import test_support -_fname = tempfile.mktemp() +_fname = test_support.TESTFN def _delete_files(): for ext in [".dir", ".dat", ".bak"]: =================================================================== Index: dist/src/Lib/test/test_gzip.py --- dist/src/Lib/test/test_gzip.py 30 Jul 2002 23:26:01 -0000 1.10 +++ dist/src/Lib/test/test_gzip.py 3 Aug 2002 06:32:26 -0000 @@ -1,8 +1,8 @@ -from test.test_support import verify +from test.test_support import verify, TESTFN import sys, os -import gzip, tempfile +import gzip -filename = tempfile.mktemp() +filename = TESTFN data1 = """ int length=DEFAULTALLOC, err = Z_OK; PyObject *RetVal; =================================================================== Index: dist/src/Lib/test/test_netrc.py --- dist/src/Lib/test/test_netrc.py 23 Jul 2002 19:03:57 -0000 1.3 +++ dist/src/Lib/test/test_netrc.py 3 Aug 2002 06:32:26 -0000 @@ -1,5 +1,5 @@ -import netrc, os, tempfile, unittest +import netrc, os, unittest from test import test_support TEST_NETRC = """ @@ -17,7 +17,7 @@ default login log2 password pass2 """ -temp_filename = tempfile.mktemp() +temp_filename = test_support.TESTFN class NetrcTestCase(unittest.TestCase): =================================================================== Index: dist/src/Lib/test/test_pkg.py --- dist/src/Lib/test/test_pkg.py 23 Jul 2002 19:03:58 -0000 1.15 +++ dist/src/Lib/test/test_pkg.py 3 Aug 2002 06:32:26 -0000 @@ -8,7 +8,8 @@ from test.test_support import verify, ve # Helpers to create and destroy hierarchies. def mkhier(root, descr): - mkdir(root) + if not os.path.isdir(root): + mkdir(root) for name, contents in descr: comps = name.split() fullname = root @@ -52,18 +53,17 @@ def fixdir(lst): # Helper to run a test def runtest(hier, code): - root = tempfile.mktemp() + root = tempfile.mkdtemp() mkhier(root, hier) savepath = sys.path[:] - codefile = tempfile.mktemp() - f = open(codefile, "w") - f.write(code) - f.close() + codefile = tempfile.NamedTemporaryFile() + codefile.write(code) + codefile.flush() try: sys.path.insert(0, root) if verbose: print "sys.path =", sys.path try: - execfile(codefile, globals(), {}) + execfile(codefile.name, globals(), {}) except: traceback.print_exc(file=sys.stdout) finally: @@ -72,7 +72,6 @@ def runtest(hier, code): cleanout(root) except (os.error, IOError): pass - os.remove(codefile) # Test descriptions =================================================================== Index: dist/src/Lib/test/test_pkgimport.py --- dist/src/Lib/test/test_pkgimport.py 23 Jul 2002 19:03:58 -0000 1.6 +++ dist/src/Lib/test/test_pkgimport.py 3 Aug 2002 06:32:26 -0000 @@ -17,8 +17,7 @@ class TestImport(unittest.TestCase): del sys.modules[module_name] def setUp(self): - self.test_dir = tempfile.mktemp() - os.mkdir(self.test_dir) + self.test_dir = tempfile.mkdtemp() sys.path.append(self.test_dir) self.package_dir = os.path.join(self.test_dir, self.package_name) =================================================================== Index: dist/src/Lib/test/test_tempfile.py --- dist/src/Lib/test/test_tempfile.py 29 Oct 2001 21:46:08 -0000 1.1 +++ dist/src/Lib/test/test_tempfile.py 3 Aug 2002 06:32:26 -0000 @@ -1,10 +1,707 @@ -# SF bug #476138: tempfile behavior across platforms -# Ensure that a temp file can be closed any number of times without error. +# tempfile.py unit tests. import tempfile +import os +import sys +import re +import errno +import warnings -f = tempfile.TemporaryFile("w+b") -f.write('abc\n') -f.close() -f.close() -f.close() +import unittest +from test import test_support + +if hasattr(os, 'stat'): + import stat + has_stat = 1 +else: + has_stat = 0 + +has_textmode = (tempfile._text_openflags != tempfile._bin_openflags) + +# This is organized as one test for each chunk of code in tempfile.py, +# in order of their appearance in the file. Testing which requires +# threads is not done here. + +# Common functionality. +class TC(unittest.TestCase): + + str_check = re.compile(r"[a-zA-Z0-9_-]{6}$") + + def failOnException(self, what, ei=None): + if ei is None: + ei = sys.exc_info() + self.fail("%s raised %s: %s" % (what, ei[0], ei[1])) + + def nameCheck(self, name, dir, pre, suf): + (ndir, nbase) = os.path.split(name) + npre = nbase[:len(pre)] + nsuf = nbase[len(nbase)-len(suf):] + + self.assertEqual(ndir, dir, + "file '%s' not in directory '%s'" % (name, dir)) + self.assertEqual(npre, pre, + "file '%s' does not begin with '%s'" % (nbase, pre)) + self.assertEqual(nsuf, suf, + "file '%s' does not end with '%s'" % (nbase, suf)) + + nbase = nbase[len(pre):len(nbase)-len(suf)] + self.assert_(self.str_check.match(nbase), + "random string '%s' does not match /^[a-zA-Z0-9_-]{6}$/" + % nbase) + +test_classes = [] + +class test_exports(TC): + def test_exports(self): + """There are no surprising symbols in the tempfile module""" + dict = tempfile.__dict__ + + expected = { + "NamedTemporaryFile" : 1, + "TemporaryFile" : 1, + "mkstemp" : 1, + "mkdtemp" : 1, + "mktemp" : 1, + "TMP_MAX" : 1, + "gettempprefix" : 1, + "gettempdir" : 1, + "tempdir" : 1, + "template" : 1 + } + + unexp = [] + for key in dict: + if key[0] != '_' and key not in expected: + unexp.append(key) + self.failUnless(len(unexp) == 0, + "unexpected keys: %s" % unexp) + +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.""" + + def setUp(self): + self.r = tempfile._RandomNameSequence() + + def test_get_six_char_str(self): + """_RandomNameSequence returns a six-character string""" + s = self.r.next() + self.nameCheck(s, '', '', '') + + def test_many(self): + """_RandomNameSequence returns no duplicate strings (stochastic)""" + + dict = {} + r = self.r + for i in xrange(1000): + s = r.next() + self.nameCheck(s, '', '', '') + self.failIf(s in dict) + dict[s] = 1 + + def test_supports_iter(self): + """_RandomNameSequence supports the iterator protocol""" + + i = 0 + r = self.r + try: + for s in r: + i += 1 + if i == 20: + break + except: + failOnException("iteration") + +test_classes.append(test__RandomNameSequence) + + +class test__candidate_tempdir_list(TC): + """Test the internal function _candidate_tempdir_list.""" + + def test_nonempty_list(self): + """_candidate_tempdir_list returns a nonempty list of strings""" + + cand = tempfile._candidate_tempdir_list() + + self.failIf(len(cand) == 0) + for c in cand: + self.assert_(isinstance(c, basestring), + "%s is not a string" % c) + + def test_wanted_dirs(self): + """_candidate_tempdir_list contains the expected directories""" + + # Make sure the interesting environment variables are all set. + added = [] + try: + for envname in 'TMPDIR', 'TEMP', 'TMP': + dirname = os.getenv(envname) + if not dirname: + os.environ[envname] = os.path.abspath(envname) + added.append(envname) + + cand = tempfile._candidate_tempdir_list() + + for envname in 'TMPDIR', 'TEMP', 'TMP': + dirname = os.getenv(envname) + if not dirname: raise ValueError + self.assert_(dirname in cand) + + try: + dirname = os.getcwd() + except (AttributeError, os.error): + dirname = os.curdir + + self.assert_(dirname in cand) + + # Not practical to try to verify the presence of OS-specific + # paths in this list. + finally: + for p in added: + del os.environ[p] + +test_classes.append(test__candidate_tempdir_list) + + +# We test _get_default_tempdir by testing gettempdir. + + +class test__get_candidate_names(TC): + """Test the internal function _get_candidate_names.""" + + def test_retval(self): + """_get_candidate_names returns a _RandomNameSequence object""" + obj = tempfile._get_candidate_names() + self.assert_(isinstance(obj, tempfile._RandomNameSequence)) + + def test_same_thing(self): + """_get_candidate_names always returns the same object""" + a = tempfile._get_candidate_names() + b = tempfile._get_candidate_names() + + self.assert_(a is b) + +test_classes.append(test__get_candidate_names) + + +class test__mkstemp_inner(TC): + """Test the internal function _mkstemp_inner.""" + + class mkstemped: + _bflags = tempfile._bin_openflags + _tflags = tempfile._text_openflags + _close = os.close + _unlink = os.unlink + + def __init__(self, dir, pre, suf, bin): + if bin: flags = self._bflags + else: flags = self._tflags + + (self.fd, self.name) = tempfile._mkstemp_inner(dir, pre, suf, flags) + + def write(self, str): + os.write(self.fd, str) + + def __del__(self): + self._close(self.fd) + self._unlink(self.name) + + def do_create(self, dir=None, pre="", suf="", bin=1): + if dir is None: + dir = tempfile.gettempdir() + try: + file = self.mkstemped(dir, pre, suf, bin) + except: + self.failOnException("_mkstemp_inner") + + self.nameCheck(file.name, dir, pre, suf) + return file + + def test_basic(self): + """_mkstemp_inner can create files""" + self.do_create().write("blat") + self.do_create(pre="a").write("blat") + self.do_create(suf="b").write("blat") + self.do_create(pre="a", suf="b").write("blat") + self.do_create(pre="aa", suf=".txt").write("blat") + + def test_basic_many(self): + """_mkstemp_inner can create many files (stochastic)""" + extant = range(1000) + for i in extant: + extant[i] = self.do_create(pre="aa") + + def test_choose_directory(self): + """_mkstemp_inner can create files in a user-selected directory""" + dir = tempfile.mkdtemp() + try: + self.do_create(dir=dir).write("blat") + finally: + os.rmdir(dir) + + def test_file_mode(self): + """_mkstemp_inner creates files with the proper mode""" + if not has_stat: + return # ugh, can't use TestSkipped. + + file = self.do_create() + mode = stat.S_IMODE(os.stat(file.name).st_mode) + self.assertEqual(mode, 0600) + + def test_noinherit(self): + """_mkstemp_inner file handles are not inherited by child processes""" + # FIXME: Find a way to test this on Windows. + if os.name != 'posix': + return # ugh, can't use TestSkipped. + + file = self.do_create() + + # We have to exec something, so that FD_CLOEXEC will take + # effect. The sanest thing to try is /bin/sh; we can easily + # instruct it to attempt to write to the fd and report success + # or failure. Unfortunately, sh syntax does not permit use of + # fds numerically larger than 9; abandon this test if so. + if file.fd > 9: + raise test_support.TestSkipped, 'cannot test with fd %d' % file.fd + + pid = os.fork() + if pid: + status = os.wait()[1] + self.failUnless(os.WIFEXITED(status), + "child process did not exit (status %d)" % status) + + # We want the child to have exited _un_successfully, indicating + # failure to write to the closed fd. + self.failUnless(os.WEXITSTATUS(status) != 0, + "child process exited successfully") + + else: + try: + # Throw away stderr. + nul = os.open('/dev/null', os.O_RDWR) + os.dup2(nul, 2) + os.execv('/bin/sh', ['sh', '-c', 'echo blat >&%d' % file.fd]) + except: + os._exit(0) + + def test_textmode(self): + """_mkstemp_inner can create files in text mode""" + if not has_textmode: + return # ugh, can't use TestSkipped. + + self.do_create(bin=0).write("blat\n") + # XXX should test that the file really is a text file + +test_classes.append(test__mkstemp_inner) + + +class test_gettempprefix(TC): + """Test gettempprefix().""" + + def test_sane_template(self): + """gettempprefix returns a nonempty prefix string""" + p = tempfile.gettempprefix() + + self.assert_(isinstance(p, basestring)) + self.assert_(len(p) > 0) + + def test_usable_template(self): + """gettempprefix returns a usable prefix string""" + + # Create a temp directory, avoiding use of the prefix. + # Then attempt to create a file whose name is + # prefix + 'xxxxxx.xxx' in that directory. + p = tempfile.gettempprefix() + "xxxxxx.xxx" + d = tempfile.mkdtemp(prefix="") + try: + p = os.path.join(d, p) + try: + fd = os.open(p, os.O_RDWR | os.O_CREAT) + except: + self.failOnException("os.open") + os.close(fd) + os.unlink(p) + finally: + os.rmdir(d) + +test_classes.append(test_gettempprefix) + + +class test_gettempdir(TC): + """Test gettempdir().""" + + def test_directory_exists(self): + """gettempdir returns a directory which exists""" + + dir = tempfile.gettempdir() + self.assert_(os.path.isabs(dir) or dir == os.curdir, + "%s is not an absolute path" % dir) + self.assert_(os.path.isdir(dir), + "%s is not a directory" % dir) + + def test_directory_writable(self): + """gettempdir returns a directory writable by the user""" + + # sneaky: just instantiate a NamedTemporaryFile, which + # defaults to writing into the directory returned by + # gettempdir. + try: + file = tempfile.NamedTemporaryFile() + file.write("blat") + file.close() + except: + self.failOnException("create file in %s" % tempfile.gettempdir()) + + def test_same_thing(self): + """gettempdir always returns the same object""" + a = tempfile.gettempdir() + b = tempfile.gettempdir() + + self.assert_(a is b) + +test_classes.append(test_gettempdir) + + +class test_mkstemp(TC): + """Test mkstemp().""" + def do_create(self, dir=None, pre="", suf="", ): + if dir is None: + dir = tempfile.gettempdir() + try: + (fd, name) = tempfile.mkstemp(dir=dir, prefix=pre, suffix=suf) + except: + self.failOnException("mkstemp") + + try: + self.nameCheck(name, dir, pre, suf) + finally: + os.close(fd) + os.unlink(name) + + def test_basic(self): + """mkstemp can create files""" + self.do_create() + self.do_create(pre="a") + self.do_create(suf="b") + self.do_create(pre="a", suf="b") + self.do_create(pre="aa", suf=".txt") + + def test_choose_directory(self): + """mkstemp can create directories in a user-selected directory""" + dir = tempfile.mkdtemp() + try: + self.do_create(dir=dir) + finally: + os.rmdir(dir) + +test_classes.append(test_mkstemp) + + +class test_mkdtemp(TC): + """Test mkdtemp().""" + + def do_create(self, dir=None, pre="", suf=""): + if dir is None: + dir = tempfile.gettempdir() + try: + name = tempfile.mkdtemp(dir=dir, prefix=pre, suffix=suf) + except: + self.failOnException("mkdtemp") + + try: + self.nameCheck(name, dir, pre, suf) + return name + except: + os.rmdir(name) + raise + + def test_basic(self): + """mkdtemp can create directories""" + os.rmdir(self.do_create()) + os.rmdir(self.do_create(pre="a")) + os.rmdir(self.do_create(suf="b")) + os.rmdir(self.do_create(pre="a", suf="b")) + os.rmdir(self.do_create(pre="aa", suf=".txt")) + + def test_basic_many(self): + """mkdtemp can create many directories (stochastic)""" + extant = range(1000) + try: + for i in extant: + extant[i] = self.do_create(pre="aa") + finally: + for i in extant: + if(isinstance(i, basestring)): + os.rmdir(i) + + def test_choose_directory(self): + """mkdtemp can create directories in a user-selected directory""" + dir = tempfile.mkdtemp() + try: + os.rmdir(self.do_create(dir=dir)) + finally: + os.rmdir(dir) + + def test_mode(self): + """mkdtemp creates directories with the proper mode""" + if not has_stat: + return # ugh, can't use TestSkipped. + + dir = self.do_create() + try: + mode = stat.S_IMODE(os.stat(dir).st_mode) + self.assertEqual(mode, 0700) + finally: + os.rmdir(dir) + +test_classes.append(test_mkdtemp) + + +class test_mktemp(TC): + """Test mktemp().""" + + # For safety, all use of mktemp must occur in a private directory. + # We must also suppress the RuntimeWarning it generates. + def setUp(self): + self.dir = tempfile.mkdtemp() + warnings.filterwarnings("ignore", + category=RuntimeWarning, + message="mktemp") + + def tearDown(self): + if self.dir: + os.rmdir(self.dir) + self.dir = None + # XXX This clobbers any -W options. + warnings.resetwarnings() + + class mktemped: + _unlink = os.unlink + _bflags = tempfile._bin_openflags + + def __init__(self, dir, pre, suf): + self.name = tempfile.mktemp(dir=dir, prefix=pre, suffix=suf) + # Create the file. This will raise an exception if it's + # mysteriously appeared in the meanwhile. + os.close(os.open(self.name, self._bflags, 0600)) + + def __del__(self): + self._unlink(self.name) + + def do_create(self, pre="", suf=""): + try: + file = self.mktemped(self.dir, pre, suf) + except: + self.failOnException("mktemp") + + self.nameCheck(file.name, self.dir, pre, suf) + return file + + def test_basic(self): + """mktemp can choose usable file names""" + self.do_create() + self.do_create(pre="a") + self.do_create(suf="b") + self.do_create(pre="a", suf="b") + self.do_create(pre="aa", suf=".txt") + + def test_many(self): + """mktemp can choose many usable file names (stochastic)""" + extant = range(1000) + for i in extant: + extant[i] = self.do_create(pre="aa") + + def test_warning(self): + """mktemp issues a warning when used""" + warnings.filterwarnings("error", + category=RuntimeWarning, + message="mktemp") + self.assertRaises(RuntimeWarning, + tempfile.mktemp, (), { 'dir': self.dir }) + +test_classes.append(test_mktemp) + + +# We test _TemporaryFileWrapper by testing NamedTemporaryFile. + + +class test_NamedTemporaryFile(TC): + """Test NamedTemporaryFile().""" + + def do_create(self, dir=None, pre="", suf=""): + if dir is None: + dir = tempfile.gettempdir() + try: + file = tempfile.NamedTemporaryFile(dir=dir, prefix=pre, suffix=suf) + except: + self.failOnException("NamedTemporaryFile") + + self.nameCheck(file.name, dir, pre, suf) + return file + + + def test_basic(self): + """NamedTemporaryFile can create files""" + self.do_create() + self.do_create(pre="a") + self.do_create(suf="b") + self.do_create(pre="a", suf="b") + self.do_create(pre="aa", suf=".txt") + + def test_creates_named(self): + """NamedTemporaryFile creates files with names""" + f = tempfile.NamedTemporaryFile() + self.failUnless(os.path.exists(f.name), + "NamedTemporaryFile %s does not exist" % f.name) + + def test_del_on_close(self): + """A NamedTemporaryFile is deleted when closed""" + dir = tempfile.mkdtemp() + try: + f = tempfile.NamedTemporaryFile(dir=dir) + f.write('blat') + f.close() + self.failIf(os.path.exists(f.name), + "NamedTemporaryFile %s exists after close" % f.name) + finally: + os.rmdir(dir) + + def test_multiple_close(self): + """A NamedTemporaryFile can be closed many times without error""" + + f = tempfile.NamedTemporaryFile() + f.write('abc\n') + f.close() + try: + f.close() + f.close() + except: + self.failOnException("close") + + # How to test the mode and bufsize parameters? + +test_classes.append(test_NamedTemporaryFile) + + +class test_TemporaryFile(TC): + """Test TemporaryFile().""" + + def test_basic(self): + """TemporaryFile can create files""" + # No point in testing the name params - the file has no name. + try: + tempfile.TemporaryFile() + except: + self.failOnException("TemporaryFile") + + def test_has_no_name(self): + """TemporaryFile creates files with no names (on this system)""" + dir = tempfile.mkdtemp() + f = tempfile.TemporaryFile(dir=dir) + f.write('blat') + + # Sneaky: because this file has no name, it should not prevent + # us from removing the directory it was created in. + try: + os.rmdir(dir) + except: + ei = sys.exc_info() + # cleanup + f.close() + os.rmdir(dir) + self.failOnException("rmdir", ei) + + def test_multiple_close(self): + """A TemporaryFile can be closed many times without error""" + f = tempfile.TemporaryFile() + f.write('abc\n') + f.close() + try: + f.close() + f.close() + except: + self.failOnException("close") + + # How to test the mode and bufsize parameters? + +class dummy_test_TemporaryFile(TC): + def test_dummy(self): + """TemporaryFile and NamedTemporaryFile are the same (on this system)""" + pass + +if tempfile.NamedTemporaryFile is tempfile.TemporaryFile: + test_classes.append(dummy_test_TemporaryFile) +else: + test_classes.append(test_TemporaryFile) + +def test_main(): + suite = unittest.TestSuite() + for c in test_classes: + suite.addTest(unittest.makeSuite(c)) + test_support.run_suite(suite) + +if __name__ == "__main__": + test_main() =================================================================== Index: dist/src/Lib/test/test_uu.py --- dist/src/Lib/test/test_uu.py 23 Jul 2002 19:04:09 -0000 1.4 +++ dist/src/Lib/test/test_uu.py 3 Aug 2002 06:32:26 -0000 @@ -124,8 +124,7 @@ except uu.Error, e: verify(str(e) == 'No valid begin line found in input file') # Test to verify that decode() will refuse to overwrite an existing file -import tempfile -outfile = tempfile.mktemp() +outfile = TESTFN + "out" inp = StringIO('Here is a message to be uuencoded') out = StringIO() uu.encode(inp, out, outfile) =================================================================== Index: dist/src/Lib/test/test_wave.py --- dist/src/Lib/test/test_wave.py 23 Jul 2002 19:04:09 -0000 1.3 +++ dist/src/Lib/test/test_wave.py 3 Aug 2002 06:32:26 -0000 @@ -1,5 +1,5 @@ -from test.test_support import TestFailed -import os, tempfile +from test.test_support import TestFailed, TESTFN +import os import wave def check(t, msg=None): @@ -11,9 +11,7 @@ sampwidth = 2 framerate = 8000 nframes = 100 -testfile = tempfile.mktemp() - -f = wave.open(testfile, 'wb') +f = wave.open(TESTFN, 'wb') f.setnchannels(nchannels) f.setsampwidth(sampwidth) f.setframerate(framerate) @@ -22,7 +20,7 @@ output = '\0' * nframes * nchannels * sa f.writeframes(output) f.close() -f = wave.open(testfile, 'rb') +f = wave.open(TESTFN, 'rb') check(nchannels == f.getnchannels(), "nchannels") check(sampwidth == f.getsampwidth(), "sampwidth") check(framerate == f.getframerate(), "framerate") @@ -31,4 +29,4 @@ input = f.readframes(nframes) check(input == output, "data") f.close() -os.remove(testfile) +os.remove(TESTFN) =================================================================== Index: dist/src/Lib/test/test_whichdb.py --- dist/src/Lib/test/test_whichdb.py 2 Aug 2002 17:10:10 -0000 1.1 +++ dist/src/Lib/test/test_whichdb.py 3 Aug 2002 06:32:26 -0000 @@ -11,7 +11,7 @@ import anydbm import tempfile import glob -_fname = tempfile.mktemp() +_fname = test.test_support.TESTFN def _delete_files(): # we don't know the precise name the underlying database uses =================================================================== Index: dist/src/Tools/compiler/regrtest.py --- dist/src/Tools/compiler/regrtest.py 17 Sep 2001 21:31:35 -0000 1.3 +++ dist/src/Tools/compiler/regrtest.py 3 Aug 2002 06:32:27 -0000 @@ -15,15 +15,13 @@ import test import tempfile def copy_test_suite(): - dest = tempfile.mktemp() - os.mkdir(dest) + dest = tempfile.mkdtemp() os.system("cp -r %s/* %s" % (test.__path__[0], dest)) print "Creating copy of test suite in", dest return dest def copy_library(): - dest = tempfile.mktemp() - os.mkdir(dest) + dest = tempfile.mkdtemp() libdir = os.path.split(test.__path__[0])[0] print "Found standard library in", libdir print "Creating copy of standard library in", dest =================================================================== Index: dist/src/Tools/faqwiz/faqwiz.py --- dist/src/Tools/faqwiz/faqwiz.py 31 Mar 2000 00:58:00 -0000 1.26 +++ dist/src/Tools/faqwiz/faqwiz.py 3 Aug 2002 06:32:27 -0000 @@ -807,19 +807,19 @@ class FaqWizard: f.close() import tempfile - tfn = tempfile.mktemp() - f = open(tfn, 'w') - emit(LOGHEADER, self.ui, os.environ, date=date, _file=f) - f.close() + tf = tempfile.NamedTemporaryFile() + emit(LOGHEADER, self.ui, os.environ, date=date, _file=tfn) + tf.flush() + tf.seek(0) - command = interpolate(SH_CHECKIN, file=file, tfn=tfn) + command = interpolate(SH_CHECKIN, file=file, tfn=tf.name) log("\n\n" + command) p = os.popen(command) output = p.read() sts = p.close() log("output: " + output) log("done: " + str(sts)) - log("TempFile:\n" + open(tfn).read() + "end") + log("TempFile:\n" + tf.read() + "end") if not sts: self.prologue(T_COMMITTED) =================================================================== Index: dist/src/Tools/idle/IOBinding.py --- dist/src/Tools/idle/IOBinding.py 10 Jun 2002 18:52:02 -0000 1.7 +++ dist/src/Tools/idle/IOBinding.py 3 Aug 2002 06:32:27 -0000 @@ -159,9 +159,11 @@ class IOBinding: if self.get_saved(): filename = self.filename else: - filename = tempfilename = tempfile.mktemp() + (tfd, tfn) = tempfile.mkstemp() + os.close(tfd) + filename = tfn if not self.writefile(filename): - os.unlink(tempfilename) + os.unlink(tfn) return "break" edconf = idleconf.getsection('EditorWindow') command = edconf.get('print-command') =================================================================== Index: nondist/sandbox/help/pydoc.py --- nondist/sandbox/help/pydoc.py 27 Feb 2001 14:00:27 -0000 1.7 +++ nondist/sandbox/help/pydoc.py 3 Aug 2002 06:32:27 -0000 @@ -780,8 +780,8 @@ def getpager(): return lambda a: pipepager(a, 'less') import tempfile - filename = tempfile.mktemp() - open(filename, 'w').close() + (fd, filename) = tempfile.mkstemp() + os.close(fd) try: if hasattr(os, 'system') and os.system('more %s' % filename) == 0: return lambda text: pipepager(text, 'more') @@ -803,8 +803,8 @@ def pipepager(text, cmd): def tempfilepager(text, cmd): """Page through text by invoking a program on a temporary file.""" import tempfile - filename = tempfile.mktemp() - file = open(filename, 'w') + (fd, filename) = tempfile.mkstemp() + file = os.fdopen(fd, 'w') file.write(text) file.close() try: