
    ^j                     `    d Z ddlmZ ddZddZddZddZddZdd	Zd
 Z	 G d de
      Zy)z
Node Searching.

.. note:: You can speed-up node searching, by installing https://pypi.org/project/fastcache/ and
          using :any:`cachedsearch`.
    )PreOrderIterNc                 $    t        | |||||      S )a  
    Search nodes matching `filter_` but stop at `maxlevel` or `stop`.

    Return tuple with matching nodes.

    Args:
        node: top node, start searching.

    Keyword Args:
        filter_: function called with every `node` as argument, `node` is returned if `True`.
        stop: stop iteration at `node` if `stop` function returns `True` for `node`.
        maxlevel (int): maximum descending in the node hierarchy.
        mincount (int): minimum number of nodes.
        maxcount (int): maximum number of nodes.

    Example tree:

    >>> from anytree import Node, RenderTree, AsciiStyle
    >>> f = Node("f")
    >>> b = Node("b", parent=f)
    >>> a = Node("a", parent=b)
    >>> d = Node("d", parent=b)
    >>> c = Node("c", parent=d)
    >>> e = Node("e", parent=d)
    >>> g = Node("g", parent=f)
    >>> i = Node("i", parent=g)
    >>> h = Node("h", parent=i)
    >>> print(RenderTree(f, style=AsciiStyle()).by_attr())
    f
    |-- b
    |   |-- a
    |   +-- d
    |       |-- c
    |       +-- e
    +-- g
        +-- i
            +-- h

    >>> findall(f, filter_=lambda node: node.name in ("a", "b"))
    (Node('/f/b'), Node('/f/b/a'))
    >>> findall(f, filter_=lambda node: d in node.path)
    (Node('/f/b/d'), Node('/f/b/d/c'), Node('/f/b/d/e'))

    The number of matches can be limited:

    >>> findall(f, filter_=lambda node: d in node.path, mincount=4)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    anytree.search.CountError: Expecting at least 4 elements, but found 3. ... Node('/f/b/d/e'))
    >>> findall(f, filter_=lambda node: d in node.path, maxcount=2)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    anytree.search.CountError: Expecting 2 elements at maximum, but found 3. ... Node('/f/b/d/e'))
    )filter_stopmaxlevelmincountmaxcount_findall)noder   r   r   r   r	   s         G/opt/ringagent/.cad-venv/lib/python3.12/site-packages/anytree/search.pyfindallr      s    n D'xRZemnn    c                 .    t        | fd|||      S )a  
    Search nodes with attribute `name` having `value` but stop at `maxlevel`.

    Return tuple with matching nodes.

    Args:
        node: top node, start searching.
        value: value which need to match

    Keyword Args:
        name (str): attribute name need to match
        maxlevel (int): maximum descending in the node hierarchy.
        mincount (int): minimum number of nodes.
        maxcount (int): maximum number of nodes.

    Example tree:

    >>> from anytree import Node, RenderTree, AsciiStyle
    >>> f = Node("f")
    >>> b = Node("b", parent=f)
    >>> a = Node("a", parent=b)
    >>> d = Node("d", parent=b)
    >>> c = Node("c", parent=d)
    >>> e = Node("e", parent=d)
    >>> g = Node("g", parent=f)
    >>> i = Node("i", parent=g)
    >>> h = Node("h", parent=i)
    >>> print(RenderTree(f, style=AsciiStyle()).by_attr())
    f
    |-- b
    |   |-- a
    |   +-- d
    |       |-- c
    |       +-- e
    +-- g
        +-- i
            +-- h

    >>> findall_by_attr(f, "d")
    (Node('/f/b/d'),)
    c                     t        |       S N_filter_by_namennamevalues    r   <lambda>z!findall_by_attr.<locals>.<lambda>q   s    /!T59 r   )r   r   r   r	   r
   )r   r   r   r   r   r	   s    ``   r   findall_by_attrr   E   s"    T 9 r   c                      t        | |||      S )a  
    Search for *single* node matching `filter_` but stop at `maxlevel` or `stop`.

    Return matching node.

    Args:
        node: top node, start searching.

    Keyword Args:
        filter_: function called with every `node` as argument, `node` is returned if `True`.
        stop: stop iteration at `node` if `stop` function returns `True` for `node`.
        maxlevel (int): maximum descending in the node hierarchy.

    Example tree:

    >>> from anytree import Node, RenderTree, AsciiStyle
    >>> f = Node("f")
    >>> b = Node("b", parent=f)
    >>> a = Node("a", parent=b)
    >>> d = Node("d", parent=b)
    >>> c = Node("c", parent=d)
    >>> e = Node("e", parent=d)
    >>> g = Node("g", parent=f)
    >>> i = Node("i", parent=g)
    >>> h = Node("h", parent=i)
    >>> print(RenderTree(f, style=AsciiStyle()).by_attr())
    f
    |-- b
    |   |-- a
    |   +-- d
    |       |-- c
    |       +-- e
    +-- g
        +-- i
            +-- h

    >>> find(f, lambda node: node.name == "d")
    Node('/f/b/d')
    >>> find(f, lambda node: node.name == "z")
    >>> find(f, lambda node: b in node.path)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
        ...
    anytree.search.CountError: Expecting 1 elements at maximum, but found 5. (Node('/f/b')... Node('/f/b/d/e'))
    )r   r   r   _find)r   r   r   r   s       r   findr   x   s    Z wTHEEr   c                 *    t        | fd|      S )a$  
    Search for *single* node with attribute `name` having `value` but stop at `maxlevel`.

    Return matching node.

    Args:
        node: top node, start searching.
        value: value which need to match


    Keyword Args:
        name (str): attribute name need to match
        maxlevel (int): maximum descending in the node hierarchy.

    Example tree:

    >>> from anytree import Node, RenderTree, AsciiStyle
    >>> f = Node("f")
    >>> b = Node("b", parent=f)
    >>> a = Node("a", parent=b)
    >>> d = Node("d", parent=b)
    >>> c = Node("c", parent=d, foo=4)
    >>> e = Node("e", parent=d)
    >>> g = Node("g", parent=f)
    >>> i = Node("i", parent=g)
    >>> h = Node("h", parent=i)
    >>> print(RenderTree(f, style=AsciiStyle()).by_attr())
    f
    |-- b
    |   |-- a
    |   +-- d
    |       |-- c
    |       +-- e
    +-- g
        +-- i
            +-- h

    >>> find_by_attr(f, "d")
    Node('/f/b/d')
    >>> find_by_attr(f, name="foo", value=4)
    Node('/f/b/d/c', foo=4)
    >>> find_by_attr(f, name="foo", value=8)
    c                     t        |       S r   r   r   s    r   r   zfind_by_attr.<locals>.<lambda>   s    D%)H r   )r   r   r   )r   r   r   r   s    `` r   find_by_attrr!      s    X HS[\\r   c                 4    t        | |||d      }|r|d   S d S )N   )r   r   r	   r   r
   )r   r   r   r   itemss        r   r   r      s%    T71ME58&$&r   c                     t        t        | |||            }t        |      }|||k  rd}t        |||fz  |      |||kD  rd}t        |||fz  |      |S )Nz-Expecting at least %d elements, but found %d.z/Expecting %d elements at maximum, but found %d.)tupler   len
CountError)	r   r   r   r   r   r	   result	resultlenmsgs	            r   r   r      sw    <gtX>?FFI	H 4=)44f==	H 4?)44f==Mr   c                 @    	 t        | |      |k(  S # t        $ r Y yw xY w)NF)getattrAttributeError)r   r   r   s      r   r   r      s+    tT"e++ s    	c                        e Zd Z fdZ xZS )r(   c                 J    |r|dt        |      z   z  }t        | 	  |       y)z2Error raised on `mincount` or `maxcount` mismatch. N)reprsuper__init__)selfr+   r)   	__class__s      r   r4   zCountError.__init__   s&    3f%%Cr   )__name__
__module____qualname__r4   __classcell__)r6   s   @r   r(   r(      s     r   r(   )NNNNN)r   NNN)NNN)r   N)NN)NNNN)__doc__anytree.iteratorsr   r   r   r   r!   r   r   r   RuntimeErrorr(    r   r   <module>r?      sE    +7ot0f-F`,]^'
	 r   