blob: 770f72c25295cbe756ef32b618682090e6b09b1b [file] [log] [blame]
Olivier Deprezf4ef2d02021-04-20 13:36:24 +02001"""Temporary files.
2
3This module provides generic, low- and high-level interfaces for
4creating temporary files and directories. All of the interfaces
5provided by this module can be used without fear of race conditions
6except for 'mktemp'. 'mktemp' is subject to race conditions and
7should not be used; it is provided for backward compatibility only.
8
9The default path names are returned as str. If you supply bytes as
10input, 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
17This 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
39import functools as _functools
40import warnings as _warnings
41import io as _io
42import os as _os
43import shutil as _shutil
44import errno as _errno
45from random import Random as _Random
46import sys as _sys
47import types as _types
48import weakref as _weakref
49import _thread
50_allocate_lock = _thread.allocate_lock
51
52_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
53if hasattr(_os, 'O_NOFOLLOW'):
54 _text_openflags |= _os.O_NOFOLLOW
55
56_bin_openflags = _text_openflags
57if hasattr(_os, 'O_BINARY'):
58 _bin_openflags |= _os.O_BINARY
59
60if hasattr(_os, 'TMP_MAX'):
61 TMP_MAX = _os.TMP_MAX
62else:
63 TMP_MAX = 10000
64
65# This variable _was_ unused for legacy reasons, see issue 10354.
66# But as of 3.5 we actually use it at runtime so changing it would
67# have a possibly desirable side effect... But we do not want to support
68# that as an API. It is undocumented on purpose. Do not depend on this.
69template = "tmp"
70
71# Internal routines.
72
73_once_lock = _allocate_lock()
74
75
76def _exists(fn):
77 try:
78 _os.lstat(fn)
79 except OSError:
80 return False
81 else:
82 return True
83
84
85def _infer_return_type(*args):
86 """Look at the type of all args and divine their implied return type."""
87 return_type = None
88 for arg in args:
89 if arg is None:
90 continue
91 if isinstance(arg, bytes):
92 if return_type is str:
93 raise TypeError("Can't mix bytes and non-bytes in "
94 "path components.")
95 return_type = bytes
96 else:
97 if return_type is bytes:
98 raise TypeError("Can't mix bytes and non-bytes in "
99 "path components.")
100 return_type = str
101 if return_type is None:
102 return str # tempfile APIs return a str by default.
103 return return_type
104
105
106def _sanitize_params(prefix, suffix, dir):
107 """Common parameter processing for most APIs in this module."""
108 output_type = _infer_return_type(prefix, suffix, dir)
109 if suffix is None:
110 suffix = output_type()
111 if prefix is None:
112 if output_type is str:
113 prefix = template
114 else:
115 prefix = _os.fsencode(template)
116 if dir is None:
117 if output_type is str:
118 dir = gettempdir()
119 else:
120 dir = gettempdirb()
121 return prefix, suffix, dir, output_type
122
123
124class _RandomNameSequence:
125 """An instance of _RandomNameSequence generates an endless
126 sequence of unpredictable strings which can safely be incorporated
127 into file names. Each string is eight characters long. Multiple
128 threads can safely use the same instance at the same time.
129
130 _RandomNameSequence is an iterator."""
131
132 characters = "abcdefghijklmnopqrstuvwxyz0123456789_"
133
134 @property
135 def rng(self):
136 cur_pid = _os.getpid()
137 if cur_pid != getattr(self, '_rng_pid', None):
138 self._rng = _Random()
139 self._rng_pid = cur_pid
140 return self._rng
141
142 def __iter__(self):
143 return self
144
145 def __next__(self):
146 c = self.characters
147 choose = self.rng.choice
148 letters = [choose(c) for dummy in range(8)]
149 return ''.join(letters)
150
151def _candidate_tempdir_list():
152 """Generate a list of candidate temporary directories which
153 _get_default_tempdir will try."""
154
155 dirlist = []
156
157 # First, try the environment.
158 for envname in 'TMPDIR', 'TEMP', 'TMP':
159 dirname = _os.getenv(envname)
160 if dirname: dirlist.append(dirname)
161
162 # Failing that, try OS-specific locations.
163 if _os.name == 'nt':
164 dirlist.extend([ _os.path.expanduser(r'~\AppData\Local\Temp'),
165 _os.path.expandvars(r'%SYSTEMROOT%\Temp'),
166 r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
167 else:
168 dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
169
170 # As a last resort, the current directory.
171 try:
172 dirlist.append(_os.getcwd())
173 except (AttributeError, OSError):
174 dirlist.append(_os.curdir)
175
176 return dirlist
177
178def _get_default_tempdir():
179 """Calculate the default directory to use for temporary files.
180 This routine should be called exactly once.
181
182 We determine whether or not a candidate temp dir is usable by
183 trying to create and write to a file in that directory. If this
184 is successful, the test file is deleted. To prevent denial of
185 service, the name of the test file must be randomized."""
186
187 namer = _RandomNameSequence()
188 dirlist = _candidate_tempdir_list()
189
190 for dir in dirlist:
191 if dir != _os.curdir:
192 dir = _os.path.abspath(dir)
193 # Try only a few names per directory.
194 for seq in range(100):
195 name = next(namer)
196 filename = _os.path.join(dir, name)
197 try:
198 fd = _os.open(filename, _bin_openflags, 0o600)
199 try:
200 try:
201 with _io.open(fd, 'wb', closefd=False) as fp:
202 fp.write(b'blat')
203 finally:
204 _os.close(fd)
205 finally:
206 _os.unlink(filename)
207 return dir
208 except FileExistsError:
209 pass
210 except PermissionError:
211 # This exception is thrown when a directory with the chosen name
212 # already exists on windows.
213 if (_os.name == 'nt' and _os.path.isdir(dir) and
214 _os.access(dir, _os.W_OK)):
215 continue
216 break # no point trying more names in this directory
217 except OSError:
218 break # no point trying more names in this directory
219 raise FileNotFoundError(_errno.ENOENT,
220 "No usable temporary directory found in %s" %
221 dirlist)
222
223_name_sequence = None
224
225def _get_candidate_names():
226 """Common setup sequence for all user-callable interfaces."""
227
228 global _name_sequence
229 if _name_sequence is None:
230 _once_lock.acquire()
231 try:
232 if _name_sequence is None:
233 _name_sequence = _RandomNameSequence()
234 finally:
235 _once_lock.release()
236 return _name_sequence
237
238
239def _mkstemp_inner(dir, pre, suf, flags, output_type):
240 """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
241
242 names = _get_candidate_names()
243 if output_type is bytes:
244 names = map(_os.fsencode, names)
245
246 for seq in range(TMP_MAX):
247 name = next(names)
248 file = _os.path.join(dir, pre + name + suf)
249 _sys.audit("tempfile.mkstemp", file)
250 try:
251 fd = _os.open(file, flags, 0o600)
252 except FileExistsError:
253 continue # try again
254 except PermissionError:
255 # This exception is thrown when a directory with the chosen name
256 # already exists on windows.
257 if (_os.name == 'nt' and _os.path.isdir(dir) and
258 _os.access(dir, _os.W_OK)):
259 continue
260 else:
261 raise
262 return (fd, _os.path.abspath(file))
263
264 raise FileExistsError(_errno.EEXIST,
265 "No usable temporary file name found")
266
267
268# User visible interfaces.
269
270def gettempprefix():
271 """The default prefix for temporary directories."""
272 return template
273
274def gettempprefixb():
275 """The default prefix for temporary directories as bytes."""
276 return _os.fsencode(gettempprefix())
277
278tempdir = None
279
280def gettempdir():
281 """Accessor for tempfile.tempdir."""
282 global tempdir
283 if tempdir is None:
284 _once_lock.acquire()
285 try:
286 if tempdir is None:
287 tempdir = _get_default_tempdir()
288 finally:
289 _once_lock.release()
290 return tempdir
291
292def gettempdirb():
293 """A bytes version of tempfile.gettempdir()."""
294 return _os.fsencode(gettempdir())
295
296def mkstemp(suffix=None, prefix=None, dir=None, text=False):
297 """User-callable function to create and return a unique temporary
298 file. The return value is a pair (fd, name) where fd is the
299 file descriptor returned by os.open, and name is the filename.
300
301 If 'suffix' is not None, the file name will end with that suffix,
302 otherwise there will be no suffix.
303
304 If 'prefix' is not None, the file name will begin with that prefix,
305 otherwise a default prefix is used.
306
307 If 'dir' is not None, the file will be created in that directory,
308 otherwise a default directory is used.
309
310 If 'text' is specified and true, the file is opened in text
311 mode. Else (the default) the file is opened in binary mode.
312
313 If any of 'suffix', 'prefix' and 'dir' are not None, they must be the
314 same type. If they are bytes, the returned name will be bytes; str
315 otherwise.
316
317 The file is readable and writable only by the creating user ID.
318 If the operating system uses permission bits to indicate whether a
319 file is executable, the file is executable by no one. The file
320 descriptor is not inherited by children of this process.
321
322 Caller is responsible for deleting the file when done with it.
323 """
324
325 prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
326
327 if text:
328 flags = _text_openflags
329 else:
330 flags = _bin_openflags
331
332 return _mkstemp_inner(dir, prefix, suffix, flags, output_type)
333
334
335def mkdtemp(suffix=None, prefix=None, dir=None):
336 """User-callable function to create and return a unique temporary
337 directory. The return value is the pathname of the directory.
338
339 Arguments are as for mkstemp, except that the 'text' argument is
340 not accepted.
341
342 The directory is readable, writable, and searchable only by the
343 creating user.
344
345 Caller is responsible for deleting the directory when done with it.
346 """
347
348 prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
349
350 names = _get_candidate_names()
351 if output_type is bytes:
352 names = map(_os.fsencode, names)
353
354 for seq in range(TMP_MAX):
355 name = next(names)
356 file = _os.path.join(dir, prefix + name + suffix)
357 _sys.audit("tempfile.mkdtemp", file)
358 try:
359 _os.mkdir(file, 0o700)
360 except FileExistsError:
361 continue # try again
362 except PermissionError:
363 # This exception is thrown when a directory with the chosen name
364 # already exists on windows.
365 if (_os.name == 'nt' and _os.path.isdir(dir) and
366 _os.access(dir, _os.W_OK)):
367 continue
368 else:
369 raise
370 return file
371
372 raise FileExistsError(_errno.EEXIST,
373 "No usable temporary directory name found")
374
375def mktemp(suffix="", prefix=template, dir=None):
376 """User-callable function to return a unique temporary file name. The
377 file is not created.
378
379 Arguments are similar to mkstemp, except that the 'text' argument is
380 not accepted, and suffix=None, prefix=None and bytes file names are not
381 supported.
382
383 THIS FUNCTION IS UNSAFE AND SHOULD NOT BE USED. The file name may
384 refer to a file that did not exist at some point, but by the time
385 you get around to creating it, someone else may have beaten you to
386 the punch.
387 """
388
389## from warnings import warn as _warn
390## _warn("mktemp is a potential security risk to your program",
391## RuntimeWarning, stacklevel=2)
392
393 if dir is None:
394 dir = gettempdir()
395
396 names = _get_candidate_names()
397 for seq in range(TMP_MAX):
398 name = next(names)
399 file = _os.path.join(dir, prefix + name + suffix)
400 if not _exists(file):
401 return file
402
403 raise FileExistsError(_errno.EEXIST,
404 "No usable temporary filename found")
405
406
407class _TemporaryFileCloser:
408 """A separate object allowing proper closing of a temporary file's
409 underlying file object, without adding a __del__ method to the
410 temporary file."""
411
412 file = None # Set here since __del__ checks it
413 close_called = False
414
415 def __init__(self, file, name, delete=True):
416 self.file = file
417 self.name = name
418 self.delete = delete
419
420 # NT provides delete-on-close as a primitive, so we don't need
421 # the wrapper to do anything special. We still use it so that
422 # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
423 if _os.name != 'nt':
424 # Cache the unlinker so we don't get spurious errors at
425 # shutdown when the module-level "os" is None'd out. Note
426 # that this must be referenced as self.unlink, because the
427 # name TemporaryFileWrapper may also get None'd out before
428 # __del__ is called.
429
430 def close(self, unlink=_os.unlink):
431 if not self.close_called and self.file is not None:
432 self.close_called = True
433 try:
434 self.file.close()
435 finally:
436 if self.delete:
437 unlink(self.name)
438
439 # Need to ensure the file is deleted on __del__
440 def __del__(self):
441 self.close()
442
443 else:
444 def close(self):
445 if not self.close_called:
446 self.close_called = True
447 self.file.close()
448
449
450class _TemporaryFileWrapper:
451 """Temporary file wrapper
452
453 This class provides a wrapper around files opened for
454 temporary use. In particular, it seeks to automatically
455 remove the file when it is no longer needed.
456 """
457
458 def __init__(self, file, name, delete=True):
459 self.file = file
460 self.name = name
461 self.delete = delete
462 self._closer = _TemporaryFileCloser(file, name, delete)
463
464 def __getattr__(self, name):
465 # Attribute lookups are delegated to the underlying file
466 # and cached for non-numeric results
467 # (i.e. methods are cached, closed and friends are not)
468 file = self.__dict__['file']
469 a = getattr(file, name)
470 if hasattr(a, '__call__'):
471 func = a
472 @_functools.wraps(func)
473 def func_wrapper(*args, **kwargs):
474 return func(*args, **kwargs)
475 # Avoid closing the file as long as the wrapper is alive,
476 # see issue #18879.
477 func_wrapper._closer = self._closer
478 a = func_wrapper
479 if not isinstance(a, int):
480 setattr(self, name, a)
481 return a
482
483 # The underlying __enter__ method returns the wrong object
484 # (self.file) so override it to return the wrapper
485 def __enter__(self):
486 self.file.__enter__()
487 return self
488
489 # Need to trap __exit__ as well to ensure the file gets
490 # deleted when used in a with statement
491 def __exit__(self, exc, value, tb):
492 result = self.file.__exit__(exc, value, tb)
493 self.close()
494 return result
495
496 def close(self):
497 """
498 Close the temporary file, possibly deleting it.
499 """
500 self._closer.close()
501
502 # iter() doesn't use __getattr__ to find the __iter__ method
503 def __iter__(self):
504 # Don't return iter(self.file), but yield from it to avoid closing
505 # file as long as it's being used as iterator (see issue #23700). We
506 # can't use 'yield from' here because iter(file) returns the file
507 # object itself, which has a close method, and thus the file would get
508 # closed when the generator is finalized, due to PEP380 semantics.
509 for line in self.file:
510 yield line
511
512
513def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
514 newline=None, suffix=None, prefix=None,
515 dir=None, delete=True, *, errors=None):
516 """Create and return a temporary file.
517 Arguments:
518 'prefix', 'suffix', 'dir' -- as for mkstemp.
519 'mode' -- the mode argument to io.open (default "w+b").
520 'buffering' -- the buffer size argument to io.open (default -1).
521 'encoding' -- the encoding argument to io.open (default None)
522 'newline' -- the newline argument to io.open (default None)
523 'delete' -- whether the file is deleted on close (default True).
524 'errors' -- the errors argument to io.open (default None)
525 The file is created as mkstemp() would do it.
526
527 Returns an object with a file-like interface; the name of the file
528 is accessible as its 'name' attribute. The file will be automatically
529 deleted when it is closed unless the 'delete' argument is set to False.
530 """
531
532 prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
533
534 flags = _bin_openflags
535
536 # Setting O_TEMPORARY in the flags causes the OS to delete
537 # the file when it is closed. This is only supported by Windows.
538 if _os.name == 'nt' and delete:
539 flags |= _os.O_TEMPORARY
540
541 (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
542 try:
543 file = _io.open(fd, mode, buffering=buffering,
544 newline=newline, encoding=encoding, errors=errors)
545
546 return _TemporaryFileWrapper(file, name, delete)
547 except BaseException:
548 _os.unlink(name)
549 _os.close(fd)
550 raise
551
552if _os.name != 'posix' or _sys.platform == 'cygwin':
553 # On non-POSIX and Cygwin systems, assume that we cannot unlink a file
554 # while it is open.
555 TemporaryFile = NamedTemporaryFile
556
557else:
558 # Is the O_TMPFILE flag available and does it work?
559 # The flag is set to False if os.open(dir, os.O_TMPFILE) raises an
560 # IsADirectoryError exception
561 _O_TMPFILE_WORKS = hasattr(_os, 'O_TMPFILE')
562
563 def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
564 newline=None, suffix=None, prefix=None,
565 dir=None, *, errors=None):
566 """Create and return a temporary file.
567 Arguments:
568 'prefix', 'suffix', 'dir' -- as for mkstemp.
569 'mode' -- the mode argument to io.open (default "w+b").
570 'buffering' -- the buffer size argument to io.open (default -1).
571 'encoding' -- the encoding argument to io.open (default None)
572 'newline' -- the newline argument to io.open (default None)
573 'errors' -- the errors argument to io.open (default None)
574 The file is created as mkstemp() would do it.
575
576 Returns an object with a file-like interface. The file has no
577 name, and will cease to exist when it is closed.
578 """
579 global _O_TMPFILE_WORKS
580
581 prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
582
583 flags = _bin_openflags
584 if _O_TMPFILE_WORKS:
585 try:
586 flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT
587 fd = _os.open(dir, flags2, 0o600)
588 except IsADirectoryError:
589 # Linux kernel older than 3.11 ignores the O_TMPFILE flag:
590 # O_TMPFILE is read as O_DIRECTORY. Trying to open a directory
591 # with O_RDWR|O_DIRECTORY fails with IsADirectoryError, a
592 # directory cannot be open to write. Set flag to False to not
593 # try again.
594 _O_TMPFILE_WORKS = False
595 except OSError:
596 # The filesystem of the directory does not support O_TMPFILE.
597 # For example, OSError(95, 'Operation not supported').
598 #
599 # On Linux kernel older than 3.11, trying to open a regular
600 # file (or a symbolic link to a regular file) with O_TMPFILE
601 # fails with NotADirectoryError, because O_TMPFILE is read as
602 # O_DIRECTORY.
603 pass
604 else:
605 try:
606 return _io.open(fd, mode, buffering=buffering,
607 newline=newline, encoding=encoding,
608 errors=errors)
609 except:
610 _os.close(fd)
611 raise
612 # Fallback to _mkstemp_inner().
613
614 (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
615 try:
616 _os.unlink(name)
617 return _io.open(fd, mode, buffering=buffering,
618 newline=newline, encoding=encoding, errors=errors)
619 except:
620 _os.close(fd)
621 raise
622
623class SpooledTemporaryFile:
624 """Temporary file wrapper, specialized to switch from BytesIO
625 or StringIO to a real file when it exceeds a certain size or
626 when a fileno is needed.
627 """
628 _rolled = False
629
630 def __init__(self, max_size=0, mode='w+b', buffering=-1,
631 encoding=None, newline=None,
632 suffix=None, prefix=None, dir=None, *, errors=None):
633 if 'b' in mode:
634 self._file = _io.BytesIO()
635 else:
636 self._file = _io.TextIOWrapper(_io.BytesIO(),
637 encoding=encoding, errors=errors,
638 newline=newline)
639 self._max_size = max_size
640 self._rolled = False
641 self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,
642 'suffix': suffix, 'prefix': prefix,
643 'encoding': encoding, 'newline': newline,
644 'dir': dir, 'errors': errors}
645
646 __class_getitem__ = classmethod(_types.GenericAlias)
647
648 def _check(self, file):
649 if self._rolled: return
650 max_size = self._max_size
651 if max_size and file.tell() > max_size:
652 self.rollover()
653
654 def rollover(self):
655 if self._rolled: return
656 file = self._file
657 newfile = self._file = TemporaryFile(**self._TemporaryFileArgs)
658 del self._TemporaryFileArgs
659
660 pos = file.tell()
661 if hasattr(newfile, 'buffer'):
662 newfile.buffer.write(file.detach().getvalue())
663 else:
664 newfile.write(file.getvalue())
665 newfile.seek(pos, 0)
666
667 self._rolled = True
668
669 # The method caching trick from NamedTemporaryFile
670 # won't work here, because _file may change from a
671 # BytesIO/StringIO instance to a real file. So we list
672 # all the methods directly.
673
674 # Context management protocol
675 def __enter__(self):
676 if self._file.closed:
677 raise ValueError("Cannot enter context with closed file")
678 return self
679
680 def __exit__(self, exc, value, tb):
681 self._file.close()
682
683 # file protocol
684 def __iter__(self):
685 return self._file.__iter__()
686
687 def close(self):
688 self._file.close()
689
690 @property
691 def closed(self):
692 return self._file.closed
693
694 @property
695 def encoding(self):
696 return self._file.encoding
697
698 @property
699 def errors(self):
700 return self._file.errors
701
702 def fileno(self):
703 self.rollover()
704 return self._file.fileno()
705
706 def flush(self):
707 self._file.flush()
708
709 def isatty(self):
710 return self._file.isatty()
711
712 @property
713 def mode(self):
714 try:
715 return self._file.mode
716 except AttributeError:
717 return self._TemporaryFileArgs['mode']
718
719 @property
720 def name(self):
721 try:
722 return self._file.name
723 except AttributeError:
724 return None
725
726 @property
727 def newlines(self):
728 return self._file.newlines
729
730 def read(self, *args):
731 return self._file.read(*args)
732
733 def readline(self, *args):
734 return self._file.readline(*args)
735
736 def readlines(self, *args):
737 return self._file.readlines(*args)
738
739 def seek(self, *args):
740 return self._file.seek(*args)
741
742 def tell(self):
743 return self._file.tell()
744
745 def truncate(self, size=None):
746 if size is None:
747 self._file.truncate()
748 else:
749 if size > self._max_size:
750 self.rollover()
751 self._file.truncate(size)
752
753 def write(self, s):
754 file = self._file
755 rv = file.write(s)
756 self._check(file)
757 return rv
758
759 def writelines(self, iterable):
760 file = self._file
761 rv = file.writelines(iterable)
762 self._check(file)
763 return rv
764
765
766class TemporaryDirectory(object):
767 """Create and return a temporary directory. This has the same
768 behavior as mkdtemp but can be used as a context manager. For
769 example:
770
771 with TemporaryDirectory() as tmpdir:
772 ...
773
774 Upon exiting the context, the directory and everything contained
775 in it are removed.
776 """
777
778 def __init__(self, suffix=None, prefix=None, dir=None):
779 self.name = mkdtemp(suffix, prefix, dir)
780 self._finalizer = _weakref.finalize(
781 self, self._cleanup, self.name,
782 warn_message="Implicitly cleaning up {!r}".format(self))
783
784 @classmethod
785 def _rmtree(cls, name):
786 def onerror(func, path, exc_info):
787 if issubclass(exc_info[0], PermissionError):
788 def resetperms(path):
789 try:
790 _os.chflags(path, 0)
791 except AttributeError:
792 pass
793 _os.chmod(path, 0o700)
794
795 try:
796 if path != name:
797 resetperms(_os.path.dirname(path))
798 resetperms(path)
799
800 try:
801 _os.unlink(path)
802 # PermissionError is raised on FreeBSD for directories
803 except (IsADirectoryError, PermissionError):
804 cls._rmtree(path)
805 except FileNotFoundError:
806 pass
807 elif issubclass(exc_info[0], FileNotFoundError):
808 pass
809 else:
810 raise
811
812 _shutil.rmtree(name, onerror=onerror)
813
814 @classmethod
815 def _cleanup(cls, name, warn_message):
816 cls._rmtree(name)
817 _warnings.warn(warn_message, ResourceWarning)
818
819 def __repr__(self):
820 return "<{} {!r}>".format(self.__class__.__name__, self.name)
821
822 def __enter__(self):
823 return self.name
824
825 def __exit__(self, exc, value, tb):
826 self.cleanup()
827
828 def cleanup(self):
829 if self._finalizer.detach():
830 self._rmtree(self.name)
831
832 __class_getitem__ = classmethod(_types.GenericAlias)