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:
22 except (AttributeError, os
.error
):
24 attempdirs
= ['/tmp', '/var/tmp', '/usr/tmp', pwd
]
26 attempdirs
.insert(0, 'C:\\TEMP')
27 attempdirs
.insert(0, '\\TEMP')
28 elif os
.name
== 'mac':
31 refnum
, dirid
= macfs
.FindFolder(MACFS
.kOnSystemDisk
,
32 MACFS
.kTemporaryFolderType
, 1)
33 dirname
= macfs
.FSSpec((refnum
, dirid
, '')).as_pathname()
34 attempdirs
.insert(0, dirname
)
37 for envname
in 'TMPDIR', 'TEMP', 'TMP':
38 if os
.environ
.has_key(envname
):
39 attempdirs
.insert(0, os
.environ
[envname
])
40 testfile
= gettempprefix() + 'test'
41 for dir in attempdirs
:
43 filename
= os
.path
.join(dir, testfile
)
44 if os
.name
== 'posix':
46 fd
= os
.open(filename
,
47 os
.O_RDWR | os
.O_CREAT | os
.O_EXCL
, 0700)
51 fp
= os
.fdopen(fd
, 'w')
59 fp
= open(filename
, 'w')
68 msg
= "Can't find a usable temporary directory amongst " + `attempdirs`
73 # template caches the result of gettempprefix, for speed, when possible.
74 # XXX unclear why this isn't "_template"; left it "template" for backward
76 if os
.name
== "posix":
77 # We don't try to cache the template on posix: the pid may change on us
78 # between calls due to a fork, and on Linux the pid changes even for
79 # another thread in the same process. Since any attempt to keep the
80 # cache in synch would have to call os.getpid() anyway in order to make
81 # sure the pid hasn't changed between calls, a cache wouldn't save any
82 # time. In addition, a cache is difficult to keep correct with the pid
83 # changing willy-nilly, and earlier attempts proved buggy (races).
86 # Else the pid never changes, so gettempprefix always returns the same
89 template
= '~' + `os
.getpid()`
+ '-'
90 elif os
.name
== 'mac':
91 template
= 'Python-Tmp-'
93 template
= 'tmp' # XXX might choose a better one
96 """Function to calculate a prefix of the filename to use.
98 This incorporates the current process id on systems that support such a
99 notion, so that concurrent processes don't generate the same prefix.
104 return '@' + `os
.getpid()`
+ '.'
109 def mktemp(suffix
=""):
110 """User-callable function to return a unique temporary file name."""
112 pre
= gettempprefix()
114 i
= _counter
.get_next()
115 file = os
.path
.join(dir, pre
+ str(i
) + suffix
)
116 if not os
.path
.exists(file):
120 class TemporaryFileWrapper
:
121 """Temporary file wrapper
123 This class provides a wrapper around files opened for temporary use.
124 In particular, it seeks to automatically remove the file when it is
127 def __init__(self
, file, path
):
139 def __getattr__(self
, name
):
140 file = self
.__dict
__['file']
141 a
= getattr(file, name
)
142 if type(a
) != type(0):
143 setattr(self
, name
, a
)
147 def TemporaryFile(mode
='w+b', bufsize
=-1, suffix
=""):
148 """Create and return a temporary file (opened read-write by default)."""
149 name
= mktemp(suffix
)
150 if os
.name
== 'posix':
151 # Unix -- be very careful
152 fd
= os
.open(name
, os
.O_RDWR|os
.O_CREAT|os
.O_EXCL
, 0700)
155 return os
.fdopen(fd
, mode
, bufsize
)
160 # Non-unix -- can't unlink file that's still open, use wrapper
161 file = open(name
, mode
, bufsize
)
162 return TemporaryFileWrapper(file, name
)
164 # In order to generate unique names, mktemp() uses _counter.get_next().
165 # This returns a unique integer on each call, in a threadsafe way (i.e.,
166 # multiple threads will never see the same integer). The integer will
167 # usually be a Python int, but if _counter.get_next() is called often
168 # enough, it will become a Python long.
169 # Note that the only name that survives this next block of code
172 class _ThreadSafeCounter
:
173 def __init__(self
, mutex
, initialvalue
=0):
175 self
.i
= initialvalue
182 except OverflowError:
183 newi
= long(result
) + 1
198 _counter
= _ThreadSafeCounter(_DummyMutex())
202 _counter
= _ThreadSafeCounter(thread
.allocate_lock())
205 del _ThreadSafeCounter