Simple substring-based matching

def _align_with_substrings(self, chains_to_skip = set()):
        '''Simple substring-based matching'''
        for c in self.representative_chains:
            # Skip specified chains
            if c not in chains_to_skip:
                #colortext.pcyan(c)
                #colortext.warning(self.fasta[c])
                fasta_sequence = self.fasta[c]

                substring_matches = {}

                for uniparc_id, uniparc_sequence in sorted(self.uniparc_sequences.iteritems()):
                    uniparc_sequence = str(uniparc_sequence)
                    idx = uniparc_sequence.find(fasta_sequence)
                    if idx != -1:
                        substring_matches[uniparc_id] = 0
                    elif len(fasta_sequence) > 30:
                        idx = uniparc_sequence.find(fasta_sequence[5:-5])
                        if idx != -1:
                            substring_matches[uniparc_id] = 5
                        else:
                            idx = uniparc_sequence.find(fasta_sequence[7:-7])
                            if idx != -1:
                                substring_matches[uniparc_id] = 7
                    elif len(fasta_sequence) > 15:
                        idx = uniparc_sequence.find(fasta_sequence[3:-3])
                        if idx != -1:
                            substring_matches[uniparc_id] = 3

                self.substring_matches[c] = substring_matches

        # Restrict the matches to a given set of UniParc IDs. This can be used to remove ambiguity when the correct mapping has been determined e.g. from the SIFTS database.
        colortext.pcyan('*' * 100)
        pprint.pprint(self.substring_matches)
        if self.restrict_to_uniparc_values:
            for c in self.representative_chains:
                #print('HERE!')
                #print(c)
                if set(map(str, self.substring_matches[c].keys())).intersection(set(self.restrict_to_uniparc_values)) > 0:
                    # Only restrict in cases where there is at least one match in self.restrict_to_uniparc_values
                    # Otherwise, chains which are not considered in self.restrict_to_uniparc_values may throw away valid matches
                    # e.g. when looking for structures related to 1KTZ (A -> P10600 -> UPI000000D8EC, B -> P37173 -> UPI000011DD7E),
                    #      we find the close match 2PJY. However, 2PJY has 3 chains: A -> P10600, B -> P37173, and C -> P36897 -> UPI000011D62A
                    restricted_matches = dict((str(k), self.substring_matches[c][k]) for k in self.substring_matches[c].keys() if str(k) in self.restrict_to_uniparc_values)
                    if len(restricted_matches) != len(self.substring_matches[c]):
                        removed_matches = sorted(set(self.substring_matches[c].keys()).difference(set(restricted_matches)))
                        # todo: see above re:quiet colortext.pcyan('Ignoring {0} as those chains were not included in the list self.restrict_to_uniparc_values ({1}).'.format(', '.join(removed_matches), ', '.join(self.restrict_to_uniparc_values)))
                    self.substring_matches[c] = restricted_matches
        #pprint.pprint(self.substring_matches)
        #colortext.pcyan('*' * 100)

        # Use the representatives' alignments for their respective equivalent classes
        for c_1, related_chains in self.equivalence_fiber.iteritems():
            for c_2 in related_chains:
                self.substring_matches[c_2] = self.substring_matches[c_1]