Skip to content

Commit e4eec1b

Browse files
author
Eric Tsai
committed
change parameter file naming to .ini
1 parent d8587de commit e4eec1b

7 files changed

Lines changed: 101 additions & 80 deletions

File tree

src/election_anomaly/__init__.py

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030

3131
multi_data_loader_pars = [
3232
"project_root",
33-
"db_paramfile",
34-
"db_name",
3533
"results_dir",
3634
"archive_dir",
3735
]
@@ -58,11 +56,11 @@ def __new__(self):
5856
not create DataLoader object."""
5957
try:
6058
d, parameter_err = ui.get_runtime_parameters(
61-
multi_data_loader_pars, param_file="multi.par"
59+
multi_data_loader_pars, param_file="run_time.ini", header="election_anomaly"
6260
)
6361
except FileNotFoundError as e:
6462
print(
65-
"Parameter file multi.par not found. Ensure that it is located"
63+
"Parameter file run_time.ini not found. Ensure that it is located"
6664
" in the current directory. DataLoader object not created."
6765
)
6866
return None
@@ -78,26 +76,20 @@ def __new__(self):
7876
def __init__(self):
7977
# grab parameters
8078
self.d, self.parameter_err = ui.get_runtime_parameters(
81-
multi_data_loader_pars, param_file="multi.par"
79+
multi_data_loader_pars, param_file="run_time.ini", header="election_anomaly"
8280
)
8381

8482
# prepare to track files loaded, dictionary of dictionaries, keys are parameter file paths
8583
self.tracker = dict()
8684

8785
# create db if it does not already exist
88-
error = db.establish_connection(
89-
paramfile=self.d["db_paramfile"], db_name=self.d["db_name"]
90-
)
86+
error = db.establish_connection()
9187
if error:
92-
db.create_new_db(
93-
self.d["project_root"], self.d["db_paramfile"], self.d["db_name"]
94-
)
88+
db.create_new_db(self.d["project_root"])
9589

9690
# connect to db
9791
try:
98-
self.engine = db.sql_alchemy_connect(
99-
paramfile=self.d["db_paramfile"], db_name=self.d["db_name"]
100-
)
92+
self.engine = db.sql_alchemy_connect()
10193
Session = sessionmaker(bind=self.engine)
10294
self.session = Session()
10395
except Exception as e:
@@ -108,8 +100,8 @@ def load_all(self, load_jurisdictions: bool = True) -> dict:
108100
"""returns a dictionary of any files that threw an error"""
109101
mungers_path = os.path.join(self.d["project_root"], "mungers")
110102

111-
# list .par files and pull their jurisdiction_paths
112-
par_files = [f for f in os.listdir(self.d["results_dir"]) if f[-4:] == ".par"]
103+
# list .ini files and pull their jurisdiction_paths
104+
par_files = [f for f in os.listdir(self.d["results_dir"]) if f[-4:] == ".ini"]
113105
params = dict()
114106
param_err = dict()
115107
juris_path = dict()
@@ -120,6 +112,7 @@ def load_all(self, load_jurisdictions: bool = True) -> dict:
120112
single_data_loader_pars,
121113
optional_keys=["aux_data_dir"],
122114
param_file=par_file,
115+
header="election_anomaly"
123116
)
124117
juris_path[f] = params[f]["jurisdiction_path"]
125118
# update file_tracker
@@ -129,7 +122,7 @@ def load_all(self, load_jurisdictions: bool = True) -> dict:
129122
self.tracker["parameter_error"] = param_err[f]
130123

131124
err = dict()
132-
# group .par files by jurisdiction_path
125+
# group .ini files by jurisdiction_path
133126
jurisdiction_paths = {juris_path[f] for f in par_files}
134127
files = dict()
135128
for jp in jurisdiction_paths:
@@ -219,8 +212,9 @@ def move_loaded_results_file(self, sdl, f: str, load_error: dict):
219212
else:
220213
# move results file and its parameter file to a subfolder of the archive directory
221214
# named for the db
215+
db_param = ui.get_runtime_parameters(["dbname"], "run_time.ini", "postgresql")[0]
222216
self.tracker[f]["status"] = "loaded"
223-
new_dir = os.path.join(self.d["archive_dir"], self.d["db_name"])
217+
new_dir = os.path.join(self.d["archive_dir"], db_param["dbname"])
224218
ui.archive(f, self.d["results_dir"], new_dir)
225219
ui.archive(sdl.d["results_file"], self.d["results_dir"], new_dir)
226220
print_str = f"\tArchived {f} and its results file."
@@ -246,7 +240,10 @@ def __init__(
246240
# grab parameters
247241
par_file = os.path.join(results_dir, par_file_name)
248242
self.d, self.parameter_err = ui.get_runtime_parameters(
249-
single_data_loader_pars, optional_keys=["aux_data_dir"], param_file=par_file
243+
single_data_loader_pars,
244+
optional_keys=["aux_data_dir"],
245+
param_file=par_file,
246+
header="election_anomaly"
250247
)
251248

252249
# change any blank parameters to 'none'
@@ -346,10 +343,10 @@ class JurisdictionPrepper:
346343
def __new__(cls):
347344
"""Checks if parameter file exists and is correct. If not, does
348345
not create JurisdictionPrepper object."""
349-
param_file = "jurisdiction_prep.par"
346+
param_file = "jurisdiction_prep.ini"
350347
try:
351348
d, parameter_err = ui.get_runtime_parameters(
352-
prep_pars, param_file="jurisdiction_prep.par"
349+
prep_pars, param_file=param_file, header="election_anomaly"
353350
)
354351
except FileNotFoundError as e:
355352
print(
@@ -699,10 +696,10 @@ def add_sub_county_rus_from_multi_results_file(
699696
self, dir: str, error: dict = None, sub_ru_type: str = "precinct"
700697
) -> dict:
701698
"""Adds all elements in <elements> to <element>.txt and, naively, to <dictionary.txt>
702-
for each file in <dir> named (with munger) in a .par file in the directory"""
699+
for each file in <dir> named (with munger) in a .ini file in the directory"""
703700
if not error:
704701
error = dict()
705-
for par_file_name in [x for x in os.listdir(dir) if x[-4:] == ".par"]:
702+
for par_file_name in [x for x in os.listdir(dir) if x[-4:] == ".ini"]:
706703
par_file = os.path.join(dir, par_file_name)
707704
file_dict, missing_params = ui.get_runtime_parameters(
708705
["results_file", "munger_name"],
@@ -727,8 +724,8 @@ def add_elements_from_multi_results_file(
727724
self, elements: iter, dir: str, error: dict
728725
):
729726
"""Adds all elements in <elements> to <element>.txt and, naively, to <dictionary.txt>
730-
for each file in <dir> named (with munger) in a .par file in the directory"""
731-
for par_file_name in [x for x in os.listdir(dir) if x[-4:] == ".par"]:
727+
for each file in <dir> named (with munger) in a .ini file in the directory"""
728+
for par_file_name in [x for x in os.listdir(dir) if x[-4:] == ".ini"]:
732729
par_file = os.path.join(dir, par_file_name)
733730
file_dict, missing_params = ui.get_runtime_parameters(
734731
["results_file", "munger_name"],
@@ -868,7 +865,8 @@ def __init__(self):
868865
self.d, self.parameter_err = ui.get_runtime_parameters(
869866
prep_pars,
870867
optional_keys=optional_prep_pars,
871-
param_file="jurisdiction_prep" ".par",
868+
param_file="jurisdiction_prep.ini",
869+
header="election_anomaly"
872870
)
873871
self.state_house = int(self.d["count_of_state_house_districts"])
874872
self.state_senate = int(self.d["count_of_state_senate_districts"])
@@ -886,12 +884,12 @@ def make_par_files(
886884
results_note: str = "none",
887885
aux_data_dir: str = "",
888886
):
889-
"""Utility to create parameter files for multiple files. Makes a parameter file for each (non-.par,non .*) file in <dir>,
887+
"""Utility to create parameter files for multiple files. Makes a parameter file for each (non-.ini,non .*) file in <dir>,
890888
once all other necessary parameters are specified."""
891-
data_file_list = [f for f in os.listdir(dir) if (f[-4:] != ".par") & (f[0] != ".")]
889+
data_file_list = [f for f in os.listdir(dir) if (f[-4:] != ".ini") & (f[0] != ".")]
892890
for f in data_file_list:
893891
par_text = f"[election_anomaly]\nresults_file={f}\njurisdiction_path={jurisdiction_path}\nmunger_name={munger_name}\ntop_reporting_unit={top_ru}\nelection={election}\nresults_short_name={top_ru}_{f}\nresults_download_date={download_date}\nresults_source={source}\nresults_note={results_note}\naux_data_dir={aux_data_dir}\n"
894-
par_name = ".".join(f.split(".")[:-1]) + ".par"
892+
par_name = ".".join(f.split(".")[:-1]) + ".ini"
895893
with open(os.path.join(dir, par_name), "w") as p:
896894
p.write(par_text)
897895
return
@@ -903,7 +901,7 @@ def __new__(self):
903901
not create DataLoader object."""
904902
try:
905903
d, parameter_err = ui.get_runtime_parameters(
906-
["db_paramfile", "db_name", "results_file"]
904+
["dbname"], "run_time.ini", "postgresql"
907905
)
908906
except FileNotFoundError as e:
909907
print(
@@ -921,14 +919,12 @@ def __new__(self):
921919
return super().__new__(self)
922920

923921
def __init__(self):
924-
self.d, self.parameter_err = ui.get_runtime_parameters(
925-
["db_paramfile", "db_name", "results_file"]
926-
)
927-
self.d["results_file_short"] = get_filename(self.d["results_file"])
922+
# self.d, self.parameter_err = ui.get_runtime_parameters(
923+
# ["db_paramfile", "db_name", "results_file"]
924+
# )
925+
# self.d["results_file_short"] = get_filename(self.d["results_file"])
928926

929-
eng = db.sql_alchemy_connect(
930-
paramfile=self.d["db_paramfile"], db_name=self.d["db_name"]
931-
)
927+
eng = db.sql_alchemy_connect("run_time.ini")
932928
Session = sessionmaker(bind=eng)
933929
self.session = Session()
934930

@@ -947,7 +943,7 @@ def display_options(self, input: str, verbose: bool=False, filters: list=None):
947943

948944
def top_counts_by_vote_type(self, election: str, rollup_unit: str, sub_unit: str) -> str:
949945
d, error = ui.get_runtime_parameters(
950-
["rollup_directory"], param_file="multi.par"
946+
["rollup_directory"], param_file="run_time.ini", header="election_anomaly"
951947
)
952948
if error:
953949
err_str = (
@@ -966,29 +962,30 @@ def top_counts_by_vote_type(self, election: str, rollup_unit: str, sub_unit: str
966962
connection.close()
967963
return err_str
968964

969-
def top_counts(self, rollup_unit: str , sub_unit: str):
970-
d, error = ui.get_runtime_parameters(["rollup_directory"])
965+
def top_counts(self, election: str, rollup_unit: str , sub_unit: str):
966+
d, error = ui.get_runtime_parameters(
967+
["rollup_directory"], param_file="run_time.ini", header="election_anomaly"
968+
)
971969
if error:
972970
print("Parameter file missing requirements.")
973971
print(error)
974972
print("Data not created.")
975973
return
976974
else:
975+
connection = self.session.bind.raw_connection()
976+
cursor = connection.cursor()
977977
rollup_unit_id = db.name_to_id(self.session, "ReportingUnit", rollup_unit)
978978
sub_unit_id = db.name_to_id(self.session, "ReportingUnitType", sub_unit)
979-
results_info = db.get_datafile_info(
980-
self.session, self.d["results_file_short"]
981-
)
979+
election_id = db.name_to_id(self.session, "Election", election)
982980
rollup = a.create_rollup(
983-
self.session,
981+
cursor,
984982
d["rollup_directory"],
985-
top_ru_id=rollup_unit_id,
986-
sub_rutype_id=sub_unit_id,
987-
sub_rutype_othertext="",
988-
datafile_id_list=results_info[0],
989-
election_id=results_info[1],
983+
rollup_unit_id,
984+
sub_unit_id,
985+
election_id,
990986
by_vote_type=False,
991987
)
988+
connection.close()
992989
return
993990

994991
def scatter(
@@ -1009,7 +1006,7 @@ def scatter(
10091006
html, png, jpeg, webp, svg, pdf, and eps. Note that some filetypes may need plotly-orca
10101007
installed as well."""
10111008
d, error = ui.get_runtime_parameters(
1012-
["rollup_directory"], param_file="analyze.par"
1009+
["rollup_directory"], param_file="run_time.ini", header="election_anomaly"
10131010
)
10141011
if error:
10151012
print("Parameter file missing requirements.")
@@ -1065,7 +1062,7 @@ def bar(
10651062
) -> list:
10661063
"""contest_type is one of state, congressional, state-senate, state-house"""
10671064
d, error = ui.get_runtime_parameters(
1068-
["rollup_directory", "sub_reporting_unit_type"], param_file="analyze.par"
1065+
["rollup_directory"], param_file="run_time.ini", header="election_anomaly"
10691066
)
10701067
if error:
10711068
print("Parameter file missing requirements.")
@@ -1110,7 +1107,7 @@ def split_category_input(self, input_str: str):
11101107
def export_outlier_data(self, jurisdiction: str, contest: str=None):
11111108
"""contest_type is one of state, congressional, state-senate, state-house"""
11121109
d, error = ui.get_runtime_parameters(
1113-
["rollup_directory", "sub_reporting_unit_type"], param_file="analyze.par"
1110+
["rollup_directory"], param_file="run_time.ini", header="election_anomaly"
11141111
)
11151112
if error:
11161113
print("Parameter file missing requirements.")

src/election_anomaly/database/__init__.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@
8080
Puerto Rico
8181
US Virgin Islands"""
8282

83+
db_pars = [
84+
"host",
85+
"port",
86+
"dbname",
87+
"user",
88+
"password"
89+
]
8390

8491
def get_database_names(con):
8592
"""Return dataframe with one column called `datname` """
@@ -163,21 +170,24 @@ def append_to_composing_reporting_unit_join(engine, ru):
163170
return cruj_dframe
164171

165172

166-
def establish_connection(paramfile, db_name="postgres"):
173+
def establish_connection(paramfile="run_time.ini", dbname=None):
167174
"""Check for DB and relevant tables; if they don't exist, return
168175
error message"""
169176
try:
170-
params = ui.config(paramfile)
177+
params = ui.get_runtime_parameters(
178+
db_pars, param_file=paramfile, header="postgresql"
179+
)[0]
171180
except MissingSectionHeaderError as e:
172181
return {"message": "database.ini file not found suggested location."}
173-
params["dbname"] = db_name
182+
if dbname:
183+
params["dbname"] = dbname
174184
try:
175185
con = psycopg2.connect(**params)
176186
except psycopg2.OperationalError as e:
177187
return {"message": "Unable to establish connection to database."}
178188

179189
# Look for tables
180-
engine = sql_alchemy_connect(paramfile, db_name)
190+
engine = sql_alchemy_connect(paramfile)
181191
elems, enums, joins, o = get_cdf_db_table_names(engine)
182192

183193
# All tables except "Others" must be created. Essentially looks for
@@ -189,10 +199,11 @@ def establish_connection(paramfile, db_name="postgres"):
189199
return None
190200

191201

192-
def create_new_db(project_root, paramfile, db_name):
202+
def create_new_db(project_root, param_file="run_time.ini"):
193203
# get connection to default postgres DB to create new one
194204
try:
195-
params = ui.config(paramfile)
205+
params = ui.get_runtime_parameters(db_pars, param_file, "postgresql")[0]
206+
db_name = params["dbname"]
196207
params["dbname"] = "postgres"
197208
con = psycopg2.connect(**params)
198209
except:
@@ -203,7 +214,7 @@ def create_new_db(project_root, paramfile, db_name):
203214
cur = con.cursor()
204215
db_df = get_database_names(con)
205216

206-
eng = sql_alchemy_connect(paramfile=paramfile, db_name=db_name)
217+
eng = sql_alchemy_connect(param_file, dbname=params["dbname"])
207218
Session = sqlalchemy.orm.sessionmaker(bind=eng)
208219
sess = Session()
209220

@@ -231,14 +242,14 @@ def create_new_db(project_root, paramfile, db_name):
231242

232243

233244
def sql_alchemy_connect(
234-
paramfile: str = None, db_name: str = "postgres"
245+
paramfile: str = "run_time.ini", dbname: str = "postgres"
235246
) -> sqlalchemy.engine:
236247
"""Returns an engine and a metadata object"""
237-
if not paramfile:
238-
paramfile = ui.pick_paramfile()
239-
params = ui.config(paramfile)
240-
if db_name != "postgres":
241-
params["dbname"] = db_name
248+
params = ui.get_runtime_parameters(
249+
db_pars, param_file=paramfile, header="postgresql"
250+
)[0]
251+
if dbname != "postgres":
252+
params["dbname"] = dbname
242253
# We connect with the help of the PostgreSQL URL
243254
url = "postgresql://{user}:{password}@{host}:{port}/{dbname}"
244255
url = url.format(**params)

src/election_anomaly/user_interface/__init__.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,12 @@ def config(
588588
return d
589589

590590

591-
def get_runtime_parameters(required_keys, optional_keys=None, param_file="multi.par"):
591+
def get_runtime_parameters(
592+
required_keys: list,
593+
param_file: str,
594+
header: str,
595+
optional_keys: list = None,
596+
):
592597
d = {}
593598
missing_required_params = {"missing": []}
594599

@@ -600,15 +605,15 @@ def get_runtime_parameters(required_keys, optional_keys=None, param_file="multi.
600605

601606
for k in required_keys:
602607
try:
603-
d[k] = parser["election_anomaly"][k]
608+
d[k] = parser[header][k]
604609
except KeyError:
605610
missing_required_params["missing"].append(k)
606611

607612
if optional_keys is None:
608613
optional_keys = []
609614
for k in optional_keys:
610615
try:
611-
d[k] = parser["election_anomaly"][k]
616+
d[k] = parser[header][k]
612617
except KeyError:
613618
d[k] = None
614619

0 commit comments

Comments
 (0)