o
    Q `j                     @   s8  d Z ddlmZ ddlZddlmZ ddlmZ ddlmZ ddlm	Z	 dd	l
mZ dd
lmZ ddlmZ ddlmZ ejrkddlmZmZmZmZmZmZmZmZmZmZ ddlmZ ddlmZ eeege f Z!ej"dddZ#eddZ$	 G dd de%Z&G dd dej'e# Z(e& Z)e)j*Z*e)j+Z,e)jZ-e)j.Z/dS )zMachinery for walking a filesystem.

*Walking* a filesystem means recursively visiting a directory and
any sub-directories. It is a fairly common requirement for copying,
searching etc. See :ref:`walking` for details.
    )unicode_literalsN)defaultdict)deque)
namedtuple   )	make_repr)FSError)abspath)combine)normpath)
AnyCallable
CollectionIteratorListOptionalMutableMappingTextTupleType)FS)Info_Fr   )ZboundStepzpath, dirs, filesc                       s   e Zd ZdZ								d, fdd	Zedd Zed	d
 Zedd Zedd Z	dd Z
	d-ddZdd Zdd Zdd Zdd Zdd Z	d-ddZ		d.d d!Zd/d"d#Zd/d$d%Z		d.d&d'Z	d-d(d)Z	d-d*d+Z  ZS )0Walkera  A walker object recursively lists directories in a filesystem.

    Arguments:
        ignore_errors (bool): If `True`, any errors reading a
            directory will be ignored, otherwise exceptions will
            be raised.
        on_error (callable, optional): If ``ignore_errors`` is `False`,
            then this callable will be invoked for a path and the exception
            object. It should return `True` to ignore the error, or `False`
            to re-raise it.
        search (str): If ``'breadth'`` then the directory will be
            walked *top down*. Set to ``'depth'`` to walk *bottom up*.
        filter (list, optional): If supplied, this parameter should be
            a list of filename patterns, e.g. ``['*.py']``. Files will
            only be returned if the final component matches one of the
            patterns.
        exclude (list, optional): If supplied, this parameter should be
            a list of filename patterns, e.g. ``['~*']``. Files matching
            any of these patterns will be removed from the walk.
        filter_dirs (list, optional): A list of patterns that will be used
            to match directories paths. The walk will only open directories
            that match at least one of these patterns.
        exclude_dirs (list, optional): A list of patterns that will be
            used to filter out directories from the walk. e.g.
            ``['*.svn', '*.git']``.
        max_depth (int, optional): Maximum directory depth to walk.

    FNbreadthc	           	         s   |dvrt d|| _|r|rt dn|r| jn| j}t|s$td|| _|| _|| _|| _	|| _
|| _|| _tt|   d S )N)r   depthz#search must be 'breadth' or 'depth'z,on_error is invalid when ignore_errors==Truezon_error must be callable)
ValueErrorignore_errors_ignore_errors_raise_errorscallable	TypeErroron_errorsearchfilterexcludefilter_dirsexclude_dirs	max_depthsuperr   __init__)	selfr   r#   r$   r%   r&   r'   r(   r)   	__class__ )/usr/lib/python3/dist-packages/fs/walk.pyr+   R   s$   zWalker.__init__c                 C      dS )zDefault on_error callback.Tr/   clspatherrorr/   r/   r0   r   r      zWalker._ignore_errorsc                 C   r1   )z%Callback to re-raise dir scan errors.Fr/   r2   r/   r/   r0   r    x   r6   zWalker._raise_errorsc                 C   s    | d}|r|dd S dS )zRCalculate the 'depth' of a directory path (number of
        components).
        /r   r   )stripcount)r3   r4   _pathr/   r/   r0   _calculate_depth~   s   
zWalker._calculate_depthc                 C   s   t |S )a  Bind a `Walker` instance to a given filesystem.

        This *binds* in instance of the Walker to a given filesystem, so
        that you won't need to explicitly provide the filesystem as a
        parameter.

        Arguments:
            fs (FS): A filesystem object.

        Returns:
            ~fs.walk.BoundWalker: a bound walker.

        Example:
            >>> from fs import open_fs
            >>> from fs.walk import Walker
            >>> home_fs = open_fs('~/')
            >>> walker = Walker.bind(home_fs)
            >>> for path in walker.files(filter=['*.py']):
            ...     print(path)

        Unless you have written a customized walker class, you will be
        unlikely to need to call this explicitly, as filesystem objects
        already have a ``walk`` attribute which is a bound walker
        object.

        Example:
            >>> from fs import open_fs
            >>> home_fs = open_fs('~/')
            >>> for path in home_fs.walk.files(filter=['*.py']):
            ...     print(path)

        )BoundWalker)r3   fsr/   r/   r0   bind   s   #zWalker.bindc                 C   sN   t | jj| jdf| jd f| jdf| jd f| jd f| jd f| j	d f| j
d fd	S )NFr   )r   r#   r$   r%   r&   r'   r(   r)   )r   r.   __name__r   r#   r$   r%   r&   r'   r(   r)   r,   r/   r/   r0   __repr__   s   zWalker.__repr__c                 C   s*   | j dkr| j|||dS | j|||dS )zGet the walk generator.r   
namespaces)r$   _walk_breadth_walk_depth)r,   r=   r4   rC   r/   r/   r0   
_iter_walk   s   
zWalker._iter_walkc                 C   sJ   | j dur|| j |jrdS | jdur|| j|jsdS | |||S )z?Check if a directory should be considered in the walk.
        NF)r(   matchnamer'   check_open_dirr,   r=   r4   infor/   r/   r0   _check_open_dir   s
   zWalker._check_open_dirc                 C   r1   )ad  Check if a directory should be opened.

        Override to exclude directories from the walk.

        Arguments:
            fs (FS): A filesystem instance.
            path (str): Path to directory.
            info (Info): A resource info object for the directory.

        Returns:
            bool: `True` if the directory should be opened.

        Tr/   rJ   r/   r/   r0   rI      s   zWalker.check_open_dirc                 C   s&   | j dur|| j krdS | |||S )z0Check if a directory contents should be scanned.NF)r)   check_scan_dir)r,   r=   r4   rK   r   r/   r/   r0   _check_scan_dir   s   zWalker._check_scan_dirc                 C   r1   )a  Check if a directory should be scanned.

        Override to omit scanning of certain directories. If a directory
        is omitted, it will appear in the walk but its files and
        sub-directories will not.

        Arguments:
            fs (FS): A filesystem instance.
            path (str): Path to directory.
            info (Info): A resource info object for the directory.

        Returns:
            bool: `True` if the directory should be scanned.

        Tr/   rJ   r/   r/   r0   rM      s   zWalker.check_scan_dirc                 C   s.   | j dur|| j |jrdS || j|jS )a  Check if a filename should be included.

        Override to exclude files from the walk.

        Arguments:
            fs (FS): A filesystem instance.
            info (Info): A resource info object.

        Returns:
            bool: `True` if the file should be included.

        NF)r&   rG   rH   r%   )r,   r=   rK   r/   r/   r0   
check_file   s   zWalker.check_filec              
   c   sX    z|j ||dD ]}|V  q	W dS  ty+ } z| ||s  W Y d}~dS d}~ww )a  Get an iterator of `Info` objects for a directory path.

        Arguments:
            fs (FS): A filesystem instance.
            dir_path (str): A path to a directory on the filesystem.
            namespaces (list): A list of additional namespaces to
                include in the `Info` objects.

        Returns:
            ~collections.Iterator: iterator of `Info` objects for
            resources within the given path.

        rB   N)scandirr   r#   )r,   r=   dir_pathrC   rK   r5   r/   r/   r0   _scan  s   zWalker._scanr7   c                 c   s    t t|}tt}| j|||d}|D ]/\}}|du r=g }	g }
|| D ]}|jr,|	n|
| q%t||	|
V  ||= q|| | qdS )a\  Walk the directory structure of a filesystem.

        Arguments:
            fs (FS): A filesystem instance.
            path (str): A path to a directory on the filesystem.
            namespaces (list, optional): A list of additional namespaces
                to add to the `Info` objects.

        Returns:
            collections.Iterator: an iterator of `~fs.walk.Step` instances.

        The return value is an iterator of ``(<path>, <dirs>, <files>)``
        named tuples,  where ``<path>`` is an absolute path to a
        directory, and ``<dirs>`` and ``<files>`` are a list of
        `~fs.info.Info` objects for directories and files in ``<path>``.

        Example:
            >>> home_fs = open_fs('~/')
            >>> walker = Walker(filter=['*.py'])
            >>> namespaces = ['details']
            >>> for path, dirs, files in walker.walk(home_fs, namespaces)
            ...    print("[{}]".format(path))
            ...    print("{} directories".format(len(dirs)))
            ...    total = sum(info.size for info in files)
            ...    print("{} bytes {}".format(total))

        rB   N)r	   r   r   listrF   is_dirappendr   )r,   r=   r4   rC   r:   Zdir_info_walkrQ   rK   dirsfiles_infor/   r/   r0   walk*  s   "zWalker.walkc                 c   s>    t }| j||dD ]\}}|dur|js|||jV  q
dS )aD  Walk a filesystem, yielding absolute paths to files.

        Arguments:
            fs (FS): A filesystem instance.
            path (str): A path to a directory on the filesystem.

        Yields:
            str: absolute path to files on the filesystem found
            recursively within the given directory.

        r4   Nr
   rF   rT   rH   r,   r=   r4   _combiner:   rK   r/   r/   r0   rX   Z     zWalker.filesc                 c   s>    t }| j||dD ]\}}|dur|jr|||jV  q
dS )aP  Walk a filesystem, yielding absolute paths to directories.

        Arguments:
            fs (FS): A filesystem instance.
            path (str): A path to a directory on the filesystem.

        Yields:
            str: absolute path to directories on the filesystem found
            recursively within the given directory.

        r[   Nr\   r]   r/   r/   r0   rW   l  r_   zWalker.dirsc                 c   sB    t }| j|||d}|D ]\}}|dur|||j|fV  qdS )a  Walk a filesystem, yielding tuples of ``(<path>, <info>)``.

        Arguments:
            fs (FS): A filesystem instance.
            path (str): A path to a directory on the filesystem.
            namespaces (list, optional): A list of additional namespaces
                to add to the `Info` objects.

        Yields:
            (str, Info): a tuple of ``(<absolute path>, <resource info>)``.

        r4   rC   N)r
   rF   rH   )r,   r=   r4   rC   r^   rV   r:   rK   r/   r/   r0   rK   ~  s   zWalker.infoc                 c   s    t |g}|j}|j}t}| j}| j}	| j}
| j}| j}|	|}|ri| }||||dD ]2}|j	rU|	|| d }|
|||rT||fV  |||||rT||||j
 q-|||r_||fV  q-|dfV  |s#dS dS )z3Walk files using a *breadth first* search.
        rB   r   N)r   
appendleftpopr
   rR   r;   rL   rN   rO   rT   rH   )r,   r=   r4   rC   queuepushrb   r^   rR   r;   rL   rN   _check_filer   rQ   rK   _depthr/   r/   r0   rD     s4   
	



zWalker._walk_breadthc                 c   s   t }| j}| j}| j}| j}| j}	||}
|||||ddfg}|j}|r|d \}}}t|d}|du rF|dur=|V  |dfV  |d= n=|jry|||
 d }||||rx|||||rs|||j	}||||||d||ff n||fV  n
|	||r||fV  |s&dS dS )z1Walk files using a *depth first* search.
        rB   Nr   )
r
   rR   r;   rL   rN   rO   rU   nextrT   rH   )r,   r=   r4   rC   r^   rR   r;   rL   rN   re   r   stackrd   rQ   Z
iter_filesparentrK   rf   r:   r/   r/   r0   rE     sF   




zWalker._walk_depth)FNr   NNNNNNr7   Nr7   )r?   
__module____qualname____doc__r+   classmethodr   r    r;   r>   rA   rF   rL   rI   rN   rM   rO   rR   rZ   rX   rW   rK   rD   rE   __classcell__r/   r/   r-   r0   r   4   sR     



$




0


(r   c                   @   s`   e Zd ZdZefddZdd Zdd Z			dd
dZeZ	dddZ
dddZ			dddZd	S )r<   a  A class that binds a `Walker` instance to a `FS` instance.

    Arguments:
        fs (FS): A filesystem instance.
        walker_class (type): A `~fs.walk.WalkerBase`
            sub-class. The default uses `~fs.walk.Walker`.

    You will typically not need to create instances of this class
    explicitly. Filesystems have a `~FS.walk` property which returns a
    `BoundWalker` object.

    Example:
        >>> import fs
        >>> home_fs = fs.open_fs('~/')
        >>> home_fs.walk
        BoundWalker(OSFS('/Users/will', encoding='utf-8'))

    A `BoundWalker` is callable. Calling it is an alias for
    `~fs.walk.BoundWalker.walk`.

    c                 C   s   || _ || _d S rk   )r=   walker_class)r,   r=   rs   r/   r/   r0   r+     s   
zBoundWalker.__init__c                 C   s   d | jS )NzBoundWalker({!r}))formatr=   r@   r/   r/   r0   rA     s   zBoundWalker.__repr__c                 O   s   | j |i |}|S )z"Create a walker instance.
        )rs   )r,   argskwargswalkerr/   r/   r0   _make_walker  s   zBoundWalker._make_walkerr7   Nc                 K   "   | j di |}|j| j||dS )a7
  Walk the directory structure of a filesystem.

        Arguments:
            path (str):
            namespaces (list, optional): A list of namespaces to include
                in the resource information, e.g. ``['basic', 'access']``
                (defaults to ``['basic']``).

        Keyword Arguments:
            ignore_errors (bool): If `True`, any errors reading a
                directory will be ignored, otherwise exceptions will be
                raised.
            on_error (callable): If ``ignore_errors`` is `False`, then
                this callable will be invoked with a path and the exception
                object. It should return `True` to ignore the error, or
                `False` to re-raise it.
            search (str): If ``'breadth'`` then the directory will be
                walked *top down*. Set to ``'depth'`` to walk *bottom up*.
            filter (list): If supplied, this parameter should be a list
                of file name patterns, e.g. ``['*.py']``. Files will only be
                returned if the final component matches one of the
                patterns.
            exclude (list, optional): If supplied, this parameter should be
                a list of filename patterns, e.g. ``['~*', '.*']``. Files matching
                any of these patterns will be removed from the walk.
            filter_dirs (list, optional): A list of patterns that will be used
                to match directories paths. The walk will only open directories
                that match at least one of these patterns.
            exclude_dirs (list): A list of patterns that will be used
                to filter out directories from the walk, e.g. ``['*.svn',
                '*.git']``.
            max_depth (int, optional): Maximum directory depth to walk.

        Returns:
            ~collections.Iterator: an iterator of ``(<path>, <dirs>, <files>)``
            named tuples,  where ``<path>`` is an absolute path to a
            directory, and ``<dirs>`` and ``<files>`` are a list of
            `~fs.info.Info` objects for directories and files in ``<path>``.

        Example:
            >>> home_fs = open_fs('~/')
            >>> walker = Walker(filter=['*.py'])
            >>> for path, dirs, files in walker.walk(home_fs, namespaces=['details']):
            ...     print("[{}]".format(path))
            ...     print("{} directories".format(len(dirs)))
            ...     total = sum(info.size for info in files)
            ...     print("{} bytes {}".format(total))

        This method invokes `Walker.walk` with bound `FS` object.

        r`   Nr/   )rx   rZ   r=   r,   r4   rC   rv   rw   r/   r/   r0   rZ     s   :zBoundWalker.walkc                 K       | j di |}|j| j|dS )aA  Walk a filesystem, yielding absolute paths to files.

        Arguments:
            path (str): A path to a directory.

        Keyword Arguments:
            ignore_errors (bool): If `True`, any errors reading a
                directory will be ignored, otherwise exceptions will be
                raised.
            on_error (callable): If ``ignore_errors`` is `False`, then
                this callable will be invoked with a path and the exception
                object. It should return `True` to ignore the error, or
                `False` to re-raise it.
            search (str): If ``'breadth'`` then the directory will be
                walked *top down*. Set to ``'depth'`` to walk *bottom up*.
            filter (list): If supplied, this parameter should be a list
                of file name patterns, e.g. ``['*.py']``. Files will only be
                returned if the final component matches one of the
                patterns.
            exclude (list, optional): If supplied, this parameter should be
                a list of filename patterns, e.g. ``['~*', '.*']``. Files matching
                any of these patterns will be removed from the walk.
            filter_dirs (list, optional): A list of patterns that will be used
                to match directories paths. The walk will only open directories
                that match at least one of these patterns.
            exclude_dirs (list): A list of patterns that will be used
                to filter out directories from the walk, e.g. ``['*.svn',
                '*.git']``.
            max_depth (int, optional): Maximum directory depth to walk.

        Returns:
            ~collections.Iterator: An iterator over file paths (absolute
            from the filesystem root).

        This method invokes `Walker.files` with the bound `FS` object.

        r[   Nr/   )rx   rX   r=   r,   r4   rv   rw   r/   r/   r0   rX   U  s   'zBoundWalker.filesc                 K   r{   )au  Walk a filesystem, yielding absolute paths to directories.

        Arguments:
            path (str): A path to a directory.

        Keyword Arguments:
            ignore_errors (bool): If `True`, any errors reading a
                directory will be ignored, otherwise exceptions will be
                raised.
            on_error (callable): If ``ignore_errors`` is `False`, then
                this callable will be invoked with a path and the exception
                object. It should return `True` to ignore the error, or
                `False` to re-raise it.
            search (str): If ``'breadth'`` then the directory will be
                walked *top down*. Set to ``'depth'`` to walk *bottom up*.
            filter_dirs (list, optional): A list of patterns that will be used
                to match directories paths. The walk will only open directories
                that match at least one of these patterns.
            exclude_dirs (list): A list of patterns that will be used
                to filter out directories from the walk, e.g. ``['*.svn',
                '*.git']``.
            max_depth (int, optional): Maximum directory depth to walk.

        Returns:
            ~collections.Iterator: an iterator over directory paths
            (absolute from the filesystem root).

        This method invokes `Walker.dirs` with the bound `FS` object.

        r[   Nr/   )rx   rW   r=   r|   r/   r/   r0   rW     s    zBoundWalker.dirsc                 K   ry   )a  Walk a filesystem, yielding path and `Info` of resources.

        Arguments:
            path (str): A path to a directory.
            namespaces (list, optional): A list of namespaces to include
                in the resource information, e.g. ``['basic', 'access']``
                (defaults to ``['basic']``).

        Keyword Arguments:
            ignore_errors (bool): If `True`, any errors reading a
                directory will be ignored, otherwise exceptions will be
                raised.
            on_error (callable): If ``ignore_errors`` is `False`, then
                this callable will be invoked with a path and the exception
                object. It should return `True` to ignore the error, or
                `False` to re-raise it.
            search (str): If ``'breadth'`` then the directory will be
                walked *top down*. Set to ``'depth'`` to walk *bottom up*.
            filter (list): If supplied, this parameter should be a list
                of file name patterns, e.g. ``['*.py']``. Files will only be
                returned if the final component matches one of the
                patterns.
            exclude (list, optional): If supplied, this parameter should be
                a list of filename patterns, e.g. ``['~*', '.*']``. Files matching
                any of these patterns will be removed from the walk.
            filter_dirs (list, optional): A list of patterns that will be used
                to match directories paths. The walk will only open directories
                that match at least one of these patterns.
            exclude_dirs (list): A list of patterns that will be used
                to filter out directories from the walk, e.g. ``['*.svn',
                '*.git']``.
            max_depth (int, optional): Maximum directory depth to walk.

        Returns:
            ~collections.Iterable: an iterable yielding tuples of
            ``(<absolute path>, <resource info>)``.

        This method invokes `Walker.info` with the bound `FS` object.

        r`   Nr/   )rx   rK   r=   rz   r/   r/   r0   rK     s   /zBoundWalker.inforl   rm   )r?   rn   ro   rp   r   r+   rA   rx   rZ   __call__rX   rW   rK   r/   r/   r/   r0   r<     s    	
=

*%r<   )0rp   Z
__future__r   typingcollectionsr   r   r   Z_reprr   errorsr   r4   r	   r
   r   ZTYPE_CHECKINGr   r   r   r   r   r   r   r   r   r   baser   rK   r   	ExceptionboolZOnErrorTypeVarr   r   objectr   ZGenericr<   Zdefault_walkerrZ   rX   Z
walk_filesZ	walk_inforW   	walk_dirsr/   r/   r/   r0   <module>   s<    0
   > k
