<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>

CC BY-SA 3.0
2017-05-31T14:36:06.500Z
2017-05-31T19:39:46.323Z
2017-05-31T19:39:46.323Z
BioGeek
<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>

CC BY-SA 3.0
2017-05-31T13:58:21.710Z
Keep in mind that `record.id` is not equal to the full record header, as `record.description` is a second part of it. If you parse the headers and they contain two space separated entries, record.id will only print the first one.
Jenez
CC BY-SA 3.0
2017-05-31T14:04:02.130Z
In addition, it seems you open the original file unnecessarily since you never do anything with the `original` object.
Jenez
CC BY-SA 3.0
2017-05-31T14:16:39.653Z
I think @Jenez is completely correct; Also you asked the same question on Biostars and got the same answer https://www.biostars.org/p/156428/
Chris_Rands
CC BY-SA 3.0
2017-05-31T14:23:05.713Z
@Jenez why not post that as an answer?
terdon
CC BY-SA 3.0
2017-05-31T14:24:18.933Z
@Chris_Rands yes, but we need content here so BioGeek was nice enough to ask again so we can have another answered post! Now the next person who comes here with a similar issue will find an answer. Yay!
terdon
CC BY-SA 3.0
2017-05-31T14:35:13.910Z
Don’t write paths as `r"foo\bar"`, this only works on Windows. Write them as `"foo/bar"` (no raw string needed), this works everywhere (including Windows).
Konrad Rudolph
CC BY-SA 3.0
2017-05-31T14:44:08.590Z
@terdon Because I felt it didn't accurately answer the question fully. It was more of a nudge in the right direction.
Jenez
CC BY-SA 3.0
2017-05-31T15:55:20.467Z
Regarding file paths, I suppose it is even better to use `os.path.join`, which automatically choses the correct separator.
bli
<fasta><python>
Changing the record id in a FASTA file using BioPython
# Changing the record id in a FASTA file using BioPython

(Asked by: username_0 on 2017-05-31)

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?

**Tags:** fasta, python
> **Comments:**
> **username_1**: Keep in mind that `record.id` is not equal to the full record header, as `record.description` is a second part of it. If you parse the headers and they contain two space separated entries, record.id will only print the first one.  
> **username_1**: In addition, it seems you open the original file unnecessarily since you never do anything with the `original` object.  
> **username_2**: I think @Jenez is completely correct; Also you asked the same question on Biostars and got the same answer https://www.biostars.org/p/156428/  
> **username_3**: @Jenez why not post that as an answer?  
> **username_3**: @Chris_Rands yes, but we need content here so BioGeek was nice enough to ask again so we can have another answered post! Now the next person who comes here with a similar issue will find an answer. Yay!  
> **username_4**: Don’t write paths as `r"foo\bar"`, this only works on Windows. Write them as `"foo/bar"` (no raw string needed), this works everywhere (including Windows).  
> **username_1**: @terdon Because I felt it didn't accurately answer the question fully. It was more of a nudge in the right direction.  
> **username_5**: Regarding file paths, I suppose it is even better to use `os.path.join`, which automatically choses the correct separator.  

---

## 1 answers

### Answer by username_0 on 2017-05-31. Score: 11 | Accepted answer

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


---

