blob: 631ca07da8497573057be54b4a5ec182e3922d6a [file]
#!/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:
#
# 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
#
# whatif.rb depends on this positional argv shape. Keep it.
import sys
if __name__ != '__main__':
raise Exception('ERROR: not intended to be used as a library.')
import argparse
import re
import pathlib
THIS_SCRIPT = pathlib.Path(__file__).resolve()
THIS_DIR = THIS_SCRIPT.parent
sys.path.append(str(THIS_DIR / 'monitoring'))
import stv_tool
def parse_args(argv):
parser = argparse.ArgumentParser(
prog=THIS_SCRIPT.name,
description='Run alternate STV scenarios (seats, drop, runoff).',
)
parser.add_argument(
'-v', '--verbose', action='store_true',
help='Verbose STV tracing',
)
parser.add_argument('votefile', help='vote-results.json or raw_board_votes.txt')
parser.add_argument(
'rest', nargs=argparse.REMAINDER,
help='[seats] [name ...] or [seats] [-name ...]',
)
return parser.parse_args(argv)
args = parse_args(sys.argv[1:])
if args.verbose:
stv_tool.VERBOSE = True
data = stv_tool.LoadData.from_path(args.votefile)
names = list(data.names)
votes = data.votes
rest = list(args.rest)
if rest and rest[0].isdigit():
seats = int(rest.pop(0))
else:
seats = 9
alias = {}
for name in names:
lname = re.sub(r'[^\w ]', '', name.lower())
alias[lname.replace(' ', '')] = name
for part in lname.split(' '):
alias[part] = name
for arg in rest:
if arg.lstrip('-').lower() not in alias:
sys.stderr.write('invalid selection: %s\n' % arg)
sys.exit(1)
if not rest:
pass
elif rest[0][0] == '-':
for name in rest:
names.remove(alias[name.lstrip('-').lower()])
else:
names = [alias[n.lower()] for n in sorted(rest)]
trimmed = []
for voteseq in votes:
newseq = [v for v in voteseq if v in names]
if newseq:
trimmed.append(newseq)
candidates = stv_tool.run_stv(names, trimmed, seats)
candidates.print_results()
print('Done!')