
    I&g5                         d Z ddlZddlZddlZddlZddlmZ ddlZddl	Z	ddl
Z
ddlmZ ddlZddlZddlZddlZdZdZdZ e       Zej0                  d        Zd	 Z G d
 de      Z G d de      Z	 	 ddZy)z
An object-oriented file access library for Python.

More module documentation to come soon. For now, take a look at the File class
to see what it does.

Issues should be filed at http://github.com/javawizard/fileutils/issues.
    N)closing)partialskiprecurseyieldc                  >    t         D ]  } | j                  d        y )NT)ignore_missing)_delete_on_exitdeletefs    X/mounts/lovelace/software/anaconda3/envs/py312/lib/python3.12/site-packages/fileutils.py_r   $   s     &	%&    c                     | t        |       S y)zL
    Returns File(f), unless f is None, in which case None is returned.
    N)Filer   s    r   file_or_noner   *   s     	}Awr   c                      e Zd ZdZd Zed        Zed        Zed        Zed        Z	ed        Z
ed        Zed	        Zd
 Zd Zed        Zd Zed        Zd Zd Zd ZeZd Zd Zd Zed        ZdHdZed        Zed        ZdIdZed        ZdJdZed        Z dHdZ!dHdZ"dHd Z#dKd"Z$ed#        Z%d$ Z&d% Z'dLd&Z(dLd'Z)dLd(Z*dMd)Z+e,jZ                  d!fd*Z.dHd+Z/dHd,Z0dHd-Z1dNd.Z2d/ Z3d0 Z4ed1        Z5dLd2Z6d3 Z7dNd4Z8dHd5Z9dJd6Z:dHd7Z;dHd8Z<d9 Z=ed:        Z>dHd;Z?ed<        Z@e@j                  d=        Z@d> ZBd? ZCdJd@ZDdA ZEdB ZFdLdCZGdD ZHeHZIdE ZJdF ZKdG ZLy)Or   a  
    An object representing a file or folder. File objects are intended to be as
    opaque as possible; one should rarely, if ever, need to know about the
    pathname of a File object, or that a File even has a pathname associated
    with it.
    
    The file or folder referred to by a File object need not exist. One can
    test whether a File object represents a file that does exist using the
    exists property.
    
    File objects cannot be changed to refer to a different file after they are
    created.
    c                     |r#t        |d   t              r|d   j                  }n!|rt        j                  j
                  | }nd}t        j                  j                  |      }|| _        y)a  
        Creates a new file from the specified path components. Each component
        represents the name of a folder or a file. These are internally joined
        as if by os.path.join(*path_components).
        
        It's also possible, although not recommended, to pass a full pathname
        (in the operating system's native format) into File. On Windows, one
        could therefore do File(r"C:\some\file"), and File("/some/file") on
        Linux and other Unix operating systems.
        
        You can also call File(File(...)). This is equivalent to File(...) and
        exists to make it easier for functions to accept either a pathname or
        a File object.
        
        Passing no arguments (i.e. File()) results in a file that refers to the
        working directory as of the time the File instance was constructed.
        
        Pathnames are internally stored in absolute form; as a result, changing
        the working directory after creating a File instance will not change
        the file referred to.
        r    N)
isinstancer   _pathospathjoinabspath)selfpath_componentsr   s      r   __init__zFile.__init__B   sX    . z/!*<dC"1%++D77<<1DDwwt$
r   c                 T    t         j                  j                  | j                        S )z
        True if this File is a folder, False if it isn't. If the file/folder
        doesn't actually exist yet, this will be False.
        
        If this file is a symbolic link that points to a folder, this will be
        True.
        )r   r   isdirr   r   s    r   	is_folderzFile.is_folderd   s     ww}}TZZ((r   c                     | j                   S )z)
        Same as self.is_folder.
        )r#   r"   s    r   is_directoryzFile.is_directoryo   s    
 ~~r   c                 T    t         j                  j                  | j                        S )z
        True if this File is a file, False if it isn't. If the file/folder
        doesn't actually exist yet, this will be False.
        
        If this file is a symbolic link that points to a file, this will be
        True.
        )r   r   isfiler   r"   s    r   is_filezFile.is_filev   s     ww~~djj))r   c                 T    t         j                  j                  | j                        S )z
        True if this File is a symbolic link, False if it isn't. This will be
        True even for broken symbolic links.
        )r   r   islinkr   r"   s    r   is_linkzFile.is_link   s     ww~~djj))r   c                 r    | j                   xr* t        j                  j                  | j                         S )zY
        True if this File is a symbolic link that is broken, False if it isn't.
        )r+   r   r   existsr   r"   s    r   	is_brokenzFile.is_broken   s'    
 ||>BGGNN4::$> >>r   c                 T    t         j                  j                  | j                        S )z
        True if this file/folder exists, False if it doesn't. This will be True
        even for broken symbolic links; use self.valid if you want an
        alternative that returns False for broken symbolic links.
        )r   r   lexistsr   r"   s    r   r-   zFile.exists   s     wwtzz**r   c                 T    t         j                  j                  | j                        S )z
        True if this file/folder exists, False if it doesn't. This will be
        False for broken symbolic links; use self.exists if you want an
        alternative that returns True for broken symbolic links.
        )r   r   r-   r   r"   s    r   validz
File.valid   s     ww~~djj))r   c                 L    | j                   st        d| j                  z        y)zy
        Checks to see whether this File refers to a folder. If it doesn't, an
        exception will be thrown.
        z)"%s" does not exist or is not a directoryN)r#   	Exceptionr   r"   s    r   check_folderzFile.check_folder   s%    
 ~~G$**TUU r   c                 L    | j                   st        d| j                  z        y)zw
        Checks to see whether this File refers to a file. If it doesn't, an
        exception will be thrown.
        z$"%s" does not exist or is not a fileN)r(   r4   r   r"   s    r   
check_filezFile.check_file   s%    
 ||BTZZOPP r   c                 x    | j                   sy| j                  D cg c]  }| j                  |       c}S c c}w )z
        A list of all of the children of this file, as a list of File objects.
        If this file is not a folder, the value of this property is None.
        N)r#   child_nameschild)r   ps     r   childrenzFile.children   s0     ~~'+'7'78!

1888s   7c                     | j                   S )zG
        An obsolete method that simply returns self.children.
        )r<   r"   s    r   listz	File.list   s     }}r   c                 l    | j                   syt        t        j                  | j                              S )z
        A list of the names of all of the children of this file, as a list of
        strings. If this file is not a folder, the value of this property is
        None.
        N)r#   sortedr   listdirr   r"   s    r   r9   zFile.child_names   s&     ~~bjj,--r   c                     | j                   S )zJ
        An obsolete method that simply returns self.child_names.
        )r9   r"   s    r   
list_nameszFile.list_names   s     r   c                 4    t        | j                  g|i |S )z
        Opens the file referred to by this File object and returns a Python
        file instance. *args and **kwargs are passed through to Python's open
        function as if by open(self.path, *args, **kwargs).
        )openr   )r   argskwargss      r   rE   z	File.open   s     DJJ0000r   c                 h    t        t        j                  j                  | j                  g|       S )a7  
        Returns a File object representing the child of this file with the
        specified name. If multiple names are present, they will be joined
        together. If no names are present, self will be returned.
        
        If any names are absolute, all names before them (and self) will be
        discarded. Relative names (like "..") are also allowed. If you want a
        method that guarantees that the result is a child of self, use
        self.safe_child(...).
        
        This method is analogous to os.path.join(self.path, *names).
        )r   r   r   r   )r   namess     r   r:   z
File.child   s%     BGGLL3U344r   c                     t        j                  t        j                  j	                  | j                  |            D cg c]  }t        |       c}S c c}w )z
        Expands the specified path relative to self and returns a list of all
        matching files, as File objects. This is a thin wrapper around a call
        to Python's glob.glob function.
        )_globglobr   r   r   r   )r   rL   r   s      r   rL   z	File.glob   s8     "'BGGLLD,I!JKAQKKKs    Ac                 h     | j                   | }| j                  |      st        d|d|       |S )a  
        Same as self.child(*names), but checks that the resulting file is a
        descendant of self. If it's not, an exception will be thrown. This
        allows unsanitized paths to be used without fear that things like ".."
        will be used to escape the confines of self.
        
        The pathname may contain occurrences of ".." so long as they do not
        escape self. For example, "a/b/../c" is perfectly fine, but "a/../.."
        is not.
        zNames z escape the parent )r:   ancestor_of
ValueError)r   rI   r:   s      r   
safe_childzFile.safe_child   s7     

E"&tLMMr   c                 8    | j                   j                  |      S )z
        Returns a File object representing the sibling of this file with the
        specified name. This is equivalent to self.parent.child(name).
        )parentr:   r   names     r   siblingzFile.sibling  s    
 {{  &&r   c                     t         j                  j                  | j                        }||dk(  ryt	        |      }|| k(  ry|S )z
        Returns a File representing the parent of this file. If this file has
        no parent (for example, if it's "/" on Unix-based operating systems or
        a drive letter on Windows), None will be returned.
        Nr   )r   r   dirnamer   r   )r   rW   r   s      r   rR   zFile.parent  sB     ''//$**- ?gmM9r   c                 p    |r| }n| j                   }g }| |j                  |       |j                   }| |S )z
        Returns a list of all of the ancestors of this file, with self.parent
        first. If including_self is True, self will be first, self.parent will
        be second, and so on.
        )rR   append)r   including_selfcurrentresultss       r   get_ancestorszFile.get_ancestors  sD     GkkG!NN7#nnG ! r   c                 "    | j                         S )a  
        A list of all of the ancestors of this file, with self.parent first.
        
        This property simply returns self.get_ancestors(). Have a look at that
        method if you need to do more complex things like include self as one
        of the returned ancestors.
        )r]   r"   s    r   	ancestorszFile.ancestors.  s     !!##r   c                 T    t         j                  j                  | j                        S )z
        The name of this file. For example, File("a", "b", "c").name will be
        "c".
        
        On Unix-based operating systems, File("/").name will be the empty
        string.
        )r   r   basenamer   r"   s    r   rT   z	File.name9  s     ww

++r   Nc                 z    |t         j                  j                  }|j                  | j	                  |            S )a  
        Gets the path to the file represented by this File object.
        
        If relative_to is specified, the returned path will be a relative path,
        the path of this file relative to the specified one. Otherwise, the
        returned path will be absolute.
        
        If separator (which must be a string) is specified, it will be used as
        the separator to place between path components in the returned path.
        Otherwise, os.path.sep will be used as the separator. 
        )r   r   sepr   get_path_components)r   relative_to	separators      r   get_pathzFile.get_pathD  s1     I~~d66{CDDr   c                 "    | j                         S )a  
        The absolute path to the file represented by this File object, in a
        format native to the operating system in use. This pathname can then be
        used with Python's traditional file-related utilities.
        
        This property simply returns self.get_path(). See the documentation for
        that method for more complex ways of creating paths (including
        obtaining relative paths).
        )rg   r"   s    r   r   z	File.pathT  s     }}r   c                     |3| j                   j                  t        j                  j                        S t        j                  j                  | j                   t        |      j                         j                  t        j                        S )a  
        Returns a list of the components in this file's path, including (on
        POSIX-compliant systems) an empty leading component for absolute paths.
        
        If relative_to is specified, the returned set of components will
        represent a relative path, the path of this file relative to the
        specified one. Otherwise, the returned components will represent an
        absolute path.
        )r   splitr   r   rc   relpathr   r   re   s     r   rd   zFile.get_path_componentsa  sZ     ::##BGGKK0077??4::tK/@/F/FGMMbffUUr   c                 "    | j                         S )zL
        A property that simply returns self.get_path_components().
        )rd   r"   s    r   r   zFile.path_componentsp  s    
 ''))r   c                    t        |      }| j                          |j                  r|st        d|z        |j	                  d      5 }| j                         D ]  }|j                  |        	 ddd       y# 1 sw Y   yxY w)a7  
        Copies the contents of this file to the specified File object or
        pathname. An exception will be thrown if the specified file already
        exists and overwrite is False.
        
        This does not currently work for folders; I hope to add this ability
        in the near future.
        %r already existswbN)r   r7   r-   r4   rE   read_blockswrite)r   other	overwritewrite_toblocks        r   copy_tozFile.copy_tow  sx     U<<	/%788ZZ 	&))+ &u%&	& 	& 	&s   	'A::Bc                 Z    | j                  |j                  | j                        |       y)a  
        Copies this file to an identically named file inside the specified
        folder. This is just shorthand for self.copy_to(other.child(self.name))
        which, from experience, seems to be by far the most common use case for
        the copy_to function.
        N)rw   r:   rT   )r   rs   rt   s      r   	copy_intozFile.copy_into  s     	U[[+Y7r   c                     | j                   r|st        d| z        t        j                  |      }| j	                  d      5 }t        j                  ||       ddd       y# 1 sw Y   yxY w)z
        Downloads the specified URL and saves it to self. If self already
        exists and overwrite is False, an exception will be thrown; otherwise,
        self will be overwritten.
        ro   rp   N)r-   r4   urllib2urlopenrE   shutilcopyfileobj)r   urlrt   sr   s        r   download_fromzFile.download_from  s^     ;;y/$677OOC YYt_ 	%q!$	% 	% 	%s   A##A,Tc              #      K   |dn ||       }|t         dfv r|r|  |t        dfv s|r5|s2| j                  xs g D ]  }|j                  |d|      D ]  }|    yyyw)a  
        A generator that recursively yields all child File objects of this file.
        Files and directories (and the files and directories contained within
        them, and so on) are all included.
        
        A filter function accepting one argument can be specified. It will be
        called for each file and folder. It can return one of True, False,
        SKIP, YIELD, or RECURSE, with the behavior of each outlined in the
        following table:
            
                                  Don't yield   Do yield
                                +-------------+----------+
            Don't recurse into  | SKIP        | YIELD    |
                                +-------------+----------+
            Do recurse into     | RECURSE     | True     |
                                +-------------+----------+
            
            False behaves the same as RECURSE if recurse_skipped is True, or
            SKIP otherwise.
        
        If include_self is True (the default), this file (a.k.a. self) will be
        yielded as well (if it matches the specified filter function). If it's
        False, only this file's children (and their children, and so on) will
        be yielded.
        NT)YIELDRECURSEr<   r   )r   filterinclude_selfrecurse_skippedincluder:   r   s          r   r   zFile.recurse  s|     4 !.$fTludm#Jwo%/'," vt_E AG CJ/s   AA!c                     | j                   rt        d | j                  D              S | j                  r)t        j
                  j                  | j                        S y)a  
        The size, in bytes, of this file. This is the number of bytes that the
        file contains; the number of actual bytes of disk space it consumes is
        usually larger.
        
        If this file is actually a folder, the sizes of its child files and
        folders will be recursively summed up and returned. This can take quite
        some time for large folders.
        
        This is the same as len(self).
        c              3   4   K   | ]  }|j                     y wNsize).0r   s     r   	<genexpr>zFile.size.<locals>.<genexpr>  s     5!qvv5s   r   )r#   sumr<   r(   r   r   getsizer   r"   s    r   r   z	File.size  sA     >>5t}}555\\77??4::..r   c                     | j                   S r   r   r"   s    r   __len__zFile.__len__  s    yyr   c                 j    t        j                  | j                  t        |      j                         y)zu
        Rename this file or folder to the specified name, which can be a File
        object or a pathname.
        N)r   renamer   r   r   r   rs   s     r   	rename_tozFile.rename_to  s     
 			$**d5k../r   c                 ~    | j                  d|rdndz         5 }|j                         cddd       S # 1 sw Y   yxY w)ak  
        Read the contents of this file and return them as a string. This is
        usually a bad idea if the file in question is large, as the entire
        contents of the file will be loaded into memory.
        
        If binary is True (the default), the file will be read byte-for-byte.
        If it's False, the file will be read in text mode.
        rbr   NrE   read)r   binaryr   s      r   r   z	File.read  s9     YYsVc45 	668	 	 	s   3<c                     | j                  d|rdndz         5 }|j                  |       ddd       y# 1 sw Y   yxY w)a  
        Overwrite this file with the specified data. After this is called,
        self.size will be equal to len(data), and self.read() will be equal to
        data. If you want to append data instead, use self.append().
        
        If binary is True (the default), the file will be written
        byte-for-byte. If it's False, the file will be written in text mode. 
        wr   r   NrE   rr   r   datar   r   s       r   rr   z
File.write  s;     YYsVc45 	GGDM	 	 	   4=c                     | j                  d|rdndz         5 }|j                  |       ddd       y# 1 sw Y   yxY w)z
        Append the specified data to the end of this file.
        
        If binary is True (the default), the file will be appended to
        byte-for-byte. If it's False, the file will be appended to in text
        mode.
        ar   r   Nr   r   s       r   rY   zFile.append  s;     YYsVc45 	GGDM	 	 	r   c              #      K   | j                  d|rdndz         5 }|j                  |      }|r| |j                  |      }|rddd       y# 1 sw Y   yxY ww)a  
        A generator that yields successive blocks of data from this file. Each
        block will be no larger than block_size bytes, which defaults to 16384.
        This is useful when reading/processing files larger than would
        otherwise fit into memory.
        
        One could implement, for example, a copy function thus:
        
        with target.open("wb") as target_stream:
            for block in source.read_blocks():
                target_stream.write(block)
        r   r   r   Nr   )r   
block_sizer   r   r   s        r   rq   zFile.read_blocks   s\      YYsVc45 	*66*%D
vvj) 	* 	* 	*s   A+A	AAAc                      |       }| j                  d      5 }t        t        |j                  d      d      D ]  }|j	                  |        	 ddd       |r|j                         }|S # 1 sw Y   xY w)a  
        Compute the hash of this file and return it, as a hexidecimal string.
        
        The default algorithm is md5. An alternate constructor from hashlib
        can be passed as the algorithm parameter; file.hash(hashlib.sha1)
        would, for example, compute the SHA-1 hash instead.
        
        If return_hex is False (it defaults to True), the hash object itself
        will be returned instead of the return value of its hexdigest() method.
        One can use this to access the binary hash instead.
        rb
   r   N)rE   iter_partialr   update	hexdigest)r   	algorithm
return_hexhasherr   rv   s         r   hashz	File.hash  sr     YYt_ 	%hqvvr2B7 %e$%	% %%'F	% 	%s   7A--A6c                 (    | j                  |       y)z
        An obsolete alias for self.create_folder(ignore_existing=silent)
        present for backward compatibility reasons.
        )ignore_existingNcreate_folderr   silents     r   mkdirz
File.mkdir'  s    
 	62r   c                 *    | j                  |d       yz
        An obsolete alias for self.create_folder(ignore_existing=silent,
        recursive=True) present for backward compatibility reasons.
        T)r   	recursiveNr   r   s     r   mkdirszFile.mkdirs.      
 	6TBr   c                 *    | j                  |d       yr   r   r   s     r   makedirszFile.makedirs5  r   r   c                    | j                   r|ryt        d| j                  z        |r>| j                  r2| j                  j                  s| j                  j                  d       t        j                  | j                         y)aE  
        Creates the folder referred to by this File object. If it already
        exists but is not a folder, an exception will be thrown. If it already
        exists and is a folder, an exception will be thrown if ignore_existing
        is False (the default); if ignore_existing is True, no exception will
        be thrown.
        
        If the to-be-created folder's parent does not exist and recursive is
        False, an exception will be thrown. If recursive is True, the folder's
        parent, its parent's parent, and so on will be created automatically.
        NzThe folder %r already exists.Tr   )r#   r4   r   rR   r-   r   r   r   )r   r   r   s      r   r   zFile.create_folder<  sd     >>   ?$)) KLL T[[1C1C))D)9HHTYYr   c                 B    t        j                  | j                         y)am  
        Sets the current working directory to self.
        
        Since File instances internally store paths in absolute form, other
        File instances will continue to work just fine after this is called.
        
        If you need to restore the working directory at any point, you might
        want to consider using self.as_working instead.
        N)r   chdirr   r"   s    r   	change_tozFile.change_toZ  s     	r   c                 $    | j                          y)z0
        An alias for self.change_to().
        N)r   r"   s    r   cdzFile.cdf  s     	r   c                     t        |       S )a  
        A property that returns a context manager. This context manager sets
        the working directory to self upon being entered and restores it to
        what it previously was upon being exited. One can use this to replace
        something like:
        
        old_dir = File()
        new_dir.cd()
        try:
            ...stuff...
        finally:
            old_dir.cd()
        
        with the much nicer:
        
        with new_dir.as_working:
            ...stuff...
        
        and get exactly the same effect.
        
        The context manager's __enter__ returns self (this file), so you can
        also use an "as" clause on the with statement to get access to the
        file in case you haven't got it stored in a variable anywhere.
        )
_AsWorkingr"   s    r   
as_workingzFile.as_workingl  s    4 $r   c                 T   t        t        j                  t        |      j                  d            5 }| j                         D ]M  }|r|j                  |       }n|j                  | j                        }|j                  |j                  |       O 	 ddd       y# 1 sw Y   yxY w)a.  
        Creates a zip archive of this folder and writes it to the specified
        filename, which can be either a pathname or a File object.
        
        If contents is True (the default), the files (and folders, and so on
        recursively) contained within this folder will be written directly to
        the zip file. If it's False, the folder will be written itself. The
        difference is that, given a folder foo which looks like this:
        
        foo/
            bar
            baz/
                qux
        
        Specifying contents=False will result in a zip file whose contents look
        something like:
        
        zipfile.zip/
            foo/
                bar
                baz/
                    qux
        
        Whereas specifying contents=True will result in this:
        
        zipfile.zip/
            bar
            baz/
                qux
        
        NOTE: This has only been tested on Linux. I still need to test it on
        Windows to make sure pathnames are being handled correctly.
        r   N)	r   
zip_moduleZipFiler   r   r   relative_pathrR   rr   )r   filenamecontentszipfiler   path_in_zips         r   zip_intozFile.zip_into  s    D Z''X(;(;SAB 	3g\\^ 3"#//$"7K"#//$++">Kaffk23	3 	3 	3s   A!BB'c                     t        |      }|j                  d       t        t        j                  | j
                  d            5 }|j                  |j                         ddd       y# 1 sw Y   yxY w)av  
        Unzips the zip file referred to by self into the specified folder,
        which will be automatically created (as if by File(folder).mkdirs())
        if it does not yet exist.
        
        NOTE: This is an unsafe operation! The same warning present on Python's
        zipfile.ZipFile.extractall applies here, namely that a maliciously
        crafted zip file could cause absolute filesystem paths to be
        overwritten. I hope to hand-roll my own extraction code in the future
        that will explicitly filter out absolute paths.
        
        The return value of this function is File(folder).
        T)r   r   N)r   r   r   r   r   r   
extractallr   )r   folderr   s      r   
unzip_intozFile.unzip_into  s]     fT"Z''

C89 	,Wv{{+	, 	, 	,s   A,,A5c                 (   | j                   s|st        d      y| j                  rM| j                  sA| j                  D ]  }|j                           t        j                  | j                         yt        j                  | j                         y)a  
        Deletes this file or folder, recursively deleting children if
        necessary.
        
        The contents parameter has no effect, and is present for backward
        compatibility.
        
        If the file does not exist and ignore_missing is False, an exception
        will be thrown. If the file does not exist but ignore_missing is True,
        this function simply does nothing.
        
        Note that symbolic links are never recursed into, and are instead
        themselves removed.
        zThis file does not exist.N)r-   r4   r#   r+   r<   r   r   rmdirr   remover   )r   r   r	   r:   s       r   r   zFile.delete  sh     {{! ;<< "^^DLL HHTYYIIdjj!r   c                 &    | j                  |       y)z
        This has been merged into the delete method and as such should no
        longer be used. It has the exact same effect as delete.
        N)r   )r   r   s     r   delete_folderzFile.delete_folder  s    
 	Hr   c                 <    |
t               }| j                  |      S )z
        An obsolete alias for self.get_path(relative_to=...), except that, if
        relative_to is None, the working directory will be used instead.
        )r   rg   rl   s     r   r   zFile.relative_path  s     
 &K}}[))r   c                 :    | t        |      j                  |      v S )a  
        Returns true if this file is an ancestor of the specified file. A file
        is an ancestor of another file if that other file's parent is this
        file, or its parent's parent is this file, and so on.
        
        If including_self is True, the file is considered to be an ancestor of
        itself, i.e. True will be returned in the case that self == other.
        Otherwise, only the file's immediate parent, and its parent's parent,
        and so on are considered to be ancestors.
        )r   r]   r   rs   rZ   s      r   rN   zFile.ancestor_of  s     tE{00@@@r   c                 8    t        |      j                  | |      S )z
        Returns true if this file is a descendant of the specified file. This
        is equivalent to File(other).ancestor_of(self, including_self).
        )r   rN   r   s      r   descendant_ofzFile.descendant_of  s    
 E{&&t^<<r   c                     t        |t              r+t        j                  |j                  | j
                         yt        j                  || j
                         y)a  
        Creates this file as a symbolic link pointing to other, which can be
        a pathname or a File object. Note that if it's a pathname, a symbolic
        link will be created with the exact path specified; it will therefore
        be absolute if the path is absolute or relative (to the link itself) if
        the path is relative. If a File object, however, is used, the symbolic
        link will always be absolute.
        N)r   r   r   symlinkr   r   r   s     r   link_tozFile.link_to  s6     eT"JJuzz4::.JJudjj)r   c                 Z    | j                   syt        j                  | j                        S )z
        Returns the target to which this file, which is expected to be a
        symbolic link, points, as a string. If this file is not a symbolic
        link, None is returned.
        N)r+   r   readlinkr   r"   s    r   link_targetzFile.link_target  s!     ||{{4::&&r   c                     | j                   s| S t        | j                  | j                        }|r|j	                  d      S |S )a  
        Dereference the symbolic link represented by this file and return a
        File object pointing to the symbolic link's referent.
        
        If recursive is False, a File object pointing directly to the referent
        will be returned. If recursive is True, the referent itself will be
        recursively dereferenced, and the returned File will be guaranteed not
        to be a link.
        
        If this file is not a symbolic link, self will be returned.
        Tr   )r+   r   r   r   dereference)r   r   targets      r   r   zFile.dereference  sD     ||K dii!1!12%%%55Mr   c                     | t         v S )aV  
        A boolean indicating whether or not this file (which may be a file or a
        folder) should be deleted on interpreter shutdown. This is False by
        default, but may be set to True to request that a particular file be
        deleted on exit, and potentially set back to False to cancel such a
        request.
        
        Note that such files are not absolutely guaranteed to be deleted on
        exit. Deletion is handled via an atexit hook, so files will not be
        deleted if, for example, the interpreter crashes or os._exit() is
        called.
        
        The value of this property is shared among all File instances pointing
        to a given path. For example:
        
            File("test").delete_on_exit = True # Instance 1
            print File("test").delete_on_exit # Instance 2, prints "True"
        )r
   r"   s    r   delete_on_exitzFile.delete_on_exit1  s    ( &&r   c                 ^    |rt         j                  |        y t         j                  |        y r   )r
   adddiscard)r   values     r   r   zFile.delete_on_exitG  s!    %##D)r   c                     ddl }	 t        |j                  | j                              S # t        $ rG}|j
                  t
        j                  k(  s|j
                  t
        j                  k(  rg cY d}~S  d}~ww xY w)a  
        Returns a list of the names of all of the extended attributes present
        on this file.
        
        This is only supported on Linux and Max OS X right now. I hope to add
        Windows support in the future.
        
        Note that some Linux filesystems must be mounted with a particular
        option to enable extended attribute support. Ext2/3/4, for example,
        must be mounted with the user_xattr mount option set. (I heard
        somewhere that user_xattr might become a default option in the near
        future, but such a default is certainly not widely deployed yet.)
        
        Also note that some filesystems (such as ext2/3/4) require the
        attribute name to have a particular format (in the case of ext2/3/4,
        "prefix.name", where "prefix" is one of "system", "trusted",
        "security", and "user"). An "Operation not supported" error will be
        produced if an invalid format is used.
        
        Setting extended attributes on symlinks will result in undefined and
        platform-specific behavior. Don't do it unless you know what you're
        doing.
        
        Extended attribute support currently requires the PyPI module "xattr"
        to be installed. An exception will be thrown if it is not available.
        You can usually install it by running "sudo pip install xattr".
        
        NOTE: For now, if xattr support is not enabled, this will just return
        the empty list. Try using set_xattr if you want to get an exception if
        extended attributes aren't enabled. I'll probably add a method for
        checking if extended attributes are enabled on the file in question
        later on.
        r   N)xattrr>   	listxattrr   IOErrorerrno
EOPNOTSUPPENOENT)r   r   es      r   list_xattrszFile.list_xattrsN  s^    D 				233 	ww%***agg.E		s    #* 	A:;A5.A:4A55A:c                 F    ddl }|j                  | j                  ||       y)z
        Sets an extended attribute with the specified name and value on this
        file.
        
        The same compatibility warnings present on list_xattrs apply here.
        r   N)r   setxattrr   )r   rT   r   r   s       r   	set_xattrzFile.set_xattrz  s     	tyy$.r   c                 $   ddl }	 |j                  | j                  |      S # t        $ rd}|j                  t        j
                  k(  s:|j                  t        j                  k(  s|j                  t        j                  k(  r|cY d}~S  d}~ww xY w)a3  
        Returns the value of the extended attribute with the specified name
        on this file, as a string, or returns the value of default (which
        defaults to None) if no such extended attribute exists.
        
        The same compatibility warnings present on list_xattrs apply here.
        r   N)r   getxattrr   r   r   ENODATAr   r   )r   rT   defaultr   r   s        r   	get_xattrzFile.get_xattr  sj     		>>$))T22 	5==(AGGu7G7G,Gww%,,.	s!   " 	BAB
B	B

Bc                 *    | j                  |d      duS )z
        Returns True if this file has an extended attribute with the specified
        name, or False if it doesn't.
        
        The same compatibility warnings present on list_xattrs apply here.
        N)r  rS   s     r   	has_xattrzFile.has_xattr  s     ~~dD)55r   c                     ddl }	 |j                  | j                  |      S # t        $ r>}|j                  t        j
                  k(  rt        d| j                  d|       d}~ww xY w)ai  
        Same as get_xattr, but throws a KeyError if the specified extended
        attribute does not exist instead of returning a default value.
        
        The same compatibility warnings present on list_xattrs apply here.
        
        Note that an IOError will be thrown if extended attributes aren't
        supported instead of KeyError.
        r   NzFile z has no attribute )r   r   r   r   r   r   KeyError)r   rT   r   r   s       r   check_xattrzFile.check_xattr  sX     		>>$))T22 	ww%--'		4PQQ		s   " 	A)9A$$A)c                 (   ddl }	 |j                  | j                  |       y# t        $ re}|j                  t        j
                  k(  s:|j                  t        j                  k(  s|j                  t        j                  k(  r|rn Y d}~yd}~ww xY w)a_  
        Deletes the extended attribute with the specified name from this file.
        If the attribute does not exist and silent is true, nothing will
        happen. If the attribute does not exist and silent is false, an
        exception will be thrown.
        
        The same compatibility warnings present on list_xattrs apply here.
        r   N)r   removexattrr   r   r   r   r   r   )r   rT   r   r   r   s        r   delete_xattrzFile.delete_xattr  sn     		dii. 	5==(AGGu7G7G,Gww%,,.F 		s   # 	BABBc                      d| j                   z  S )Nzfileutils.File(%r))r   r"   s    r   __str__zFile.__str__  s    #djj00r   c                     t        |t              st        S t        t        j
                  j                  | j
                        t        j
                  j                  |j
                              S r   )r   r   NotImplementedcmpr   r   normcaser   s     r   __cmp__zFile.__cmp__  sE    %&!!277##DII.0@0@0LMMr   c                 f    t        t        j                  j                  | j                              S r   )r   r   r   r  r"   s    r   __hash__zFile.__hash__  s     BGG$$TYY/00r   c                      y)z
        Returns True. File objects are always true values; to test for their
        existence, use self.exists instead.
        T r"   s    r   __nonzero__zFile.__nonzero__  s    
 r   )F)NNr   )NTT)T)i @  T)FF)M__name__
__module____qualname____doc__r   propertyr#   r%   r(   r+   r.   r-   r2   r5   r7   r<   r>   r9   rC   rE   r:   __div__rL   rP   rU   rR   r]   r_   rT   rg   r   rd   r   rw   ry   r   r   r   r   r   r   rr   rY   rq   hashlibmd5r   r   r   r   r   r   r   r   r   r   r   r   r   rN   r   r   r   r   r   setterr   r   r  r  r  r	  r  __repr__r  r  r  r  r   r   r   r   4   s    D ) )   * * * * ? ? + + * *VQ 9 9 . . 15  GL '  "  $ $ , ,E  
 
V * *&"8
% D  &0

	*& %[[T (3CC <
    6(3T,&"2*A=* ' ', ' '* * **X/&6&(1 HN
1r   r   c                   "    e Zd ZdZd Zd Zd Zy)r   z
    The class of the context managers returned from File.as_working. See that
    method's docstring for more information on what this class does.
    c                     || _         y r   )r   )r   r   s     r   r   z_AsWorking.__init__  s	    r   c                     t        j                         | _        | j                  j	                          | j                  S r   )r   getcwdold_pathr   r   r"   s    r   	__enter__z_AsWorking.__enter__  s'    		{{r   c                 B    t        j                  | j                         y r   )r   r   r$  )r   rF   s     r   __exit__z_AsWorking.__exit__  s    
r   N)r  r  r  r  r   r%  r'  r  r   r   r   r     s    
 r   r   c                     t        |xs t        j                               }t        t        j                  | ||j                              }||_        |S )aC  
    Creates a folder (with tmpfile.mkdtemp) with the specified prefix, suffix,
    and parent folder (or the current platform's default temporary directory if
    no parent is specified).
    
    If delete_on_exit is True, the returned file's delete_on_exit property will
    be set to True just before returning it.
    )r   tempfile
gettempdirmkdtempr   r   )suffixprefixrR   r   r   s        r   create_temporary_folderr.    sF     &1H//12F(""666;;?@F*FMr   )r   tmpNF)r  r   os.pathr}   r   r   
contextlibr   r   urllibr  	functoolsr   r   rL   rK   r{   atexitr)  SKIPr   r   setr
   registerr   r   objectr   r   r.  r  r   r   <module>r9     s    
        )    
 %& &
f6 fR   " =A+0r   