Mercurial > hg > elinux-vote
changeset 5:58e4b36d5e74
Clean up the code
author | "German Poo-Caaman~o <gpoo@gnome.org>" |
---|---|
date | Thu, 14 Dec 2006 10:22:46 -0300 |
parents | ffa9fad76d38 |
children | 80df109584f7 |
files | vote-counter.py |
diffstat | 1 files changed, 215 insertions(+), 210 deletions(-) [+] |
line wrap: on
line diff
--- a/vote-counter.py Thu Dec 07 18:41:27 2006 -0300 +++ b/vote-counter.py Thu Dec 14 10:22:46 2006 -0300 @@ -1,4 +1,6 @@ #! /usr/bin/python +# +# Usage: python vote-counter.py mbox secret-cookie addresses import re import sys @@ -8,8 +10,8 @@ MAX_CANDIDATES = 1 candidate_tuples = [ \ - ("UNIVERSIDAD TECNICA FEDERICO SANTA MARIA", 1), \ - ("UNIVERSIDAD DE CONCEPCION", 2) ] + ("UNIVERSIDAD TECNICA FEDERICO SANTA MARIA", 1), \ + ("UNIVERSIDAD DE CONCEPCION", 2) ] class Ballot: def __init__ (self): @@ -23,254 +25,257 @@ self.votes.append((name, id)) class Candidate: - def __init__ (self, name, id): + def __init__(self, name, id): self.name = name self.id = id self.count = 0 - self.voters = [] - -def get_voters(filename): - # hash from valid addresses to whether they have sent in a ballot yet - addresses = {} + self.voters = [] - nospam_re = re.compile("no_spam\.?") - comment_re = re.compile("^#.*") - entry_re = re.compile(" *(.*?)(<.*?>) *\((.*?)\) *") +# hash from valid addresses to whether they have sent in a ballot yet +class Voters(dict): + def load_from_file(self, filename): + def unmunge_email(addr): + unmunged = nospam_re.sub("", addr) + return unmunged - def unmunge_email(addr): - unmunged = nospam_re.sub("", addr) - return unmunged + nospam_re = re.compile("no_spam\.?") + comment_re = re.compile("^#.*") + entry_re = re.compile(" *(.*?)(<.*?>) *\((.*?)\) *") - fp = open(filename) + fp = open(filename) - for line in fp.readlines(): - line = comment_re.sub("", line) - string.strip(line) - if line == "" or line == "\n": - continue + for line in fp.readlines(): + line = comment_re.sub("", line) + string.strip(line) + if line == "" or line == "\n": + continue - match = entry_re.search(line) - if match: - name = string.strip(match.group(1)) - email = unmunge_email(string.strip(match.group(2))) - contribution = string.strip(match.group(3)) - addresses[string.strip(email)] = 0 - else: - print "No match: " + line + match = entry_re.search(line) + if match: + name = string.strip(match.group(1)) + email = unmunge_email(string.strip(match.group(2))) + contribution = string.strip(match.group(3)) + self[string.strip(email)] = 0 + else: + print "No match: " + line - fp.close() + fp.close() - return addresses + def valid_voter(self, addr): + return self.has_key(addr) def get_ballots_from_mbox(filename, candidates): - ballots = [] - current_ballot = 0 + ballots = [] + current_ballot = 0 + + from_line_re = re.compile ("^From: *(.*)") + member_name_re = re.compile (">? *Member: *(.*)") + member_address_re = re.compile (">? *Member Address: *([^ ]*)") + auth_token_re = re.compile (">? *Validation Token: *(.*)") + vote_re = re.compile (">? *([A-Z ]+) *\(ID# *([0-9]+)\)") - from_line_re = re.compile ("^From: *(.*)") - member_name_re = re.compile (">? *Member: *(.*)") - member_address_re = re.compile (">? *Member Address: *([^ ]*)") - auth_token_re = re.compile (">? *Validation Token: *(.*)") - vote_re = re.compile (">? *([A-Z ]+) *\(ID# *([0-9]+)\)") + fp = open(filename) + for line in fp.readlines(): + match = from_line_re.match(line) + if match: + email = string.strip(match.group(1)) + if current_ballot: + ballots.append(current_ballot) + current_ballot = Ballot() + current_ballot.email = email + + continue - handle = open(filename) - for line in handle.readlines(): - match = from_line_re.match(line) - if match: - email = string.strip(match.group(1)) - if current_ballot: - ballots.append(current_ballot) - current_ballot = Ballot() - current_ballot.email = email + match = member_name_re.match(line) + if match: + member = string.strip(match.group(1)) + if (current_ballot.member_name): + print "Duplicate member name in ballot from '%s' - " \ + "duplicates ''%s', '%s'" \ + % (current_ballot.email, current_ballot.member_name, + member) + else: + current_ballot.member_name = member - continue - - match = member_name_re.match(line) - if match: - member = string.strip(match.group(1)) - if (current_ballot.member_name): - print "Duplicate member name in ballot from '%s' - " \ - "duplicates ''%s', '%s'" \ - % (current_ballot.email, current_ballot.member_name, - member) - else: - current_ballot.member_name = member + continue + + match = member_address_re.match(line) + if match: + member = string.strip(match.group(1)) + if (current_ballot.member): + print "Duplicate member address in ballot from '%s' - " \ + "duplicates ''%s', '%s'" \ + % (current_ballot.email, current_ballot.member, member) + else: + current_ballot.member = member - continue - - match = member_address_re.match(line) - if match: - member = string.strip(match.group(1)) - if (current_ballot.member): - print "Duplicate member address in ballot from '%s' - " \ - "duplicates ''%s', '%s'" \ - % (current_ballot.email, current_ballot.member, member) - else: - current_ballot.member = member + continue + + match = auth_token_re.match(line) + if match: + token = string.strip(match.group(1)) + if (current_ballot.token): + print "Duplicate auth token in ballot from '%s' - " \ + "duplicates '%s', '%s'" \ + % (current_ballot.email, current_ballot.token, token) + else: + current_ballot.token = token + continue - continue - - match = auth_token_re.match(line) - if match: - token = string.strip(match.group(1)) - if (current_ballot.token): - print "Duplicate auth token in ballot from '%s' - " \ - "duplicates '%s', '%s'" \ - % (current_ballot.email, current_ballot.token, token) - else: - current_ballot.token = token - continue + match = vote_re.match(line) + if match: + name = string.strip(match.group(1)) + id = string.strip(match.group(2)) + + id = int(id) - match = vote_re.match(line) - if match: - name = string.strip(match.group(1)) - id = string.strip(match.group(2)) - - id = int(id) + if not candidates.has_key(id): + print "Unknown candidate '%s' ID %d in ballot from '%s'" \ + % (name, id, current_ballot.email) + elif not candidates[id].name == name: + print "Candidate name '%s' for ID '%s' doesn't match, " \ + "expected '%s'" % (name, id, candidates[id].name) + else: + current_ballot.add_vote(name, id) + continue + + if current_ballot: + ballots.append(current_ballot) + + fp.close () - if not candidates.has_key(id): - print "Unknown candidate '%s' ID %d in ballot from '%s'" \ - % (name, id, current_ballot.email) - elif not candidates[id].name == name: - print "Candidate name '%s' for ID '%s' doesn't match, " \ - "expected '%s'" % (name, id, candidates[id].name) - else: - current_ballot.add_vote(name, id) - continue - - if current_ballot: - ballots.append(current_ballot) - - handle.close () + return ballots + +def check_ballots(ballots, valid_addressess): + valid_ballots = {} - return ballots - -def valid_voter(addr): - return valid_addresses.has_key(addr) - -def print_error(ballots): - valid_ballots = {} + def contains_dups (b): + dups = {} + for (name, id) in b.votes: + if dups.has_key (id): + return True + dups[id] = 1 + return False - def contains_dups (b): - dups = {} - for v in b.votes: - id = v[1] - if dups.has_key (id): - return 1 - dups[id] = 1 - return 0 + dup_tokens = {} + def md5_is_bad(b): + #key = b.member + secret_cookie + key = "%s%s" % (b.member, secret_cookie) + m = md5.new(key) + digest = m.digest() + token = m.hexdigest() + if token == b.token: + if dup_tokens.has_key(token): + print "Auth token occurs twice, someone voted more than once" + return True + else: + dup_tokens[token] = 1 + return False + else: + print "Bad auth token is %s hashed from '%s'" % (token, key) + return True - dup_tokens = {} - def md5_is_bad(b): - #key = b.member + secret_cookie - key = "%s%s" % (b.member, secret_cookie) - m = md5.new(key) - digest = m.digest() - token = m.hexdigest() - if token == b.token: - if dup_tokens.has_key(token): - print "Auth token occurs twice, someone voted more than once" - return 1 - else: - dup_tokens[token] = 1 - return 0 - else: - print "Bad auth token is %s hashed from '%s'" % (token, key) - return 1 - - i = 0 - for b in ballots: - error = 0 - if not b.member: - error = "missing member address" - elif not b.token: - error = "missing auth token" - elif len(b.votes) > MAX_CANDIDATES: - error = "too many votes (%d votes)" % len(b.votes) - elif len(b.votes) == 0: - error = "didn't list any candidates" - elif contains_dups(b): - error = "contains duplicate votes for the same candidate" - elif md5_is_bad(b): - error = "bad authentication token" - elif not valid_voter(b.member): - error = "ballot from someone not in the list of valid voters" - else: - if valid_ballots.has_key(b.token): - old = valid_ballots[b.token] - print "Overriding previous valid ballot %d from %s with " \ - "new ballot %d" % (old[1], old[0].email, i) - valid_ballots[b.token] = (b, i) + i = 0 + for b in ballots: + error = 0 + if not b.member: + error = "missing member address" + elif not b.token: + error = "missing auth token" + elif len(b.votes) > MAX_CANDIDATES: + error = "too many votes (%d votes)" % len(b.votes) + elif len(b.votes) == 0: + error = "didn't list any candidates" + elif contains_dups(b): + error = "contains duplicate votes for the same candidate" + elif md5_is_bad(b): + error = "bad authentication token" + elif not valid_addresses.valid_voter(b.member): + error = "ballot from someone not in the list of valid voters" + else: + if valid_ballots.has_key(b.token): + old = valid_ballots[b.token] + print "Overriding previous valid ballot %d from %s with " \ + "new ballot %d" % (old[1], old[0].email, i) + valid_ballots[b.token] = (b, i) - if error: - print "Ignoring ballot %d from '%s' due to: %s" % (i, b.email, error) - - i = i + 1 + if error: + print "Ignoring ballot %d from '%s' due to: %s" \ + % (i, b.email, error) + + i = i + 1 - return valid_ballots + return valid_ballots + +def print_valid_ballots(valid_ballots, valid_addresses, candidates): + valids = valid_ballots.values() + valids.sort(lambda a, b: cmp(a[1], b[1])) -def print_valid_votes(valid_ballots, valid_addresses, candidates): - valids = valid_ballots.values() - valids.sort(lambda a, b: cmp(a[1], b[1])) - for (b, i) in valids: - print "Ballot %d:" % i + for (b, i) in valids: + print "Ballot %d:" % i - print " From: " + b.email - print " Member: " + b.member_name - print " Member Address: " + b.member - print " Token: " + b.token - print " Voted for %d candidates:" % len(b.votes) + print " From: " + b.email + print " Member: " + b.member_name + print " Member Address: " + b.member + print " Token: " + b.token + print " Voted for %d candidates:" % len(b.votes) - voted_for = [] + voted_for = [] - valid_addresses[b.member] = 1 + valid_addresses[b.member] = 1 - for v in b.votes: - id = v[1] - candidates[id].count = candidates[id].count + 1 - candidates[id].voters.append (b.member) - voted_for.append(candidates[id].name) + for (name, id) in b.votes: + candidates[id].count += 1 + candidates[id].voters.append(b.member) + voted_for.append(candidates[id].name) - for v in voted_for: - print " " + v - - return valids + for v in voted_for: + print " " + v -def print_no_votes(valid_addresses): - print "The following members did not vote:" - for addr in valid_addresses.keys (): - if not valid_addresses[addr]: - print addr +def print_voters_without_ballot(valid_addresses): + print "\nThe following members did not vote:" + for addr in valid_addresses.keys (): + if not valid_addresses[addr]: + print addr -def print_summary(valid_addresses, candidates, valids): - candidate_list = candidates.values() - candidate_list.sort(lambda a, b: cmp(b.count, a.count)) +def print_summary(valid_ballots, valid_addresses, candidates): + candidate_list = candidates.values() + candidate_list.sort(lambda a, b: cmp(b.count, a.count)) - print "\n\nELECTION RESULTS:" + print "\n\nELECTION RESULTS:" - print " %d of %d members cast a valid ballot" \ - % (len(valids), len(valid_addresses.keys())) + print " %d of %d members cast a valid ballot" \ + % (len(valid_ballots), len(valid_addresses.keys())) - for candidate in candidate_list: - print " %s (%d votes)" % (candidate.name, candidate.count) + for candidate in candidate_list: + print " %s (%d votes)" % (candidate.name, candidate.count) if __name__ == '__main__': - candidates = {} - for (name, id) in candidate_tuples: - candidates[id] = Candidate(name, id) + candidates = {} + for (name, id) in candidate_tuples: + candidates[id] = Candidate(name, id) - mbox_filename = sys.argv[1] # mail archive file - secret_cookie = sys.argv[2] # secret cookie - voter_filename = sys.argv[3] # valid voter addresses file + try: + mbox_filename = sys.argv[1] # mail archive file + secret_cookie = sys.argv[2] # secret cookie + voter_filename = sys.argv[3] # valid voter addresses file + except: + print "Usage: %s mbox secret-cookie list-of-voters" % sys.argv[0] + sys.exit(1) - valid_addresses = get_voters(voter_filename) - ballots = get_ballots_from_mbox(mbox_filename, candidates) + valid_addresses = Voters() + valid_addresses.load_from_file(voter_filename) - valid_ballots = print_error(ballots) + ballots = get_ballots_from_mbox(mbox_filename, candidates) + + valid_ballots = check_ballots(ballots, valid_addresses) - ## Print results only after all errors have been printed, so - ## we don't lose any errors. - valids = print_valid_votes(valid_ballots, valid_addresses, candidates) - print_no_votes(valid_addresses) + ## Print results only after all errors have been printed, so + ## we don't lose any errors. + print_valid_ballots(valid_ballots, valid_addresses, candidates) + print_voters_without_ballot(valid_addresses) - print_summary(valid_addresses, candidates, valids) + print_summary(valid_ballots, valid_addresses, candidates) + +# vi:set ts=4 sw=4 expandtab: