blob: 3ad6d7c08524b3c1264c2db9dc3aafa92dcac25e [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
Guido van Rossum41f95031992-03-31 19:02:01 +00009# Parameters that the caller may set to override the defaults
Guido van Rossum41f95031992-03-31 19:02:01 +000010tempdir = None
11template = None
12
Guido van Rossum41f95031992-03-31 19:02:01 +000013def gettempdir():
Guido van Rossume7b146f2000-02-04 15:28:42 +000014 """Function to calculate the directory to use."""
Guido van Rossumf4aaf861996-05-28 23:31:34 +000015 global tempdir
Guido van Rossum4033ad71996-08-08 18:33:56 +000016 if tempdir is not None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000017 return tempdir
Guido van Rossum29e5f5d1998-04-09 14:27:57 +000018 try:
19 pwd = os.getcwd()
20 except (AttributeError, os.error):
21 pwd = os.curdir
Guido van Rossume504c0c2000-08-29 14:55:03 +000022 attempdirs = ['/var/tmp', '/usr/tmp', '/tmp', pwd]
Guido van Rossum3e065ad1996-08-20 20:38:59 +000023 if os.name == 'nt':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000024 attempdirs.insert(0, 'C:\\TEMP')
25 attempdirs.insert(0, '\\TEMP')
Guido van Rossumf4f756c1997-04-11 19:00:53 +000026 elif os.name == 'mac':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000027 import macfs, MACFS
28 try:
29 refnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk,
Guido van Rossum57a06611998-04-28 16:03:34 +000030 MACFS.kTemporaryFolderType, 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000031 dirname = macfs.FSSpec((refnum, dirid, '')).as_pathname()
32 attempdirs.insert(0, dirname)
33 except macfs.error:
34 pass
Guido van Rossumca549821997-08-12 18:00:12 +000035 for envname in 'TMPDIR', 'TEMP', 'TMP':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000036 if os.environ.has_key(envname):
37 attempdirs.insert(0, os.environ[envname])
Guido van Rossum3e065ad1996-08-20 20:38:59 +000038 testfile = gettempprefix() + 'test'
Guido van Rossumf4aaf861996-05-28 23:31:34 +000039 for dir in attempdirs:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000040 try:
Guido van Rossum00f09b32000-04-24 13:28:02 +000041 filename = os.path.join(dir, testfile)
42 if os.name == 'posix':
43 try:
44 fd = os.open(filename, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700)
45 except OSError:
46 pass
47 else:
48 fp = os.fdopen(fd, 'w')
49 fp.write('blat')
50 fp.close()
51 os.unlink(filename)
52 del fp, fd
53 tempdir = dir
54 break
55 else:
56 fp = open(filename, 'w')
57 fp.write('blat')
58 fp.close()
59 os.unlink(filename)
60 tempdir = dir
61 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000062 except IOError:
63 pass
Guido van Rossumf4aaf861996-05-28 23:31:34 +000064 if tempdir is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000065 msg = "Can't find a usable temporary directory amongst " + `attempdirs`
66 raise IOError, msg
Guido van Rossumf4aaf861996-05-28 23:31:34 +000067 return tempdir
Guido van Rossum41f95031992-03-31 19:02:01 +000068
69
Tim Peters9fadfb02001-01-13 03:04:02 +000070# template caches the result of gettempprefix, for speed, when possible.
71# XXX unclear why this isn't "_template"; left it "template" for backward
72# compatibility.
73if os.name == "posix":
74 # We don't try to cache the template on posix: the pid may change on us
75 # between calls due to a fork, and on Linux the pid changes even for
76 # another thread in the same process. Since any attempt to keep the
77 # cache in synch would have to call os.getpid() anyway in order to make
78 # sure the pid hasn't changed between calls, a cache wouldn't save any
79 # time. In addition, a cache is difficult to keep correct with the pid
80 # changing willy-nilly, and earlier attempts proved buggy (races).
81 template = None
82
83# Else the pid never changes, so gettempprefix always returns the same
84# string.
85elif os.name == "nt":
86 template = '~' + `os.getpid()` + '-'
87elif os.name == 'mac':
88 template = 'Python-Tmp-'
89else:
90 template = 'tmp' # XXX might choose a better one
Guido van Rossumb0e57181998-10-14 20:27:05 +000091
Tim Peters2caf8df2001-01-14 05:05:51 +000092_pidcache = {}
Guido van Rossum41f95031992-03-31 19:02:01 +000093def gettempprefix():
Tim Peters9fadfb02001-01-13 03:04:02 +000094 """Function to calculate a prefix of the filename to use.
95
96 This incorporates the current process id on systems that support such a
97 notion, so that concurrent processes don't generate the same prefix.
98 """
99
Guido van Rossumb0e57181998-10-14 20:27:05 +0000100 if template is None:
Tim Peters2caf8df2001-01-14 05:05:51 +0000101 p = os.getpid()
102 t = _pidcache.get(p, 0)
103 if t:
104 return t
105 if len(_pidcache) > 100: # stop unbounded growth
106 _pidcache.clear()
107 t = _pidcache[p] = '@' + `p` + '.'
108 return t
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 """
131 def __init__(self, file, path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000132 self.file = file
133 self.path = path
Guido van Rossumca549821997-08-12 18:00:12 +0000134
135 def close(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000136 self.file.close()
137 os.unlink(self.path)
Guido van Rossumca549821997-08-12 18:00:12 +0000138
139 def __del__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000140 try: self.close()
141 except: pass
Guido van Rossumca549821997-08-12 18:00:12 +0000142
143 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000144 file = self.__dict__['file']
145 a = getattr(file, name)
Guido van Rossum6b708d51999-06-01 18:55:36 +0000146 if type(a) != type(0):
147 setattr(self, name, a)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000148 return a
Guido van Rossumca549821997-08-12 18:00:12 +0000149
150
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000151def TemporaryFile(mode='w+b', bufsize=-1, suffix=""):
Guido van Rossume7b146f2000-02-04 15:28:42 +0000152 """Create and return a temporary file (opened read-write by default)."""
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000153 name = mktemp(suffix)
Guido van Rossumdce3d551998-10-24 01:34:45 +0000154 if os.name == 'posix':
155 # Unix -- be very careful
156 fd = os.open(name, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700)
Guido van Rossum2457fc21998-10-24 15:02:59 +0000157 try:
158 os.unlink(name)
159 return os.fdopen(fd, mode, bufsize)
160 except:
161 os.close(fd)
162 raise
Guido van Rossumca549821997-08-12 18:00:12 +0000163 else:
Guido van Rossumdce3d551998-10-24 01:34:45 +0000164 # Non-unix -- can't unlink file that's still open, use wrapper
165 file = open(name, mode, bufsize)
166 return TemporaryFileWrapper(file, name)
Tim Peters1baa22a2001-01-12 10:02:46 +0000167
168# In order to generate unique names, mktemp() uses _counter.get_next().
169# This returns a unique integer on each call, in a threadsafe way (i.e.,
170# multiple threads will never see the same integer). The integer will
171# usually be a Python int, but if _counter.get_next() is called often
172# enough, it will become a Python long.
173# Note that the only name that survives this next block of code
174# is "_counter".
175
176class _ThreadSafeCounter:
177 def __init__(self, mutex, initialvalue=0):
178 self.mutex = mutex
179 self.i = initialvalue
180
181 def get_next(self):
182 self.mutex.acquire()
183 result = self.i
184 try:
185 newi = result + 1
186 except OverflowError:
187 newi = long(result) + 1
188 self.i = newi
189 self.mutex.release()
190 return result
191
192try:
193 import thread
194
195except ImportError:
196 class _DummyMutex:
197 def acquire(self):
198 pass
199
200 release = acquire
201
202 _counter = _ThreadSafeCounter(_DummyMutex())
203 del _DummyMutex
204
205else:
206 _counter = _ThreadSafeCounter(thread.allocate_lock())
207 del thread
208
209del _ThreadSafeCounter