Code Review Asked by rmcknst2 on January 2, 2022
This is my first Python project. Any tips on making it more efficient, less cluttered, and could you think of some cases that I haven’t in which my code will break.
For clarification the vendor list csv file is set up like this:
[vendorname][email1][email2]...[email-n]
There are probably also some left-over test print()
lines in there.
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from configparser import ConfigParser
from os import startfile
import yagmail
import csv
import time
import os.path
from sys import exit
from keyring import *
from keyring import get_keyring
import keyring.backends.Windows
import smtplib
keyring.backends.Windows.WinVaultKeyring
print(get_keyring())
print("------------")
def open_vend_direct():
vend_directory = filedialog.askopenfilename(
initialdir="/", title="Select file", filetypes=(("Excel Files (CSV)", "*.csv"), ("all files", "*.*")))
parser = ConfigParser()
parser.read('config.ini')
parser.set('VendorList', 'List_Location', vend_directory)
with open('config.ini', 'w') as f:
parser.write(f)
vend_text.set(vend_directory)
def open_attach_direct():
vend_attach_direct = filedialog.askdirectory()
parser = ConfigParser()
parser.read('config.ini')
parser.set('VendorFile', 'file_Location', vend_attach_direct)
with open('config.ini', 'w') as f:
parser.write(f)
attach_text.set(vend_attach_direct)
def open_log_direct():
log_locate = filedialog.askdirectory()
parser = ConfigParser()
parser.read('config.ini')
parser.set('LogFolder', 'log_location', log_locate)
with open('config.ini', 'w') as f:
parser.write(f)
log_text.set(log_locate)
def apply_option():
checkbox1 = open_log.get()
if checkbox1 == 0:
checkbox1 = '0'
else:
checkbox1 = '1'
checkbox2 = send_log.get()
if checkbox2 == 0:
checkbox2 = '0'
else:
checkbox2 = '1'
parser = ConfigParser()
parser.read('config.ini')
parser.set('LogFolder', 'auto_open', checkbox1)
parser.set('LogFolder', 'send_default', checkbox2)
with open('config.ini', 'w') as f:
parser.write(f)
def change_operator_email():
def apply_operator():
def ok():
error_window.destroy()
str_operator = str(operator.get())
if not str_operator:
error_window = Toplevel()
error_window.title("Error")
error_label = ttk.Label(
error_window, text="Invalid Entry").grid(row=1, column=2)
ok_button = ttk.Button(
error_window, text="Ok", command=ok).grid(row=2, column=2)
empt_label1 = ttk.Label(error_window, text='').grid(
column=1, row=1, sticky=W)
empt_label2 = ttk.Label(error_window, text='').grid(
column=3, row=1, sticky=W)
for child in error_window.winfo_children():
child.grid_configure(padx=5, pady=9)
else:
parser.set('AccountInfo', 'operator_email', str_operator)
with open('config.ini', 'w') as f:
parser.write(f)
operator_text.set(str_operator)
op_window.destroy()
op_window = Toplevel()
op_window.title("Operator Email Change")
change_operator_email_prompt = ttk.Label(
op_window, text='--New Operator Email--').grid(row=0, column=2)
msg1 = ttk.Label(op_window, text='Email: ',).grid(row=1, column=1)
operator = StringVar()
operator_entry = ttk.Entry(
op_window, textvariable=operator).grid(row=1, column=2)
apply_operator_button = ttk.Button(
op_window, text='Apply', command=apply_operator).grid(row=1, column=3)
for child in op_window.winfo_children():
child.grid_configure(padx=5, pady=9)
return
def quit_option_menu():
exit()
def change_credentials():
def apply_cred():
def ok():
error_window.destroy()
str_email = str(cred_email.get())
str_pass = str(cred_pass.get())
if not str_email:
error_window = Toplevel()
error_window.title("Error")
error_label = ttk.Label(
error_window, text="Invalid Entry").grid(row=1, column=2)
ok_button = ttk.Button(
error_window, text="Ok", command=ok).grid(row=2, column=2)
empt_label1 = ttk.Label(error_window, text='').grid(
column=1, row=1, sticky=W)
empt_label2 = ttk.Label(error_window, text='').grid(
column=3, row=1, sticky=W)
for child in error_window.winfo_children():
child.grid_configure(padx=5, pady=9)
elif only_email.get() == 1:
parser.set('AccountInfo', 'sender_email', str_email)
with open('config.ini', 'w') as f:
parser.write(f)
elif not str_pass:
error_window = Toplevel()
error_window.title("Error")
error_label = ttk.Label(
error_window, text="Invalid Entry").grid(row=1, column=2)
ok_button = ttk.Button(
error_window, text="Ok", command=ok).grid(row=2, column=2)
empt_label1 = ttk.Label(error_window, text='').grid(
column=1, row=1, sticky=W)
empt_label2 = ttk.Label(error_window, text='').grid(
column=3, row=1, sticky=W)
for child in error_window.winfo_children():
child.grid_configure(padx=5, pady=9)
else:
parser.set('AccountInfo', 'sender_email', str_email)
with open('config.ini', 'w') as f:
parser.write(f)
keyring.set_password('yagmail', str_email, str_pass)
return
def yag_tip():
return
def hide_pass():
if only_email.get() == 1:
hide_msg = ttk.Label(
credential_window, text=" ").grid(row=4, column=2)
else:
new_password = Entry(
credential_window, textvariable=cred_pass).grid(row=4, column=2)
credential_window = Toplevel()
credential_window.title("Change Credentials")
only_email = IntVar(0)
only_email_check = ttk.Checkbutton(
credential_window, text='Email Change Only -- This means you have already set the credentials up', variable=only_email, command=hide_pass).grid(column=2, row=1)
change_credentials_prompt = ttk.Label(
credential_window, text="Change Gmail Credentials for Yagmail").grid(row=2, column=2)
msg2 = ttk.Label(credential_window, text="New Email: ").grid(
row=3, column=1)
msg2 = ttk.Label(credential_window, text="New Password: ").grid(
row=4, column=1)
cred_email = StringVar()
cred_pass = StringVar()
new_email = Entry(credential_window, textvariable=cred_email).grid(
row=3, column=2)
new_password = Entry(
credential_window, textvariable=cred_pass).grid(row=4, column=2)
apply_cred_button = ttk.Button(
credential_window, text='Apply', command=apply_cred).grid(row=5, column=3)
tip_button = ttk.Button(
credential_window, text='Yagmail Credential Tips', command=yag_tip).grid(row=5, column=1)
for child in credential_window.winfo_children():
child.grid_configure(padx=5, pady=9)
def run_vendsend():
parser = ConfigParser()
parser.read('config.ini')
version = 1.9
# ---------------------------------------------------------------------------------------
yag = yagmail.SMTP(parser.get('AccountInfo', 'sender_email'))
def csv_reader(filename):
vendor_names, vendor_emails = ([] for i in range(2))
csv_file = filename
with open(csv_file) as csvfile:
readCSV = csv.reader(csvfile, delimiter=',')
num_col = len(next(readCSV))
# main csv reader
with open(csv_file) as csvfile:
readCSV = csv.reader(csvfile, delimiter=',')
for row in readCSV:
name = row[0]
vendor_names.append(name)
email = []
for i in range(1, num_col):
email.append(row[i])
vendor_emails.append(email)
final_list = [[vendor_names[x]] + [vendor_emails[x]]
for x in range(len(vendor_names))]
return final_list
def no_email_check(vendors):
filt_count = 0
list1 = vendors
for i in (list1):
filter = [""]
for u in filter:
while True:
try:
list1[filt_count][1].remove(u)
except:
break
filt_count += 1
flagged = [contact[0] for contact in list1 if not contact[1]]
return flagged
def email_filter(vendors):
filt_count = 0
list1 = vendors
for i in (list1):
filter = [""]
for u in filter:
while True:
try:
list1[filt_count][1].remove(u)
except:
break
filt_count += 1
for k in range(len(list1) - 1, 0, -1):
if not list1[k][1]:
list1.pop(k)
return list1
def name_filter(vendors):
unfiltered = vendors[:]
filtered = []
for i in unfiltered:
filtered.append([i[0].strip(' '), i[1]])
return filtered
def reporter_tool(removed, invalid_e, n_attach):
vendor_removed = removed
invalid_emails = invalid_e
no_attach = n_attach
timestr = time.strftime("%Y-%m-%d-(%H-%M-%S)")
parser = ConfigParser()
parser.read('config.ini')
reporter_name = (parser.get('LogFolder', 'Log_Location') +
'\vendsend_log_' + timestr + '.txt')
fh = open(reporter_name, 'w')
fh.write('-----Vendors With No Emails-----n')
f_len = len(vendor_removed)
fcount = 0
if f_len > 0:
while fcount < f_len:
fh.write(vendor_removed[fcount])
fh.write("n")
fcount += 1
else:
fh.write("nulln")
fh.write('n')
fh.write('-----Invalid Emails-----n')
f_len = len(invalid_emails)
fcount = 0
if f_len > 0:
while fcount < f_len:
for i in invalid_emails:
fh.write("%sn" % i)
fh.write("n")
fcount += 1
else:
fh.write("nulln")
fh.write('n')
fh.write("-----Vendors with no Attachments-----n")
f_len = len(no_attach)
fcount = 0
if f_len > 0:
while fcount < f_len:
fh.write(no_attach[fcount])
fh.write("n")
fcount += 1
fh.write("n***Possible causes:n")
fh.write(" -Invalid Directory Path n")
fh.write(
" -Vendor name from the name file doesn't match the file name n")
else:
fh.write("nulln")
fh.close()
if open_log.get() == 1:
os.startfile(reporter_name)
if send_log.get() == 1:
yag.send(parser.get('AccountInfo', 'operator_email'),
('Log for ' + timestr), reporter_name)
vendor_csv = parser.get('VendorList', 'List_Location')
attach_directory = (parser.get('VendorFile', 'File_Location') + "\")
vendor_info = csv_reader(vendor_csv)
vendor_removed = no_email_check(vendor_info)
vendor_info = email_filter(vendor_info)
vendor_info = name_filter(vendor_info)
# -----test purposes only-----
#v_len = len(vendor_info)
#tcount = 0
# while tcount < v_len:
# print(vendor_info[tcount])
# print()
#tcount += 1
# print('----------------Reporter---------------')
#r_len = len(vendor_removed)
#rcount = 0
# while rcount < r_len:
# print(vendor_removed[rcount])
# print()
#rcount += 1
vendor_count = 0
num_vendors = len(vendor_info)
invalid_emails = []
no_attach = []
while vendor_count < num_vendors:
recipient = vendor_info[vendor_count][1]
subject = 'Open PO' + ' for ' + vendor_info[vendor_count][0]
attachment = attach_directory + vendor_info[vendor_count][0] + '.txt'
if os.path.isfile(attachment) == True:
pass
else:
no_attach.append(vendor_info[vendor_count][0])
vendor_count += 1
continue
contents = ['-Automated Email Test-', 'Hi ' + vendor_info[vendor_count][0] +
'. Attached below is the document of your open POs', 'DO NOT REPLY', attachment]
try:
yag.send(recipient, subject, contents)
except yagmail.error.YagInvalidEmailAddress:
invalid_emails.append(vendor_info[vendor_count])
print('error.YagInvalidEmailAddress for ' +
vendor_info[vendor_count][0] + 'n')
except yagmail.error.YagAddressError:
invalid_emails.append(vendor_info[vendor_count])
print('error.YagAddressError for ' +
vendor_info[vendor_count][0] + 'n')
except smtplib.SMTPAuthenticationError:
print('one')
smtb_window = Toplevel()
smtb_window.title("Error")
error_header = ttk.Label(
smtb_window, text="---AUTHENTICATION ERROR---").grid(column=1, row=1)
error_message = ttk.Label(
smtb_window, text="smtplib.SMTPAuthenticationError: (534, b'5.7.9 Application-specific password required.").grid(column=1, row=2)
error_message2 = ttk.Label(
smtb_window, text="Learn more at https://support.google.com/mail/?p=InvalidSecondFactor ").grid(column=1, row=3)
empt_label = ttk.Label(optionmenu, text='').grid(
column=1, row=4, sticky=W)
error_message3 = ttk.Label(
smtb_window, text="This error means you need to set up an ""app password" + " within gmail.").grid(column=1, row=5)
for child in smtplib.winfo_children():
child.grid_configure(padx=5, pady=9)
return
vendor_count = vendor_count + 1
reporter_tool(vendor_removed, invalid_emails, no_attach)
exit()
parser = ConfigParser()
parser.read('config.ini')
root = Tk()
root.title("VendSend Menu")
optionmenu = ttk.Frame(root, padding="3 3 12 12")
optionmenu. grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
###############################
# row 1
vend_list_button = ttk.Button(optionmenu, text='Vendor List Directory',
command=open_vend_direct).grid(column=1, row=1, sticky=W)
vend_text = StringVar()
vend_text.set(parser.get('VendorList', 'list_location'))
vend_list_locat = ttk.Label(optionmenu, textvar=vend_text).grid(
column=2, row=1, sticky=(W, E))
############################
# row 2
vend_attach_button = ttk.Button(optionmenu, text='Vendor File Directory',
command=open_attach_direct).grid(column=1, row=2, sticky=W)
attach_text = StringVar()
attach_text.set(parser.get('VendorFile', 'file_location'))
vend_attach_locat = ttk.Label(optionmenu, textvar=attach_text).grid(
column=2, row=2, sticky=(W, E))
###########################
# row 3
log_location_button = ttk.Button(
optionmenu, text='Log Folder Preference', command=open_log_direct).grid(column=1, row=3, sticky=W)
log_text = StringVar()
log_text.set(parser.get('LogFolder', 'log_location'))
log_locat = ttk.Label(optionmenu, textvar=log_text).grid(
column=2, row=3, sticky=(W, E))
open_log = IntVar(value=parser.get('LogFolder', 'auto_open'))
open_log_check = ttk.Checkbutton(
optionmenu, text='Open Log Automatically After Script End', variable=open_log, command=apply_option).grid(column=3, row=3, sticky=W)
##########################
# row 4
empt_label = ttk.Label(optionmenu, text='').grid(column=1, row=4, sticky=W)
###########################
# row 5
operator_email_button = ttk.Button(optionmenu, text='Change Operator Email',
command=change_operator_email).grid(column=1, row=5, sticky=W)
operator_text = StringVar()
operator_text.set(parser.get('AccountInfo', 'operator_email'))
operator_label = ttk.Label(optionmenu, textvar=operator_text).grid(
column=2, row=5, sticky=W)
send_log = IntVar(value=parser.get('LogFolder', 'send_default'))
send_log_check = ttk.Checkbutton(
optionmenu, text='Send Log To Operator Email', variable=send_log, command=apply_option).grid(column=3, row=5, sticky=W)
##########################
# row 6
change_credentials_button = ttk.Button(
optionmenu, text='Change Program Credentials', command=change_credentials).grid(column=1, row=6, sticky=W)
###########################
# row7
empt_label1 = ttk.Label(optionmenu, text='').grid(column=1, row=7, sticky=W)
###########################
# row 8
apply_changes = ttk.Button(optionmenu, text='Apply Changes',
command=apply_option).grid(column=1, row=8, sticky=W)
run_program = ttk.Button(optionmenu, text='Run Program',
command=run_vendsend).grid(column=2, row=8, sticky=W)
quit_option = ttk.Button(optionmenu, text='Quit', command=quit_option_menu).grid(
column=3, row=8, sticky=W)
for child in optionmenu.winfo_children():
child.grid_configure(padx=5, pady=9)
root.mainloop()
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP