# Path: dividebatur/aecdata/utils.py
# def ticket_sort_key(ticket):
#     "sort key for an ATL ticket, eg. A..Z, AA..ZZ"
#     return (len(ticket), ticket)
# 
# def named_tuple_iter(name, reader, header, **kwargs):
#     field_names = [t for t in [t.strip().replace('-', '_')
#                                for t in header] if t]
#     typ = namedtuple(name, field_names)
#     mappings = []
#     for field_name in kwargs:
#         idx = field_names.index(field_name)
#         mappings.append((idx, kwargs[field_name]))
#     for row in reader:
#         for idx, map_fn in mappings:
#             row[idx] = map_fn(row[idx])
#         yield typ(*row)


import csv
import collections
from .utils import ticket_sort_key, named_tuple_iter
        # Add the final group, assuming it isn't the ungrouped candidates
        if current_group is not None and current_group != "UG":
            group = Group(current_group,
                          current_party,
                          party_ab[current_party],
                          tuple(current_candidates))
            self.groups.append(group)
            self.group_by_id[group.group_id] = group

    def _load_all_candidates(self, all_candidates_csv):
        candidates = []
        with open(all_candidates_csv, 'rt') as fd:
            reader = csv.reader(fd)
            header = next(reader)
            for candidate in sorted(named_tuple_iter('AllCandidate', reader, header, ballot_position=int), key=lambda row: (ticket_sort_key(row.ticket), row.ballot_position)):
                if candidate.state_ab != self.state:
                    continue
                if candidate.nom_ty != 'S':
                    continue
                candidates.append(candidate)
        return candidates

    def _load_senate_candidates(self, senate_candidates_csv):
        by_name_party = {}
        party_ab = {}
        seen_ids = set()
        with open(senate_candidates_csv, 'rt') as fd:
            reader = csv.reader(fd)
            next(reader)  # skip the version
            header = next(reader)

# Path: dividebatur/aecdata/utils.py
# def ticket_sort_key(ticket):
#     "sort key for an ATL ticket, eg. A..Z, AA..ZZ"
#     return (len(ticket), ticket)
# 
# def named_tuple_iter(name, reader, header, **kwargs):
#     field_names = [t for t in [t.strip().replace('-', '_')
#                                for t in header] if t]
#     typ = namedtuple(name, field_names)
#     mappings = []
#     for field_name in kwargs:
#         idx = field_names.index(field_name)
#         mappings.append((idx, kwargs[field_name]))
#     for row in reader:
#         for idx, map_fn in mappings:
#             row[idx] = map_fn(row[idx])
#         yield typ(*row)


# Path: dividebatur/aecdata/candidatelist.py
import csv
import collections
from .utils import ticket_sort_key, named_tuple_iter

        # Add the final group, assuming it isn't the ungrouped candidates
        if current_group is not None and current_group != "UG":
            group = Group(current_group,
                          current_party,
                          party_ab[current_party],
                          tuple(current_candidates))
            self.groups.append(group)
            self.group_by_id[group.group_id] = group

    def _load_all_candidates(self, all_candidates_csv):
        candidates = []
        with open(all_candidates_csv, 'rt') as fd:
            reader = csv.reader(fd)
            header = next(reader)
            for candidate in sorted(named_tuple_iter('AllCandidate', reader, header, ballot_position=int), key=lambda row: (ticket_sort_key(row.ticket), row.ballot_position)):
                if candidate.state_ab != self.state:
                    continue
                if candidate.nom_ty != 'S':
                    continue
                candidates.append(candidate)
        return candidates

    def _load_senate_candidates(self, senate_candidates_csv):
        by_name_party = {}
        party_ab = {}
        seen_ids = set()
        with open(senate_candidates_csv, 'rt') as fd:
            reader = csv.reader(fd)
            next(reader)  # skip the version
            header = next(reader)

            for candidate in named_tuple_iter(