text: user450: I have the following FASTA file, original.fasta:
  >foo
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  
  I need to change the record id from foo to bar, so I wrote the following code:
  from Bio import SeqIO
  
  original_file = r"path\to\original.fasta"
  corrected_file = r"path\to\corrected.fasta"
  
  with open(original_file) as original, open(corrected_file, 'w') as corrected:
      records = SeqIO.parse(original_file, 'fasta')
      for record in records:
          print record.id             # prints 'foo'
          if record.id == 'foo':
              record.id = 'bar'
          print record.id             # prints 'bar' as expected
          SeqIO.write(record, corrected, 'fasta')
  
  We printed the record id before and after the change, and get the expected result. We can even doublecheck by reading in the corrected file again with BioPython and printing out the record id:
  with open(corrected_file) as corrected:
      for record in SeqIO.parse(corrected, 'fasta'):
          print record.id                  # prints 'bar', as expected
  
  However, if we open the corrected file in a text editor, we see that the record id is not bar but  bar foo:
  >bar foo
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  
  We can confirm that this is what is written to the file if we read the file using plain Python:
  with open(corrected_file) as corrected:
      print corrected.readlines()[0][1:] # prints 'bar foo'
  
  Is this a bug in BioPython? And if not, what did I do wrong and how do I change the record id in a FASTA file using BioPython?
  
  user450: If I use SeqIO.parse(filehandle, 'fasta') to parse a FASTA file, then it will return a SeqRecord object where the id and name are the first word (everything before the first whitespace) of the line beginning with > and the description is the complete line (all not including the initial >). (This behaviour can overruled by providing a custom title2ids function).
  So, if I for example have a original.fasta file like:
  >Lorem|ipsum>dolor sit amet
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  
  Then I will get:
  >>> from Bio import SeqIO
  >>> path = r'C:\path\to\original.fasta'
  >>> records = SeqIO.parse(open(path), 'fasta')
  >>> record = next(records)
  >>> record.id
  'Lorem|ipsum>dolor'
  >>> record.name
  'Lorem|ipsum>dolor'
  >>> record.description
  'Lorem|ipsum>dolor sit amet'
  
  So, what happens in my case when you do 
      if record.id == 'foo':
          record.id = 'bar'
  
  is that the record.id is successfully changed from foo to bar, but that the record.description is not changed and stays foo. That's why, when the FASTA file is printed out, I see the described behaviour of 
  >bar foo
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  
  So, the solution to my problem is to both change the id AND the description:
  from Bio import SeqIO
  
  original_file = r"path\to\original.fasta"
  corrected_file = r"path\to\corrected.fasta"
  
  with open(original_file) as original, open(corrected_file, 'w') as corrected:
      records = SeqIO.parse(original_file, 'fasta')
      for record in records:
          if record.id == 'foo':
              record.id = 'bar'
              record.description = 'bar'
          SeqIO.write(record, corrected, 'fasta')
  
  with open(corrected_file) as corrected:
      records = SeqIO.parse(corrected, 'fasta')
      for record in records:
          print record.id             # prints bar
          print record.name           # prints bar
          print record.description    # prints bar
  
  
original_text: 450: <p>I have the following FASTA file, <code>original.fasta</code>:</p>
  
  <pre><code>&gt;foo
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  </code></pre>
  
  <p>I need to change the record id from <code>foo</code> to <code>bar</code>, so I wrote the following code:</p>
  
  <pre><code>from Bio import SeqIO
  
  original_file = r"path\to\original.fasta"
  corrected_file = r"path\to\corrected.fasta"
  
  with open(original_file) as original, open(corrected_file, 'w') as corrected:
      records = SeqIO.parse(original_file, 'fasta')
      for record in records:
          print record.id             # prints 'foo'
          if record.id == 'foo':
              record.id = 'bar'
          print record.id             # prints 'bar' as expected
          SeqIO.write(record, corrected, 'fasta')
  </code></pre>
  
  <p>We printed the record id before and after the change, and get the expected result. We can even doublecheck by reading in the corrected file again with BioPython and printing out the record id:</p>
  
  <pre><code>with open(corrected_file) as corrected:
      for record in SeqIO.parse(corrected, 'fasta'):
          print record.id                  # prints 'bar', as expected
  </code></pre>
  
  <p>However, if we open the corrected file in a text editor, we see that the record id is not <code>bar</code> but  <code>bar foo</code>:</p>
  
  <pre><code>&gt;bar foo
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  </code></pre>
  
  <p>We can confirm that this is what is written to the file if we read the file using plain Python:</p>
  
  <pre><code>with open(corrected_file) as corrected:
      print corrected.readlines()[0][1:] # prints 'bar foo'
  </code></pre>
  
  <p>Is this a bug in BioPython? And if not, what did I do wrong and how do I change the record id in a FASTA file using BioPython?</p>
   450: <p>If I use <code>SeqIO.parse(filehandle, 'fasta')</code> to parse a FASTA file, then it will return a <code>SeqRecord</code> object where the <code>id</code> and <code>name</code> are the first word (everything before the first whitespace) of the line beginning with <code>&gt;</code> and the <code>description</code> is the complete line (all not including the initial <code>&gt;</code>). (This behaviour can overruled by providing <a href="https://github.com/biopython/biopython/blob/dbdf7c155af3e7f203ea966acedc12740271ed73/Bio/SeqIO/FastaIO.py#L102" rel="noreferrer">a custom <code>title2ids</code> function</a>).</p>
  
  <p>So, if I for example have a <code>original.fasta</code> file like:</p>
  
  <pre><code>&gt;Lorem|ipsum&gt;dolor sit amet
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  </code></pre>
  
  <p>Then I will get:</p>
  
  <pre><code>&gt;&gt;&gt; from Bio import SeqIO
  &gt;&gt;&gt; path = r'C:\path\to\original.fasta'
  &gt;&gt;&gt; records = SeqIO.parse(open(path), 'fasta')
  &gt;&gt;&gt; record = next(records)
  &gt;&gt;&gt; record.id
  'Lorem|ipsum&gt;dolor'
  &gt;&gt;&gt; record.name
  'Lorem|ipsum&gt;dolor'
  &gt;&gt;&gt; record.description
  'Lorem|ipsum&gt;dolor sit amet'
  </code></pre>
  
  <p>So, what happens in my case when you do </p>
  
  <pre><code>    if record.id == 'foo':
          record.id = 'bar'
  </code></pre>
  
  <p>is that the <code>record.id</code> is successfully changed from <code>foo</code> to <code>bar</code>, but that the <code>record.description</code> is not changed and stays <code>foo</code>. That's why, when the FASTA file is printed out, I see the described behaviour of </p>
  
  <pre><code>&gt;bar foo
  GCTCACACATAGTTGATGCAGATGTTGAATTCACTATGAGGTGGGAGGATGTAGGGCCA
  </code></pre>
  
  <p>So, the solution to my problem is to both change the <code>id</code> AND the <code>description</code>:</p>
  
  <pre><code>from Bio import SeqIO
  
  original_file = r"path\to\original.fasta"
  corrected_file = r"path\to\corrected.fasta"
  
  with open(original_file) as original, open(corrected_file, 'w') as corrected:
      records = SeqIO.parse(original_file, 'fasta')
      for record in records:
          if record.id == 'foo':
              record.id = 'bar'
              record.description = 'bar'
          SeqIO.write(record, corrected, 'fasta')
  
  with open(corrected_file) as corrected:
      records = SeqIO.parse(corrected, 'fasta')
      for record in records:
          print record.id             # prints bar
          print record.name           # prints bar
          print record.description    # prints bar
  </code></pre>
  