def __init__(self, filename, fast_filter=None, info_delimiter=';', key_delimiter='=', quotechar='',
                 tag_map={'ID': 'ID', 'Parent': 'Parent'}, preset=None):
        """This will read an entire GFF/GTF/GFF3 file and establish parent-child relations and
         allow for querying based on attributes such as transcripts, gene ids, and allow writing
         of useful file types such as fasta files of coding sequences, etc. It works at the
         "feature" level, which allows for grouping of exons of a gene and so on.

         The implementation is liberal because GFF/GFF3/GTF standards are so poorly followed. So
         errors such as a missing parent feature will be reported, but not break usage.

        :param filename: GFF file to read
        :param fast_filter: A list of attributes to keep in memory a reference to for fast querying
        :param info_delimiter: The character to split the info field on (default: ";")
        :param key_delimiter: The character to split the key-value pairings of the info field on (default: "=")
        :param quotechar: The character surrounding values in the info field (default: None)
        :param tag_map: A dictionary which can substitute the ID and Parent tags for alternatives
        :param preset: A string identifying various presets (choices: cufflinks)
        """
        super(GFFReader, self).__init__(filename)
        self.positions = {}
        self.fast_attributes = {}
        self.filters = set(fast_filter) if fast_filter else []
        GFF_TAGS = copy.deepcopy(config.GFF_TAGS)
        self.feature_map = {}
        child_list = []
        if preset and preset.lower() == 'cufflinks':
            key_delimiter=' '
            quotechar='"'
            self.id_tag = 'transcript_id'
            self.parent_tag = 'gene_id'#'transcript_id'#it's weird, but we're our own parent
        else:
            self.id_tag = tag_map['ID']
            self.parent_tag = tag_map['Parent']
        GFF_TAGS.add(self.id_tag)
        GFF_TAGS.add(self.parent_tag)
        for gff_object in GFFIterator(filename, info_delimiter=info_delimiter,
                                      key_delimiter=key_delimiter, quotechar=quotechar):
            chrom, start, end = gff_object.seqid, int(gff_object.start), int(gff_object.end)
            try:
                self.positions[chrom][(start, end)].append(gff_object)
            except KeyError:
                try:
                    self.positions[chrom][(start, end)] = [gff_object]
                except KeyError:
                    self.positions[chrom] = {(start, end): [gff_object]}
            fast_lookup = [fast_access for fast_access in self.filters for attribute in gff_object.attributes if fast_access in attribute]
            for fast_access in fast_lookup:
                try:
                    self.fast_attributes[fast_access].append(gff_object)
                except KeyError:
                    self.fast_attributes[fast_access] = [gff_object]
            known_tags = set([attribute for attribute in gff_object.attributes if attribute in GFF_TAGS])
            if self.id_tag in known_tags:
                gff_id = gff_object.attributes.get(self.id_tag, None)
                if gff_id:
                    try:
                        gff_feature = self.feature_map[gff_id]
                    except KeyError:
                        gff_feature = structure.GFFFeature(gff_id)
                        self.feature_map[gff_id] = gff_feature
                    gff_feature.features.add(gff_object)
                    #This is kept in the known_tags valid ID block, if we don't use IDs we shouldn't
                    #be using parent-child relations either
                    if self.parent_tag in known_tags:
                        child_list.append(gff_object)
            else:
                #this is a poorly formed GFF file and feature relations cannot be clearly established
                gff_id = str(len(self.feature_map))
                gff_feature = structure.GFFFeature(gff_id)
                gff_feature.features.add(gff_object)
                self.feature_map[gff_id] = gff_feature
        #Add parent-child relationships here since all GFF objects will be made at this point
        for child_gff_object in child_list:
            #get parents from the gff entries
            parent_ids = child_gff_object.attributes[self.parent_tag].split(',')
            for parent_id in parent_ids:
                parent_feature = self.feature_map.get(parent_id, None)
                if not parent_feature:
                    #missing the parent feature, make it but complain about it
                    parent_feature = structure.GFFFeature(parent_id)
                    self.feature_map[parent_id] = parent_feature
                    sys.stderr.write('Missing Parent Feature: %s\n' % parent_id)
                parent_feature.add_child(self.feature_map.get(child_gff_object.attributes.get(self.id_tag, None)))
def __init__ ( self , filename , fast_filter = None , info_delimiter = ';' , key_delimiter = '=' , quotechar = '' , tag_map = { 'ID' : 'ID' , 'Parent' : 'Parent' } , preset = None ) : super ( GFFReader , self ) . __init__ ( filename ) self . positions = { } self . fast_attributes = { } self . filters = set ( fast_filter ) if fast_filter else [ ] GFF_TAGS = copy . deepcopy ( config . GFF_TAGS ) self . feature_map = { } child_list = [ ] if preset and preset . lower ( ) == 'cufflinks' : key_delimiter = ' ' quotechar = '"' self . id_tag = 'transcript_id' self . parent_tag = 'gene_id' else : self . id_tag = tag_map [ 'ID' ] self . parent_tag = tag_map [ 'Parent' ] GFF_TAGS . add ( self . id_tag ) GFF_TAGS . add ( self . parent_tag ) for gff_object in GFFIterator ( filename , info_delimiter = info_delimiter , key_delimiter = key_delimiter , quotechar = quotechar ) : chrom , start , end = gff_object . seqid , int ( gff_object . start ) , int ( gff_object . end ) try : self . positions [ chrom ] [ ( start , end ) ] . append ( gff_object ) except KeyError : try : self . positions [ chrom ] [ ( start , end ) ] = [ gff_object ] except KeyError : self . positions [ chrom ] = { ( start , end ) : [ gff_object ] } fast_lookup = [ fast_access for fast_access in self . filters for attribute in gff_object . attributes if fast_access in attribute ] for fast_access in fast_lookup : try : self . fast_attributes [ fast_access ] . append ( gff_object ) except KeyError : self . fast_attributes [ fast_access ] = [ gff_object ] known_tags = set ( [ attribute for attribute in gff_object . attributes if attribute in GFF_TAGS ] ) if self . id_tag in known_tags : gff_id = gff_object . attributes . get ( self . id_tag , None ) if gff_id : try : gff_feature = self . feature_map [ gff_id ] except KeyError : gff_feature = structure . GFFFeature ( gff_id ) self . feature_map [ gff_id ] = gff_feature gff_feature . features . add ( gff_object ) if self . parent_tag in known_tags : child_list . append ( gff_object ) else : gff_id = str ( len ( self . feature_map ) ) gff_feature = structure . GFFFeature ( gff_id ) gff_feature . features . add ( gff_object ) self . feature_map [ gff_id ] = gff_feature for child_gff_object in child_list : parent_ids = child_gff_object . attributes [ self . parent_tag ] . split ( ',' ) for parent_id in parent_ids : parent_feature = self . feature_map . get ( parent_id , None ) if not parent_feature : parent_feature = structure . GFFFeature ( parent_id ) self . feature_map [ parent_id ] = parent_feature sys . stderr . write ( 'Missing Parent Feature: %s\n' % parent_id ) parent_feature . add_child ( self . feature_map . get ( child_gff_object . attributes . get ( self . id_tag , None ) ) )
This will read an entire GFF/GTF/GFF3 file and establish parent-child relations and
         allow for querying based on attributes such as transcripts, gene ids, and allow writing
         of useful file types such as fasta files of coding sequences, etc. It works at the
         "feature" level, which allows for grouping of exons of a gene and so on.

         The implementation is liberal because GFF/GFF3/GTF standards are so poorly followed. So
         errors such as a missing parent feature will be reported, but not break usage.

        :param filename: GFF file to read
        :param fast_filter: A list of attributes to keep in memory a reference to for fast querying
        :param info_delimiter: The character to split the info field on (default: ";")
        :param key_delimiter: The character to split the key-value pairings of the info field on (default: "=")
        :param quotechar: The character surrounding values in the info field (default: None)
        :param tag_map: A dictionary which can substitute the ID and Parent tags for alternatives
        :param preset: A string identifying various presets (choices: cufflinks)