nodes: 0, module; 1, function_definition; 2, function_name:flatten_comments; 3, parameters; 4, block; 5, identifier:comments; 6, default_parameter; 7, expression_statement; 8, expression_statement; 9, for_statement; 10, expression_statement; 11, while_statement; 12, return_statement; 13, identifier:root_level; 14, integer:0; 15, comment:"""
          Flatten a PRAW comment tree while preserving the nested level of each
          comment via the `nested_level` attribute.
  
          There are a couple of different ways that the input comment list can be
          organized depending on its source:
  
              1. Comments that are returned from the get_submission() api call.
                 In this case, the comments list will contain only top level
                 comments and replies will be attached to those comments via
                 the `comment.replies` property.
  
              2. Comments that are returned from the comments() method on a
                 MoreComments object. In this case, the api returns all of the
                 comments and replies as a flat list. We need to sort out which
                 ones are replies to other comments by looking at the parent_id
                 parameter and checking if the id matches another comment.
  
          In addition, there is a bug in praw where a MoreComments object that is
          also a reply will be added below the comment as a sibling instead of
          a child. So it is especially important that this method is robust and
          double-checks all of the parent_id's of the comments.
  
          Reference:
              https://github.com/praw-dev/praw/issues/391
  
          """; 16, assignment; 17, identifier:item; 18, identifier:stack; 19, block; 20, assignment; 21, identifier:stack; 22, block; 23, identifier:retval; 24, identifier:stack; 25, subscript; 26, expression_statement; 27, pattern_list; 28, expression_list; 29, expression_statement; 30, comment:# The MoreComments item count should never be zero, discard it if; 31, comment:# it is. Need to look into this further.; 32, if_statement; 33, if_statement; 34, comment:# Add all of the attached replies to the front of the stack to be; 35, comment:# parsed separately; 36, if_statement; 37, comment:# The comment is now a potential parent for the items that are; 38, comment:# remaining on the stack.; 39, expression_statement; 40, expression_statement; 41, identifier:comments; 42, slice; 43, assignment; 44, identifier:retval; 45, identifier:parent_candidates; 46, list; 47, dictionary; 48, assignment; 49, boolean_operator; 50, block; 51, attribute; 52, comment:# Search the list of previous comments for a possible parent; 53, comment:# The match is based off of the parent_id parameter E.g.; 54, comment:#   parent.id = c0tprcm; 55, comment:#   child.parent_id = t1_c0tprcm; 56, block; 57, call; 58, block; 59, assignment; 60, call; 61, attribute; 62, identifier:root_level; 63, identifier:item; 64, call; 65, call; 66, comparison_operator:item.count == 0; 67, continue_statement; 68, identifier:item; 69, identifier:parent_id; 70, expression_statement; 71, if_statement; 72, identifier:hasattr; 73, argument_list; 74, for_statement; 75, expression_statement; 76, subscript; 77, identifier:item; 78, attribute; 79, argument_list; 80, identifier:item; 81, identifier:nested_level; 82, attribute; 83, argument_list; 84, identifier:isinstance; 85, argument_list; 86, attribute; 87, integer:0; 88, assignment; 89, identifier:parent; 90, block; 91, identifier:item; 92, string; 93, identifier:n; 94, attribute; 95, block; 96, assignment; 97, identifier:parent_candidates; 98, attribute; 99, identifier:retval; 100, identifier:append; 101, identifier:item; 102, identifier:stack; 103, identifier:pop; 104, integer:0; 105, identifier:item; 106, attribute; 107, identifier:item; 108, identifier:count; 109, identifier:parent; 110, call; 111, expression_statement; 112, string_content:replies; 113, identifier:item; 114, identifier:replies; 115, expression_statement; 116, subscript; 117, attribute; 118, identifier:item; 119, identifier:id; 120, attribute; 121, identifier:MoreComments; 122, attribute; 123, argument_list; 124, assignment; 125, assignment; 126, identifier:stack; 127, slice; 128, identifier:item; 129, identifier:replies; 130, identifier:praw; 131, identifier:objects; 132, identifier:parent_candidates; 133, identifier:get; 134, subscript; 135, attribute; 136, binary_operator:parent.nested_level + 1; 137, attribute; 138, binary_operator:item.nested_level + 1; 139, integer:0; 140, integer:0; 141, attribute; 142, slice; 143, identifier:item; 144, identifier:nested_level; 145, attribute; 146, integer:1; 147, identifier:n; 148, identifier:nested_level; 149, attribute; 150, integer:1; 151, identifier:item; 152, identifier:parent_id; 153, integer:3; 154, identifier:parent; 155, identifier:nested_level; 156, identifier:item; 157, identifier:nested_level
code: def flatten_comments(comments, root_level=0):
          """
          Flatten a PRAW comment tree while preserving the nested level of each
          comment via the `nested_level` attribute.
  
          There are a couple of different ways that the input comment list can be
          organized depending on its source:
  
              1. Comments that are returned from the get_submission() api call.
                 In this case, the comments list will contain only top level
                 comments and replies will be attached to those comments via
                 the `comment.replies` property.
  
              2. Comments that are returned from the comments() method on a
                 MoreComments object. In this case, the api returns all of the
                 comments and replies as a flat list. We need to sort out which
                 ones are replies to other comments by looking at the parent_id
                 parameter and checking if the id matches another comment.
  
          In addition, there is a bug in praw where a MoreComments object that is
          also a reply will be added below the comment as a sibling instead of
          a child. So it is especially important that this method is robust and
          double-checks all of the parent_id's of the comments.
  
          Reference:
              https://github.com/praw-dev/praw/issues/391
  
          """
  
          stack = comments[:]
          for item in stack:
              item.nested_level = root_level
  
          retval, parent_candidates = [], {}
          while stack:
              item = stack.pop(0)
  
              # The MoreComments item count should never be zero, discard it if
              # it is. Need to look into this further.
              if isinstance(item, praw.objects.MoreComments) and item.count == 0:
                  continue
  
              if item.parent_id:
                  # Search the list of previous comments for a possible parent
                  # The match is based off of the parent_id parameter E.g.
                  #   parent.id = c0tprcm
                  #   child.parent_id = t1_c0tprcm
                  parent = parent_candidates.get(item.parent_id[3:])
                  if parent:
                      item.nested_level = parent.nested_level + 1
  
              # Add all of the attached replies to the front of the stack to be
              # parsed separately
              if hasattr(item, 'replies'):
                  for n in item.replies:
                      n.nested_level = item.nested_level + 1
                  stack[0:0] = item.replies
  
              # The comment is now a potential parent for the items that are
              # remaining on the stack.
              parent_candidates[item.id] = item
  
              retval.append(item)
          return retval