1 """Temporary files and filenames."""
3 # XXX This tries to be not UNIX specific, but I don't know beans about
4 # how to choose a temp directory or filename on MS-DOS or other
5 # systems so it may have to be changed...
9 __all__
= ["mktemp", "TemporaryFile", "tempdir", "gettempprefix"]
11 # Parameters that the caller may set to override the defaults
16 """Function to calculate the directory to use."""
18 if tempdir
is not None:
21 # _gettempdir_inner deduces whether a candidate temp dir is usable by
22 # trying to create a file in it, and write to it. If that succeeds,
23 # great, it closes the file and unlinks it. There's a race, though:
24 # the *name* of the test file it tries is the same across all threads
25 # under most OSes (Linux is an exception), and letting multiple threads
26 # all try to open, write to, close, and unlink a single file can cause
27 # a variety of bogus errors (e.g., you cannot unlink a file under
28 # Windows if anyone has it open, and two threads cannot create the
29 # same file in O_EXCL mode under Unix). The simplest cure is to serialize
30 # calls to _gettempdir_inner. This isn't a real expense, because the
31 # first thread to succeed sets the global tempdir, and all subsequent
32 # calls to gettempdir() reuse that without trying _gettempdir_inner.
33 _tempdir_lock
.acquire()
35 return _gettempdir_inner()
37 _tempdir_lock
.release()
39 def _gettempdir_inner():
40 """Function to calculate the directory to use."""
42 if tempdir
is not None:
46 except (AttributeError, os
.error
):
48 attempdirs
= ['/tmp', '/var/tmp', '/usr/tmp', pwd
]
50 attempdirs
.insert(0, 'C:\\TEMP')
51 attempdirs
.insert(0, '\\TEMP')
52 elif os
.name
== 'mac':
55 refnum
, dirid
= macfs
.FindFolder(MACFS
.kOnSystemDisk
,
56 MACFS
.kTemporaryFolderType
, 1)
57 dirname
= macfs
.FSSpec((refnum
, dirid
, '')).as_pathname()
58 attempdirs
.insert(0, dirname
)
61 elif os
.name
== 'riscos':
62 scrapdir
= os
.getenv('Wimp$ScrapDir')
64 attempdirs
.insert(0, scrapdir
)
65 for envname
in 'TMPDIR', 'TEMP', 'TMP':
66 if os
.environ
.has_key(envname
):
67 attempdirs
.insert(0, os
.environ
[envname
])
68 testfile
= gettempprefix() + 'test'
69 for dir in attempdirs
:
71 filename
= os
.path
.join(dir, testfile
)
72 if os
.name
== 'posix':
74 fd
= os
.open(filename
,
75 os
.O_RDWR | os
.O_CREAT | os
.O_EXCL
, 0700)
79 fp
= os
.fdopen(fd
, 'w')
87 fp
= open(filename
, 'w')
96 msg
= "Can't find a usable temporary directory amongst " + `attempdirs`
101 # template caches the result of gettempprefix, for speed, when possible.
102 # XXX unclear why this isn't "_template"; left it "template" for backward
104 if os
.name
== "posix":
105 # We don't try to cache the template on posix: the pid may change on us
106 # between calls due to a fork, and on Linux the pid changes even for
107 # another thread in the same process. Since any attempt to keep the
108 # cache in synch would have to call os.getpid() anyway in order to make
109 # sure the pid hasn't changed between calls, a cache wouldn't save any
110 # time. In addition, a cache is difficult to keep correct with the pid
111 # changing willy-nilly, and earlier attempts proved buggy (races).
114 # Else the pid never changes, so gettempprefix always returns the same
116 elif os
.name
== "nt":
117 template
= '~' + `os
.getpid()`
+ '-'
118 elif os
.name
in ('mac', 'riscos'):
119 template
= 'Python-Tmp-'
121 template
= 'tmp' # XXX might choose a better one
124 """Function to calculate a prefix of the filename to use.
126 This incorporates the current process id on systems that support such a
127 notion, so that concurrent processes don't generate the same prefix.
132 return '@' + `os
.getpid()`
+ '.'
137 def mktemp(suffix
=""):
138 """User-callable function to return a unique temporary file name."""
140 pre
= gettempprefix()
142 i
= _counter
.get_next()
143 file = os
.path
.join(dir, pre
+ str(i
) + suffix
)
144 if not os
.path
.exists(file):
148 class TemporaryFileWrapper
:
149 """Temporary file wrapper
151 This class provides a wrapper around files opened for temporary use.
152 In particular, it seeks to automatically remove the file when it is
156 # Cache the unlinker so we don't get spurious errors at shutdown
157 # when the module-level "os" is None'd out. Note that this must
158 # be referenced as self.unlink, because the name TemporaryFileWrapper
159 # may also get None'd out before __del__ is called.
162 def __init__(self
, file, path
):
165 self
.close_called
= 0
168 if not self
.close_called
:
169 self
.close_called
= 1
171 self
.unlink(self
.path
)
176 def __getattr__(self
, name
):
177 file = self
.__dict
__['file']
178 a
= getattr(file, name
)
179 if type(a
) != type(0):
180 setattr(self
, name
, a
)
184 def TemporaryFile(mode
='w+b', bufsize
=-1, suffix
=""):
185 """Create and return a temporary file (opened read-write by default)."""
186 name
= mktemp(suffix
)
187 if os
.name
== 'posix':
188 # Unix -- be very careful
189 fd
= os
.open(name
, os
.O_RDWR|os
.O_CREAT|os
.O_EXCL
, 0700)
192 return os
.fdopen(fd
, mode
, bufsize
)
197 # Non-unix -- can't unlink file that's still open, use wrapper
198 file = open(name
, mode
, bufsize
)
199 return TemporaryFileWrapper(file, name
)
201 # In order to generate unique names, mktemp() uses _counter.get_next().
202 # This returns a unique integer on each call, in a threadsafe way (i.e.,
203 # multiple threads will never see the same integer). The integer will
204 # usually be a Python int, but if _counter.get_next() is called often
205 # enough, it will become a Python long.
206 # Note that the only names that survive this next block of code
207 # are "_counter" and "_tempdir_lock".
209 class _ThreadSafeCounter
:
210 def __init__(self
, mutex
, initialvalue
=0):
212 self
.i
= initialvalue
219 except OverflowError:
220 newi
= long(result
) + 1
235 _counter
= _ThreadSafeCounter(_DummyMutex())
236 _tempdir_lock
= _DummyMutex()
240 _counter
= _ThreadSafeCounter(thread
.allocate_lock())
241 _tempdir_lock
= thread
.allocate_lock()
244 del _ThreadSafeCounter