4
\$\begingroup\$
# Prints Updates of whats currently happening
print('Importing Libraries')
# imports stuff
from tkinter import *
import sys, string, os, subprocess, openpyxl, time
from selenium import webdriver
from splinter import Browser
from twilio.rest import TwilioRestClient
import tkMessageBox
# Prints Updates of what's happening
print("Finished Importing")
# Prints Updates of what's happening
print("Pulling Settings")
# Opens settings excel document
settingsWorkbook = openpyxl.load_workbook('settings.xlsx')
# Gets the settings sheet
settingsSheet = settingsWorkbook.get_sheet_by_name('Sheet1')
# Finds the value for oder codes workbook name
ordersWorkbookName = settingsSheet['B6'].value
# If it is empty;
if str(ordersWorkbookName)=='None':
 # Sets to default
 ordersWorkbookName = sheet['C6'].value
# Gets the value of order codes sheet name
ordersSheetName = settingsSheet['B7'].value
# If its empty;
if str(ordersSheetName) == 'None':
 # Sets to default
 ordersSheetName = settingsSheet['C7'].value
# Gets folder directory
folderDirectory = settingsSheet['B2'].value
# If its empty;
if str(folderDirectory) == 'None':
 # Prionts error message
 print('Please Finish Settings by filling in: Folder Directory')
 sys.exit()
chromeDriverDirectory = settingsSheet['B3'].value
if str(chromeDriverDirectory) == 'None':
 print('Please Finish Settings by Filling in: Chrome Driver directory')
 sys.exit()
ordersDirectory = settingsSheet['B5'].value
if str(ordersDirectory) == 'None':
 print('Please Finish Settings by Filling in: Excel Orders File Directory')
 sys.exit()
saveValue = settingsSheet['B8'].value
if str(saveValue) == 'None':
 saveValue = settingsSheet['C8'].value
 print('Using Default Save Value')
settingsDirectory = settingsSheet['B4'].value
if str(settingsDirectory) == 'None':
 print('Please Finish Settings by Filling in: Excel Settings File Directory')
 sys.exit
# Prints Updates of what's happening
print('Finished Pulling Settings')
# Prints Updates of what's happening
print("Defining Functions")
# Defines function that opens windows explorer in the current directory
def windowExplorer():
 subprocess.Popen('explorer "'+folderDirectory+'"')
# Unused Function; changes status at bottom of GUI
def changeStatus():
 status='Running Stock Checker...'
 status = Label(root, text=str(status), bd=1, relief=SUNKEN, anchor=W)
 status.grid(row=7, columnspan=2, sticky=N+E+S+W)
# Main function, finds the stock of each item
def findInfo():
 # Gets the phone number imputted
 phoneNumberUsed = phoneNumber.get()
 # Opens phone number history
 phoneNumbersFile = open('phoneNumbers.txt', 'w')
 # Writes the current phone number
 phoneNumbersFile.write(phoneNumberUsed)
 # Closes phone number history
 phoneNumbersFile.close
 # Gets the value for the "Stop After" value
 stopIntValue = stopValue.get()
 # Sets twilio account SID
 accountSID=''
 # Sets twilio auth token
 authToken=''
 # Sets the client of twilio allowing use
 client = TwilioRestClient(accountSID,authToken)
 # Sets number the messages are sent from
 myTwilioNumber=''
 # Due to Tkinter being unresponsive when running stock checker, if it stops before allowing it to say completed it shows this
 labelStopped.pack()
 # Stuff to do with browser drivers
 print('Starting Driver')
 executable_path = {'executable_path':str(chromeDriverDirectory)}
 browser = Browser('chrome', **executable_path)
 # Maximises the window
 browser.driver.maximize_window()
 # Visits Diamond UK Main page
 browser.visit('https://retailer.diamondcomics.co.uk/Login/Login?ReturnUrl=%2f')
 # Prints Updates of what's happening
 print('Logging In...')
 # Fills in Username
 browser.find_by_id('UserName').fill('')
 # Fills in Password
 browser.find_by_id('Password').fill('')
 # Clicks 'Login' Button
 browser.find_by_id('Submit').first.click()
 # Navigating: Hits 'Orders'
 try:
 browser.find_by_xpath('//*[@id="NavigationMenu"]/li[3]/a').first.click()
 except:
 # Prints Updates of what's happening
 print('Log In Failed')
 browser.quit()
 sys.exit()
 # Prints Updates of what's happening
 print('Successfully Logged In')
 # Navigating: Hits 'Reorders'
 browser.find_by_xpath('//*[@id="NavigationMenu"]/li[3]/ul/li[2]/a').first.click()
 # Navigating: Hits 'Create a Reorder'
 browser.find_by_xpath('//*[@id="MainContent"]/div/div/div[1]/a').first.click()
 # Prints Updates of what's happening
 print('Loading Excel...')
 # Opens Excel with info in
 excelWorkbook = openpyxl.load_workbook(str(ordersWorkbookName)+'.xlsx')
 sheet = excelWorkbook.get_sheet_by_name(str(ordersSheetName))
 # Finds the total number of rows
 row_count = sheet.max_row
 # Sets X to 2, allows navigation through excel sheet for program
 x=2
 # Sets Y to 1, so it knows how many 'runs' it has done to allow excel save every 10 runs
 y=1
 # Sets Z to 1, so when it prints status reports it tells you which number
 z = 1
 # Sets A to 1, another variable used
 a = 1
 while True:
 # sets value to that of Done?
 doneValue = sheet['A'+str(x)].value
 # checks if it is equal to 'Done'
 if doneValue == 'Done' or doneValue == 'Failed':
 # If so skips this one and moves to next one
 x = x+1
 # Prints a status message
 print('Number '+str(z)+' is already done')
 # Adds one onto Z for status reasons
 z = z+1
 # Restarts while loop
 continue
 # Prints when starting
 print('Starting number: '+str(z))
 # Sleep to allow the website to catch up 
 time.sleep(2)
 # Sets info to the relevant order code
 info = sheet['B'+str(x)].value
 # Tries to fill with info
 try:
 # Finds 'Order Code' box and fills with info (Set Above)
 browser.find_by_xpath('//*[@id="txtQAItemCode"]').fill(info)
 # If it receives 'TypeError' meaning no value
 except TypeError:
 # It breaks the loop
 break
 # Finds 'Quantity' Box and fills with the desired quantity
 browser.find_by_id('txtQAQuantity').fill('5')
 # Clicks the 'Add Item' Button
 browser.find_by_id('btnAddItem').first.click()
 # Waits for fancy animations to complete... stupid website
 time.sleep(1.5)
 try:
 # Takes the quantity off the information
 quantity = browser.find_by_xpath('//*[@id="ReorderLineGrid"]/div/table/tbody/tr/td[8]/div').first.value
 except:
 sheet['A'+str(x)] = 'Failed'
 print('Number '+str(z)+' failed')
 browser.reload()
 sheet['C'+str(x)] = 'Failed to find product, error with Item Code most likely'
 x = x+1
 y = y+1
 z = z+1
 a = a+1
 continue
 # Inputs quantity into excel
 sheet['C'+str(x)] = quantity
 # Deletes the reorder as of not to annoy anyone... *couch* Steve *cough*
 try:
 browser.find_by_text('Delete').first.click()
 except:
 browser.reload()
 time.sleep(1)
 try:
 browser.find_by_text('Delete').first.click()
 except:
 print('Not sure what happened')
 # Sets the 'Done?' tab in excel to tell its done
 sheet['A'+str(x)] = 'Done'
 # Saves the excel workbook
 # excelWorkbook.save('orders.xlsx')
 # Prints when finished
 if stopIntValue == '':
 print('Finished number: '+str(z)+' out of '+str(row_count))
 numberLeft = row_count - z
 else:
 print('Finished number: '+str(z))
 print(str(a)+' out of '+str(stopIntValue))
 numberLeft = int(stopIntValue) - a
 timeLeft = numberLeft * 3.9
 if timeLeft>60:
 timeLeft = timeLeft/60
 if timeLeft>60:
 timeLeft = timeLeft/60
 timeLeft = str(timeLeft)
 if timeLeft[1] == '.':
 timeLeftHours = timeLeft[:1]
 timeLeftHoursMinutes = timeLeft[2:]
 timeLeftHoursMinutes = int(timeLeftHoursMinutes)
 timeLeftHoursMinutes = timeLeftHoursMinutes*60
 timeLeftHoursMinutes = str(timeLeftHoursMinutes)
 timeLeftHoursMinutes = timeLeftHoursMinutes[:2]
 if timeLeft[2] == '.':
 timeLeftHours = timeLeft[:2]
 timeLeftHoursMinutes = timeLeft[3:]
 timeLeftHoursMinutes = int(timeLeftHoursMinutes)
 timeLeftHoursMinutes = timeLeftHoursMinutes*60
 timeLeftHoursMinutes = str(timeLeftHoursMinutes)
 timeLeftHoursMinutes = timeLeftHoursMinutes[:2]
 if timeLeft[3] == '.':
 timeLeftHours = timeLeft[:3]
 timeLeftHoursMinutes = timeLeft[3:]
 timeLeftHoursMinutes = int(timeLeftHoursMinutes)
 timeLeftHoursMinutes = timeLeftHoursMinutes*60
 timeLeftHoursMinutes = str(timeLeftHoursMinutes)
 timeLeftHoursMinutes = timeLeftHoursMinutes[:2]
 print('ETA: '+str(timeLeftHours) + ' hours and '+str(timeLeftHoursMinutes)+' minutes')
 else:
 timeLeft = str(timeLeft)
 if timeLeft[1] == '.':
 timeLeftMinutes = timeLeft[:1]
 else:
 timeLeftMinutes = timeLeft[:2]
 print('ETA :'+str(timeLeftMinutes) + ' minutes')
 else:
 timeLeft = str(timeLeft)
 if timeLeft[1] == '.':
 timeLeftSeconds = timeLeft[:1]
 else:
 timeLeftSeconds = str(timeLeft[:2])
 print('ETA: '+str(timeLeftSeconds) + ' seconds')
 if y == int(saveValue):
 try:
 excelWorkbook.save(str(ordersWorkbookName)+'.xlsx')
 except:
 print('Please close '+str(orderWorkbookName)+'.xlsx and restart.')
 browser.quit()
 sys.exit()
 print('Excel Saved')
 y = 1
 stopStatus = 'no'
 if stopIntValue != '':
 stopStatus = 'yes'
 if stopStatus == 'yes':
 if a == int(stopIntValue):
 print(stopIntValue+' completed')
 print('Stopping Script')
 if phoneNumberUsed != '':
 print("Sending Text")
 message = client.messages.create(body='Stock Checker has completed '+str(stopIntValue) , from_=myTwilioNumber, to=phoneNumberUsed)
 else:
 print('Text Not Wanted')
 break
 # Adds one onto X as its finished one 'run'
 x=x+1
 # adds one onto Y as its finished another 'run'
 y=y+1
 z=z+1
 a=a+1
 #excelWorkbook.save('orders.xlsx')
 print('Final Excel Save')
 try:
 excelWorkbook.save(str(ordersWorkbookName)+'.xlsx')
 except:
 print('Please close '+str(orderWorkbookName)+'.xlsx and restart.')
 browser.quit()
 sys.exit()
 print('Excel Saved')
 # Closes Browser 
 browser.quit()
 # Removes the 'Working' text
 labelStopped.pack_forget()
 # Adds a piece of text saying 'Completed'
 labelCompletetionMain.pack()
# Function behind opening the current Excel sheet
def excelEdit():
 os.system('start excel.exe "'+ordersDirectory+'"')
def settingsEdit():
 os.system('start excel.exe "'+settingsDirectory+'"')
# Function behind resetting done factor 
def resetAll():
 while True:
 check =tkMessageBox.askyesno('Are You Sure?','Are You Sure You Want to Reset All?')
 if check == False:
 break
 # Opens Excel with info in
 excelWorkbook = openpyxl.load_workbook(str(ordersWorkbookName)+'.xlsx')
 sheet = excelWorkbook.get_sheet_by_name(str(ordersSheetName))
 # Finds number of rows in the Sheet
 row_count = sheet.max_row
 x = 2
 for i in range(row_count):
 sheet['A'+str(x)] = ''
 x = x+1
 # Saves the excel workbook
 excelWorkbook.save(str(ordersWorkbookName)+'.xlsx')
print("Finished Defining")
print('Starting Tkinter')
root = Tk()
menu = Menu(root)
root.config(menu=menu)
# Title on top of window
root.title('Stock Checker V6.1')
root = Frame(root)
root.pack()
subMenu = Menu(menu)
menu.add_cascade(label="Options", menu=subMenu)
subMenu.add_command(label="Edit Order Codes", command=excelEdit)
subMenu.add_command(label="Reset All", command=resetAll)
subMenu.add_command(label="Edit Settings", command=settingsEdit)
stopValue = StringVar()
phoneNumber = StringVar()
#buttonToUpload = Button(root, text="Upload Excel", command = windowExplorer)
labelForExcel = Label(root, text="Make sure the excel document is called 'orders'") 
buttonToRun = Button(root, text="Run Stock Checker" ,command = findInfo)
global labelCompletetionMain
labelCompletetionMain = Label(root, text='Completed')
global labelCompletionRestAll
labelCompletionResetAll = Label(root, text='Completed')
labelToResize = Label(root, text="Please DO NOT resize the window of Google Chrome")
global labelWorking
labelStopped = Label(root, text='Stopped Unexpectadly')
#labelToEditExcel = Label(root, text="Please be Patient")
#buttonToResetAll = Button(root, text="Reset all", command = resetAll)
#labelToResetAll = Label(root, text="If not used, will skip orders with a done by the side of it")
labelForEntry = Label(root, text="*Stop after: ")
labelForPhoneNumber = Label(root, text="*Phone Number: ")
#labelForPhoneNumber2 = Label(root, text="Leave empty for no text message")
labelForAsterisk = Label(root, text="* fields not necessary")
#status = Label(root, text=str(status), bd=1, relief=SUNKEN, anchor=W)
labelForEntry.grid(row=0, pady=5)
waitEntry = Entry(root, textvariable = stopValue).grid(row=0, column=1)
labelForPhoneNumber.grid(row=1, sticky=E)
phoneNumberEntry = Entry(root, textvariable = phoneNumber).grid(row=1, column=1, pady=5)
#labelForPhoneNumber2.grid(row=1, column=2)
#buttonToUpload.grid(row=3, sticky=E)
buttonToRun.grid(row=2, columnspan=2, pady=5)
#labelToEditExcel.grid(row=4, column=1, pady=5)
#buttonToResetAll.grid(row=3, pady=5, column=1)
#labelToResetAll.grid(row=4, column=1)
labelForAsterisk.grid(row=4, pady = 5, columnspan=2)
labelToResize.grid(row=6, columnspan=2 )
labelForExcel.grid(row=5, columnspan=2)
#status.grid(row=7, columnspan=2, sticky=N+E+S+W)
print("Finished Tkinter")
phoneNumberUsed = phoneNumber.get()
phoneNumbersFile = open('phoneNumbers.txt', 'r+')
firstNumber = phoneNumbersFile.readline()
if firstNumber != '':
 phoneNumber.set(firstNumber)
phoneNumbersFile.close()
root.mainloop()

That's my code. I have removed personal data etc. I know that my comments are only here and there, that is because my code has been changing so drastically I haven't been able to update comments much. Any improvements please, and I'm semi-new to python, no professional, so be nice.

pic of GUI

200_success
146k22 gold badges190 silver badges478 bronze badges
asked Nov 19, 2016 at 21:44
\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

Your code looks hard to read and not like Python code.

The main reason for this is that every second line is a comment. Most of these comments just repeat what the surrounding code does. These comments don't have any positive value and should therefore be removed.

The other reason is that you didn't structure the code into paragraphs. After each chunk of lines that do something useful, there should be a blank line to give the reader a time to breathe.

The third reason is that in Python code, all lines that begin in column 1 are definitions (for classes or functions), but not executable code. To make your code more pythonic, move all code that is currently in column 1 into functions.

Also, don't write any code above the import statements.

A typical Python file looks like this:

from selenium import browser
import sys
def first_function():
 code()
def next_function():
 code()
 more_code()
def main():
 # setup UI elements
 root.mainloop()
if __name__ == '__main__':
 main()

So far for the style.

A large portion of the code is for formatting the ETA. This code should be in its own function since the details of formatting it are not interesting enough for a reader of the findInfo function. The only thing that is interesting at this level is print("ETA: %s" % format_eta(seconds)).

I didn't read the whole code for calculating the ETA, since it seems far too large. Did you mean this?

def format_eta(seconds):
 hh = seconds / 3600
 mm = seconds / 60 % 60
 ss = seconds % 60
 if hh != 0:
 return "%d hours %d minutes" % (hh, mm)
 return "%d minutes %d seconds" % (mm, ss)
answered Nov 19, 2016 at 22:48
\$\endgroup\$
1
\$\begingroup\$

Don't use wildcard imports with tkinter

Your code does this: from tkinter import *. PEP8 explicitly states that wildcard imports are bad. Instead, import the library with its given name ir give it a shorthand, and then prefix the commands with library name. This will make your code easier to understand and maintain over time.

import tkinter as tk
...
root = tk.Tk()
...

Don't use comments that say what the code is doing.

Comments should be used to explain why, and only for code that isn't obvious. You should strive to write obvious code. For this entire project I see the need for maybe two or three comments.

In other words, remove comments like these because they add no value:

# Prints Updates of whats currently happening
# imports stuff
# Prints Updates of what's happening
# Prints Updates of what's happening
# Opens settings excel document
...

If you think the code isn't clear without the comments, use properly named functions. For example, instead of dozens of print statements and dozens of comments saying that you're printing something, make a function:

def update_user(message):
 print(message)
...
update_user("Pulling Settings")
...
update_user("Defining Functions")

If you then later decide to show these in a GUI, you can modify update_user without having to go back and modify a dozen or more print statements.

use whitespace and logical grouping to make your code more readable.

Consider this block of code:

# Opens settings excel document
settingsWorkbook = openpyxl.load_workbook('settings.xlsx')
# Gets the settings sheet
settingsSheet = settingsWorkbook.get_sheet_by_name('Sheet1')
# Finds the value for oder codes workbook name
ordersWorkbookName = settingsSheet['B6'].value
# If it is empty;
if str(ordersWorkbookName)=='None':
 # Sets to default
 ordersWorkbookName = sheet['C6'].value

A little reorganization would make that block of code considerably easier to understand:

# Get the order codes, and set a default if not found:
settingsWorkbook = openpyxl.load_workbook('settings.xlsx')
settingsSheet = settingsWorkbook.get_sheet_by_name('Sheet1')
ordersWorkbookName = settingsSheet['B6'].value
if str(ordersWorkbookName)=='None':
 ordersWorkbookName = sheet['C6'].value

That is 6 lines rather than 10, and is much easier to understand since you aren't mentally switching back and forth between reading comments and trying to understand code.

The same advice applies to the whole program - use spacing and grouping to organize your code.

answered Dec 26, 2016 at 13:18
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.