def _do_merge(self, f, merge_strategy, add_duplicate=False):
        if merge_strategy == 'error':
            raise ValueError("Duplicate ID {0.id}".format(f))

        if merge_strategy == 'warning':
            logger.warning(
                "Duplicate lines in file for id '{0.id}'; "
                "ignoring all but the first".format(f))
            return None, merge_strategy

        elif merge_strategy == 'replace':
            return f, merge_strategy

        # This is by far the most complicated strategy.
        elif merge_strategy == 'merge':

            # Recall that if we made it to this method, there was at least one
            # ID collision.

            # This will eventually contain the features that match ID AND that
            # match non-attribute fields like start, stop, strand, etc.
            features_to_merge = []

            # Iterate through all features that have the same ID according to
            # the id_spec provided.
            if self.verbose == "debug":
                logger.debug('candidates with same idspec: %s'
                             % ([i.id for i in self._candidate_merges(f)]))

            # If force_merge_fields was provided, don't pay attention to these
            # fields if they're different.  We are assuming attributes will be
            # different, hence the [:-1]
            _gffkeys_to_check = list(
                set(constants._gffkeys[:-1])
                .difference(self.force_merge_fields))

            for existing_feature in self._candidate_merges(f):
                # Check other GFF fields (if not specified in
                # self.force_merge_fields) to make sure they match.
                other_attributes_same = True
                for k in _gffkeys_to_check:
                    if getattr(existing_feature, k) != getattr(f, k):
                        other_attributes_same = False
                        break

                if other_attributes_same:
                    # All the other GFF fields match.  So this existing feature
                    # should be merged.
                    features_to_merge.append(existing_feature)
                    if self.verbose == 'debug':
                        logger.debug(
                            'same attributes between:\nexisting: %s'
                            '\nthis    : %s'
                            % (existing_feature, f))
                else:
                    # The existing feature's GFF fields don't match, so don't
                    # append anything.
                    if self.verbose == 'debug':
                        logger.debug(
                            'different attributes between:\nexisting: %s\n'
                            'this    : %s'
                            % (existing_feature, f))

            if (len(features_to_merge) == 0):
                # No merge candidates found, so we should make a new ID for
                # this feature. This can happen when idspecs match, but other
                # fields (like start/stop) are different.  Call this method
                # again, but using the "create_unique" strategy, and then
                # record the newly-created ID in the duplicates table.
                orig_id = f.id
                uniqued_feature, merge_strategy = self._do_merge(
                    f, merge_strategy='create_unique')
                self._add_duplicate(orig_id, uniqued_feature.id)
                return uniqued_feature, merge_strategy

            # Whoo! Found some candidates to merge.
            else:
                if self.verbose == 'debug':
                    logger.debug('num candidates: %s' % len(features_to_merge))

                # This is the attributes dictionary we'll be modifying.
                merged_attributes = copy.deepcopy(f.attributes)

                # Keep track of non-attribute fields (this will be an empty
                # dict if no force_merge_fields)
                final_fields = dict(
                    [(field, set([getattr(f, field)]))
                     for field in self.force_merge_fields])

                # Update the attributes
                for existing_feature in features_to_merge:
                    if self.verbose == 'debug':
                        logger.debug(
                            '\nmerging\n\n%s\n%s\n' % (f, existing_feature))
                    for k in existing_feature.attributes.keys():
                        v = merged_attributes.setdefault(k, [])
                        v.extend(existing_feature[k])
                        merged_attributes[k] = v

                    # Update the set of non-attribute fields found so far
                    for field in self.force_merge_fields:
                        final_fields[field].update(
                            [getattr(existing_feature, field)])

                # Set the merged attributes
                for k, v in merged_attributes.items():
                    merged_attributes[k] = list(set(v))
                existing_feature.attributes = merged_attributes

                # Set the final merged non-attributes
                for k, v in final_fields.items():
                    setattr(existing_feature, k, ','.join(sorted(map(str, v))))

                if self.verbose == 'debug':
                    logger.debug('\nMERGED:\n%s' % existing_feature)
                return existing_feature, merge_strategy

        elif merge_strategy == 'create_unique':
            f.id = self._increment_featuretype_autoid(f.id)
            return f, merge_strategy
        else:
            raise ValueError("Invalid merge strategy '%s'"
                             % (merge_strategy))
Different merge strategies upon name conflicts.
dataset/ETHPy150Open daler/gffutils/gffutils/create.py/_DBCreator._do_merge