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