def group_issues_by_fingerprint(issues):
    """
    Groups issues by fingerprint. Grouping is done by issue code in addition.
    IMPORTANT: It is assumed that all issues come from the SAME analyzer.
    """
    issues_by_fingerprint = defaultdict(list)
    for issue in issues:
        if not 'fingerprint' in issue:
            raise AttributeError("No fingerprint defined for issue with analyzer %s and code %s!" %
                (issue.get('analyzer','(undefined)'),issue['code']))
        fp_code = "%s:%s" % (issue['fingerprint'],issue['code'])
        if fp_code in issues_by_fingerprint:
            grouped_issue = issues_by_fingerprint[fp_code]
        else:
            grouped_issue = issue.copy()
            grouped_issue['occurrences'] = []
            if 'location' in grouped_issue:
                del grouped_issue['location']
            issues_by_fingerprint[fp_code] = grouped_issue

        locations = issue.get('location',[])
        if locations:
            for i,start_stop in enumerate(locations):

                occurrence = {
                    'from_row' : None,
                    'to_row' : None,
                    'from_column' : None,
                    'to_column' : None,
                    'sequence' : i
                }

                grouped_issue['occurrences'].append(occurrence)

                if not isinstance(start_stop,(list,tuple)) or not len(start_stop) == 2:
                    continue

                start,stop = start_stop

                if isinstance(start,(list,tuple)) and len(start) == 2:
                    occurrence['from_row'] = start[0]
                    occurrence['from_column'] = start[1]

                if isinstance(stop,(list,tuple)) and len(stop) == 2:
                    occurrence['to_row'] = stop[0]
                    occurrence['to_column'] = stop[1]

            grouped_issue['occurrences'] = sorted(grouped_issue['occurrences'],key = lambda x: (x['from_row'],x['from_column']))

    return issues_by_fingerprint.values()
Groups issues by fingerprint. Grouping is done by issue code in addition.
    IMPORTANT: It is assumed that all issues come from the SAME analyzer.