docs: def _process_g2p(self, limit=None):
          """
          Here, we process the fish-to-phenotype associations,
          which also include environmental perturbations.
          The phenotypes may also be recorded as observed at specific stages.
          We create association objects with as much of the information
          as possible.
  
          A full association object may include:
  
          assoc hasSubject effective genotype
          assoc hasObject phenotype
          assoc hasSource publication (PMID or ZFIN pub id)
          assoc hasEnvironment environment
          assoc hasStartStage start_stage_id
          assoc hasEndStage end_stage_id
  
          :param limit:
          :return:
  
          """
          LOG.info("Processing G2P")
          line_counter = 0
          if self.test_mode:
              graph = self.testgraph
          else:
              graph = self.graph
  
          missing_zpids = list()
          mapped_zpids = list()
  
          model = Model(graph)
          eco_id = self.globaltt['experimental phenotypic evidence']
          raw = '/'.join((self.rawdir, self.files['pheno']['file']))
          with open(raw, 'r', encoding="utf8") as csvfile:
              filereader = csv.reader(csvfile, delimiter='\t', quotechar='\"')
              for row in filereader:
                  line_counter += 1
  
                  (fish_num, fish_name, start_stage_id, start_stage_name,
                   end_stage_id, end_stage_name, subterm1_id, subterm1_name,
                   postcomp1_rel_id, postcomp1_rel_name, superterm1_id,
                   superterm1_name, quality_id, quality_name, modifier,
                   subterm2_id, subterm2_name, postcomp2_rel_id,
                   postcomp2_rel_name, superterm2_id, superterm2_name, pub_id,
                   env_id
                   # , empty  # till next time
                  ) = row
  
                  if self.test_mode and (
                          fish_num not in self.test_ids['fish'] or
                          env_id not in self.test_ids['environment']):
                      continue
                  fish_id = 'ZFIN:' + fish_num.strip()
                  env_id = 'ZFIN:' + env_id.strip()
  
                  # ########### PHENOTYPES ##########
                  phenotype_id = self._map_sextuple_to_phenotype(superterm1_id,
                                                                 subterm1_id,
                                                                 quality_id,
                                                                 superterm2_id,
                                                                 subterm2_id,
                                                                 modifier)
  
                  if phenotype_id is None:
                      # check to see if it is a "normal" phenotype;
                      # if so, then
                      # check to see if the "abnormal" version is found
                      # if the abnormal version is not found, then report it
                      if modifier == 'normal':
                          p2 = self._map_sextuple_to_phenotype(
                              superterm1_id, subterm1_id, quality_id,
                              superterm2_id, subterm2_id, 'abnormal')
                          if p2 is None:
                              missing_zpids.append([
                                  superterm1_id, subterm1_id, quality_id,
                                  superterm2_id, subterm2_id, modifier])
                          else:
                              pass
                              # LOG.info("Normal phenotype found,
                              # and abnormal version exists")
                      else:
                          missing_zpids.append([
                              superterm1_id, subterm1_id, quality_id,
                              superterm2_id, subterm2_id, modifier])
  
                  else:
                      mapped_zpids.append([
                          superterm1_id, subterm1_id, quality_id,
                          superterm2_id, subterm2_id, modifier])
  
                  if pub_id != '':
                      pub_id = 'ZFIN:' + pub_id.strip()
                      ref = Reference(graph, pub_id)
                      ref.addRefToGraph()
  
                  if not re.match(r'^normal', modifier):
                      if phenotype_id is None:
                          continue
                      if start_stage_id != '':
                          start_stage_id = 'ZFIN:' + start_stage_id.strip()
                      if end_stage_id != '':
                          end_stage_id = 'ZFIN:' + end_stage_id.strip()
  
                      # add association
                      assoc = G2PAssoc(graph, self.name, fish_id, phenotype_id)
  
                      # only add the environment if there's components to it
                      if env_id in self.environment_hash \
                              and len(self.environment_hash.get(env_id)) > 0:
                          assoc.set_environment(env_id)
                      assoc.set_stage(start_stage_id, end_stage_id)
                      assoc.add_evidence(eco_id)
                      assoc.add_source(pub_id)
                      assoc.add_association_to_graph()
                      assoc_id = assoc.get_association_id()
                      if env_id not in self.environment_hash \
                              or len(self.environment_hash.get(env_id)) > 0:
                          model.addComment(
                              assoc_id, 'Legacy environment id ' + env_id)
                  else:
                      # TODO add normal phenotypes as associations #134 when
                      # https://github.com/sba1/bio-ontology-zp/issues/9
                      # is finished, we can use these add normal phenotypes
                      # as a comment on the genotype for now
                      clist = []
                      for x in [superterm1_name, subterm1_name, quality_name,
                                superterm2_name, subterm2_name, modifier]:
                          if x != '':
                              clist += [x]
  
                      c = '+'.join(clist)
                      c = ' '.join(("Normal phenotype observed:", c, "(" + pub_id + ")"))
                      if pub_id != '':
                          graph.addTriple(pub_id, self.globaltt['mentions'], fish_id)
  
                  if not self.test_mode and limit is not None and line_counter > limit:
                      break
  
          myset = set([','.join(x) for x in mapped_zpids])
          myset2 = set([','.join(x) for x in missing_zpids])
          LOG.info(
              "Phenotype-sextuples: %d mapped : %d unmapped", len(myset), len(myset2))
          self._write_missing_zp_report(missing_zpids)
  
          return