Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
tempfile.py978 linesDownload Raw Back to Lib
1"""Temporary files.2 3This module provides generic, low- and high-level interfaces for4creating temporary files and directories.  All of the interfaces5provided by this module can be used without fear of race conditions6except for 'mktemp'.  'mktemp' is subject to race conditions and7should not be used; it is provided for backward compatibility only.8 9The default path names are returned as str.  If you supply bytes as10input, 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 before20             giving up.21  tempdir  - If this is set to a string before the first use of22             any routine from this module, it will be considered as23             another candidate location to store temporary files.24"""25 26__all__ = [27    "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces28    "SpooledTemporaryFile", "TemporaryDirectory",29    "mkstemp", "mkdtemp",                  # low level safe interfaces30    "mktemp",                              # deprecated unsafe interface31    "TMP_MAX", "gettempprefix",            # constants32    "tempdir", "gettempdir",33    "gettempprefixb", "gettempdirb",34   ]35 36 37# Imports.38 39import functools as _functools40import warnings as _warnings41import io as _io42import os as _os43import shutil as _shutil44import errno as _errno45from random import Random as _Random46import sys as _sys47import types as _types48import weakref as _weakref49import _thread50_allocate_lock = _thread.allocate_lock51 52_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL53if hasattr(_os, 'O_NOFOLLOW'):54    _text_openflags |= _os.O_NOFOLLOW55 56_bin_openflags = _text_openflags57if hasattr(_os, 'O_BINARY'):58    _bin_openflags |= _os.O_BINARY59 60# This is more than enough.61# Each name contains over 40 random bits.  Even with a million temporary62# files, the chance of a conflict is less than 1 in a million, and with63# 20 attempts, it is less than 1e-120.64TMP_MAX = 2065 66# This variable _was_ unused for legacy reasons, see issue 10354.67# But as of 3.5 we actually use it at runtime so changing it would68# have a possibly desirable side effect...  But we do not want to support69# that as an API.  It is undocumented on purpose.  Do not depend on this.70template = "tmp"71 72# Internal routines.73 74_once_lock = _allocate_lock()75 76 77def _exists(fn):78    try:79        _os.lstat(fn)80    except OSError:81        return False82    else:83        return True84 85 86def _infer_return_type(*args):87    """Look at the type of all args and divine their implied return type."""88    return_type = None89    for arg in args:90        if arg is None:91            continue92 93        if isinstance(arg, _os.PathLike):94            arg = _os.fspath(arg)95 96        if isinstance(arg, bytes):97            if return_type is str:98                raise TypeError("Can't mix bytes and non-bytes in "99                                "path components.")100            return_type = bytes101        else:102            if return_type is bytes:103                raise TypeError("Can't mix bytes and non-bytes in "104                                "path components.")105            return_type = str106    if return_type is None:107        if tempdir is None or isinstance(tempdir, str):108            return str  # tempfile APIs return a str by default.109        else:110            # we could check for bytes but it'll fail later on anyway111            return bytes112    return return_type113 114 115def _sanitize_params(prefix, suffix, dir):116    """Common parameter processing for most APIs in this module."""117    output_type = _infer_return_type(prefix, suffix, dir)118    if suffix is None:119        suffix = output_type()120    if prefix is None:121        if output_type is str:122            prefix = template123        else:124            prefix = _os.fsencode(template)125    if dir is None:126        if output_type is str:127            dir = gettempdir()128        else:129            dir = gettempdirb()130    return prefix, suffix, dir, output_type131 132 133class _RandomNameSequence:134    """An instance of _RandomNameSequence generates an endless135    sequence of unpredictable strings which can safely be incorporated136    into file names.  Each string is eight characters long.  Multiple137    threads can safely use the same instance at the same time.138 139    _RandomNameSequence is an iterator."""140 141    characters = "abcdefghijklmnopqrstuvwxyz0123456789_"142 143    @property144    def rng(self):145        cur_pid = _os.getpid()146        if cur_pid != getattr(self, '_rng_pid', None):147            self._rng = _Random()148            self._rng_pid = cur_pid149        return self._rng150 151    def __iter__(self):152        return self153 154    def __next__(self):155        return ''.join(self.rng.choices(self.characters, k=8))156 157def _candidate_tempdir_list():158    """Generate a list of candidate temporary directories which159    _get_default_tempdir will try."""160 161    dirlist = []162 163    # First, try the environment.164    for envname in 'TMPDIR', 'TEMP', 'TMP':165        dirname = _os.getenv(envname)166        if dirname: dirlist.append(dirname)167 168    # Failing that, try OS-specific locations.169    if _os.name == 'nt':170        dirlist.extend([ _os.path.expanduser(r'~\AppData\Local\Temp'),171                         _os.path.expandvars(r'%SYSTEMROOT%\Temp'),172                         r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])173    else:174        dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])175 176    # As a last resort, the current directory.177    try:178        dirlist.append(_os.getcwd())179    except (AttributeError, OSError):180        dirlist.append(_os.curdir)181 182    return dirlist183 184def _get_default_tempdir(dirlist=None):185    """Calculate the default directory to use for temporary files.186    This routine should be called exactly once.187 188    We determine whether or not a candidate temp dir is usable by189    trying to create and write to a file in that directory.  If this190    is successful, the test file is deleted.  To prevent denial of191    service, the name of the test file must be randomized."""192 193    namer = _RandomNameSequence()194    if dirlist is None:195        dirlist = _candidate_tempdir_list()196 197    for dir in dirlist:198        if dir != _os.curdir:199            dir = _os.path.abspath(dir)200        for seq in range(TMP_MAX):201            name = next(namer)202            filename = _os.path.join(dir, name)203            try:204                fd = _os.open(filename, _bin_openflags, 0o600)205                try:206                    try:207                        _os.write(fd, b'blat')208                    finally:209                        _os.close(fd)210                finally:211                    _os.unlink(filename)212                return dir213            except FileExistsError:214                pass215            except PermissionError:216                # See the comment in mkdtemp().217                if _os.name == 'nt' and _os.path.isdir(dir):218                    continue219                break   # no point trying more names in this directory220            except OSError:221                break   # no point trying more names in this directory222    raise FileNotFoundError(_errno.ENOENT,223                            "No usable temporary directory found in %s" %224                            dirlist)225 226_name_sequence = None227 228def _get_candidate_names():229    """Common setup sequence for all user-callable interfaces."""230 231    global _name_sequence232    if _name_sequence is None:233        _once_lock.acquire()234        try:235            if _name_sequence is None:236                _name_sequence = _RandomNameSequence()237        finally:238            _once_lock.release()239    return _name_sequence240 241 242def _mkstemp_inner(dir, pre, suf, flags, output_type):243    """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""244 245    dir = _os.path.abspath(dir)246    names = _get_candidate_names()247    if output_type is bytes:248        names = map(_os.fsencode, names)249 250    for seq in range(TMP_MAX):251        name = next(names)252        file = _os.path.join(dir, pre + name + suf)253        _sys.audit("tempfile.mkstemp", file)254        try:255            fd = _os.open(file, flags, 0o600)256        except FileExistsError:257            continue    # try again258        except PermissionError:259            # See the comment in mkdtemp().260            if _os.name == 'nt' and _os.path.isdir(dir) and seq < TMP_MAX - 1:261                continue262            else:263                raise264        return fd, file265 266    raise FileExistsError(_errno.EEXIST,267                          "No usable temporary file name found")268 269def _dont_follow_symlinks(func, path, *args):270    # Pass follow_symlinks=False, unless not supported on this platform.271    if func in _os.supports_follow_symlinks:272        func(path, *args, follow_symlinks=False)273    elif not _os.path.islink(path):274        func(path, *args)275 276def _resetperms(path):277    try:278        chflags = _os.chflags279    except AttributeError:280        pass281    else:282        _dont_follow_symlinks(chflags, path, 0)283    _dont_follow_symlinks(_os.chmod, path, 0o700)284 285 286# User visible interfaces.287 288def gettempprefix():289    """The default prefix for temporary directories as string."""290    return _os.fsdecode(template)291 292def gettempprefixb():293    """The default prefix for temporary directories as bytes."""294    return _os.fsencode(template)295 296tempdir = None297 298def _gettempdir():299    """Private accessor for tempfile.tempdir."""300    global tempdir301    if tempdir is None:302        _once_lock.acquire()303        try:304            if tempdir is None:305                tempdir = _get_default_tempdir()306        finally:307            _once_lock.release()308    return tempdir309 310def gettempdir():311    """Returns tempfile.tempdir as str."""312    return _os.fsdecode(_gettempdir())313 314def gettempdirb():315    """Returns tempfile.tempdir as bytes."""316    return _os.fsencode(_gettempdir())317 318def mkstemp(suffix=None, prefix=None, dir=None, text=False):319    """User-callable function to create and return a unique temporary320    file.  The return value is a pair (fd, name) where fd is the321    file descriptor returned by os.open, and name is the filename.322 323    If 'suffix' is not None, the file name will end with that suffix,324    otherwise there will be no suffix.325 326    If 'prefix' is not None, the file name will begin with that prefix,327    otherwise a default prefix is used.328 329    If 'dir' is not None, the file will be created in that directory,330    otherwise a default directory is used.331 332    If 'text' is specified and true, the file is opened in text333    mode.  Else (the default) the file is opened in binary mode.334 335    If any of 'suffix', 'prefix' and 'dir' are not None, they must be the336    same type.  If they are bytes, the returned name will be bytes; str337    otherwise.338 339    The file is readable and writable only by the creating user ID.340    If the operating system uses permission bits to indicate whether a341    file is executable, the file is executable by no one. The file342    descriptor is not inherited by children of this process.343 344    Caller is responsible for deleting the file when done with it.345    """346 347    prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)348 349    if text:350        flags = _text_openflags351    else:352        flags = _bin_openflags353 354    return _mkstemp_inner(dir, prefix, suffix, flags, output_type)355 356 357def mkdtemp(suffix=None, prefix=None, dir=None):358    """User-callable function to create and return a unique temporary359    directory.  The return value is the pathname of the directory.360 361    Arguments are as for mkstemp, except that the 'text' argument is362    not accepted.363 364    The directory is readable, writable, and searchable only by the365    creating user.366 367    Caller is responsible for deleting the directory when done with it.368    """369 370    prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)371 372    names = _get_candidate_names()373    if output_type is bytes:374        names = map(_os.fsencode, names)375 376    for seq in range(TMP_MAX):377        name = next(names)378        file = _os.path.join(dir, prefix + name + suffix)379        _sys.audit("tempfile.mkdtemp", file)380        try:381            _os.mkdir(file, 0o700)382        except FileExistsError:383            continue    # try again384        except PermissionError:385            # On Posix, this exception is raised when the user has no386            # write access to the parent directory.387            # On Windows, it is also raised when a directory with388            # the chosen name already exists, or if the parent directory389            # is not a directory.390            # We cannot distinguish between "directory-exists-error" and391            # "access-denied-error".392            if _os.name == 'nt' and _os.path.isdir(dir) and seq < TMP_MAX - 1:393                continue394            else:395                raise396        return _os.path.abspath(file)397 398    raise FileExistsError(_errno.EEXIST,399                          "No usable temporary directory name found")400 401def mktemp(suffix="", prefix=template, dir=None):402    """User-callable function to return a unique temporary file name.  The403    file is not created.404 405    Arguments are similar to mkstemp, except that the 'text' argument is406    not accepted, and suffix=None, prefix=None and bytes file names are not407    supported.408 409    THIS FUNCTION IS UNSAFE AND SHOULD NOT BE USED.  The file name may410    refer to a file that did not exist at some point, but by the time411    you get around to creating it, someone else may have beaten you to412    the punch.413    """414 415##    from warnings import warn as _warn416##    _warn("mktemp is a potential security risk to your program",417##          RuntimeWarning, stacklevel=2)418 419    if dir is None:420        dir = gettempdir()421 422    names = _get_candidate_names()423    for seq in range(TMP_MAX):424        name = next(names)425        file = _os.path.join(dir, prefix + name + suffix)426        if not _exists(file):427            return file428 429    raise FileExistsError(_errno.EEXIST,430                          "No usable temporary filename found")431 432 433class _TemporaryFileCloser:434    """A separate object allowing proper closing of a temporary file's435    underlying file object, without adding a __del__ method to the436    temporary file."""437 438    cleanup_called = False439    close_called = False440 441    def __init__(442        self,443        file,444        name,445        delete=True,446        delete_on_close=True,447        warn_message="Implicitly cleaning up unknown file",448    ):449        self.file = file450        self.name = name451        self.delete = delete452        self.delete_on_close = delete_on_close453        self.warn_message = warn_message454 455    def cleanup(self, windows=(_os.name == 'nt'), unlink=_os.unlink):456        if not self.cleanup_called:457            self.cleanup_called = True458            try:459                if not self.close_called:460                    self.close_called = True461                    self.file.close()462            finally:463                # Windows provides delete-on-close as a primitive, in which464                # case the file was deleted by self.file.close().465                if self.delete and not (windows and self.delete_on_close):466                    try:467                        unlink(self.name)468                    except FileNotFoundError:469                        pass470 471    def close(self):472        if not self.close_called:473            self.close_called = True474            try:475                self.file.close()476            finally:477                if self.delete and self.delete_on_close:478                    self.cleanup()479 480    def __del__(self):481        close_called = self.close_called482        self.cleanup()483        if not close_called:484            _warnings.warn(self.warn_message, ResourceWarning)485 486 487class _TemporaryFileWrapper:488    """Temporary file wrapper489 490    This class provides a wrapper around files opened for491    temporary use.  In particular, it seeks to automatically492    remove the file when it is no longer needed.493    """494 495    def __init__(self, file, name, delete=True, delete_on_close=True):496        self.file = file497        self.name = name498        self._closer = _TemporaryFileCloser(499            file,500            name,501            delete,502            delete_on_close,503            warn_message=f"Implicitly cleaning up {self!r}",504        )505 506    def __repr__(self):507        file = self.__dict__['file']508        return f"<{type(self).__name__} {file=}>"509 510    def __getattr__(self, name):511        # Attribute lookups are delegated to the underlying file512        # and cached for non-numeric results513        # (i.e. methods are cached, closed and friends are not)514        file = self.__dict__['file']515        a = getattr(file, name)516        if hasattr(a, '__call__'):517            func = a518            @_functools.wraps(func)519            def func_wrapper(*args, **kwargs):520                return func(*args, **kwargs)521            # Avoid closing the file as long as the wrapper is alive,522            # see issue #18879.523            func_wrapper._closer = self._closer524            a = func_wrapper525        if not isinstance(a, int):526            setattr(self, name, a)527        return a528 529    # The underlying __enter__ method returns the wrong object530    # (self.file) so override it to return the wrapper531    def __enter__(self):532        self.file.__enter__()533        return self534 535    # Need to trap __exit__ as well to ensure the file gets536    # deleted when used in a with statement537    def __exit__(self, exc, value, tb):538        result = self.file.__exit__(exc, value, tb)539        self._closer.cleanup()540        return result541 542    def close(self):543        """544        Close the temporary file, possibly deleting it.545        """546        self._closer.close()547 548    # iter() doesn't use __getattr__ to find the __iter__ method549    def __iter__(self):550        # Don't return iter(self.file), but yield from it to avoid closing551        # file as long as it's being used as iterator (see issue #23700).  We552        # can't use 'yield from' here because iter(file) returns the file553        # object itself, which has a close method, and thus the file would get554        # closed when the generator is finalized, due to PEP380 semantics.555        for line in self.file:556            yield line557 558def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,559                       newline=None, suffix=None, prefix=None,560                       dir=None, delete=True, *, errors=None,561                       delete_on_close=True):562    """Create and return a temporary file.563    Arguments:564    'prefix', 'suffix', 'dir' -- as for mkstemp.565    'mode' -- the mode argument to io.open (default "w+b").566    'buffering' -- the buffer size argument to io.open (default -1).567    'encoding' -- the encoding argument to io.open (default None)568    'newline' -- the newline argument to io.open (default None)569    'delete' -- whether the file is automatically deleted (default True).570    'delete_on_close' -- if 'delete', whether the file is deleted on close571       (default True) or otherwise either on context manager exit572       (if context manager was used) or on object finalization. .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 name of the file577    is accessible as its 'name' attribute.  The file will be automatically578    deleted when it is closed unless the 'delete' argument is set to False.579 580    On POSIX, NamedTemporaryFiles cannot be automatically deleted if581    the creating process is terminated abruptly with a SIGKILL signal.582    Windows can delete the file even in this case.583    """584 585    prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)586 587    flags = _bin_openflags588 589    # Setting O_TEMPORARY in the flags causes the OS to delete590    # the file when it is closed.  This is only supported by Windows.591    if _os.name == 'nt' and delete and delete_on_close:592        flags |= _os.O_TEMPORARY593 594    if "b" not in mode:595        encoding = _io.text_encoding(encoding)596 597    name = None598    def opener(*args):599        nonlocal name600        fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)601        return fd602    try:603        file = _io.open(dir, mode, buffering=buffering,604                        newline=newline, encoding=encoding, errors=errors,605                        opener=opener)606        try:607            raw = getattr(file, 'buffer', file)608            raw = getattr(raw, 'raw', raw)609            raw.name = name610            return _TemporaryFileWrapper(file, name, delete, delete_on_close)611        except:612            file.close()613            raise614    except:615        if name is not None and not (616            _os.name == 'nt' and delete and delete_on_close):617            _os.unlink(name)618        raise619 620if _os.name != 'posix' or _sys.platform == 'cygwin':621    # On non-POSIX and Cygwin systems, assume that we cannot unlink a file622    # while it is open.623    TemporaryFile = NamedTemporaryFile624 625else:626    # Is the O_TMPFILE flag available and does it work?627    # The flag is set to False if os.open(dir, os.O_TMPFILE) raises an628    # IsADirectoryError exception629    _O_TMPFILE_WORKS = hasattr(_os, 'O_TMPFILE')630 631    def TemporaryFile(mode='w+b', buffering=-1, encoding=None,632                      newline=None, suffix=None, prefix=None,633                      dir=None, *, errors=None):634        """Create and return a temporary file.635        Arguments:636        'prefix', 'suffix', 'dir' -- as for mkstemp.637        'mode' -- the mode argument to io.open (default "w+b").638        'buffering' -- the buffer size argument to io.open (default -1).639        'encoding' -- the encoding argument to io.open (default None)640        'newline' -- the newline argument to io.open (default None)641        'errors' -- the errors argument to io.open (default None)642        The file is created as mkstemp() would do it.643 644        Returns an object with a file-like interface.  The file has no645        name, and will cease to exist when it is closed.646        """647        global _O_TMPFILE_WORKS648 649        if "b" not in mode:650            encoding = _io.text_encoding(encoding)651 652        prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)653 654        flags = _bin_openflags655        if _O_TMPFILE_WORKS:656            fd = None657            def opener(*args):658                nonlocal fd659                flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT660                fd = _os.open(dir, flags2, 0o600)661                return fd662            try:663                file = _io.open(dir, mode, buffering=buffering,664                                newline=newline, encoding=encoding,665                                errors=errors, opener=opener)666                raw = getattr(file, 'buffer', file)667                raw = getattr(raw, 'raw', raw)668                raw.name = fd669                return file670            except IsADirectoryError:671                # Linux kernel older than 3.11 ignores the O_TMPFILE flag:672                # O_TMPFILE is read as O_DIRECTORY. Trying to open a directory673                # with O_RDWR|O_DIRECTORY fails with IsADirectoryError, a674                # directory cannot be open to write. Set flag to False to not675                # try again.676                _O_TMPFILE_WORKS = False677            except OSError:678                # The filesystem of the directory does not support O_TMPFILE.679                # For example, OSError(95, 'Operation not supported').680                #681                # On Linux kernel older than 3.11, trying to open a regular682                # file (or a symbolic link to a regular file) with O_TMPFILE683                # fails with NotADirectoryError, because O_TMPFILE is read as684                # O_DIRECTORY.685                pass686            # Fallback to _mkstemp_inner().687 688        fd = None689        def opener(*args):690            nonlocal fd691            fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)692            try:693                _os.unlink(name)694            except BaseException as e:695                _os.close(fd)696                raise697            return fd698        file = _io.open(dir, mode, buffering=buffering,699                        newline=newline, encoding=encoding, errors=errors,700                        opener=opener)701        raw = getattr(file, 'buffer', file)702        raw = getattr(raw, 'raw', raw)703        raw.name = fd704        return file705 706class SpooledTemporaryFile(_io.IOBase):707    """Temporary file wrapper, specialized to switch from BytesIO708    or StringIO to a real file when it exceeds a certain size or709    when a fileno is needed.710    """711    _rolled = False712 713    def __init__(self, max_size=0, mode='w+b', buffering=-1,714                 encoding=None, newline=None,715                 suffix=None, prefix=None, dir=None, *, errors=None):716        if 'b' in mode:717            self._file = _io.BytesIO()718        else:719            encoding = _io.text_encoding(encoding)720            self._file = _io.TextIOWrapper(_io.BytesIO(),721                            encoding=encoding, errors=errors,722                            newline=newline)723        self._max_size = max_size724        self._rolled = False725        self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,726                                   'suffix': suffix, 'prefix': prefix,727                                   'encoding': encoding, 'newline': newline,728                                   'dir': dir, 'errors': errors}729 730    __class_getitem__ = classmethod(_types.GenericAlias)731 732    def _check(self, file):733        if self._rolled: return734        max_size = self._max_size735        if max_size and file.tell() > max_size:736            self.rollover()737 738    def rollover(self):739        if self._rolled: return740        file = self._file741        newfile = self._file = TemporaryFile(**self._TemporaryFileArgs)742        del self._TemporaryFileArgs743 744        pos = file.tell()745        if hasattr(newfile, 'buffer'):746            newfile.buffer.write(file.detach().getvalue())747        else:748            newfile.write(file.getvalue())749        newfile.seek(pos, 0)750 751        self._rolled = True752 753    # The method caching trick from NamedTemporaryFile754    # won't work here, because _file may change from a755    # BytesIO/StringIO instance to a real file. So we list756    # all the methods directly.757 758    # Context management protocol759    def __enter__(self):760        if self._file.closed:761            raise ValueError("Cannot enter context with closed file")762        return self763 764    def __exit__(self, exc, value, tb):765        self._file.close()766 767    # file protocol768    def __iter__(self):769        return self._file.__iter__()770 771    def __del__(self):772        if not self.closed:773            _warnings.warn(774                "Unclosed file {!r}".format(self),775                ResourceWarning,776                stacklevel=2,777                source=self778            )779            self.close()780 781    def close(self):782        self._file.close()783 784    @property785    def closed(self):786        return self._file.closed787 788    @property789    def encoding(self):790        return self._file.encoding791 792    @property793    def errors(self):794        return self._file.errors795 796    def fileno(self):797        self.rollover()798        return self._file.fileno()799 800    def flush(self):801        self._file.flush()802 803    def isatty(self):804        return self._file.isatty()805 806    @property807    def mode(self):808        try:809            return self._file.mode810        except AttributeError:811            return self._TemporaryFileArgs['mode']812 813    @property814    def name(self):815        try:816            return self._file.name817        except AttributeError:818            return None819 820    @property821    def newlines(self):822        return self._file.newlines823 824    def readable(self):825        return self._file.readable()826 827    def read(self, *args):828        return self._file.read(*args)829 830    def read1(self, *args):831        return self._file.read1(*args)832 833    def readinto(self, b):834        return self._file.readinto(b)835 836    def readinto1(self, b):837        return self._file.readinto1(b)838 839    def readline(self, *args):840        return self._file.readline(*args)841 842    def readlines(self, *args):843        return self._file.readlines(*args)844 845    def seekable(self):846        return self._file.seekable()847 848    def seek(self, *args):849        return self._file.seek(*args)850 851    def tell(self):852        return self._file.tell()853 854    def truncate(self, size=None):855        if size is None:856            return self._file.truncate()857        else:858            if size > self._max_size:859                self.rollover()860            return self._file.truncate(size)861 862    def writable(self):863        return self._file.writable()864 865    def write(self, s):866        file = self._file867        rv = file.write(s)868        self._check(file)869        return rv870 871    def writelines(self, iterable):872        if self._max_size == 0 or self._rolled:873            return self._file.writelines(iterable)874 875        it = iter(iterable)876        for line in it:877            self.write(line)878            if self._rolled:879                return self._file.writelines(it)880 881    def detach(self):882        return self._file.detach()883 884 885class TemporaryDirectory:886    """Create and return a temporary directory.  This has the same887    behavior as mkdtemp but can be used as a context manager.  For888    example:889 890        with TemporaryDirectory() as tmpdir:891            ...892 893    Upon exiting the context, the directory and everything contained894    in it are removed (unless delete=False is passed or an exception895    is raised during cleanup and ignore_cleanup_errors is not True).896 897    Optional Arguments:898        suffix - A str suffix for the directory name.  (see mkdtemp)899        prefix - A str prefix for the directory name.  (see mkdtemp)900        dir - A directory to create this temp dir in.  (see mkdtemp)901        ignore_cleanup_errors - False; ignore exceptions during cleanup?902        delete - True; whether the directory is automatically deleted.903    """904 905    def __init__(self, suffix=None, prefix=None, dir=None,906                 ignore_cleanup_errors=False, *, delete=True):907        self.name = mkdtemp(suffix, prefix, dir)908        self._ignore_cleanup_errors = ignore_cleanup_errors909        self._delete = delete910        self._finalizer = _weakref.finalize(911            self, self._cleanup, self.name,912            warn_message="Implicitly cleaning up {!r}".format(self),913            ignore_errors=self._ignore_cleanup_errors, delete=self._delete)914 915    @classmethod916    def _rmtree(cls, name, ignore_errors=False, repeated=False):917        def onexc(func, path, exc):918            if isinstance(exc, PermissionError):919                if repeated and path == name:920                    if ignore_errors:921                        return922                    raise923 924                try:925                    if path != name:926                        _resetperms(_os.path.dirname(path))927                    _resetperms(path)928 929                    try:930                        _os.unlink(path)931                    except IsADirectoryError:932                        cls._rmtree(path, ignore_errors=ignore_errors)933                    except PermissionError:934                        # The PermissionError handler was originally added for935                        # FreeBSD in directories, but it seems that it is raised936                        # on Windows too.937                        # bpo-43153: Calling _rmtree again may938                        # raise NotADirectoryError and mask the PermissionError.939                        # So we must re-raise the current PermissionError if940                        # path is not a directory.941                        if not _os.path.isdir(path) or _os.path.isjunction(path):942                            if ignore_errors:943                                return944                            raise945                        cls._rmtree(path, ignore_errors=ignore_errors,946                                    repeated=(path == name))947                except FileNotFoundError:948                    pass949            elif isinstance(exc, FileNotFoundError):950                pass951            else:952                if not ignore_errors:953                    raise954 955        _shutil.rmtree(name, onexc=onexc)956 957    @classmethod958    def _cleanup(cls, name, warn_message, ignore_errors=False, delete=True):959        if delete:960            cls._rmtree(name, ignore_errors=ignore_errors)961            _warnings.warn(warn_message, ResourceWarning)962 963    def __repr__(self):964        return "<{} {!r}>".format(self.__class__.__name__, self.name)965 966    def __enter__(self):967        return self.name968 969    def __exit__(self, exc, value, tb):970        if self._delete:971            self.cleanup()972 973    def cleanup(self):974        if self._finalizer.detach() or _os.path.exists(self.name):975            self._rmtree(self.name, ignore_errors=self._ignore_cleanup_errors)976 977    __class_getitem__ = classmethod(_types.GenericAlias)978 
codekingpro/portable-devtools · Team Ai