docs: def _get_orthologs(self, limit):
          """
          This will process each of the specified pairwise orthology files,
          creating orthology associations based on the specified orthology code.
          this currently assumes that each of the orthology files is identically
          formatted. Relationships are made between genes here.
  
          There is also a nominal amount of identifier re-formatting:
          MGI:MGI --> MGI
          Ensembl --> ENSEMBL
  
          we skip any genes where we don't know how to map the gene identifiers.
          For example, Gene:Huwe1 for RAT is not an identifier, so we skip any
          mappings to this identifier.  Often, the there are two entries for the
          same gene (base on equivalent Uniprot id), and so we are not actually
          losing any information.
  
          We presently have a hard-coded filter to select only orthology
          relationships where one of the pair is in our species of interest
          (Mouse and Human, for the moment).
          This will be added as a configurable parameter in the future.
  
          Genes are also added to a grouping class defined with a PANTHER id.
  
          Triples:
          <gene1_id> RO:othologous <gene2_id>
          <assoc_id> :hasSubject <gene1_id>
          <assoc_id> :hasObject <gene2_id>
          <assoc_id> :hasPredicate <RO:orthologous>
          <assoc_id> dc:evidence ECO:phylogenetic_evidence
  
          <panther_id> a DATA:gene_family
          <panther_id> RO:has_member <gene1_id>
          <panther_id> RO:has_member <gene2_id>
  
          :param limit:
          :return:
  
          """
          LOG.info("getting orthologs")
  
          if self.test_mode:
              graph = self.testgraph
  
          else:
              graph = self.graph
          model = Model(graph)
          unprocessed_gene_ids = set()  # may be faster to make a set after
  
          for k in self.files.keys():
              f = '/'.join((self.rawdir, self.files[k]['file']))
              matchcounter = 0
              mytar = tarfile.open(f, 'r:gz')
  
              # assume that the first entry is the item
              fname = mytar.getmembers()[0]
              LOG.info("Parsing %s", fname.name)
              line_counter = 0
              with mytar.extractfile(fname) as csvfile:
                  for line in csvfile:
                      # skip comment lines
                      if re.match(r'^#', line.decode()):
                          LOG.info("Skipping header line")
                          continue
                      line_counter += 1
  
                      # a little feedback to the user since there's so many
                      if line_counter % 1000000 == 0:
                          LOG.info(
                              "Processed %d lines from %s",
                              line_counter, fname.name)
  
                      line = line.decode().strip()
  
                      # parse each row. ancestor_taxon is unused
                      # HUMAN|Ensembl=ENSG00000184730|UniProtKB=Q0VD83
                      #   	MOUSE|MGI=MGI=2176230|UniProtKB=Q8VBT6
                      #       	LDO	Euarchontoglires	PTHR15964
                      (a, b, orthology_class, ancestor_taxon,
                       panther_id) = line.split('\t')
                      (species_a, gene_a, protein_a) = a.split('|')
                      (species_b, gene_b, protein_b) = b.split('|')
  
                      # skip the entries that don't have homolog relationships
                      # with the test ids
                      if self.test_mode and not (
                              re.sub(r'UniProtKB=', '',
                                     protein_a) in self.test_ids or
                              re.sub(r'UniProtKB=', '', protein_b)
                              in self.test_ids):
                          continue
  
                      # map the taxon abbreviations to ncbi taxon id numbers
                      taxon_a = self.resolve(species_a).split(':')[1].strip()
                      taxon_b = self.resolve(species_b).split(':')[1].strip()
  
                      # ###uncomment the following code block
                      # if you want to filter based on taxid of favorite animals
                      # taxids = [9606,10090,10116,7227,7955,6239,8355]
                      # taxids = [9606] #human only
                      # retain only those orthologous relationships to genes
                      # in the specified taxids
                      # using AND will get you only those associations where
                      # gene1 AND gene2 are in the taxid list (most-filter)
                      # using OR will get you any associations where
                      # gene1 OR gene2 are in the taxid list (some-filter)
                      if self.tax_ids is not None and \
                              (taxon_a not in self.tax_ids) and \
                              (taxon_b not in self.tax_ids):
                          continue
                      else:
                          matchcounter += 1
                          if limit is not None and matchcounter > limit:
                              break
  
                      # ### end code block for filtering on taxon
  
                      # fix the gene identifiers
                      gene_a = re.sub(r'=', ':', gene_a)
                      gene_b = re.sub(r'=', ':', gene_b)
  
                      clean_gene = self._clean_up_gene_id(
                          gene_a, species_a, self.curie_map)
                      if clean_gene is None:
                          unprocessed_gene_ids.add(gene_a)
                      gene_a = clean_gene
                      clean_gene = self._clean_up_gene_id(
                          gene_b, species_b, self.curie_map)
                      if clean_gene is None:
                          unprocessed_gene_ids.add(gene_b)
                      gene_b = clean_gene
  
                      # a special case here; mostly some rat genes
                      # they use symbols instead of identifiers.  will skip
                      if gene_a is None or gene_b is None:
                          continue
  
                      rel = self.resolve(orthology_class)
  
                      evidence_id = self.globaltt['phylogenetic evidence']
  
                      # add the association and relevant nodes to graph
                      assoc = OrthologyAssoc(graph, self.name, gene_a, gene_b, rel)
                      assoc.add_evidence(evidence_id)
  
                      # add genes to graph;
                      # assume labels will be taken care of elsewhere
                      model.addClassToGraph(gene_a, None)
                      model.addClassToGraph(gene_b, None)
  
                      # might as well add the taxon info for completeness
                      graph.addTriple(
                          gene_a, self.globaltt['in taxon'], 'NCBITaxon:' + taxon_a)
                      graph.addTriple(
                          gene_b, self.globaltt['in taxon'], 'NCBITaxon:' + taxon_b)
  
                      assoc.add_association_to_graph()
  
                      # note this is incomplete...
                      # it won't construct the full family hierarchy,
                      # just the top-grouping
                      assoc.add_gene_family_to_graph(
                          ':'.join(('PANTHER', panther_id)))
  
                      if not self.test_mode \
                              and limit is not None and line_counter > limit:
                          break
                  # make report on unprocessed_gene_ids
  
              LOG.info("finished processing %s", f)
              LOG.warning(
                  "The following gene ids were unable to be processed: %s",
                  str(unprocessed_gene_ids))
  
          return