예제 #1
0
def validate(ranks, vote):
    errors = []
    # Only one rank per choice
    for i, rank_list in enumerate(ranks):
        if len(rank_list) > 1:
            errors.append(f'Choice {i+1} has multiple ranks assigned.')
    actual_ranks = [rank_list[0] for rank_list in ranks if rank_list]

    counter = collections.Counter(actual_ranks)
    # Can't skip ranks
    for i in range(max(actual_ranks)):
        if counter[i + 1] == 0:
            errors.append(f'Rank {i+1} has been skipped.')
            break
    # Can't assign same rank to two choices
    for i in range(len(ranks)):
        if counter[i + 1] > 1:
            errors.append(f'Rank {i+1} has been assigned more than once.')

    choices = [None] * max(actual_ranks)
    for i, rank in enumerate(ranks):
        if rank:
            choices[rank[0] - 1] = vote.choices[i]
    ballot = pyrankvote.Ballot(ranked_candidates=choices)
    return ballot, errors
예제 #2
0
    def test_create_object(self):
        """Test that voting with two equal candidates raises DuplicateCandidateError"""

        candidate1 = pyrankvote.Candidate("Per")
        candidate2 = pyrankvote.Candidate("Maria")
        candidate3 = pyrankvote.Candidate("Aase")

        ranked_candidates = (candidate1, candidate2, candidate3)

        ballot = pyrankvote.Ballot(ranked_candidates)
        self.assertTupleEqual(ranked_candidates, ballot.ranked_candidates)
예제 #3
0
    def test_new_candidate_objects(self):
        """Test that if one of the candidate that are voted for are not a cadidate, that a TypeError is raised"""
        class NewCandidate:
            def __init__(self, name):
                self.name = "New " + name

            def __hash__(self):
                return hash(self.name)

        candidate1 = NewCandidate("Per")
        candidate2 = NewCandidate("Aase")

        # This should NOT raise an error
        pyrankvote.Ballot(ranked_candidates=[candidate1, candidate2])
예제 #4
0
    def test_raise_error_if_not_all_obj_are_candidate_objects(self):
        """Test that if one of the candidate that are voted for are not a cadidate, that a TypeError is raised"""

        candidate1 = pyrankvote.Candidate("Per")
        candidate2 = "Aase"

        def tester(_):
            pyrankvote.Ballot(ranked_candidates=[candidate1, candidate2])

        msg = "Candidate 2 is a string, not a Candidate, and should raise a TypeError"
        self.assertRaises(TypeError, tester, msg)

        # TEST THE OPPOSITE
        candidate1 = pyrankvote.Candidate("Per")
        candidate2 = pyrankvote.Candidate("Aase")

        # This should NOT raise an error
        pyrankvote.Ballot(ranked_candidates=[candidate1, candidate2])
예제 #5
0
    def test_raise_duplicate_candidate_error(self):
        """Test that voting with two equal candidates raises DuplicateCandidateError"""

        candidate1 = pyrankvote.Candidate("Per")
        candidate2 = pyrankvote.Candidate("Per")
        candidate3 = pyrankvote.Candidate("Aase")

        def tester(_):
            pyrankvote.Ballot(
                ranked_candidates=[candidate1, candidate2, candidate3])

        msg = "Candidate 1 and 2 is equal and should raise duplicate candidate error"
        self.assertRaises(pyrankvote.models.DuplicateCandidatesError, tester,
                          msg)

        # TEST THE OPPOSITE
        candidate1 = pyrankvote.Candidate("Per")
        candidate2 = pyrankvote.Candidate("Maria")
        candidate3 = pyrankvote.Candidate("Aase")

        # This should NOT raise an error
        pyrankvote.Ballot(
            ranked_candidates=[candidate1, candidate2, candidate3])
예제 #6
0
def main():
    gc = gspread.authorize(get_creds())
    wb = gc.open_by_key(os.environ['gsheet_id'])
    worksheet = wb.get_worksheet(0)

    candidates = {}
    for candidate in [CANDIDATE_REGEX.search(c).group(1) for c in worksheet.row_values(1) if CANDIDATE_REGEX.search(c)]:
        candidates[candidate] = pyrankvote.Candidate(candidate)

    raw_ballots = worksheet.get_all_records()

    ballots = []
    for raw_ballot in raw_ballots:
        ballot = sorted({candidates[CANDIDATE_REGEX.search(c).group(1)]: r for (c, r) in raw_ballot.items() if CANDIDATE_REGEX.search(c)}.items(), key=lambda x: x[1])
        ballots.append(pyrankvote.Ballot(ranked_candidates=[c for c, r in ballot]))
        # print(ballot)

    election_result = pyrankvote.single_transferable_vote(candidates=candidates.values(), ballots=ballots, number_of_seats=SEATS)

    winners = election_result.get_winners()
    with open('output/results.txt', 'w+') as f:
        f.write(str(election_result))

    print(election_result)
예제 #7
0
 def tester(_):
     pyrankvote.Ballot(ranked_candidates=[candidate1, candidate2])
예제 #8
0
                    names.append(word)
        else:
            continue
    return names


votes = get_votes(path)
for vote in votes:
    names = get_names(vote)
    ballot = []
    for name in names:
        name = name[0].upper() + name[1:]
        if name not in candidates:
            candidates[name] = prv.Candidate(name)
        ballot.append(candidates[name])
    ballots.append(prv.Ballot(ranked_candidates=ballot))

Candidates = [candidates[i] for i in candidates]
election = prv.single_transferable_vote(Candidates, ballots, spots)

if "show_all" in sys.argv:
    print(election)

elif "show_last" in sys.argv:
    print(f"Final result, last of {len(election.rounds) + 1} rounds")
    print(election.rounds[-1])

else:
    winners = election.get_winners()
    for winner in winners:
        print(winner)