def walk()

in src/simplify_docx/utils/walk.py [0:0]


def walk(document, fun, TYPE="document", no_iter=None):
    """
    Walk an document tree and apply a function to matching nodes

    :param document: Simplified Docx element to walk
    :type document:object
    :param fun: A function to apply at each node in the document. If ``fun``
            takes just one parameter, it is passed the current element,
            otherwise it is passed the current element, the containing element,
            and the position of the current element within the containing
            element which is an integer in the current element is contained in
            an array of ``VALUE``s and ``None`` if the current element is the
            parent's ``VALUE``.
    :type fun: Callable
    :param TYPE: The node ``TYPE``s at which to apply the function ``fun``
    :type TYPE: str
    :param no_iter: Optional. A list of elmenet ``TYPE``s into which the walker
            should refrain from walking into. For example, setting
            ``no_iter=["paragraph"]`` would prevent the walker from traversing
            children (``VALUE``s) paragraph nodes.
    :type no_iter: Sequence[str]

    :return: ``None``
    :return type: None
    """
    _sig = signature(fun)
    _params = _sig.parameters

    has_multiple_parameters = len(_params) > 1 or any(
        param.kind in (param.VAR_KEYWORD, param.VAR_POSITIONAL)
        for param in _params.values()
    )

    stack = [(document, None)]
    while True:
        try:
            current, index = stack.pop()
        except IndexError:
            break

        if index is None:
            # CURRENT IS AN OBJECT:

            # APPLY THE FUNCTION
            if TYPE is None or current.get("TYPE", None) == TYPE:
                if has_multiple_parameters:
                    try:
                        parent, parent_index = stack[-1]
                    except IndexError:
                        out = fun(current, None, None)
                    else:
                        out = fun(current, parent, parent_index - 1)
                else:
                    out = fun(current)
                if out is not None:
                    return out

            val = current.get("VALUE", None)
            if isinstance(val, dict) and current.get("TYPE", None):
                # CHILD IS AN ELEMENT TO BE WAKLED
                stack.append((val, None))
                continue

            if (
                isinstance(val, list)
                and val
                and val[0].get("TYPE", None)
                and (no_iter is None or current["TYPE"] not in no_iter)
            ):
                # CHILD IS A LIST OF ELEMENTS
                stack.append((val, 0))
                continue

        else:
            # CURRENT IS A LIST
            try:
                nxt = current[index]
            except IndexError:
                pass
            else:
                stack.append((current, index + 1))
                stack.append((nxt, None))
                del nxt

        del current, index