Performs an in-order iteration of the operations (leaves) in an OP_TREE.

    Args:
        root: The operation or tree of operations to iterate.
        preserve_moments: Whether to yield Moments intact instead of
            flattening them

    Yields:
        Operations from the tree.

    Raises:
        TypeError: root isn't a valid OP_TREE.

def flatten_op_tree(root: OP_TREE,
                    preserve_moments: bool = False
                    ) -> Iterable[Union[Operation, Moment]]:
    """Performs an in-order iteration of the operations (leaves) in an OP_TREE.

    Args:
        root: The operation or tree of operations to iterate.
        preserve_moments: Whether to yield Moments intact instead of
            flattening them

    Yields:
        Operations from the tree.

    Raises:
        TypeError: root isn't a valid OP_TREE.
    """
    if (isinstance(root, Operation)
            or preserve_moments and isinstance(root, Moment)):
        yield root
        return

    if isinstance(root, collections.Iterable):
        for subtree in root:
            for item in flatten_op_tree(subtree, preserve_moments):
                yield item
        return

    raise TypeError('Not a collections.Iterable or an Operation: {} {}'.format(
        type(root), root))