docs: def bfs_conditional(G, source, reverse=False, keys=True, data=False,
                      yield_nodes=True, yield_if=None,
                      continue_if=None, visited_nodes=None,
                      yield_source=False):
      """
      Produce edges in a breadth-first-search starting at source, but only return
      nodes that satisfiy a condition, and only iterate past a node if it
      satisfies a different condition.
  
      conditions are callables that take (G, child, edge) and return true or false
  
      CommandLine:
          python -m utool.util_graph bfs_conditional
  
      Example:
          >>> # DISABLE_DOCTEST
          >>> import networkx as nx
          >>> import utool as ut
          >>> G = nx.Graph()
          >>> G.add_edges_from([(1, 2), (1, 3), (2, 3), (2, 4)])
          >>> continue_if = lambda G, child, edge: True
          >>> result = list(ut.bfs_conditional(G, 1, yield_nodes=False))
          >>> print(result)
          [(1, 2), (1, 3), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (4, 2)]
  
      Example:
          >>> # ENABLE_DOCTEST
          >>> import networkx as nx
          >>> import utool as ut
          >>> G = nx.Graph()
          >>> continue_if = lambda G, child, edge: (child % 2 == 0)
          >>> yield_if = lambda G, child, edge: (child % 2 == 1)
          >>> G.add_edges_from([(0, 1), (1, 3), (3, 5), (5, 10),
          >>>                   (4, 3), (3, 6),
          >>>                   (0, 2), (2, 4), (4, 6), (6, 10)])
          >>> result = list(ut.bfs_conditional(G, 0, continue_if=continue_if,
          >>>                                  yield_if=yield_if))
          >>> print(result)
          [1, 3, 5]
      """
      if reverse and hasattr(G, 'reverse'):
          G = G.reverse()
      if isinstance(G, nx.Graph):
          neighbors = functools.partial(G.edges, data=data)
      else:
          neighbors = functools.partial(G.edges, keys=keys, data=data)
  
      queue = collections.deque([])
  
      if visited_nodes is None:
          visited_nodes = set([])
      else:
          visited_nodes = set(visited_nodes)
  
      if source not in visited_nodes:
          if yield_nodes and yield_source:
              yield source
          visited_nodes.add(source)
          new_edges = neighbors(source)
          if isinstance(new_edges, list):
              new_edges = iter(new_edges)
          queue.append((source, new_edges))
  
      while queue:
          parent, edges = queue[0]
          for edge in edges:
              child = edge[1]
              if yield_nodes:
                  if child not in visited_nodes:
                      if yield_if is None or yield_if(G, child, edge):
                          yield child
              else:
                  if yield_if is None or yield_if(G, child, edge):
                      yield edge
              if child not in visited_nodes:
                  visited_nodes.add(child)
                  # Add new children to queue if the condition is satisfied
                  if continue_if is None or continue_if(G, child, edge):
                      new_edges = neighbors(child)
                      if isinstance(new_edges, list):
                          new_edges = iter(new_edges)
                      queue.append((child, new_edges))
          queue.popleft()