monitoring/nstv-rank.py (103 lines of code) (raw):

#!/usr/bin/env python # ============================================================ # # nstv-rank.py: # Usage: nstv-rank.py [-h] [-b] [-o filename] inputfile(s) # -h: Usage info (help) # -b: Generate BLT STV data format file # -o <filename> : Output file (default stdout) # # This script is designed to accept as input data in # the form as returned from the ASF Voter Tool 'Final # Tally' report email and generate output in the format # to be used by various STV ballot-counting software. # # The script allows you to use as input the full Email # message of the final tally; it takes care of correctly # handling duplicate votes (accepting only the last one) # as well as non-vote lines. Vote lines MUST have the # following format: # # [2006/06/13 18:22:30] 0422f389874d7a8ecfd2fabea0a152ed lagd # [2006/06/13 18:23:15] 9c58d57506a17c83b9d4cc8c0ed4a31e lgej # [2006/06/13 18:28:27] 9db55691a072f88d79968eed8297dc90 fcaki # [2006/06/13 19:01:13] a6d1332887e40af1dd2405cd2abf1e77 glfj # [2006/06/13 19:22:45] a9472aa4f7df905173acd8fe2d8edcb2 jkc # [2006/06/13 20:42:33] adc9914bb9112d8da4cddd6353e09ef1 eagk # # NOTE: All this depends on the format of the Final Tally # Email not changing. The assumptions are that the vote # list is ALWAYS in correct chronological order, with newer # votes after older ones. # # By default, it prints out a file in the format expected by # Voting Systems Toolbox (http://sourceforge.net/projects/votesystem): # # 32d4a49fbe6f1ee8a4f6a47f45fd5bbf,g,c,j,e,k,i,f,d,h # 04e53da3b92cd9a36fd2e9eba91915f8,i,c,j,e,l,a,g,d,b # 5e3bea51a6eef2d09722069f0c6178a5,a,c,j,g,l,h # f58528624ce66abe6ee8039e5d6a40f0,c,e,h,j,i,g,b,d,f,a,k,l # # It can also print out a file in BLT format, via the '-b' argument. ## #### VoteMain instructions #### # After installing Voting Systems Toolbox, you can execute the 'VoteMain' # program as # # java -cp Vote-0-4.jar VoteMain -system stv-meek -seats 9 outputFile # # where outputFile is the result of this script (rank). # # The output of 'VoteMain' program is the result of the elections. # # Note that the 'VoteMain' program can detect duplicate votes, as well as votes # with incorrect labels. ## #### OpenSTV instructions #### # OpenSTV (http://stv.sourceforge.net/) is a newer and better # maintained STV counting codebase. It requires the use of BLT # input files. # # The ASF uses Meek STV with: # Precision: 6 # Threshold: Droop | Dynamic | Fractional # import getopt import os.path import sys import re import string import ConfigParser def read_nominees(votefile): ini_fname = os.path.join(os.path.dirname(votefile), 'board_nominations.ini') config = ConfigParser.ConfigParser() config.read(ini_fname) try: return dict(config.items('nominees')) except: print >> sys.stderr, "Error processing input file: " + ini_fname print >> sys.stderr, " Goodbye!" sys.exit(2) def usage(error=None): print >> sys.stderr, "nstv-rank.py:" print >> sys.stderr, " Usage: nstv-rank.py [-h] [-b] [-o filename] inputfile(s)" print >> sys.stderr, " -h: This info" print >> sys.stderr, " -b: Generate BLT STV data format file" print >> sys.stderr, " -o <filename> : Output file (default stdout)" if error: print >> sys.stderr, "Error: " + error def read_votes(args): votes = { } vote_pat = re.compile(r'\[.{19}\]\s+([\w\d]{32})\s+([a-z]{1,26})', re.I) for fname in args: try: for line in open(fname): line = string.strip(line) vote = vote_pat.search(line) if vote: votes[vote.group(1)] = vote.group(2) except: print >> sys.stderr, "Error processing input file: " + fname print >> sys.stderr, " Goodbye!" sys.exit(2) return votes def print_tally(args, output, blt): votes = read_votes(args) nominees = read_nominees(args[0]) nomkeys = sorted(nominees) numseats = 9 if output: try: sys.stdout = open(a, 'w') except: print >> sys.stderr, "Cannot open output file: " + a print >> sys.stderr, " Goodbye!" sys.exit(2) if blt: numcands = len(nomkeys) print "%d %d" % (numcands, numseats) for id in votes.keys(): line = [ ] for vote in votes[id]: value = ord(vote) - ord('a') + 1 line.append(str(value)) line = "1 "+ " ".join(line) + " 0" print line print "0" for id in nomkeys: print '"%s"' % nominees[id] print '"ASF STV Board Election"' else: print "rank order" line = [ ] for id in nomkeys: line.append("%20.20s" % nominees[id]) line = "NAME, " + ", ".join(line) print line line = [ ] for id in nomkeys: line.append("%20.20s" % id) line = "LABEL," + ", ".join(line) print line for id in votes.keys(): line = id + "," + ",".join(votes[id]) print line if __name__ == '__main__': try: opts, args = getopt.getopt(sys.argv[1:], "ho:b") except getopt.GetoptError, err: print str(err) usage() sys.exit(2) output = None blt = False for o, a in opts: if o == "-b": blt = True elif o == "-h": usage() sys.exit() elif o == "-o": output = a if len(args) > 0: print_tally(args, output, blt) else: usage("No input file") sys.exit(2)