Skip to content

Commit

Permalink
Merge pull request #1088 from jmarshall/is_mapped
Browse files Browse the repository at this point in the history
Add AlignedSegment is_mapped/mate_is_mapped/is_forward/mate_is_forward properties
  • Loading branch information
AndreasHeger authored Mar 16, 2022
2 parents 7e24851 + 78e82b7 commit bd42f1c
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 5 deletions.
39 changes: 38 additions & 1 deletion pysam/libcalignedsegment.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,7 @@ cdef class AlignedSegment:
return (self.flag & BAM_FPROPER_PAIR) != 0
def __set__(self,val):
pysam_update_flag(self._delegate, val, BAM_FPROPER_PAIR)

property is_unmapped:
"""true if read itself is unmapped"""
def __get__(self):
Expand All @@ -1570,24 +1571,60 @@ cdef class AlignedSegment:
# bin as alignment length is now implicitly 1
update_bin(self._delegate)

property is_mapped:
"""true if read itself is mapped
(implemented in terms of :attr:`is_unmapped`)"""
def __get__(self):
return (self.flag & BAM_FUNMAP) == 0
def __set__(self, val):
pysam_update_flag(self._delegate, not val, BAM_FUNMAP)
update_bin(self._delegate)

property mate_is_unmapped:
"""true if the mate is unmapped"""
def __get__(self):
return (self.flag & BAM_FMUNMAP) != 0
def __set__(self,val):
pysam_update_flag(self._delegate, val, BAM_FMUNMAP)

property mate_is_mapped:
"""true if the mate is mapped
(implemented in terms of :attr:`mate_is_unmapped`)"""
def __get__(self):
return (self.flag & BAM_FMUNMAP) == 0
def __set__(self,val):
pysam_update_flag(self._delegate, not val, BAM_FMUNMAP)

property is_reverse:
"""true if read is mapped to reverse strand"""
def __get__(self):
return (self.flag & BAM_FREVERSE) != 0
def __set__(self,val):
pysam_update_flag(self._delegate, val, BAM_FREVERSE)

property is_forward:
"""true if read is mapped to forward strand
(implemented in terms of :attr:`is_reverse`)"""
def __get__(self):
return (self.flag & BAM_FREVERSE) == 0
def __set__(self,val):
pysam_update_flag(self._delegate, not val, BAM_FREVERSE)

property mate_is_reverse:
"""true is read is mapped to reverse strand"""
"""true if the mate is mapped to reverse strand"""
def __get__(self):
return (self.flag & BAM_FMREVERSE) != 0
def __set__(self,val):
pysam_update_flag(self._delegate, val, BAM_FMREVERSE)

property mate_is_forward:
"""true if the mate is mapped to forward strand
(implemented in terms of :attr:`mate_is_reverse`)"""
def __get__(self):
return (self.flag & BAM_FMREVERSE) == 0
def __set__(self,val):
pysam_update_flag(self._delegate, not val, BAM_FMREVERSE)

property is_read1:
"""true if this is read1"""
def __get__(self):
Expand Down
24 changes: 23 additions & 1 deletion tests/AlignedSegment_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ def testUpdate(self):
# reset qual
b = self.build_read()

def dual(name):
if name.endswith('is_unmapped'): return name.replace('unmapped', 'mapped')
elif name.endswith('is_mapped'): return name.replace('mapped', 'unmapped')
elif name.endswith('is_reverse'): return name.replace('reverse', 'forward')
elif name.endswith('is_forward'): return name.replace('forward', 'reverse')
else: return name

# check flags:
for x in (
"is_paired",
Expand All @@ -169,11 +176,24 @@ def testUpdate(self):
):
setattr(b, x, True)
self.assertEqual(getattr(b, x), True)
checkFieldEqual(self, a, b, ("flag", x,))
checkFieldEqual(self, a, b, ("flag", x, dual(x),))
setattr(b, x, False)
self.assertEqual(getattr(b, x), False)
checkFieldEqual(self, a, b)

for x in (
"is_mapped",
"mate_is_mapped",
"is_forward",
"mate_is_forward",
):
setattr(b, x, False)
self.assertEqual(getattr(b, x), False)
checkFieldEqual(self, a, b, ("flag", x, dual(x),))
setattr(b, x, True)
self.assertEqual(getattr(b, x), True)
checkFieldEqual(self, a, b)

def testUpdate2(self):
"""issue 135: inplace update of sequence and quality score.
Expand Down Expand Up @@ -769,6 +789,7 @@ def test_bin_values_for_unmapped_reads_ignore_length(self):
# changing unmapped flag changes bin because length is 0
a.is_unmapped = True
self.assertTrue(a.is_unmapped)
self.assertFalse(a.is_mapped)
self.assertEqual(a.bin, 4681)

# unmapped read without chromosomal location
Expand All @@ -780,6 +801,7 @@ def test_bin_values_for_mapped_reads_are_updated(self):
a = self.build_read()
a.pos = 20000
self.assertFalse(a.is_unmapped)
self.assertTrue(a.is_mapped)
self.assertEqual(a.bin, 4682)

# updating length updates bin
Expand Down
2 changes: 1 addition & 1 deletion tests/AlignmentFileFetchTestUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,6 @@ def build_aligned_pairs_with_pysam(*args, **kwargs):
with_seq = kwargs.pop("with_seq", False)
with pysam.AlignmentFile(*args, **kwargs) as inf:
data = [x.get_aligned_pairs(matches_only=matches_only, with_seq=with_seq)
for x in inf if not x.is_unmapped]
for x in inf if x.is_mapped]
return data

6 changes: 4 additions & 2 deletions tests/TestUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,10 @@ def checkFieldEqual(cls, read1, read2, exclude=[]):
".query_qualities",
".bin",
".is_paired", ".is_proper_pair",
".is_unmapped", ".mate_is_unmapped",
".is_reverse", ".mate_is_reverse",
".is_unmapped", ".is_mapped",
".mate_is_unmapped", ".mate_is_mapped",
".is_reverse", ".is_forward",
".mate_is_reverse", ".mate_is_forward",
".is_read1", ".is_read2",
".is_secondary", ".is_qcfail",
".is_duplicate"):
Expand Down

0 comments on commit bd42f1c

Please sign in to comment.