docs: def read_nodes(rows, source_id=1):
      """
      Return an iterator of rows ready to insert into table "nodes".
  
      * rows - iterator of lists (eg, output from read_archive or read_dmp)
      """
  
      ncbi_keys = ['tax_id', 'parent_id', 'rank', 'embl_code', 'division_id']
      extra_keys = ['source_id', 'is_valid']
      is_valid = True
  
      ncbi_cols = len(ncbi_keys)
  
      rank = ncbi_keys.index('rank')
      parent_id = ncbi_keys.index('parent_id')
  
      # assumes the first row is the root
      row = next(rows)
      row[rank] = 'root'
      # parent must be None for termination of recursive CTE for
      # calculating lineages
      row[parent_id] = None
      rows = itertools.chain([row], rows)
  
      yield ncbi_keys + extra_keys
  
      for row in rows:
          # replace whitespace in "rank" with underscore
          row[rank] = '_'.join(row[rank].split())
          # provide default values for source_id and is_valid
          yield row[:ncbi_cols] + [source_id, is_valid]