Tachyon /Users/simon/.local/share/uv/python/cpython-3.15.0-macos-aarch64-none/lib/python3.15/tempfile.py
63
Self Samples
115
Cumulative
8
Lines Hit
0.40%
% of Total
33
Max Self
33
Max Total
Intensity:
Cold Hot
Self Time
Total Time
Show All
Hot Only
Heat
Specialization
Line
Self
Total
Code
1
"""Temporary files.
2
3
This module provides generic, low- and high-level interfaces for
4
creating temporary files and directories. All of the interfaces
5
provided by this module can be used without fear of race conditions
6
except for 'mktemp'. 'mktemp' is subject to race conditions and
7
should not be used; it is provided for backward compatibility only.
8
9
The default path names are returned as str. If you supply bytes as
10
input, all return values will be in bytes. Ex:
11
12
>>> tempfile.mkstemp()
13
(4, '/tmp/tmptpu9nin8')
14
>>> tempfile.mkdtemp(suffix=b'')
15
b'/tmp/tmppbi8f0hy'
16
17
This module also provides some data items to the user:
18
19
TMP_MAX - maximum number of names that will be tried before
20
giving up.
21
tempdir - If this is set to a string before the first use of
22
any routine from this module, it will be considered as
23
another candidate location to store temporary files.
24
"""
25
26
__all__ = [
27
"NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
28
"SpooledTemporaryFile", "TemporaryDirectory",
29
"mkstemp", "mkdtemp", # low level safe interfaces
30
"mktemp", # deprecated unsafe interface
31
"TMP_MAX", "gettempprefix", # constants
32
"tempdir", "gettempdir",
33
"gettempprefixb", "gettempdirb",
34
]
35
36
37
# Imports.
38
39
import functools as _functools
40
import warnings as _warnings
41
import io as _io
42
import os as _os
43
import shutil as _shutil
44
import errno as _errno
45
from random import Random as _Random
46
import stat as _stat
47
import sys as _sys
48
import types as _types
49
import weakref as _weakref
50
import _thread
51
_allocate_lock = _thread.allocate_lock
52
53
_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
54
if hasattr(_os, 'O_NOFOLLOW'):
55
_text_openflags |= _os.O_NOFOLLOW
56
57
_bin_openflags = _text_openflags
58
if hasattr(_os, 'O_BINARY'):
59
_bin_openflags |= _os.O_BINARY
60
61
# This is more than enough.
62
# Each name contains over 40 random bits. Even with a million temporary
63
# files, the chance of a conflict is less than 1 in a million, and with
64
# 20 attempts, it is less than 1e-120.
65
TMP_MAX = 20
66
67
# This variable _was_ unused for legacy reasons, see issue 10354.
68
# But as of 3.5 we actually use it at runtime so changing it would
69
# have a possibly desirable side effect... But we do not want to support
70
# that as an API. It is undocumented on purpose. Do not depend on this.
71
template = "tmp"
72
73
# Internal routines.
74
75
_once_lock = _allocate_lock()
76
77
78
def _exists(fn):
79
try:
80
_os.lstat(fn)
81
except OSError:
82
return False
83
else:
84
return True
85
86
87
def _infer_return_type(*args):
88
"""Look at the type of all args and divine their implied return type."""
89
return_type = None
90
for arg in args:
91
if arg is None:
92
continue
93
94
if isinstance(arg, _os.PathLike):
95
arg = _os.fspath(arg)
96
97
if isinstance(arg, bytes):
98
if return_type is str:
99
raise TypeError("Can't mix bytes and non-bytes in "
100
"path components.")
101
return_type = bytes
102
else:
103
if return_type is bytes:
104
raise TypeError("Can't mix bytes and non-bytes in "
105
"path components.")
106
return_type = str
107
if return_type is None:
108
if tempdir is None or isinstance(tempdir, str):
109
return str # tempfile APIs return a str by default.
110
else:
111
# we could check for bytes but it'll fail later on anyway
112
return bytes
113
return return_type
114
115
116
def _sanitize_params(prefix, suffix, dir):
117
"""Common parameter processing for most APIs in this module."""
118
output_type = _infer_return_type(prefix, suffix, dir)
119
if suffix is None:
120
suffix = output_type()
121
if prefix is None:
122
if output_type is str:
123
prefix = template
124
else:
125
prefix = _os.fsencode(template)
126
if dir is None:
127
if output_type is str:
128
dir = gettempdir()
129
else:
130
dir = gettempdirb()
131
return prefix, suffix, dir, output_type
132
133
134
class _RandomNameSequence:
135
"""An instance of _RandomNameSequence generates an endless
136
sequence of unpredictable strings which can safely be incorporated
137
into file names. Each string is eight characters long. Multiple
138
threads can safely use the same instance at the same time.
139
140
_RandomNameSequence is an iterator."""
141
142
characters = "abcdefghijklmnopqrstuvwxyz0123456789_"
143
144
@property
145
def rng(self):
146
cur_pid = _os.getpid()
147
if cur_pid != getattr(self, '_rng_pid', None):
148
self._rng = _Random()
149
self._rng_pid = cur_pid
150
return self._rng
151
152
def __iter__(self):
153
return self
154
155
def __next__(self):
156
return ''.join(self.rng.choices(self.characters, k=8))
157
158
def _candidate_tempdir_list():
159
"""Generate a list of candidate temporary directories which
160
_get_default_tempdir will try."""
161
162
dirlist = []
163
164
# First, try the environment.
165
for envname in 'TMPDIR', 'TEMP', 'TMP':
166
dirname = _os.getenv(envname)
167
if dirname: dirlist.append(dirname)
168
169
# Failing that, try OS-specific locations.
170
if _os.name == 'nt':
171
dirlist.extend([ _os.path.expanduser(r'~\AppData\Local\Temp'),
172
_os.path.expandvars(r'%SYSTEMROOT%\Temp'),
173
r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
174
else:
175
dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
176
177
# As a last resort, the current directory.
178
try:
179
dirlist.append(_os.getcwd())
180
except (AttributeError, OSError):
181
dirlist.append(_os.curdir)
182
183
return dirlist
184
185
def _get_default_tempdir(dirlist=None):
186
"""Calculate the default directory to use for temporary files.
187
This routine should be called exactly once.
188
189
We determine whether or not a candidate temp dir is usable by
190
trying to create and write to a file in that directory. If this
191
is successful, the test file is deleted. To prevent denial of
192
service, the name of the test file must be randomized."""
193
194
namer = _RandomNameSequence()
195
if dirlist is None:
196
dirlist = _candidate_tempdir_list()
197
198
for dir in dirlist:
199
if dir != _os.curdir:
200
dir = _os.path.abspath(dir)
201
for seq in range(TMP_MAX):
202
name = next(namer)
203
filename = _os.path.join(dir, name)
204
try:
205
fd = _os.open(filename, _bin_openflags, 0o600)
206
try:
207
try:
208
_os.write(fd, b'blat')
209
finally:
210
_os.close(fd)
211
finally:
212
_os.unlink(filename)
213
return dir
214
except FileExistsError:
215
pass
216
except PermissionError:
217
# See the comment in mkdtemp().
218
if _os.name == 'nt' and _os.path.isdir(dir):
219
continue
220
break # no point trying more names in this directory
221
except OSError:
222
break # no point trying more names in this directory
223
raise FileNotFoundError(_errno.ENOENT,
224
"No usable temporary directory found in %s" %
225
dirlist)
226
227
_name_sequence = None
228
229
def _get_candidate_names():
230
"""Common setup sequence for all user-callable interfaces."""
231
232
global _name_sequence
233
if _name_sequence is None:
234
_once_lock.acquire()
235
try:
236
if _name_sequence is None:
237
_name_sequence = _RandomNameSequence()
238
finally:
239
_once_lock.release()
240
return _name_sequence
241
242
243
def _mkstemp_inner(dir, pre, suf, flags, output_type):
244
"""Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
245
246
dir = _os.path.abspath(dir)
247
names = _get_candidate_names()
248
if output_type is bytes:
249
names = map(_os.fsencode, names)
250
251
for seq in range(TMP_MAX):
252
name = next(names)
253
1
file = _os.path.join(dir, pre + name + suf)
254
_sys.audit("tempfile.mkstemp", file)
255
try:
256
24
24
fd = _os.open(file, flags, 0o600)
257
except FileExistsError:
258
continue # try again
259
except PermissionError:
260
# See the comment in mkdtemp().
261
if _os.name == 'nt' and _os.path.isdir(dir) and seq < TMP_MAX - 1:
262
continue
263
else:
264
raise
265
return fd, file
266
267
raise FileExistsError(_errno.EEXIST,
268
"No usable temporary file name found")
269
270
def _dont_follow_symlinks(func, path, *args):
271
# Pass follow_symlinks=False, unless not supported on this platform.
272
if func in _os.supports_follow_symlinks:
273
func(path, *args, follow_symlinks=False)
274
elif not _os.path.islink(path):
275
func(path, *args)
276
277
def _resetflags(path):
278
try:
279
chflags = _os.chflags
280
except AttributeError:
281
pass
282
else:
283
_dont_follow_symlinks(chflags, path, 0)
284
285
def _resetperms(path):
286
_resetflags(path)
287
_dont_follow_symlinks(_os.chmod, path, 0o700)
288
289
# True if TemporaryDirectory._rmtree() can work relative to open directories
290
# instead of resolving paths again.
291
_rmtree_use_dir_fd = (
292
{_os.chmod, _os.unlink, _os.lstat} <= _os.supports_dir_fd
293
and _os.chmod in _os.supports_fd
294
)
295
296
def _resetperms_fd(dir_fd, path):
297
# Same as _resetperms(), but for the directory referred to by dir_fd.
298
if dir_fd is None:
299
_resetperms(path)
300
return
301
_resetflags(path)
302
_os.chmod(dir_fd, 0o700)
303
304
try:
305
_nofollow_mode = _os.O_RDONLY | _os.O_NONBLOCK | _os.O_NOFOLLOW
306
except AttributeError:
307
_nofollow_mode = None
308
309
def _resetperms_at(name, dir_fd, path):
310
# Same as _resetperms(), but name is resolved relative to the directory
311
# file descriptor dir_fd. path is only used for os.chflags(), which
312
# doesn't support dir_fd or file descriptors.
313
if dir_fd is None:
314
_resetperms(path)
315
return
316
_resetflags(path)
317
if _os.chmod in _os.supports_follow_symlinks:
318
_os.chmod(name, 0o700, dir_fd=dir_fd, follow_symlinks=False)
319
else:
320
# dir_fd & follow_symlinks is not supported on this platform.
321
# Try chmod opening the file with O_NOFOLLOW.
322
if _nofollow_mode is not None:
323
try:
324
fd = _os.open(name, _nofollow_mode, dir_fd=dir_fd)
325
except OSError:
326
pass
327
else:
328
try:
329
_os.chmod(fd, 0o700)
330
finally:
331
_os.close(fd)
332
return
333
# If that did not work, we change by name, which is subject to a race
334
# condition.
335
stat = _os.lstat(name, dir_fd=dir_fd)
336
if not _stat.S_ISLNK(stat.st_mode):
337
_os.chmod(name, 0o700, dir_fd=dir_fd)
338
339
340
# User visible interfaces.
341
342
def gettempprefix():
343
"""The default prefix for temporary directories as string."""
344
return _os.fsdecode(template)
345
346
def gettempprefixb():
347
"""The default prefix for temporary directories as bytes."""
348
return _os.fsencode(template)
349
350
tempdir = None
351
352
def _gettempdir():
353
"""Private accessor for tempfile.tempdir."""
354
global tempdir
355
if tempdir is None:
356
_once_lock.acquire()
357
try:
358
if tempdir is None:
359
tempdir = _get_default_tempdir()
360
finally:
361
_once_lock.release()
362
return tempdir
363
364
def gettempdir():
365
"""Returns tempfile.tempdir as str."""
366
return _os.fsdecode(_gettempdir())
367
368
def gettempdirb():
369
"""Returns tempfile.tempdir as bytes."""
370
return _os.fsencode(_gettempdir())
371
372
def mkstemp(suffix=None, prefix=None, dir=None, text=False):
373
"""User-callable function to create and return a unique temporary
374
file. The return value is a pair (fd, name) where fd is the
375
file descriptor returned by os.open, and name is the filename.
376
377
If 'suffix' is not None, the file name will end with that suffix,
378
otherwise there will be no suffix.
379
380
If 'prefix' is not None, the file name will begin with that prefix,
381
otherwise a default prefix is used.
382
383
If 'dir' is not None, the file will be created in that directory,
384
otherwise a default directory is used.
385
386
If 'text' is specified and true, the file is opened in text
387
mode. Else (the default) the file is opened in binary mode.
388
389
If any of 'suffix', 'prefix' and 'dir' are not None, they must be the
390
same type. If they are bytes, the returned name will be bytes; str
391
otherwise.
392
393
The file is readable and writable only by the creating user ID.
394
If the operating system uses permission bits to indicate whether a
395
file is executable, the file is executable by no one. The file
396
descriptor is not inherited by children of this process.
397
398
Caller is responsible for deleting the file when done with it.
399
"""
400
401
prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
402
403
if text:
404
flags = _text_openflags
405
else:
406
flags = _bin_openflags
407
408
return _mkstemp_inner(dir, prefix, suffix, flags, output_type)
409
410
411
def mkdtemp(suffix=None, prefix=None, dir=None):
412
"""User-callable function to create and return a unique temporary
413
directory. The return value is the pathname of the directory.
414
415
Arguments are as for mkstemp, except that the 'text' argument is
416
not accepted.
417
418
The directory is readable, writable, and searchable only by the
419
creating user.
420
421
Caller is responsible for deleting the directory when done with it.
422
"""
423
424
prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
425
426
names = _get_candidate_names()
427
if output_type is bytes:
428
names = map(_os.fsencode, names)
429
430
for seq in range(TMP_MAX):
431
name = next(names)
432
file = _os.path.join(dir, prefix + name + suffix)
433
_sys.audit("tempfile.mkdtemp", file)
434
try:
435
_os.mkdir(file, 0o700)
436
except FileExistsError:
437
continue # try again
438
except PermissionError:
439
# On Posix, this exception is raised when the user has no
440
# write access to the parent directory.
441
# On Windows, it is also raised when a directory with
442
# the chosen name already exists, or if the parent directory
443
# is not a directory.
444
# We cannot distinguish between "directory-exists-error" and
445
# "access-denied-error".
446
if _os.name == 'nt' and _os.path.isdir(dir) and seq < TMP_MAX - 1:
447
continue
448
else:
449
raise
450
return _os.path.abspath(file)
451
452
raise FileExistsError(_errno.EEXIST,
453
"No usable temporary directory name found")
454
455
def mktemp(suffix="", prefix=template, dir=None):
456
"""User-callable function to return a unique temporary file name. The
457
file is not created.
458
459
Arguments are similar to mkstemp, except that the 'text' argument is
460
not accepted, and suffix=None, prefix=None and bytes file names are not
461
supported.
462
463
THIS FUNCTION IS UNSAFE AND SHOULD NOT BE USED. The file name may
464
refer to a file that did not exist at some point, but by the time
465
you get around to creating it, someone else may have beaten you to
466
the punch.
467
"""
468
469
## from warnings import warn as _warn
470
## _warn("mktemp is a potential security risk to your program",
471
## RuntimeWarning, stacklevel=2)
472
473
if dir is None:
474
dir = gettempdir()
475
476
names = _get_candidate_names()
477
for seq in range(TMP_MAX):
478
name = next(names)
479
file = _os.path.join(dir, prefix + name + suffix)
480
if not _exists(file):
481
return file
482
483
raise FileExistsError(_errno.EEXIST,
484
"No usable temporary filename found")
485
486
487
class _TemporaryFileCloser:
488
"""A separate object allowing proper closing of a temporary file's
489
underlying file object, without adding a __del__ method to the
490
temporary file."""
491
492
cleanup_called = False
493
close_called = False
494
495
def __init__(
496
self,
497
file,
498
name,
499
delete=True,
500
delete_on_close=True,
501
warn_message="Implicitly cleaning up unknown file",
502
):
503
self.file = file
504
self.name = name
505
self.delete = delete
506
self.delete_on_close = delete_on_close
507
self.warn_message = warn_message
508
509
def cleanup(self, windows=(_os.name == 'nt'), unlink=_os.unlink):
510
if not self.cleanup_called:
511
self.cleanup_called = True
512
try:
513
if not self.close_called:
514
self.close_called = True
515
self.file.close()
516
finally:
517
# Windows provides delete-on-close as a primitive, in which
518
# case the file was deleted by self.file.close().
519
if self.delete and not (windows and self.delete_on_close):
520
try:
521
unlink(self.name)
522
except FileNotFoundError:
523
pass
524
525
def close(self):
526
if not self.close_called:
527
self.close_called = True
528
try:
529
self.file.close()
530
finally:
531
if self.delete and self.delete_on_close:
532
self.cleanup()
533
534
def __del__(self):
535
close_called = self.close_called
536
self.cleanup()
537
if not close_called:
538
_warnings.warn(self.warn_message, ResourceWarning)
539
540
541
class _TemporaryFileWrapper:
542
"""Temporary file wrapper
543
544
This class provides a wrapper around files opened for
545
temporary use. In particular, it seeks to automatically
546
remove the file when it is no longer needed.
547
"""
548
549
def __init__(self, file, name, delete=True, delete_on_close=True):
550
self.file = file
551
self.name = name
552
self._closer = _TemporaryFileCloser(
553
file,
554
name,
555
delete,
556
delete_on_close,
557
warn_message=f"Implicitly cleaning up {self!r}",
558
)
559
560
def __repr__(self):
561
file = self.__dict__['file']
562
return f"<{type(self).__name__} {file=}>"
563
564
def __getattr__(self, name):
565
# Attribute lookups are delegated to the underlying file
566
# and cached for non-numeric results
567
# (i.e. methods are cached, closed and friends are not)
568
file = self.__dict__['file']
569
a = getattr(file, name)
570
if hasattr(a, '__call__'):
571
func = a
572
1
1
@_functools.wraps(func)
573
def func_wrapper(*args, **kwargs):
574
33
33
return func(*args, **kwargs)
575
# Avoid closing the file as long as the wrapper is alive,
576
# see issue #18879.
577
func_wrapper._closer = self._closer
578
a = func_wrapper
579
if not isinstance(a, int):
580
setattr(self, name, a)
581
return a
582
583
# The underlying __enter__ method returns the wrong object
584
# (self.file) so override it to return the wrapper
585
def __enter__(self):
586
self.file.__enter__()
587
return self
588
589
# Need to trap __exit__ as well to ensure the file gets
590
# deleted when used in a with statement
591
def __exit__(self, exc, value, tb):
592
result = self.file.__exit__(exc, value, tb)
593
self._closer.cleanup()
594
return result
595
596
def close(self):
597
"""
598
Close the temporary file, possibly deleting it.
599
"""
600
self._closer.close()
601
602
# iter() doesn't use __getattr__ to find the __iter__ method
603
def __iter__(self):
604
# Don't return iter(self.file), but yield from it to avoid closing
605
# file as long as it's being used as iterator (see issue #23700). We
606
# can't use 'yield from' here because iter(file) returns the file
607
# object itself, which has a close method, and thus the file would get
608
# closed when the generator is finalized, due to PEP380 semantics.
609
for line in self.file:
610
yield line
611
612
def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
613
newline=None, suffix=None, prefix=None,
614
dir=None, delete=True, *, errors=None,
615
delete_on_close=True):
616
"""Create and return a temporary file.
617
Arguments:
618
'prefix', 'suffix', 'dir' -- as for mkstemp.
619
'mode' -- the mode argument to io.open (default "w+b").
620
'buffering' -- the buffer size argument to io.open (default -1).
621
'encoding' -- the encoding argument to io.open (default None)
622
'newline' -- the newline argument to io.open (default None)
623
'delete' -- whether the file is automatically deleted (default True).
624
'delete_on_close' -- if 'delete', whether the file is deleted on close
625
(default True) or otherwise either on context manager exit
626
(if context manager was used) or on object finalization. .
627
'errors' -- the errors argument to io.open (default None)
628
The file is created as mkstemp() would do it.
629
630
Returns an object with a file-like interface; the name of the file
631
is accessible as its 'name' attribute. The file will be automatically
632
deleted when it is closed unless the 'delete' argument is set to False.
633
634
On POSIX, NamedTemporaryFiles cannot be automatically deleted if
635
the creating process is terminated abruptly with a SIGKILL signal.
636
Windows can delete the file even in this case.
637
"""
638
639
prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
640
641
flags = _bin_openflags
642
643
# Setting O_TEMPORARY in the flags causes the OS to delete
644
# the file when it is closed. This is only supported by Windows.
645
if _os.name == 'nt' and delete and delete_on_close:
646
flags |= _os.O_TEMPORARY
647
648
if "b" not in mode:
649
encoding = _io.text_encoding(encoding)
650
651
name = None
652
def opener(*args):
653
nonlocal name
654
1
26
fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
655
return fd
656
try:
657
1
27
file = _io.open(dir, mode, buffering=buffering,
658
newline=newline, encoding=encoding, errors=errors,
659
opener=opener)
660
try:
661
raw = getattr(file, 'buffer', file)
662
raw = getattr(raw, 'raw', raw)
663
raw.name = name
664
2
2
return _TemporaryFileWrapper(file, name, delete, delete_on_close)
665
except:
666
file.close()
667
raise
668
except:
669
if name is not None and not (
670
_os.name == 'nt' and delete and delete_on_close):
671
_os.unlink(name)
672
raise
673
674
if _os.name != 'posix' or _sys.platform == 'cygwin':
675
# On non-POSIX and Cygwin systems, assume that we cannot unlink a file
676
# while it is open.
677
TemporaryFile = NamedTemporaryFile
678
679
else:
680
# Is the O_TMPFILE flag available and does it work?
681
# The flag is set to False if os.open(dir, os.O_TMPFILE) raises an
682
# IsADirectoryError exception
683
_O_TMPFILE_WORKS = hasattr(_os, 'O_TMPFILE')
684
685
def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
686
newline=None, suffix=None, prefix=None,
687
dir=None, *, errors=None):
688
"""Create and return a temporary file.
689
Arguments:
690
'prefix', 'suffix', 'dir' -- as for mkstemp.
691
'mode' -- the mode argument to io.open (default "w+b").
692
'buffering' -- the buffer size argument to io.open (default -1).
693
'encoding' -- the encoding argument to io.open (default None)
694
'newline' -- the newline argument to io.open (default None)
695
'errors' -- the errors argument to io.open (default None)
696
The file is created as mkstemp() would do it.
697
698
Returns an object with a file-like interface. The file has no
699
name, and will cease to exist when it is closed.
700
"""
701
global _O_TMPFILE_WORKS
702
703
if "b" not in mode:
704
encoding = _io.text_encoding(encoding)
705
706
prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
707
708
flags = _bin_openflags
709
if _O_TMPFILE_WORKS:
710
fd = None
711
def opener(*args):
712
nonlocal fd
713
flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT & ~_os.O_EXCL
714
fd = _os.open(dir, flags2, 0o600)
715
return fd
716
try:
717
file = _io.open(dir, mode, buffering=buffering,
718
newline=newline, encoding=encoding,
719
errors=errors, opener=opener)
720
raw = getattr(file, 'buffer', file)
721
raw = getattr(raw, 'raw', raw)
722
raw.name = fd
723
return file
724
except IsADirectoryError:
725
# Linux kernel older than 3.11 ignores the O_TMPFILE flag:
726
# O_TMPFILE is read as O_DIRECTORY. Trying to open a directory
727
# with O_RDWR|O_DIRECTORY fails with IsADirectoryError, a
728
# directory cannot be open to write. Set flag to False to not
729
# try again.
730
_O_TMPFILE_WORKS = False
731
except OSError:
732
# The filesystem of the directory does not support O_TMPFILE.
733
# For example, OSError(95, 'Operation not supported').
734
#
735
# On Linux kernel older than 3.11, trying to open a regular
736
# file (or a symbolic link to a regular file) with O_TMPFILE
737
# fails with NotADirectoryError, because O_TMPFILE is read as
738
# O_DIRECTORY.
739
pass
740
# Fallback to _mkstemp_inner().
741
742
fd = None
743
def opener(*args):
744
nonlocal fd
745
fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
746
try:
747
_os.unlink(name)
748
except BaseException:
749
_os.close(fd)
750
raise
751
return fd
752
file = _io.open(dir, mode, buffering=buffering,
753
newline=newline, encoding=encoding, errors=errors,
754
opener=opener)
755
raw = getattr(file, 'buffer', file)
756
raw = getattr(raw, 'raw', raw)
757
raw.name = fd
758
return file
759
760
class SpooledTemporaryFile(_io.IOBase):
761
"""Temporary file wrapper, specialized to switch from BytesIO
762
or StringIO to a real file when it exceeds a certain size or
763
when a fileno is needed.
764
"""
765
_rolled = False
766
767
def __init__(self, max_size=0, mode='w+b', buffering=-1,
768
encoding=None, newline=None,
769
suffix=None, prefix=None, dir=None, *, errors=None):
770
if 'b' in mode:
771
self._file = _io.BytesIO()
772
else:
773
encoding = _io.text_encoding(encoding)
774
self._file = _io.TextIOWrapper(_io.BytesIO(),
775
encoding=encoding, errors=errors,
776
newline=newline)
777
self._max_size = max_size
778
self._rolled = False
779
self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,
780
'suffix': suffix, 'prefix': prefix,
781
'encoding': encoding, 'newline': newline,
782
'dir': dir, 'errors': errors}
783
784
__class_getitem__ = classmethod(_types.GenericAlias)
785
786
def _check(self, file):
787
if self._rolled: return
788
max_size = self._max_size
789
if max_size and file.tell() > max_size:
790
self.rollover()
791
792
def rollover(self):
793
if self._rolled: return
794
file = self._file
795
newfile = self._file = TemporaryFile(**self._TemporaryFileArgs)
796
del self._TemporaryFileArgs
797
798
pos = file.tell()
799
if hasattr(newfile, 'buffer'):
800
newfile.buffer.write(file.detach().getvalue())
801
else:
802
newfile.write(file.getvalue())
803
newfile.seek(pos, 0)
804
805
self._rolled = True
806
807
# The method caching trick from NamedTemporaryFile
808
# won't work here, because _file may change from a
809
# BytesIO/StringIO instance to a real file. So we list
810
# all the methods directly.
811
812
# Context management protocol
813
def __enter__(self):
814
if self._file.closed:
815
raise ValueError("Cannot enter context with closed file")
816
return self
817
818
def __exit__(self, exc, value, tb):
819
self._file.close()
820
821
# file protocol
822
def __iter__(self):
823
return self._file.__iter__()
824
825
def __del__(self):
826
if not self.closed:
827
_warnings.warn(
828
"Unclosed file {!r}".format(self),
829
ResourceWarning,
830
stacklevel=2,
831
source=self
832
)
833
self.close()
834
835
def close(self):
836
self._file.close()
837
838
@property
839
def closed(self):
840
return self._file.closed
841
842
@property
843
def encoding(self):
844
return self._file.encoding
845
846
@property
847
def errors(self):
848
return self._file.errors
849
850
def fileno(self):
851
self.rollover()
852
return self._file.fileno()
853
854
def flush(self):
855
self._file.flush()
856
857
def isatty(self):
858
return self._file.isatty()
859
860
@property
861
def mode(self):
862
try:
863
return self._file.mode
864
except AttributeError:
865
return self._TemporaryFileArgs['mode']
866
867
@property
868
def name(self):
869
try:
870
return self._file.name
871
except AttributeError:
872
return None
873
874
@property
875
def newlines(self):
876
return self._file.newlines
877
878
def readable(self):
879
return self._file.readable()
880
881
def read(self, *args):
882
1
1
return self._file.read(*args)
883
884
def read1(self, *args):
885
return self._file.read1(*args)
886
887
def readinto(self, b):
888
return self._file.readinto(b)
889
890
def readinto1(self, b):
891
return self._file.readinto1(b)
892
893
def readline(self, *args):
894
return self._file.readline(*args)
895
896
def readlines(self, *args):
897
return self._file.readlines(*args)
898
899
def seekable(self):
900
return self._file.seekable()
901
902
def seek(self, *args):
903
return self._file.seek(*args)
904
905
def tell(self):
906
return self._file.tell()
907
908
def truncate(self, size=None):
909
if size is None:
910
return self._file.truncate()
911
else:
912
if size > self._max_size:
913
self.rollover()
914
return self._file.truncate(size)
915
916
def writable(self):
917
return self._file.writable()
918
919
def write(self, s):
920
file = self._file
921
rv = file.write(s)
922
self._check(file)
923
return rv
924
925
def writelines(self, iterable):
926
if self._max_size == 0 or self._rolled:
927
return self._file.writelines(iterable)
928
929
it = iter(iterable)
930
for line in it:
931
self.write(line)
932
if self._rolled:
933
return self._file.writelines(it)
934
935
def detach(self):
936
return self._file.detach()
937
938
939
class TemporaryDirectory:
940
"""Create and return a temporary directory. This has the same
941
behavior as mkdtemp but can be used as a context manager. For
942
example:
943
944
with TemporaryDirectory() as tmpdir:
945
...
946
947
Upon exiting the context, the directory and everything contained
948
in it are removed (unless delete=False is passed or an exception
949
is raised during cleanup and ignore_cleanup_errors is not True).
950
951
Optional Arguments:
952
suffix - A str suffix for the directory name. (see mkdtemp)
953
prefix - A str prefix for the directory name. (see mkdtemp)
954
dir - A directory to create this temp dir in. (see mkdtemp)
955
ignore_cleanup_errors - False; ignore exceptions during cleanup?
956
delete - True; whether the directory is automatically deleted.
957
"""
958
959
def __init__(self, suffix=None, prefix=None, dir=None,
960
ignore_cleanup_errors=False, *, delete=True):
961
self.name = mkdtemp(suffix, prefix, dir)
962
self._ignore_cleanup_errors = ignore_cleanup_errors
963
self._delete = delete
964
self._finalizer = _weakref.finalize(
965
self, self._cleanup, self.name,
966
warn_message="Implicitly cleaning up {!r}".format(self),
967
ignore_errors=self._ignore_cleanup_errors, delete=self._delete)
968
969
@classmethod
970
def _rmtree(cls, name, ignore_errors=False, repeated=False, dir_fd=None,
971
fullname=None):
972
if fullname is None:
973
fullname = name
974
975
def onexc(func, path, exc, direntry=None, dir_fd=None):
976
# On DragonFly BSD, UF_NOUNLINK removal fails with EISDIR, not EPERM.
977
if isinstance(exc, (PermissionError, IsADirectoryError)):
978
if repeated and path == name:
979
if ignore_errors:
980
return
981
raise
982
983
# fullpath is path as seen from the working directory
984
fullpath = fullname + path[len(name):]
985
# base is path relative to dir_fd, the directory rmtree()
986
# reached it through, or the whole path when there is none
987
if dir_fd is None or not _rmtree_use_dir_fd:
988
base, dir_fd = path, None
989
elif direntry is None:
990
base = path
991
else:
992
base = direntry.name
993
994
try:
995
if path != name:
996
# The parent directory of path is the one referred to
997
# by dir_fd.
998
_resetperms_fd(dir_fd, _os.path.dirname(fullpath))
999
_resetperms_at(base, dir_fd, fullpath)
1000
1001
try:
1002
_os.unlink(base, dir_fd=dir_fd)
1003
except IsADirectoryError:
1004
cls._rmtree(base, ignore_errors=ignore_errors,
1005
repeated=(path == name),
1006
dir_fd=dir_fd, fullname=fullpath)
1007
except PermissionError:
1008
# The PermissionError handler was originally added for
1009
# FreeBSD in directories, but it seems that it is raised
1010
# on Windows too.
1011
# bpo-43153: Calling _rmtree again may
1012
# raise NotADirectoryError and mask the PermissionError.
1013
# So we must re-raise the current PermissionError if
1014
# path is not a directory.
1015
if (not _os.path.isdir(fullpath)
1016
or _os.path.isjunction(fullpath)):
1017
if ignore_errors:
1018
return
1019
raise
1020
cls._rmtree(base, ignore_errors=ignore_errors,
1021
repeated=(path == name),
1022
dir_fd=dir_fd, fullname=fullpath)
1023
except FileNotFoundError:
1024
pass
1025
except OSError:
1026
if ignore_errors:
1027
return
1028
raise
1029
elif isinstance(exc, FileNotFoundError):
1030
pass
1031
else:
1032
if not ignore_errors:
1033
raise
1034
1035
_shutil.rmtree(name, onexc=onexc, dir_fd=dir_fd, _onexc_kwargs=True)
1036
1037
@classmethod
1038
def _cleanup(cls, name, warn_message, ignore_errors=False, delete=True):
1039
if delete:
1040
cls._rmtree(name, ignore_errors=ignore_errors)
1041
_warnings.warn(warn_message, ResourceWarning)
1042
1043
def __repr__(self):
1044
return "<{} {!r}>".format(self.__class__.__name__, self.name)
1045
1046
def __enter__(self):
1047
return self.name
1048
1049
def __exit__(self, exc, value, tb):
1050
if self._delete:
1051
self.cleanup()
1052
1053
def cleanup(self):
1054
if self._finalizer.detach() or _os.path.exists(self.name):
1055
self._rmtree(self.name, ignore_errors=self._ignore_cleanup_errors)
1056
1057
__class_getitem__ = classmethod(_types.GenericAlias)