
    i                     l    S r SSKJr  SS jrSS jrSS jrSS jrSS jrSS	 jrS
 r	 " S S\
5      rg)z
Node Searching.

.. note:: You can speed-up node searching, by installing https://pypi.org/project/fastcache/ and
          using :any:`cachedsearch`.
    )PreOrderIterNc           	          [        XX#XES9$ )aP  
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         ;/app/mltbenv/lib/python3.13/site-packages/anytree/search.pyfindallr      s    n DRZnn    c                 *   ^^ [        U UU4S jUUUS9$ )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                    > [        U TT5      $ N_filter_by_namennamevalues    r   <lambda>!findall_by_attr.<locals>.<lambda>q   s    /!T59r   )r   r   r   r	   r
   )r   r   r   r   r   r	   s    ``   r   findall_by_attrr   E   s"    T 9 r   c                     [        XX#S9$ )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 TEEr   c                 &   ^^ [        U UU4S jUS9$ )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                    > [        U TT5      $ r   r   r   s    r   r   find_by_attr.<locals>.<lambda>   s    D%)Hr   )r   r   r   )r   r   r   r   s    `` r   find_by_attrr#      s    X HS[\\r   c                 4    [        XX#SS9nU(       a  US   $ S $ )N   )r   r   r	   r   r
   )r   r   r   r   itemss        r   r   r      s!    T1ME58&$&r   c                     [        [        XX#5      5      n[        U5      nUb  Xt:  a  Sn[        XU4-  U5      eUb  Xu:  a  Sn[        XU4-  U5      eU$ )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      sk    <t>?FFI	 4=)44f==	 4?)44f==Mr   c                 @     [        X5      U:H  $ ! [         a     gf = f)NF)getattrAttributeError)r   r   r   s      r   r   r      s)    t"e++ s    
c                   (   ^  \ rS rSrU 4S jrSrU =r$ )r*      c                 T   > U(       a  US[        U5      -   -  n[        TU ]	  U5        g)z2Error raised on `mincount` or `maxcount` mismatch. N)reprsuper__init__)selfr-   r+   	__class__s      r   r7   CountError.__init__   s&    3f%%Cr    )__name__
__module____qualname____firstlineno__r7   __static_attributes____classcell__)r9   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   r   <module>rE      sE    +7ot0f-F`,]^'
	 r   