Source code for pygfa.graph_element.subgraph

import copy
import collections

from pygfa.graph_element.parser import line


[docs]class InvalidSubgraphError(Exception): pass
[docs]def is_subgraph(obj): try: return obj.sub_id != None and \ obj.elements != None and \ hasattr(obj, 'opt_fields') except: return False
[docs]class Subgraph: def __init__(self, graph_id, elements, opt_fields={}): """Create a Subgraph object. Subgraphs can be created from the following lines: * Path * OGroup * UGroup :param graph_id: The id of the subgraph. It can be '*', but cannot be None. :param elements: An ordered dictionary of node id and orientations. :param opt_fields: A dictionary of Fields or OptFields. :note: In case of Path line, the `overlaps` won't be represented as an explicit Subgraph attribute, but it will be added into the opt_fields dictionary with the name `overlaps`. This choice has been done since the overlaps can be computed with the alignment of each edge in the Subgraph. """ if not isinstance(graph_id, str): raise InvalidSubgraphError("A subgraph has always an id " \ + "of type string, " \ +"given {0} of type {1}".format( \ graph_id, \ type(graph_id))) if not isinstance(elements, dict): raise InvalidSubgraphError(\ "A dictionary of elements id:orientation is required.") self._sub_id = graph_id self._elements = copy.deepcopy(elements) self._opt_fields = {} for key, field in opt_fields.items(): if line.is_field(field): self._opt_fields[key] = copy.deepcopy(field)
[docs] def is_path(self): for element, orn in self.elements.items(): if orn is None: return False return True
@property def sub_id(self): return self._sub_id @property def elements(self): return self._elements @property def opt_fields(self): return self._opt_fields @classmethod
[docs] def from_line(cls, line_): try: fields = copy.deepcopy(line_.fields) if line_.type == 'P': fields.pop('path_name') fields.pop('seqs_names') names = collections.OrderedDict(\ (ref[0:-1], ref[-1:]) \ for ref in line_.fields['seqs_names'].value) return Subgraph( \ line_.fields['path_name'].value, \ names, \ fields) if line_.type == 'O': fields.pop('oid') fields.pop('references') refs = collections.OrderedDict(\ (ref[0:-1], ref[-1:]) \ for ref in line_.fields['references'].value) return Subgraph( \ line_.fields['oid'].value, \ refs, \ fields) if line_.type == 'U': fields.pop('uid') fields.pop('ids') ids = collections.OrderedDict(\ (id, None) \ for id in line_.fields['ids'].value) return Subgraph( \ line_.fields['uid'].value, \ ids, \ fields) except(KeyError, AttributeError): raise line.InvalidLineError("The given line cannot be "\ + "a Subgraph.")
[docs] def as_dict(self): """Turn the Subgraph into a dictionary, Put all fields and the optional fields into a dictionary. """ retval = {} retval['sub_id'] = self.sub_id retval['elements'] = self.elements for key, value in self.opt_fields.items(): retval[key] = value return retval
def __eq__(self, other): try: if self.sub_id != other.sub_id \ or self.elements != other.elements: return False for key, field in self.opt_fields.items(): if not key in other.opt_fields \ or field != other.opt_fields[key]: return False return True except: return False def __neq__(self, other): return not self == other def __str__(self): # pragma: no cover fields = ("sub_id", "elements", "opt_fields") opt_fields_ = [] if len(self.opt_fields) > 0: opt_fields_ = str.join(\ ",\t", \ [str(field) for key, field in self.opt_fields.items()]) elements_ = str.join(\ "\t", \ [id+(orn if orn != None else "") \ for id, orn in self.elements.items()]) values = [self.sub_id, \ elements_, \ "{" + str(opt_fields_) + "}" \ ] assoc = [str.join(" : ", pair) for pair in zip(fields, values)] return str.join(",\t", assoc)
if __name__ == '__main__': # pragma: no cover pass