nodes: 0, module; 1, function_definition; 2, function_name:_get_node_groups; 3, parameters; 4, block; 5, identifier:self; 6, expression_statement; 7, expression_statement; 8, for_statement; 9, comment:# Make a dictionary of nodes based on source/target as a key; 10, expression_statement; 11, for_statement; 12, comment:# Constrain the groups to ones that have more than 1 member; 13, expression_statement; 14, return_statement; 15, comment:"""Return a list of node id lists that are topologically identical.
  
          First construct a node_dict which is keyed to the node id and
          has a value which is a dict with keys 'sources' and 'targets'.
          The 'sources' and 'targets' each contain a list of tuples
          (i, polarity, source) edge of the node. node_dict is then processed
          by _get_node_key() which returns a tuple of (s,t) where s,t are
          sorted tuples of the ids for the source and target nodes. (s,t) is
          then used as a key in node_key_dict where the values are the node
          ids. node_groups is restricted to groups greater than 1 node.
          """; 16, assignment; 17, identifier:edge; 18, attribute; 19, comment:# Add edge as a source for its target node; 20, block; 21, assignment; 22, pattern_list; 23, call; 24, block; 25, assignment; 26, identifier:node_groups; 27, identifier:node_dict; 28, dictionary_comprehension; 29, identifier:self; 30, identifier:_edges; 31, expression_statement; 32, expression_statement; 33, comment:# Add edge as target for its source node; 34, expression_statement; 35, expression_statement; 36, identifier:node_key_dict; 37, call; 38, identifier:node_id; 39, identifier:node_d; 40, attribute; 41, argument_list; 42, expression_statement; 43, expression_statement; 44, identifier:node_groups; 45, list_comprehension; 46, pair; 47, for_in_clause; 48, assignment; 49, call; 50, assignment; 51, call; 52, attribute; 53, argument_list; 54, identifier:node_dict; 55, identifier:items; 56, assignment; 57, call; 58, identifier:g; 59, for_in_clause; 60, if_clause; 61, subscript; 62, dictionary; 63, identifier:node; 64, attribute; 65, identifier:edge_data; 66, tuple; 67, attribute; 68, argument_list; 69, identifier:edge_data; 70, tuple; 71, attribute; 72, argument_list; 73, identifier:collections; 74, identifier:defaultdict; 75, lambda; 76, identifier:key; 77, call; 78, attribute; 79, argument_list; 80, identifier:g; 81, call; 82, parenthesized_expression; 83, subscript; 84, string; 85, pair; 86, pair; 87, identifier:self; 88, identifier:_nodes; 89, subscript; 90, subscript; 91, subscript; 92, subscript; 93, identifier:append; 94, identifier:edge_data; 95, subscript; 96, subscript; 97, subscript; 98, subscript; 99, identifier:append; 100, identifier:edge_data; 101, list; 102, attribute; 103, argument_list; 104, subscript; 105, identifier:append; 106, identifier:node_id; 107, attribute; 108, argument_list; 109, comparison_operator:len(g) > 1; 110, identifier:node; 111, string; 112, string_content:id; 113, string; 114, list; 115, string; 116, list; 117, subscript; 118, string; 119, subscript; 120, string; 121, subscript; 122, string; 123, subscript; 124, string; 125, subscript; 126, string; 127, subscript; 128, string; 129, subscript; 130, string; 131, subscript; 132, string; 133, identifier:self; 134, identifier:_get_node_key; 135, identifier:node_d; 136, identifier:node_key_dict; 137, identifier:key; 138, identifier:node_key_dict; 139, identifier:values; 140, call; 141, integer:1; 142, string_content:data; 143, string_content:sources; 144, string_content:targets; 145, identifier:edge; 146, string; 147, string_content:i; 148, identifier:edge; 149, string; 150, string_content:polarity; 151, identifier:edge; 152, string; 153, string_content:source; 154, identifier:node_dict; 155, subscript; 156, string_content:sources; 157, identifier:edge; 158, string; 159, string_content:i; 160, identifier:edge; 161, string; 162, string_content:polarity; 163, identifier:edge; 164, string; 165, string_content:target; 166, identifier:node_dict; 167, subscript; 168, string_content:targets; 169, identifier:len; 170, argument_list; 171, string_content:data; 172, string_content:data; 173, string_content:data; 174, subscript; 175, string; 176, string_content:data; 177, string_content:data; 178, string_content:data; 179, subscript; 180, string; 181, identifier:g; 182, identifier:edge; 183, string; 184, string_content:target; 185, identifier:edge; 186, string; 187, string_content:source; 188, string_content:data; 189, string_content:data
code: def _get_node_groups(self):
          """Return a list of node id lists that are topologically identical.
  
          First construct a node_dict which is keyed to the node id and
          has a value which is a dict with keys 'sources' and 'targets'.
          The 'sources' and 'targets' each contain a list of tuples
          (i, polarity, source) edge of the node. node_dict is then processed
          by _get_node_key() which returns a tuple of (s,t) where s,t are
          sorted tuples of the ids for the source and target nodes. (s,t) is
          then used as a key in node_key_dict where the values are the node
          ids. node_groups is restricted to groups greater than 1 node.
          """
          node_dict = {node['data']['id']: {'sources': [], 'targets': []}
                       for node in self._nodes}
          for edge in self._edges:
              # Add edge as a source for its target node
              edge_data = (edge['data']['i'], edge['data']['polarity'],
                           edge['data']['source'])
              node_dict[edge['data']['target']]['sources'].append(edge_data)
              # Add edge as target for its source node
              edge_data = (edge['data']['i'], edge['data']['polarity'],
                           edge['data']['target'])
              node_dict[edge['data']['source']]['targets'].append(edge_data)
          # Make a dictionary of nodes based on source/target as a key
          node_key_dict = collections.defaultdict(lambda: [])
          for node_id, node_d in node_dict.items():
              key = self._get_node_key(node_d)
              node_key_dict[key].append(node_id)
          # Constrain the groups to ones that have more than 1 member
          node_groups = [g for g in node_key_dict.values() if (len(g) > 1)]
          return node_groups