code: def graph_edges(self):
          
  
          # get edges with attributes
          edges = nx.get_edge_attributes(self._graph, 'branch').items()
  
          # sort them according to connected nodes
          edges_sorted = sorted(list(edges), key=lambda _: (''.join(sorted([repr(_[0][0]),repr(_[0][1])]))))
  
          for edge in edges_sorted:
              yield {'adj_nodes': edge[0], 'branch': edge[1]}
docs: Returns a generator for iterating over graph edges
  
          The edge of a graph is described by the two adjacent node and the branch
          object itself. Whereas the branch object is used to hold all relevant
          power system parameters.
  
          Yields
          ------
          int
              Description #TODO check
          
          Note
          ----
          There are generator functions for nodes (`Graph.nodes()`) and edges
          (`Graph.edges()`) in NetworkX but unlike graph nodes, which can be
          represented by objects, branch objects can only be accessed by using an
          edge attribute ('branch' is used here)
  
          To make access to attributes of the branch objects simpler and more
          intuitive for the user, this generator yields a dictionary for each edge
          that contains information about adjacent nodes and the branch object.
  
          Note, the construction of the dictionary highly depends on the structure
          of the in-going tuple (which is defined by the needs of networkX). If
          this changes, the code will break.