def check_audited_votes(e): """ old code; was in check_reported, but moved here temporarily """ if not isinstance(e.av_cpb, dict): utils.myerror("e.av_cpb is not a dict.") for cid in e.av_cpb: if cid not in e.cids: utils.mywarning("e.av_cpb key {} is not in e.cids.".format(cid)) for pbcid in e.av_cpb[cid]: if pbcid not in e.pbcids: utils.mywarning( "e.av_cpb[{}] key `{}` is not in e.pbcids".format( cid, pbcid)) if not isinstance(e.av_cpb[cid][pbcid], dict): utils.myerror("e.av_cpb[{}][{}] is not a dict.".format( cid, pbcid)) bidsset = set(e.bids_p[pbcid]) for bid in e.av_cpb[cid][pbcid]: if bid not in bidsset: utils.mywarning( "bid `{}` from e.av_cpb[{}][{}] is not in e.bids_p[{}]." .format(bid, cid, pbcid, pbcid)) for cid in e.cids: if cid not in e.av_cpb: utils.mywarning("cid `{}` is not a key for e.av_cpb.".format(cid)) for pbcid in e.possible_pbcid_c[cid]: if pbcid not in e.av_cpb[cid]: utils.mywarning("pbcid `{}` is not in e.av_cpb[{}].".format( pbcid, cid))
def read_reported_ballot_manifests(e): """ Read ballot manifest file 21-reported-ballot-manifests and expand rows if needed. """ election_pathname = os.path.join(multi.ELECTIONS_ROOT, e.election_dirname) specification_pathname = os.path.join(election_pathname, "2-reported", "21-reported-ballot-manifests") fieldnames = [ "Collection", "Box", "Position", "Stamp", "Ballot id", "Number of ballots", "Required Contests", "Possible Contests", "Comments" ] for pbcid in e.pbcids: safe_pbcid = ids.filename_safe(pbcid) filename = utils.greatest_name(specification_pathname, "manifest-" + safe_pbcid, ".csv") file_pathname = os.path.join(specification_pathname, filename) rows = csv_readers.read_csv_file(file_pathname, fieldnames, varlen=False) for row in rows: pbcid = row["Collection"] boxid = row["Box"] position = row["Position"] stamp = row["Stamp"] bid = row["Ballot id"] try: num = int(row["Number of ballots"]) except ValueError: utils.myerror( "Number {} of ballots not an integer.".format(num)) if num <= 0: utils.mywarning( "Number {} of ballots not positive.".format(num)) req = row["Required Contests"] poss = row["Possible Contests"] comments = row["Comments"] bids = utils.count_on(bid, num) stamps = utils.count_on(stamp, num) positions = utils.count_on(position, num) for i in range(num): # utils.nested_set(e.bids_p, [pbcid, bids[i]], True) if pbcid not in e.bids_p: e.bids_p[pbcid] = [] e.bids_p[pbcid].append(bids[i]) utils.nested_set(e.boxid_pb, [pbcid, bids[i]], boxid) utils.nested_set(e.position_pb, [pbcid, bids[i]], position[i]) utils.nested_set(e.stamp_pb, [pbcid, bids[i]], stamps[i]) utils.nested_set(e.required_gid_pb, [pbcid, bids[i]], req) utils.nested_set(e.possible_gid_pb, [pbcid, bids[i]], poss) utils.nested_set(e.comments_pb, [pbcid, bids[i]], comments)
def generate_election_spec_contests(e, synpar): # check number of contests assert isinstance(synpar.n_cids, int) and synpar.n_cids >= 1 # make cid for each contest e.cids = set("con{}".format(i + 1) for i in range(synpar.n_cids)) # generate contest types as plurality and additional parameters # no write-ins for cid in e.cids: e.contest_type_c[cid] = "plurality" e.params_c[cid] = "" e.write_ins_c[cid] = "no" # check number of cids with wrong reported outcome assert isinstance(synpar.n_cids_wrong, int) assert 0 <= synpar.n_cids_wrong <= synpar.n_cids # determine which, if any, cids have wrong reported outcome cids_list = list(e.cids) synpar.RandomState.shuffle(cids_list) # in-place synpar.cids_wrong = cids_list[:synpar.n_cids_wrong] # generate selids for each cid e.n_selids_c = {} e.selids_c = {} for cid in e.cids: e.n_selids_c[cid] = syn.geospace_choice(e, synpar, synpar.min_n_selids_per_cid, synpar.max_n_selids_per_cid) e.selids_c[cid] = { "sel{}".format(i): True for i in range(1, e.n_selids_c[cid] + 1) } # generate possible votes for each cid for cid in e.cids: if e.contest_type_c[cid] == "plurality": for selid in e.selids_c[cid]: utils.nested_set(e.votes_c, [cid, (selid, )], True) else: utils.myerror(("Contest {} is not plurality---" "Can't generate votes for it.").format(cid))
def read_election_spec_contest_groups(e): """ Read file election-spec-contest-groups.csv, put results into Election e. """ election_pathname = os.path.join(multi.ELECTIONS_ROOT, e.election_dirname) spec_pathname = os.path.join(election_pathname, "1-election-spec") filename = utils.greatest_name(spec_pathname, "election-spec-contest-groups", ".csv") file_pathname = os.path.join(spec_pathname, filename) fieldnames = ["Contest group", "Contest(s) or group(s)"] rows = csv_readers.read_csv_file(file_pathname, fieldnames, varlen=True) for row in rows: gid = row["Contest group"] if gid in e.cids: utils.myerror( "Contest group id {} must not also be a contest id.".format( gid)) e.gids.append(gid) e.cgids_g[gid] = row["Contest(s) or group(s)"]
def check_audit_spec(e): if not isinstance(e.risk_limit_m, dict): utils.myerror("e.risk_limit_m is not a dict.") for mid in e.risk_limit_m: if mid not in e.mids: utils.mywarning( "e.risk_limit_m mid key `{}` is not in e.mids.".format(mid)) if not (0.0 <= float(e.risk_limit_m[mid]) <= 1.0): utils.mywarning( "e.risk_limit_m[{}] not in interval [0,1]".format(mid)) if not isinstance(e.max_audit_rate_p, dict): utils.myerror("e.max_audit_rate_p is not a dict.") for pbcid in e.max_audit_rate_p: if pbcid not in e.pbcids: utils.mywarning( "pbcid `{}` is a key for e.max_audit_rate_p but not in e.pbcids." .format(pbcid)) if not 0 <= int(e.max_audit_rate_p[pbcid]): utils.mywarning( "e.max_audit_rate_p[{}] must be nonnegative.".format(pbcid)) if utils.warnings_given > 0: utils.myerror("Too many errors; terminating.")
def read_election_spec_general(e, election_dirname): """ Read file 1-election-spec/election-spec-general.csv, put results into Election e. election_dirname is the name of the directory for the election (e.g. "CO-2017-11") with ELECTIONS_ROOT """ election_pathname = os.path.join(multi.ELECTIONS_ROOT, election_dirname) spec_pathname = os.path.join(election_pathname, "1-election-spec") filename = utils.greatest_name(spec_pathname, "election-spec-general", ".csv") file_pathname = os.path.join(spec_pathname, filename) fieldnames = ["Attribute", "Value"] rows = csv_readers.read_csv_file(file_pathname, fieldnames) for row in rows: if "Election name" == row["Attribute"]: e.election_name = row["Value"] elif "Election dirname" == row["Attribute"]: new_election_dirname = row["Value"] if new_election_dirname != election_dirname: utils.mywarning( ("Inconsistent election_dirname {}" "ignored in file {}.").format(new_election_dirname, file_pathname)) else: pass # everything OK elif "Election date" == row["Attribute"]: e.election_date = row["Value"] elif "Election URL" == row["Attribute"]: e.election_url = row["Value"] for attribute in [ "election_name", "election_dirname", "election_date", "election_url" ]: if attribute not in vars(e): utils.mywarning( "Attribute {} not present in 11-general.csv.".format( attribute)) if utils.warnings_given > 0: utils.myerror("Too many errors; terminating.")
def check_reported(e): if not isinstance(e.rn_cpr, dict): utils.myerror("e.rn_cpr is not a dict.") for cid in e.rn_cpr: if cid not in e.cids: utils.mywarning("cid `{}` not in e.cids.".format(cid)) for pbcid in e.rn_cpr[cid]: if pbcid not in e.pbcids: utils.mywarning("pbcid `{}` is not in e.pbcids.".format(pbcid)) for cid in e.rn_cpr: for pbcid in e.rn_cpr[cid]: for rv in e.rn_cpr[cid][pbcid]: for selid in rv: if selid not in e.selids_c[cid] and selid[0].isalnum(): utils.mywarning( "selid `{}` is not in e.selids_c[{}].".format( selid, cid)) for cid in e.rn_cpr: for pbcid in e.rn_cpr[cid]: for rv in e.rn_cpr[cid][pbcid]: if not isinstance(e.rn_cpr[cid][pbcid][rv], int): utils.mywarning( "value `e.rn_cpr[{}][{}][{}] = `{}` is not an integer." .format(cid, pbcid, rv, e.rn_cpr[cid][pbcid][rv])) if not (0 <= e.rn_cpr[cid][pbcid][rv] <= e.rn_p[pbcid]): utils.mywarning( "value `e.rn_cpr[{}][{}][{}] = `{}` is out of range 0:{}." .format(cid, pbcid, rv, e.rn_cpr[cid][pbcid][rv], e.rn_p[pbcid])) if not (0 <= e.rn_cpr[cid][pbcid][rv] <= e.rn_c[cid]): utils.mywarning( "value `e.rn_cpr[{}][{}][{}] = `{}` is out of range 0:{}." .format(cid, pbcid, rv, e.rn_cpr[cid][pbcid][rv], e.rn_p[pbcid])) for cid in e.cids: for rv in e.votes_c[cid]: if e.rn_cr[cid][rv] != \ sum([e.rn_cpr[cid][pbcid][rv] for pbcid in e.rn_cpr[cid]]): utils.mywarning( "sum of e.rn_cpr[{}][*][{}] is not e.rn_cr[{}][{}].". format(cid, rv, cid, rv)) for cid in e.cids: if cid not in e.rn_cpr: utils.mywarning("cid `{}` is not a key for e.rn_cpr".format(cid)) for pbcid in e.possible_pbcid_c[cid]: if pbcid not in e.rn_cpr[cid]: utils.mywarning( "pbcid {} is not a key for e.rn_cpr[{}].".format( pbcid, cid)) # for selid in e.selids_c[cid]: # assert selid in e.rn_cpr[cid][pbcid], (cid, pbcid, selid) # ## not necessary, since missing selids have assumed count of 0 if not isinstance(e.rn_c, dict): utils.myerror("e.rn_c is not a dict.") for cid in e.rn_c: if cid not in e.cids: utils.mywarning("e.rn_c key `{}` is not in e.cids.".format(cid)) if not isinstance(e.rn_c[cid], int): utils.mywarning("e.rn_c[{}] = {} is not an integer.".format( cid, e.rn_c[cid])) for cid in e.cids: if cid not in e.rn_c: utils.mywarning("cid `{}` is not a key for e.rn_c".format(cid)) if not isinstance(e.rn_cr, dict): utils.myerror("e.rn_cr is not a dict.") for cid in e.rn_cr: if cid not in e.cids: utils.mywarning( "e.rn_cr key cid `{}` is not in e.cids".format(cid)) for vote in e.rn_cr[cid]: for selid in vote: if (not ids.is_writein(selid) and not ids.is_error_selid(selid)) \ and not selid in e.selids_c[cid]: utils.mywarning( "e.rn_cr[{}] key `{}` is not in e.selids_c[{}]".format( cid, selid, cid)) if not isinstance(e.rn_cr[cid][vote], int): utils.mywarning( "e.rn_cr[{}][{}] = {} is not an integer.".format( cid, vote, e.rn_cr[cid][vote])) for cid in e.cids: if cid not in e.rn_cr: utils.mywarning("cid `{}` is not a key for e.rn_cr".format(cid)) if not isinstance(e.bids_p, dict): utils.myerror("e.bids_p is not a dict.") for pbcid in e.pbcids: # if not isinstance(e.bids_p[pbcid], dict): # utils.myerror("e.bids_p[{}] is not a dict.".format(pbcid)) if not isinstance(e.bids_p[pbcid], list): utils.myerror("e.bids_p[{}] is not a list.".format(pbcid)) if not isinstance(e.rv_cpb, dict): utils.myerror("e.rv_cpb is not a dict.") for cid in e.rv_cpb: if cid not in e.cids: utils.mywarning("e.rv_cpb key `{}` is not in e.cids.".format(cid)) for pbcid in e.rv_cpb[cid]: if pbcid not in e.pbcids: utils.mywarning( "e.rv_cpb[{}] key `{}` is not in e.pbcids.".format( cid, pbcid)) if not isinstance(e.rv_cpb[cid][pbcid], dict): utils.myerror("e.rv_cpb[{}][{}] is not a dict.".format( cid, pbcid)) bidsset = set(e.bids_p[pbcid]) for bid in e.rv_cpb[cid][pbcid]: if bid not in bidsset: utils.mywarning( "bid `{}` from e.rv_cpb[{}][{}] is not in e.bids_p[{}]." .format(bid, cid, pbcid, pbcid)) for cid in e.cids: if cid not in e.rv_cpb: utils.mywarning("cid `{}` is not a key in e.rv_cpb.".format(cid)) for pbcid in e.possible_pbcid_c[cid]: if pbcid not in e.rv_cpb[cid]: utils.mywarning( ("pbcid `{}` from e.possible_pbcid_c[{}] " "is not a key for e.rv_cpb[{}].").format(pbcid, cid, cid)) if not isinstance(e.ro_c, dict): utils.myerror("e.ro_c is not a dict.") for cid in e.ro_c: if cid not in e.cids: utils.mywarning( "cid `{}` from e.rv_cpb is not in e.cids".format(cid)) for cid in e.cids: if cid not in e.ro_c: utils.mywarning("cid `{}` is not a key for e.ro_c.".format(cid)) if utils.warnings_given > 0: utils.myerror("Too many errors; terminating.")
def read_csv_file(filename, required_fieldnames=None, varlen=False): """ Read CSV file and check required fieldnames present; varlen if variable-length rows. """ # print("Reading CSV file:", filename) with open(filename) as file: reader = csv.reader(file) rows = [row for row in reader] fieldnames = rows[0] rows = rows[1:] # gather, clean, and trim field names, eliminating blanks fieldnames = [ids.clean_id(fieldname) for fieldname in fieldnames] while len(fieldnames) > 0 and fieldnames[-1] == '': fieldnames.pop() if len(set(fieldnames)) != len(fieldnames): utils.myerror("Duplicate field name:" + fieldnames) # data rows row_dicts = [] for row in rows: row = ["" if item == None else ids.clean_id(item) for item in row] while len(row) > 0 and row[-1] == '': row.pop() if not varlen: if len(row) > len(fieldnames): utils.mywarning("Ignoring extra values in row:" + str(row)) row = row[:len(fieldnames)] while len(row) < len(fieldnames): row.append("") row_dict = {} for (fieldname, value) in zip(fieldnames, row): row_dict[fieldname] = value if varlen: if len(row) < len(fieldnames) - 1: if len(row) > 0: utils.mywarning("Ignoring too-short row:" + str(row)) continue last_fieldname = fieldnames[-1] last_value = tuple(row[len(fieldnames) - 1:]) row_dict[last_fieldname] = last_value row_dicts.append(row_dict) if required_fieldnames != None: # check that all required fieldnames are present required_fieldnames = [ ids.clean_id(id) for id in required_fieldnames ] missing_fieldnames = set(required_fieldnames).difference( set(fieldnames)) if len(missing_fieldnames) > 0: utils.myerror( "File {} has fieldnames {}, while {} are required. Missing {}." .format(filename, fieldnames, required_fieldnames, missing_fieldnames)) # check to see if extra fieldnames present; warn user if so extra_fieldnames = set(fieldnames).difference( set(required_fieldnames)) if len(extra_fieldnames) > 0: utils.mywarning( "File {} has extra fieldnames (ignored): {}".format( filename, extra_fieldnames)) return row_dicts
def check_election_spec(e): if not isinstance(e.cids, (list, tuple, set)): utils.myerror("e.cids is not a set.") if len(e.cids) == 0: utils.myerror("e.cids is an empty list of contests.") for cid in e.cids: check_id(cid) if not isinstance(e.pbcids, (list, tuple)): utils.myerror("e.pbcids is not a list or a tuple.") if len(e.pbcids) == 0: utils.myerror("e.pbcids is an empty list of pbcids.") for pbcid in e.pbcids: check_id(pbcid) for cid in e.selids_c: if cid not in e.cids: utils.myerror( "e.selids_c has a key `{}` not in e.cids.".format(cid)) for selid in e.selids_c[cid]: check_id(selid) for cid in e.cids: if cid not in e.selids_c: utils.mywarning("cid `{}` should be key in e.selids_c".format(cid)) if not isinstance(e.cvr_type_p, dict): utils.myerror("e_cvr_type is not a dict.") for pbcid in e.cvr_type_p: if pbcid not in e.pbcids: utils.mywarning("pbcid `{}` is not in e.pbcids".format(pbcid)) if e.cvr_type_p[pbcid] not in ["CVR", "noCVR"]: utils.mywarning( "e.cvr_type_p[{}]==`{}` is not CVR or noCVR".format( pbcid, e.cvr_type_p[pbcid])) for pbcid in e.pbcids: if pbcid not in e.cvr_type_p: utils.mywarning( "pbcid `{}` not key in e.cvr_type_p.".format(pbcid)) if utils.warnings_given > 0: utils.myerror( "election_spec.check_election_spec: Too many errors or warnings; terminating." )