ggonnella/gfapy

Calling .complement() on GFA2 edges

fedarko opened this issue · 3 comments

Hi, and thanks for developing gfapy!

I've been working with GFA1 and GFA2 files (in particular, sample1.gfa and sample2.gfa in this repository—these specify the same general graph, but in GFA1 and GFA2 respectively). Something I've noticed is that edges in GFA1 graphs have a .complement() method, which returns an edge in the opposite direction:

>>> g1 = gfapy.Gfa.from_file("sample1.gfa")
>>> g1.edges[0]
gfapy.Line('L	1	+	2	+	5M',version='gfa1',vlevel=1)
>>> g1.edges[0].complement()                                                     
gfapy.Line('L	2	-	1	-	5M',version='gfa1',vlevel=1)

This is a really useful feature. However, it looks like this isn't available for GFA2 edges:

>>> g2 = gfapy.Gfa.from_file("sample2.gfa")
>>> g2.edges[0]
gfapy.Line('E	*	1+	2+	3	8$	0	5	0,2,TS:i:2',version='gfa2',vlevel=1)
>>> g2.edges[0].complement()                                                     
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-9-e937829f2032> in <module>
----> 1 g2.edges[0].complement()

/anaconda3/envs/metagenomescope/lib/python3.6/site-packages/gfapy/line/common/dynamic_fields.py in __getattribute__(self, name)
     23         return attr.get(self)
     24     except AttributeError as err:
---> 25       return self._get_dynamic_field(name, err)
     26 
     27   def __setattr__(self, name, value):

/anaconda3/envs/metagenomescope/lib/python3.6/site-packages/gfapy/line/common/dynamic_fields.py in _get_dynamic_field(self, name, err)
     53           "No value defined for tag {}".format(name))
     54     else:
---> 55       raise err
     56 
     57   def _set_dynamic_field(self, name, value):

/anaconda3/envs/metagenomescope/lib/python3.6/site-packages/gfapy/line/common/dynamic_fields.py in __getattribute__(self, name)
     17   def __getattribute__(self, name):
     18     try:
---> 19       attr = super().__getattribute__(name)
     20       if not isinstance(attr, DynamicField):
     21         return attr

AttributeError: 'GFA2' object has no attribute 'complement'

Is this an intentional decision? I haven't been able to find much information about the .complement() method throughout the gfapy documentation, so I can't tell if this is a bug or by design.

Thank you again for developing this project!

@fedarko First: I never answered to this - actually no idea why. It was a very busy time for me and after two weeks you had published a patch in your project to circumvent this, but still I should have answered. I am very sorry. Since I decided to close all old issues, I am re-looking at this now.

Looking into it. In GFA1 I implemented it in order to implement the "canonicize" and "is_canonical" methods, which are useful e.g. to check for equivalence. I did not implement the same complementing operation for GFA2. The reason for that is that the trace alignment cannot be trivially complemented as a CIGAR alignment, without computing the alignment itself (at least this is what I wrote in my notes, which I wanted to write here, and somehow got lost). Therefore I did not implement the feature for GFA2.

I close the issue. If there is still interest or more comments, feel free to reopen it.