docs: def nx_contracted_nodes(G, u, v, self_loops=True, inplace=False):
      """
      copy of networkx function with inplace modification
      TODO: commit to networkx
      """
      import itertools as it
      if G.is_directed():
          in_edges = ((w, u, d) for w, x, d in G.in_edges(v, data=True)
                      if self_loops or w != u)
          out_edges = ((u, w, d) for x, w, d in G.out_edges(v, data=True)
                       if self_loops or w != u)
          new_edges = it.chain(in_edges, out_edges)
      else:
          new_edges = ((u, w, d) for x, w, d in G.edges(v, data=True)
                       if self_loops or w != u)
      if inplace:
          H = G
          new_edges = list(new_edges)
      else:
          H = G.copy()
      node_dict = nx_node_dict(H)
      v_data = node_dict[v]
      H.remove_node(v)
      H.add_edges_from(new_edges)
      if 'contraction' in node_dict[u]:
          node_dict[u]['contraction'][v] = v_data
      else:
          node_dict[u]['contraction'] = {v: v_data}
      return H