text: user6738: I have a multi fasta file similar to this (relatively new here so uncertain of best way to present this; I have gone for an output and the code i used to make it - belt and braces...):
  # create a test dataset
  with open('test_dat.txt', 'w') as test_dat:
      l1 = [">AAA a aa", ">BBB b bb", ">CCC c cc"]
      l2 = ["ATGATG", "GACGAC", "TTGTTG"]
  
      for i in range(len(l1)):
          test_dat.write(l1[i] + "\n")
          test_dat.write(l2[i] + "\n")
  
  # which outputs something like this
  >AAA a aa
  ATGATG
  >BBB b bb
  GACGAC
  >CCC c cc
  TTGTTG
  
  I want to modify the fasta headers in my fasta file by adding some text to the beginning and, ideally, stripping out spaces (as i was advised that white space in the headings could cause problems for me down the line). My plan was to do this using BioPython and SeqIO.
  I started like this:
  # my attempt at altering the fasta headers using SeqIO
  from Bio import SeqIO
  
  # open my test data and create an output file
  with open('test_dat.txt', 'r') as inputs, open('test_dat_out.txt', 'w') as outputs:
  
      # create dictionary of the fasta sequences using SeqIO
      my_dict = SeqIO.to_dict(SeqIO.parse(inputs, "fasta"))
  
      # renaming my fasta headers - adding "TEST~~~TEST~~~" to front of header and remove white space
      for v in my_dict.values(): # using the values() to loop through...
          v.description = "TEST~~~TEST~~~" + v.description.replace(" ", "_")
  
      # write result to file
      SeqIO.write(my_dict.values(), outputs, 'fasta')
  
  which gave me a result with some duplication in the fasta header:
  #result i want
  >TEST~~~TEST~~~AAA_a_aa
  ATGATG
  
  #result i get
  >AAA TEST~~~TEST~~~AAA_a_aa
  ATGATG
  
  If i modify both the .id and .description in exactly the same way, as suggested here, but without removing white space:
  # renaming my fasta headers - adding "TEST~~~TEST~~~" to front of header
      for v in my_dict.values(): # using the values() to loop through...
          v.id = "TEST~~~TEST~~~" + v.id
          v.description = "TEST~~~TEST~~~" + v.description
  
  I get almost what i want, but the header still has spaces:
  >TEST~~~TEST~~~AAA a aa
  ATGATG
  
  I have tried to make the .id and .description match by adding a "_" to the end of .id, or by adding .replace(" ", "_") to both .id and .description (despite there being no spaces in .id), but I just cant seem to get exactly the output i want.
  I would really appreciate any pointers on this.
  
  user104: You're very close, but unfortunately for legacy reasons this aspect of the Biopython parser is not very intuitive. The key point is the .id is anything up until the first white space character. One day I hope the .description and .id attributes are replaced by a single attribute like .header. Anyway, here is a solution for your case:
  from Bio import SeqIO
  
  to_add = "TEST~~~TEST~~~"
  
  with open("out.fa", "w") as outputs:
      for r in SeqIO.parse("in.fa", "fasta"):
          r.id = (to_add + r.description).replace(" ", "_")
          r.description = r.id
          SeqIO.write(r, outputs, "fasta")
  
  Output on your sample input:
  >TEST~~~TEST~~~AAA_a_aa
  ATGATG
  >TEST~~~TEST~~~BBB_b_bb
  GACGAC
  >TEST~~~TEST~~~CCC_c_cc
  TTGTTG
  
  
original_text: 6738: <p>I have a multi fasta file similar to this (relatively new here so uncertain of best way to present this; I have gone for an output and the code i used to make it - belt and braces...):</p>
  
  <pre><code># create a test dataset
  with open('test_dat.txt', 'w') as test_dat:
      l1 = ["&gt;AAA a aa", "&gt;BBB b bb", "&gt;CCC c cc"]
      l2 = ["ATGATG", "GACGAC", "TTGTTG"]
  
      for i in range(len(l1)):
          test_dat.write(l1[i] + "\n")
          test_dat.write(l2[i] + "\n")
  
  # which outputs something like this
  &gt;AAA a aa
  ATGATG
  &gt;BBB b bb
  GACGAC
  &gt;CCC c cc
  TTGTTG
  </code></pre>
  
  <p>I want to modify the fasta headers in my fasta file by adding some text to the beginning and, ideally, stripping out spaces (as i was advised that white space in the headings could cause problems for me down the line). My plan was to do this using BioPython and SeqIO.</p>
  
  <p>I started like this:</p>
  
  <pre><code># my attempt at altering the fasta headers using SeqIO
  from Bio import SeqIO
  
  # open my test data and create an output file
  with open('test_dat.txt', 'r') as inputs, open('test_dat_out.txt', 'w') as outputs:
  
      # create dictionary of the fasta sequences using SeqIO
      my_dict = SeqIO.to_dict(SeqIO.parse(inputs, "fasta"))
  
      # renaming my fasta headers - adding "TEST~~~TEST~~~" to front of header and remove white space
      for v in my_dict.values(): # using the values() to loop through...
          v.description = "TEST~~~TEST~~~" + v.description.replace(" ", "_")
  
      # write result to file
      SeqIO.write(my_dict.values(), outputs, 'fasta')
  </code></pre>
  
  <p>which gave me a result with some duplication in the fasta header:</p>
  
  <pre><code>#result i want
  &gt;TEST~~~TEST~~~AAA_a_aa
  ATGATG
  
  #result i get
  &gt;AAA TEST~~~TEST~~~AAA_a_aa
  ATGATG
  </code></pre>
  
  <p>If i modify both the <code>.id</code> and <code>.description</code> in exactly the same way, as suggested <a href="https://bioinformatics.stackexchange.com/questions/307/changing-the-record-id-in-a-fasta-file-using-biopython">here</a>, but <strong>without</strong> removing white space:</p>
  
  <pre><code># renaming my fasta headers - adding "TEST~~~TEST~~~" to front of header
      for v in my_dict.values(): # using the values() to loop through...
          v.id = "TEST~~~TEST~~~" + v.id
          v.description = "TEST~~~TEST~~~" + v.description
  </code></pre>
  
  <p>I get almost what i want, but the header still has spaces:</p>
  
  <pre><code>&gt;TEST~~~TEST~~~AAA a aa
  ATGATG
  </code></pre>
  
  <p>I have tried to make the <code>.id</code> and <code>.description</code> match by adding a "_" to the end of <code>.id</code>, or by adding <code>.replace(" ", "_")</code> to both <code>.id</code> and <code>.description</code> (despite there being no spaces in <code>.id</code>), but I just cant seem to get exactly the output i want.</p>
  
  <p>I would really appreciate any pointers on this.</p>
   104: <p>You're very close, but unfortunately for legacy reasons this aspect of the Biopython parser is not very intuitive. The key point is the <code>.id</code> is anything up until the first white space character. One day I hope the <code>.description</code> and <code>.id</code> attributes are replaced by a single attribute like <code>.header</code>. Anyway, here is a solution for your case:</p>
  
  <pre><code>from Bio import SeqIO
  
  to_add = "TEST~~~TEST~~~"
  
  with open("out.fa", "w") as outputs:
      for r in SeqIO.parse("in.fa", "fasta"):
          r.id = (to_add + r.description).replace(" ", "_")
          r.description = r.id
          SeqIO.write(r, outputs, "fasta")
  </code></pre>
  
  <p>Output on your sample input:</p>
  
  <pre><code>&gt;TEST~~~TEST~~~AAA_a_aa
  ATGATG
  &gt;TEST~~~TEST~~~BBB_b_bb
  GACGAC
  &gt;TEST~~~TEST~~~CCC_c_cc
  TTGTTG
  </code></pre>
  