blob: 417b7493917aeba3f213054ca0957f77b85e52b2 [file] [log] [blame]
Guido van Rossume7b146f2000-02-04 15:28:42 +00001"""Temporary files and filenames."""
2
Guido van Rossum41f95031992-03-31 19:02:01 +00003# 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...
Guido van Rossumeee94981991-11-12 15:38:08 +00006
Guido van Rossum41f95031992-03-31 19:02:01 +00007import os
Guido van Rossumeee94981991-11-12 15:38:08 +00008
Skip Montanaro40fc1602001-03-01 04:27:19 +00009__all__ = ["mktemp", "TemporaryFile", "tempdir", "gettempprefix"]
10
Guido van Rossum41f95031992-03-31 19:02:01 +000011# Parameters that the caller may set to override the defaults
Guido van Rossum41f95031992-03-31 19:02:01 +000012tempdir = None
13template = None
14
Guido van Rossum41f95031992-03-31 19:02:01 +000015def gettempdir():
Guido van Rossume7b146f2000-02-04 15:28:42 +000016 """Function to calculate the directory to use."""
Guido van Rossumf4aaf861996-05-28 23:31:34 +000017 global tempdir
Guido van Rossum4033ad71996-08-08 18:33:56 +000018 if tempdir is not None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000019 return tempdir
Guido van Rossum29e5f5d1998-04-09 14:27:57 +000020 try:
21 pwd = os.getcwd()
22 except (AttributeError, os.error):
23 pwd = os.curdir
Guido van Rossum7dcf84f2001-03-02 05:51:16 +000024 attempdirs = ['/tmp', '/var/tmp', '/usr/tmp', pwd]
Guido van Rossum3e065ad1996-08-20 20:38:59 +000025 if os.name == 'nt':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000026 attempdirs.insert(0, 'C:\\TEMP')
27 attempdirs.insert(0, '\\TEMP')
Guido van Rossumf4f756c1997-04-11 19:00:53 +000028 elif os.name == 'mac':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000029 import macfs, MACFS
30 try:
Tim Petersb90f89a2001-01-15 03:26:36 +000031 refnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk,
32 MACFS.kTemporaryFolderType, 1)
33 dirname = macfs.FSSpec((refnum, dirid, '')).as_pathname()
34 attempdirs.insert(0, dirname)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000035 except macfs.error:
36 pass
Guido van Rossume2ae77b2001-10-24 20:42:55 +000037 elif os.name == 'riscos':
38 scrapdir = os.getenv('Wimp$ScrapDir')
39 if scrapdir:
40 attempdirs.insert(0, scrapdir)
Guido van Rossumca549821997-08-12 18:00:12 +000041 for envname in 'TMPDIR', 'TEMP', 'TMP':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000042 if os.environ.has_key(envname):
43 attempdirs.insert(0, os.environ[envname])
Guido van Rossum3e065ad1996-08-20 20:38:59 +000044 testfile = gettempprefix() + 'test'
Guido van Rossumf4aaf861996-05-28 23:31:34 +000045 for dir in attempdirs:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000046 try:
Tim Petersb90f89a2001-01-15 03:26:36 +000047 filename = os.path.join(dir, testfile)
48 if os.name == 'posix':
49 try:
Jeremy Hyltonc348cd72001-02-19 15:34:10 +000050 fd = os.open(filename,
51 os.O_RDWR | os.O_CREAT | os.O_EXCL, 0700)
Tim Petersb90f89a2001-01-15 03:26:36 +000052 except OSError:
53 pass
54 else:
55 fp = os.fdopen(fd, 'w')
56 fp.write('blat')
57 fp.close()
58 os.unlink(filename)
59 del fp, fd
60 tempdir = dir
61 break
62 else:
63 fp = open(filename, 'w')
64 fp.write('blat')
65 fp.close()
66 os.unlink(filename)
67 tempdir = dir
68 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000069 except IOError:
70 pass
Guido van Rossumf4aaf861996-05-28 23:31:34 +000071 if tempdir is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000072 msg = "Can't find a usable temporary directory amongst " + `attempdirs`
73 raise IOError, msg
Guido van Rossumf4aaf861996-05-28 23:31:34 +000074 return tempdir
Guido van Rossum41f95031992-03-31 19:02:01 +000075
76
Tim Peters9fadfb02001-01-13 03:04:02 +000077# template caches the result of gettempprefix, for speed, when possible.
78# XXX unclear why this isn't "_template"; left it "template" for backward
79# compatibility.
80if os.name == "posix":
81 # We don't try to cache the template on posix: the pid may change on us
82 # between calls due to a fork, and on Linux the pid changes even for
83 # another thread in the same process. Since any attempt to keep the
84 # cache in synch would have to call os.getpid() anyway in order to make
85 # sure the pid hasn't changed between calls, a cache wouldn't save any
86 # time. In addition, a cache is difficult to keep correct with the pid
87 # changing willy-nilly, and earlier attempts proved buggy (races).
88 template = None
89
90# Else the pid never changes, so gettempprefix always returns the same
91# string.
92elif os.name == "nt":
93 template = '~' + `os.getpid()` + '-'
Guido van Rossume2ae77b2001-10-24 20:42:55 +000094elif os.name in ('mac', 'riscos'):
Tim Peters9fadfb02001-01-13 03:04:02 +000095 template = 'Python-Tmp-'
96else:
97 template = 'tmp' # XXX might choose a better one
Guido van Rossumb0e57181998-10-14 20:27:05 +000098
Guido van Rossum41f95031992-03-31 19:02:01 +000099def gettempprefix():
Tim Peters9fadfb02001-01-13 03:04:02 +0000100 """Function to calculate a prefix of the filename to use.
101
102 This incorporates the current process id on systems that support such a
103 notion, so that concurrent processes don't generate the same prefix.
104 """
105
Tim Peters83732182001-01-14 05:12:40 +0000106 global template
Guido van Rossumb0e57181998-10-14 20:27:05 +0000107 if template is None:
Tim Peters83732182001-01-14 05:12:40 +0000108 return '@' + `os.getpid()` + '.'
Tim Peters9fadfb02001-01-13 03:04:02 +0000109 else:
110 return template
Guido van Rossumcff34541992-01-14 18:31:56 +0000111
Guido van Rossumeee94981991-11-12 15:38:08 +0000112
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000113def mktemp(suffix=""):
Guido van Rossume7b146f2000-02-04 15:28:42 +0000114 """User-callable function to return a unique temporary file name."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000115 dir = gettempdir()
116 pre = gettempprefix()
117 while 1:
Tim Peters1baa22a2001-01-12 10:02:46 +0000118 i = _counter.get_next()
119 file = os.path.join(dir, pre + str(i) + suffix)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 if not os.path.exists(file):
121 return file
Guido van Rossumca549821997-08-12 18:00:12 +0000122
123
124class TemporaryFileWrapper:
125 """Temporary file wrapper
126
127 This class provides a wrapper around files opened for temporary use.
128 In particular, it seeks to automatically remove the file when it is
129 no longer needed.
130 """
Tim Petersa255a722001-12-18 22:32:40 +0000131
132 # Cache the unlinker so we don't get spurious errors at shutdown
Tim Peters81b61bd2001-12-18 23:22:01 +0000133 # when the module-level "os" is None'd out. Note that this must
Tim Petersa255a722001-12-18 22:32:40 +0000134 # be referenced as self.unlink, because the name TemporaryFileWrapper
135 # may also get None'd out before __del__ is called.
136 unlink = os.unlink
137
Guido van Rossumca549821997-08-12 18:00:12 +0000138 def __init__(self, file, path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000139 self.file = file
140 self.path = path
Tim Petersc57a2852001-10-29 21:46:08 +0000141 self.close_called = 0
Guido van Rossumca549821997-08-12 18:00:12 +0000142
143 def close(self):
Tim Petersc57a2852001-10-29 21:46:08 +0000144 if not self.close_called:
145 self.close_called = 1
146 self.file.close()
Tim Petersa255a722001-12-18 22:32:40 +0000147 self.unlink(self.path)
Guido van Rossumca549821997-08-12 18:00:12 +0000148
149 def __del__(self):
Tim Petersc57a2852001-10-29 21:46:08 +0000150 self.close()
Guido van Rossumca549821997-08-12 18:00:12 +0000151
152 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000153 file = self.__dict__['file']
154 a = getattr(file, name)
Guido van Rossum6b708d51999-06-01 18:55:36 +0000155 if type(a) != type(0):
156 setattr(self, name, a)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000157 return a
Guido van Rossumca549821997-08-12 18:00:12 +0000158
159
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000160def TemporaryFile(mode='w+b', bufsize=-1, suffix=""):
Guido van Rossume7b146f2000-02-04 15:28:42 +0000161 """Create and return a temporary file (opened read-write by default)."""
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000162 name = mktemp(suffix)
Guido van Rossumdce3d551998-10-24 01:34:45 +0000163 if os.name == 'posix':
164 # Unix -- be very careful
165 fd = os.open(name, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700)
Guido van Rossum2457fc21998-10-24 15:02:59 +0000166 try:
167 os.unlink(name)
168 return os.fdopen(fd, mode, bufsize)
169 except:
170 os.close(fd)
171 raise
Guido van Rossumca549821997-08-12 18:00:12 +0000172 else:
Guido van Rossumdce3d551998-10-24 01:34:45 +0000173 # Non-unix -- can't unlink file that's still open, use wrapper
174 file = open(name, mode, bufsize)
175 return TemporaryFileWrapper(file, name)
Tim Peters1baa22a2001-01-12 10:02:46 +0000176
177# In order to generate unique names, mktemp() uses _counter.get_next().
178# This returns a unique integer on each call, in a threadsafe way (i.e.,
179# multiple threads will never see the same integer). The integer will
180# usually be a Python int, but if _counter.get_next() is called often
181# enough, it will become a Python long.
182# Note that the only name that survives this next block of code
183# is "_counter".
184
185class _ThreadSafeCounter:
186 def __init__(self, mutex, initialvalue=0):
187 self.mutex = mutex
188 self.i = initialvalue
189
190 def get_next(self):
191 self.mutex.acquire()
192 result = self.i
193 try:
194 newi = result + 1
195 except OverflowError:
196 newi = long(result) + 1
197 self.i = newi
198 self.mutex.release()
199 return result
200
201try:
202 import thread
203
204except ImportError:
205 class _DummyMutex:
206 def acquire(self):
207 pass
208
209 release = acquire
210
211 _counter = _ThreadSafeCounter(_DummyMutex())
212 del _DummyMutex
213
214else:
215 _counter = _ThreadSafeCounter(thread.allocate_lock())
216 del thread
217
218del _ThreadSafeCounter