EasyGui interface
This commit is contained in:
parent
0ca5217ddc
commit
66b5fd6b31
218
main.py
218
main.py
|
@ -2,9 +2,9 @@ import os
|
||||||
import json
|
import json
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import dropbox
|
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
import easygui
|
import easygui
|
||||||
|
|
||||||
|
@ -21,63 +21,89 @@ class AttributionReport(object):
|
||||||
def __init__(self, credentials_file, months=6, footer_length=None):
|
def __init__(self, credentials_file, months=6, footer_length=None):
|
||||||
self.months = months
|
self.months = months
|
||||||
self.footer_length = footer_length
|
self.footer_length = footer_length
|
||||||
|
|
||||||
self.PI_COLUMN = "PI_Name"
|
self.PI_COLUMN = "PI_Name"
|
||||||
self.ORG_COLUMN = "Org Name"
|
self.ORG_COLUMN = "Org Name"
|
||||||
self.column_order = ["Addgene Assigned",
|
self.OUTPUT_COLUMN_ORDER = ["Addgene Assigned",
|
||||||
"Plasmid ID",
|
"Plasmid ID",
|
||||||
"Deposit ID",
|
"Deposit ID",
|
||||||
"Institute",
|
"Institute",
|
||||||
"PI Name",
|
"PI Name",
|
||||||
"Date Received",
|
"Date Received",
|
||||||
"Original Date",
|
"Original Date",
|
||||||
"Original ORG",
|
"Original ORG",
|
||||||
"Original PI"]
|
"Original PI"]
|
||||||
|
|
||||||
with open(credentials_file, "r") as cred_f:
|
self.ACCEPTABLE_EXTENSIONS = ["*.csv",
|
||||||
creds = json.loads(cred_f.read())
|
"*.xls",
|
||||||
|
"*.xlsx"]
|
||||||
|
|
||||||
self.app_key = creds['app_key']
|
# columns that need to be in the files
|
||||||
self.app_secret = creds['app_secret']
|
self.REQUIRED_SF_COLUMNS = ["First Name",
|
||||||
|
"Last Name",
|
||||||
|
"Account Name",
|
||||||
|
"Date",
|
||||||
|
"Assigned"]
|
||||||
|
self.REQUIRED_DP_COLUMNS = ["Org Name",
|
||||||
|
"Deposit ID",
|
||||||
|
"Plasmid ID",
|
||||||
|
"PI_Name",
|
||||||
|
"Date Received"]
|
||||||
|
|
||||||
if not creds.get("access_token", None):
|
# After load and merging, delete these columns
|
||||||
self.authorize()
|
self.SF_TRIM_COLUMNS = ["Subject",
|
||||||
|
"First Name",
|
||||||
|
"Last Name",
|
||||||
|
"Created Date",
|
||||||
|
"LIMS Organization ID",
|
||||||
|
"Account Description"]
|
||||||
|
self.DP_TRIM_COLUMNS = ["Org ID",
|
||||||
|
"Deposit Status",
|
||||||
|
"PI_ID",
|
||||||
|
"Date Available",
|
||||||
|
"# Orders",
|
||||||
|
"# Plasmids in the Deposit",
|
||||||
|
"Addgene Contact",
|
||||||
|
"Country"]
|
||||||
|
|
||||||
|
self.DEFAULT_DIR = self.get_dropbox_dir()
|
||||||
|
|
||||||
|
def get_dropbox_dir(self):
|
||||||
|
"""
|
||||||
|
Windows and Mac get dropox dir for Business or fallback to personal
|
||||||
|
"""
|
||||||
|
if os.name == "nt":
|
||||||
|
dropbox_file = os.path.join(os.getenv('APPDATA'), 'Dropbox', 'info.json')
|
||||||
else:
|
else:
|
||||||
self.access_token = creds['access_token']
|
dropbox_file = os.path.expanduser("~/.dropbox/info.json")
|
||||||
self.user_id = creds['user_id']
|
with open(dropbox_file) as dbf:
|
||||||
|
dbconfig = json.loads(dbf.read())
|
||||||
|
|
||||||
def authorize(self):
|
if "business" in dbconfig:
|
||||||
flow = dropbox.client.DropboxOAuth2FlowNoRedirect(self.app_key, self.app_secret)
|
dropbox_dir = dbconfig['business']['path'] + "/*.xls"
|
||||||
authorize_url = flow.start()
|
elif "personal" in dbconfig:
|
||||||
print '1. Go to: ' + authorize_url
|
dropbox_dir = dbconfig['personal']['path'] + "/*.xls"
|
||||||
print '2. Click "Allow" (you might have to log in first)'
|
|
||||||
print '3. Copy the authorization code.'
|
|
||||||
code = raw_input("Enter the authorization code here: ").strip()
|
|
||||||
access_token, user_id = flow.finish(code)
|
|
||||||
self.access_token = access_token
|
|
||||||
self.user_id = user_id
|
|
||||||
|
|
||||||
creds = {"app_key": self.app_key,
|
|
||||||
"app_secret": self.app_secret,
|
|
||||||
"access_token": self.access_token,
|
|
||||||
"user_id": self.user_id}
|
|
||||||
|
|
||||||
# Save so we don't have to do this again.
|
|
||||||
with open("credentials.json", "w") as f:
|
|
||||||
f.write(json.dumps(creds))
|
|
||||||
|
|
||||||
def _open_file_frame(self, filename, date_cols):
|
|
||||||
if DROPBOX:
|
|
||||||
L.info("Getting file from Dropbox")
|
|
||||||
client = dropbox.client.DropboxClient(self.access_token)
|
|
||||||
L.info("Got file from Dropbox")
|
|
||||||
f = client.get_file(filename)
|
|
||||||
else:
|
else:
|
||||||
f = os.path.normpath(local_dropbox_path + filename)
|
dropbox_dir = os.path.expanduser("~")
|
||||||
|
|
||||||
if filename[-4:] == ".csv":
|
return dropbox_dir
|
||||||
df = pd.read_csv(f, parse_dates=date_cols, encoding='utf-8')
|
|
||||||
|
def _get_dataframe_by_extension(self, path, date_cols):
|
||||||
|
"""
|
||||||
|
Gets a dataframe either by .csv, or .xls(x),
|
||||||
|
or erroring and exiting.
|
||||||
|
"""
|
||||||
|
_, ext = os.path.splitext(path)
|
||||||
|
|
||||||
|
if ext == ".csv":
|
||||||
|
df = pd.read_csv(path, parse_dates=date_cols, encoding='utf-8')
|
||||||
|
elif ext in [".xlsx", ".xls"]:
|
||||||
|
df = pd.read_excel(path, parse_dates=date_cols, encoding='utf-8')
|
||||||
else:
|
else:
|
||||||
df = pd.read_excel(f, parse_dates=date_cols, encoding='utf-8')
|
easygui.msgbox("File was not of type {0}.\nQuitting".format(
|
||||||
|
" ".join(self.ACCEPTABLE_EXTENSIONS)),
|
||||||
|
"ERROR")
|
||||||
|
sys.exit(1)
|
||||||
return df
|
return df
|
||||||
|
|
||||||
def get_dataframes(self):
|
def get_dataframes(self):
|
||||||
|
@ -85,28 +111,67 @@ class AttributionReport(object):
|
||||||
This gets the Salesforce and the Deposit dataframes.
|
This gets the Salesforce and the Deposit dataframes.
|
||||||
Then it does some cleanup of the columns
|
Then it does some cleanup of the columns
|
||||||
"""
|
"""
|
||||||
salesforce_data_name = '/Addgene Shared/Dev/Attribution Report/salesforce_report.xlsx'
|
salesforce_df, deposit_df = self.get_files()
|
||||||
salesforce_df = self._open_file_frame(salesforce_data_name, date_cols=[4, 5])
|
|
||||||
|
|
||||||
|
# Get rid of the footer that Salesforce adds.
|
||||||
if self.footer_length:
|
if self.footer_length:
|
||||||
length_with_footer = len(salesforce_df.index)
|
length_with_footer = len(salesforce_df.index)
|
||||||
salesforce_df = salesforce_df.head(length_with_footer - self.footer_length)
|
salesforce_df = salesforce_df.head(length_with_footer - self.footer_length)
|
||||||
|
|
||||||
deposit_data_name = 'Addgene Shared/Dev/Attribution Report/deposit_data.csv'
|
|
||||||
deposit_df = self._open_file_frame(deposit_data_name, date_cols=[7, 8])
|
|
||||||
|
|
||||||
# Clean up Salesforce
|
# Clean up Salesforce
|
||||||
salesforce_df['Account Description'].fillna('', inplace=True)
|
|
||||||
salesforce_df.sort(SF_DATE, ascending=1)
|
salesforce_df.sort(SF_DATE, ascending=1)
|
||||||
salesforce_df["Full Name"] = salesforce_df["First Name"].map(unicode) + " " + salesforce_df["Last Name"]
|
salesforce_df["Full Name"] = salesforce_df["First Name"].map(unicode) + " " + salesforce_df["Last Name"]
|
||||||
del salesforce_df["First Name"]
|
|
||||||
del salesforce_df["Last Name"]
|
|
||||||
|
|
||||||
# Cleanup Deposit Data
|
# Cleanup Deposit Data
|
||||||
deposit_df['Org Name'].fillna('', inplace=True)
|
deposit_df['Org Name'].fillna('', inplace=True)
|
||||||
deposit_df.sort(DP_DATE, ascending=1)
|
deposit_df.sort(DP_DATE, ascending=1)
|
||||||
deposit_df['PI_Name'].astype(unicode)
|
deposit_df['PI_Name'].astype(unicode)
|
||||||
|
|
||||||
|
# Cleanup not needed columns
|
||||||
|
for col in self.SF_TRIM_COLUMNS:
|
||||||
|
del salesforce_df[col]
|
||||||
|
for col in self.DP_TRIM_COLUMNS:
|
||||||
|
del deposit_df[col]
|
||||||
|
|
||||||
|
return salesforce_df, deposit_df
|
||||||
|
|
||||||
|
def get_files(self):
|
||||||
|
salesforce_data_name = easygui.fileopenbox("Salesforce Export",
|
||||||
|
default=self.DEFAULT_DIR,
|
||||||
|
filetypes=self.ACCEPTABLE_EXTENSIONS)
|
||||||
|
if salesforce_data_name == ".":
|
||||||
|
easygui.msgbox("You did not select a Salesforce Export, stopping program.",
|
||||||
|
"Good Bye")
|
||||||
|
sys.exit(1)
|
||||||
|
salesforce_df = self._get_dataframe_by_extension(salesforce_data_name, date_cols=[4, 5])
|
||||||
|
if set(self.REQUIRED_SF_COLUMNS) < set(salesforce_df.columns):
|
||||||
|
L.info("Proper columns")
|
||||||
|
else:
|
||||||
|
L.info("Wrong columns")
|
||||||
|
easygui.msgbox("At a minimum, the Salesforce file must have the following columns:\n\n"
|
||||||
|
"{0}\n\n"
|
||||||
|
"Please re-run and select a proper file.".format(", ".join(self.REQUIRED_SF_COLUMNS)),
|
||||||
|
"Incorrect columns")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
deposit_data_name = easygui.fileopenbox("Deposit Data",
|
||||||
|
default=self.DEFAULT_DIR,
|
||||||
|
filetypes=self.ACCEPTABLE_EXTENSIONS)
|
||||||
|
if deposit_data_name == ".":
|
||||||
|
easygui.msgbox("You did not select a Deposit Data Export, stopping program.",
|
||||||
|
"Good Bye")
|
||||||
|
sys.exit(1)
|
||||||
|
deposit_df = self._get_dataframe_by_extension(deposit_data_name, date_cols=[7, 8])
|
||||||
|
if set(self.REQUIRED_DP_COLUMNS) < set(deposit_df.columns):
|
||||||
|
L.info("Proper columns")
|
||||||
|
else:
|
||||||
|
L.info("Wrong columns")
|
||||||
|
easygui.msgbox("At a minimum, the Deposit Data file must have the following columns:\n\n"
|
||||||
|
"{0}\n\n"
|
||||||
|
"Please re-run and select a proper file.".format(", ".join(self.REQUIRED_DP_COLUMNS)),
|
||||||
|
"Incorrect columns")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
return salesforce_df, deposit_df
|
return salesforce_df, deposit_df
|
||||||
|
|
||||||
def get_filtered(self, filtered_df, sf_row, pi_name, pi_org, kind):
|
def get_filtered(self, filtered_df, sf_row, pi_name, pi_org, kind):
|
||||||
|
@ -176,31 +241,42 @@ class AttributionReport(object):
|
||||||
mismatches.extend(by_org)
|
mismatches.extend(by_org)
|
||||||
double_matches.extend(by_both)
|
double_matches.extend(by_both)
|
||||||
|
|
||||||
return {"PI": pd.DataFrame(name_matches, columns=self.column_order),
|
return (
|
||||||
"Institute": pd.DataFrame(org_matches, columns=self.column_order),
|
("PI", pd.DataFrame(name_matches, columns=self.OUTPUT_COLUMN_ORDER)),
|
||||||
"Double": pd.DataFrame(double_matches, columns=self.column_order),
|
("Institute", pd.DataFrame(org_matches, columns=self.OUTPUT_COLUMN_ORDER)),
|
||||||
"Single": pd.DataFrame(mismatches, columns=self.column_order)}
|
("Double", pd.DataFrame(double_matches, columns=self.OUTPUT_COLUMN_ORDER)),
|
||||||
|
("Single", pd.DataFrame(mismatches, columns=self.OUTPUT_COLUMN_ORDER))
|
||||||
|
)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
frames = self.get_attribution_dataframes()
|
frames = self.get_attribution_dataframes()
|
||||||
|
|
||||||
for key, df in frames.items():
|
dirname = easygui.diropenbox("Where to save reports?", "Select Report Output Directory", self.DEFAULT_DIR)
|
||||||
fname = '{0}_Attribution_Report_{1}_Match.xlsx'.format(
|
if not dirname:
|
||||||
datetime.date.today(),
|
dirname = self.DEFAULT_DIR
|
||||||
key)
|
|
||||||
print "Writing", fname
|
|
||||||
writer = pd.ExcelWriter(
|
|
||||||
fname,
|
|
||||||
|
|
||||||
engine='xlsxwriter')
|
for key, df in frames:
|
||||||
|
fname = '{0}_Attribution_Report_{1}_Match.xlsx'.format(datetime.date.today(), key)
|
||||||
|
|
||||||
|
xls_path = os.path.join(dirname, fname)
|
||||||
|
print "Writing", xls_path
|
||||||
|
|
||||||
|
writer = pd.ExcelWriter(xls_path,
|
||||||
|
engine='xlsxwriter')
|
||||||
df.to_excel(writer,
|
df.to_excel(writer,
|
||||||
sheet_name='Sheet1',
|
sheet_name='Sheet1',
|
||||||
index=False)
|
index=False)
|
||||||
writer.save()
|
writer.save()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main():
|
||||||
report = AttributionReport(credentials_file="credentials.json",
|
try:
|
||||||
|
report = AttributionReport(credentials_file="credentials.json",
|
||||||
months=6,
|
months=6,
|
||||||
footer_length=6)
|
footer_length=6)
|
||||||
report.run()
|
report.run()
|
||||||
|
except:
|
||||||
|
easygui.exceptionbox()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -5,4 +5,5 @@ python-dateutil
|
||||||
xlwt
|
xlwt
|
||||||
#openpyxl==1.8.6
|
#openpyxl==1.8.6
|
||||||
xlsxwriter
|
xlsxwriter
|
||||||
progressbar==2.3
|
progressbar==2.3
|
||||||
|
easygui
|
Loading…
Reference in New Issue
Block a user