whatif.py (44 lines of code) (raw):

#!/usr/bin/env python3 # ##### # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ##### # Run alternate voting scenarios: vary the number of seats, remove candidates, # or do a run-off with only the specified candidates. Candidate names can # be specified using either their first name, last name, or full name without # any spaces (independent of case). Examples: # # Examples: # whatif.py ../Meetings/20110712/raw_board_votes.txt 10 # whatif.py ../Meetings/20110712/raw_board_votes.txt -LawrenceRosen # whatif.py ../Meetings/20110712/raw_board_votes.txt 1 kulp noirin geir chris import os.path import sys import re sys.path.append(os.path.join(os.path.dirname(__file__), 'monitoring')) import stv_tool def usage(): print('Usage: %s [-v] RAW_VOTES_FILE [seats] [-]name...' % scriptname) sys.exit(1) if __name__ == '__main__': scriptname = sys.argv.pop(0) if sys.argv and sys.argv[0] == '-v': stv_tool.VERBOSE = True sys.argv.pop(0) # extract required vote file argument, and load votes from it if not sys.argv or not os.path.exists(sys.argv[0]): usage() votefile = sys.argv.pop(0) names, votes = stv_tool.load_votes(votefile) # extract optional number of seats argument if sys.argv and sys.argv[0].isdigit(): seats = int(sys.argv.pop(0)) else: seats = 9 # extract an alias list of first, last, and joined names alias = {} for name in names: lname = re.sub(r'[^\w ]', '', name.lower()) alias[lname.replace(' ', '')] = name for part in lname.split(' '): alias[part] = name # validate input for arg in sys.argv: if arg.lstrip('-').lower() not in alias: sys.stderr.write('invalid selection: %s\n' % arg) usage() if not sys.argv: # no changes to the candidates running pass elif sys.argv[0][0] == '-': # remove candidates from vote for name in sys.argv: names.remove(alias[name.lstrip('-').lower()]) else: # only include specified candidates # NOTE: order is important, so sort the names for repeatability names = [ alias[n.lower()] for n in sorted(sys.argv) ] # Trim the raw votes based on cmdline params. Eliminate votes that # are not for one of the allowed names. Do not include voters who # did not vote for anybody [post-trimming]. trimmed = [ ] for voteseq in votes: newseq = [ v for v in voteseq if v in names ] if newseq: trimmed.append(newseq) # run the vote candidates = stv_tool.run_stv(names, trimmed, seats) candidates.print_results() print('Done!')