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