docs: def update_edge_keys(G):
      """
      Update the keys of edges that share a u, v with another edge but differ in
      geometry. For example, two one-way streets from u to v that bow away from
      each other as separate streets, rather than opposite direction edges of a 
      single street.
      
      Parameters
      ----------
      G : networkx multidigraph
  
      Returns
      -------
      networkx multigraph
      """
  
      # identify all the edges that are duplicates based on a sorted combination
      # of their origin, destination, and key. that is, edge uv will match edge vu
      # as a duplicate, but only if they have the same key
      edges = graph_to_gdfs(G, nodes=False, fill_edge_geometry=False)
      edges['uvk'] = edges.apply(lambda row: '_'.join(sorted([str(row['u']), str(row['v'])]) + [str(row['key'])]), axis=1)
      edges['dupe'] = edges['uvk'].duplicated(keep=False)
      dupes = edges[edges['dupe']==True].dropna(subset=['geometry'])
  
      different_streets = []
      groups = dupes[['geometry', 'uvk', 'u', 'v', 'key', 'dupe']].groupby('uvk')
      
      # for each set of duplicate edges
      for label, group in groups:
          
          # if there are more than 2 edges here, make sure to compare all
          if len(group['geometry']) > 2:
              l = group['geometry'].tolist()
              l.append(l[0])
              geom_pairs = list(zip(l[:-1], l[1:]))
          # otherwise, just compare the first edge to the second edge
          else:
              geom_pairs = [(group['geometry'].iloc[0], group['geometry'].iloc[1])]
          
          # for each pair of edges to compare
          for geom1, geom2 in geom_pairs:
              # if they don't have the same geometry, flag them as different streets
              if not is_same_geometry(geom1, geom2):
                  # add edge uvk, but not edge vuk, otherwise we'll iterate both their keys
                  # and they'll still duplicate each other at the end of this process
                  different_streets.append((group['u'].iloc[0], group['v'].iloc[0], group['key'].iloc[0]))
  
      # for each unique different street, iterate its key + 1 so it's unique
      for u, v, k in set(different_streets):
          # filter out key if it appears in data dict as we'll pass it explicitly
          attributes = {k:v for k, v in G[u][v][k].items() if k != 'key'}
          G.add_edge(u, v, key=k+1, **attributes)
          G.remove_edge(u, v, key=k)
  
      return G