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

\$\endgroup\$
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)
\$\endgroup\$
0
\$\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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.