Parse a GO annotation file (in GAF 2.0 format).

        GO annotation files can be downloaded from the
        `UniProt-GOA download site`__ or from their `FTP server`__.

        __ goa_download_
        __ goa_ftp_

        .. _goa_download: http://www.ebi.ac.uk/GOA/downloads
        .. _goa_ftp: ftp://ftp.ebi.ac.uk/pub/databases/GO/goa/

        Parameters
        ----------
        annotation_file: str
            Path of the annotation file (in GAF 2.0 format).
        genes: List (tuple, set) of str
            List of valid gene names.
        db_sel: str, optional
            Select only annotations with this ``DB`` (column 1) value.
            If empty, disable filtering based on the ``DB`` value.
        select_evidence: list of str, optional
            Only include annotations with the given evidence codes.
            It not specified, allow all evidence codes, except for those listed
            in ``exclude_evidence``.
        exclude_evidence: list of str, optional
            Exclude all annotations with any of the given evidence codes.
            If ``select_evidence`` is specified, this parameter is ignored.
            If not specified, allow all evidence codes.
        exclude_ref: list of str, optional
            Exclude all annotations with the given DB:reference (column 6).
            Example: ``["PMID:2676709"]``. Note: This filter is currently
            ignored if an annotation has more than one reference.
        strip_species: bool, optional
            Undocumented.
        ignore_case: bool, optional
            Undocumented.

        Returns
        -------
        None

def parse_annotations(
            self, annotation_file, genes, db_sel='UniProtKB',
            select_evidence=None, exclude_evidence=None,
            exclude_ref=None, strip_species=False, ignore_case=False):
        """Parse a GO annotation file (in GAF 2.0 format).

        GO annotation files can be downloaded from the
        `UniProt-GOA download site`__ or from their `FTP server`__.

        __ goa_download_
        __ goa_ftp_

        .. _goa_download: http://www.ebi.ac.uk/GOA/downloads
        .. _goa_ftp: ftp://ftp.ebi.ac.uk/pub/databases/GO/goa/

        Parameters
        ----------
        annotation_file: str
            Path of the annotation file (in GAF 2.0 format).
        genes: List (tuple, set) of str
            List of valid gene names.
        db_sel: str, optional
            Select only annotations with this ``DB`` (column 1) value.
            If empty, disable filtering based on the ``DB`` value.
        select_evidence: list of str, optional
            Only include annotations with the given evidence codes.
            It not specified, allow all evidence codes, except for those listed
            in ``exclude_evidence``.
        exclude_evidence: list of str, optional
            Exclude all annotations with any of the given evidence codes.
            If ``select_evidence`` is specified, this parameter is ignored.
            If not specified, allow all evidence codes.
        exclude_ref: list of str, optional
            Exclude all annotations with the given DB:reference (column 6).
            Example: ``["PMID:2676709"]``. Note: This filter is currently
            ignored if an annotation has more than one reference.
        strip_species: bool, optional
            Undocumented.
        ignore_case: bool, optional
            Undocumented.

        Returns
        -------
        None
        """

        assert isinstance(annotation_file, str)
        assert isinstance(genes, (list, tuple))

        if not self.terms:
            raise ValueError('You need to first parse an OBO file!')

        if select_evidence is None:
            select_evidence = []

        if exclude_evidence is None:
            exclude_evidence = []

        if exclude_ref is None:
            exclude_ref = []

        # always overwrite all previously parsed annotations
        self.clear_annotation_data()

        # store genes
        self.genes = set(genes)  # store the list of genes for later use
        genes_upper = dict((g.upper(), g) for g in genes)
        logger.info('Read %d genes.', len(genes))

        # read annotations
        self.term_annotations = dict((id_, []) for id_ in self.terms)
        self.gene_annotations = dict((g, []) for g in self.genes)
        # gene_terms is used for statistics
        gene_terms = dict((g, set()) for g in self.genes)

        # isoform_pattern = re.compile(r"UniProtKB:([A-Z][0-9A-Z]{5}-\d+)")
        # gene_pattern = re.compile(r"[a-zA-Z0-9]+\.\d+$")
        # pmid_pattern = re.compile(r"(?:PMID:\d+|DOI:[^\s]+)")
        # uniprot_pattern = re.compile(r"UniProtKB:([A-Z][0-9A-Z]{5}(?:-\d+)?)")

        unknown_gene_names = Counter()
        unknown_gene_annotations = 0

        unknown_term_ids = Counter()
        unknown_term_annotations = 0

        # Parsing!
        logger.info('Parsing annotations...')
        n = 0
        excluded_evidence_annotations = 0
        excluded_reference_annotations = 0
        valid_annotations = 0
        with misc.smart_open_read(annotation_file, mode='rb',
                                  try_gzip=True) as fh:
            reader = csv.reader(fh, dialect='excel-tab', encoding='UTF-8')
            for i, l in enumerate(reader):
                # gene = None

                if not l:
                    continue
                if ((not db_sel) or l[0] == db_sel) and l[3] != 'NOT':
                    n += 1

                    # test if evidence code is excluded
                    if (select_evidence and l[6] not in select_evidence) \
                            or l[6] in exclude_evidence:
                        excluded_evidence_annotations += 1
                        continue

                    # test if reference is excluded
                    db_ref = []
                    if l[5]:
                        db_ref = l[5].split('|')
                        if len(db_ref) == 1 and db_ref[0] in exclude_ref:
                            excluded_reference_annotations += 1
                            continue
                            
                    # determine target gene
                    if not l[2]:
                        raise Exception('Missing target gene in line %d:\n%s'
                                        % (i+1, '\t'.join(l)))

                    gene = l[2]
                    # db = l[0]
                    db_id = l[1]
                    if strip_species:
                        try:
                            gene = gene[:gene.rindex('_')]
                        except ValueError:
                            pass

                    term_id = l[4]
                    evidence = l[6]

                    invalid = False

                    if (ignore_case and gene.upper() not in genes_upper) \
                            or ((not ignore_case) and gene not in self.genes):
                        unknown_gene_annotations += 1
                        unknown_gene_names[l[2]] += 1
                        invalid = True

                    if term_id not in self.terms:
                        unknown_term_annotations += 1
                        unknown_term_ids[term_id] += 1
                        invalid = True

                    if not invalid:
                
                        valid_annotations += 1

                        # if ignore_case, convert gene to "original" name
                        if ignore_case:
                            gene = genes_upper[gene.upper()]

                        term = self.terms[term_id]

                        # parse secondary information
                        # (associated UniProt and PubMed entries)
                        # pmid = pmid_pattern.search(l[5])
                        # if pmid is not None: pmid = pmid.group(0)
                        # uniprot = uniprot_pattern.search(l[7])
                        # if uniprot is not None: uniprot = uniprot.group(1)
                        with_ = []
                        if l[7]:
                            with_ = l[7].split('|')

                        # generate annotation
                        ann = GOAnnotation(
                            gene=gene, term=term,
                            evidence=evidence, db_id=db_id,
                            db_ref=db_ref, with_=with_)

                        # add annotation to global list
                        self.annotations.append(ann)

                        # add annotation under term ID
                        self.term_annotations[term_id].append(ann)

                        # add annotation under gene
                        self.gene_annotations[gene].append(ann)
                        gene_terms[gene].add(term_id)

        # output some statistics
        if n > 0:
            logger.info('Parsed %d positive GO annotations '
                        '(%d = %.1f%% excluded based on evidence type).',
                        n, excluded_evidence_annotations,
                        100*(excluded_evidence_annotations/float(n)))

        if unknown_gene_annotations > 0:
            logger.warning('Warning: %d annotations with %d unkonwn gene '
                           'names.',
                           unknown_gene_annotations, len(unknown_gene_names))

        if unknown_term_annotations > 0:
            logger.warning('Warning: %d annotations with %d unkonwn term IDs.',
                           unknown_term_annotations, len(unknown_term_ids))

        logger.info('Found a total of %d valid annotations.',
                    valid_annotations)

        logger.info('%d unique Gene-Term associations.',
                    sum(len(gene_terms[g]) for g in genes))