How can I apply multiprocessing to this function? - python

I wrote a little script which scrapes a platform for job advertisments, everything working pretty fine but really slow, since im iterating through up to 200 advertisments for information. While I still think I could code some stuff better to make it run faster aswell, the fact that I couldnt get multiprocessing working here is what bothers me most.
These are the functions, which do the main work, i was trying to add an intern function for the for loop in def get_all_job_details() to map it, but it would always throw an PicklingError or sometimes i got "Expected exactly 2 arguments 3 given" in open_file() which i cant understand tbh.
def get_job_links(section_URL):
soup = make_soup(section_URL)
internerLink = soup.find_all("a", "internerLink primaerElement")
job_links = [BASE_URL + link["href"] for link in internerLink]
return job_links
def get_all_job_links(section_URL):
all_job_links = []
for page in range(1, PAGE_COUNT + 1):
newURL = section_URL[:-1] + str(page)
all_job_links.extend(get_job_links(newURL))
return all_job_links
def get_job_details(job_URL):
soup = make_soup(job_URL)
details = {'job_URL': job_URL, 'refnr': '', 'firmName': '',
'fName': '', 'sName': '', 'adressStr': '',
'adressPlz': '', 'adressOrt': '', 'email': '',
'jobtype': '', 'gender': '', 'status': ''}
[details.update({'refnr': refnr.text}) for refnr in soup.findAll(id=re.compile("referenznummer"))]
[details.update({'firmName': firmName.text}) for firmName in
soup.findAll(id=re.compile("ruckfragenundbewerbungenan_-2147483648"))]
[details.update({'fName': fName.text + ' '}) for fName in soup.findAll(id=re.compile("vorname_-2147483648"))]
[details.update({'sName': sName.text}) for sName in soup.findAll(id=re.compile("nachname_-2147483648"))]
[details.update({'adressStr': adressStr.text}) for adressStr in
soup.findAll(id=re.compile("ruckfragenUndBewerbungenAn.wert\['adresse'\]Strasse_-2147483648"))]
[details.update({'adressPlz': adressPlz.text}) for adressPlz in
soup.findAll(id=re.compile("ruckfragenUndBewerbungenAn.wert\['adresse'\]Plz_-2147483648"))]
[details.update({'adressOrt': adressOrt.text}) for adressOrt in
soup.findAll(id=re.compile("ruckfragenUndBewerbungenAn.wert\['adresse'\]Ort_-2147483648"))]
[details.update({'email': str(email['href'])[7:]}) for email in
soup.findAll(id=re.compile("vermittlung.stellenangeboteverwalten.detailszumstellenangebot.email"))]
jobtype = soup.b
if jobtype:
jobtype = soup.b.text
else:
jobtype = ''
if jobtype.find("Anwendungsentwicklung") > -1:
details.update({'jobtype': u"Fachinformatiker für Anwendungsentwicklung"})
elif jobtype.find("Systemintegration") > -1:
details.update({'jobtype': u"Fachinformatiker für Systemintegration"})
elif jobtype.find("Medieninformatik") > -1:
details.update({'jobtype': u"Medieninformatiker"})
elif jobtype.find("Informatikkaufmann") > -1:
details.update({'jobtype': u"Informatikkaufmann"})
elif jobtype.find("Systemkaufmann") > -1:
details.update({'jobtype': u"IT-Systemkaufmann"})
else:
details.update({'jobtype': u"Informatiker"})
soup.find("div", {"class": "ausklappBox"}).decompose()
genderdiv = str(soup.div)
gender = ''
if genderdiv.find("Frau") > -1:
gender += "Frau "
if genderdiv.find("Herr") > -1:
gender += "Herr "
if len(gender) > 5:
gender = ''
details.update({'gender': gender})
return details
def get_all_job_details(section_URL):
all_job_details = []
all_job_links = get_all_job_links(section_URL)
for i in range(len(all_job_links)):
all_job_details.append(get_job_details(all_job_links[i]))
printProgress(i, len(all_job_links) - 1, prefix='Progress:', suffix='Complete', barLength=50)
return all_job_details
def printProgress(iteration, total, prefix='', suffix='', decimals=2, barLength=100):
"""
Call in a loop to create terminal progress bar
#params] =
iteration - Required : current iteration (Int)
total - Required : total iterations (Int)
prefix - Optional : prefix string (Str)
suffix - Optional : suffix string (Str)
decimals - Optional : number of decimals in percent complete (Int)
barLength - Optional : character length of bar (Int)
"""
filledLength = int(round(barLength * iteration / float(total)))
percents = round(100.00 * (iteration / float(total)), decimals)
bar = '#' * filledLength + '-' * (barLength - filledLength)
Sys.stdout.write('%s [%s] %s%s %s\r' % (prefix, bar, percents, '%', suffix)),
Sys.stdout.flush()
if iteration == total:
print("\n\n")
So how do I do it correctly?

Related

Python Convert Inches and Feet into Inches

I am trying to convert arrays that contain both Inches and Feet into Inches. The feet are denoted with a single quote (') and inches are denoted with double quotes ("). The data comes in the following forms:
[8'x10']
[60\" x 72\"]
[5'x8',5x8,60\"x92\"]
[8'10\"x12']
What I want:
["96x120"]
["60x72"]
["60x96","60x96","60x96","60x92"]
["106x144"]
What I have:
def ft_inch(numbers):
if str(numbers).find("x") > -1:
numbers=numbers.replace('[','').replace('"','').replace('[','').replace(']','')
try:
nom = numbers.split("x")[0]
nom=nom.replace(r'\\|\"|\]|\[','')
nom_one = nom.split("'")[0]
nom_two = nom.split("'")[1]
den = numbers.split("x")[1]
den=den.replace(r'\\|\"|\[|\]','')
den_one = den.split("'")[0]
den_two = den.split("'")[1]
ft=int(nom_one)*12
inch=nom_two.replace(r'\"| |\\','')
try:
inch=int(inch)
except:
print('B')
tmp = int(ft)+int(inch)
fts=int(den_one)*12
inchs=den_two.replace(r'\"| |\\','')
try:
inchs=int(inchs)
except:
print('B')
tmp_two = int(fts)+int(inch)
return f'["{tmp}x{tmp_two}"]'
except:
return numbers
else:
return numbers
x="[5'1x8'1]"
ft_inch(x)
This works for a single array as long as it has both feet and inches but fails if its only feet [8'x8']. If anyone has a simpler solution please let me know
A regex-based approach:
import re
inputs = [["8'1x10'1"], ["60\" x 72\""], ["5'x8'", "5x8", "60\"x92\""], ["8'10\"x12'"]]
for inpt in inputs:
sub_output = []
for measurement in inpt:
m = re.match(r"(\d+['\"]?)(\d+['\"]?)?x(\d+['\"]?)(\d+['\"]?)?",
"".join(measurement.split()))
groups = [m.groups()[:2], m.groups()[2:]]
result_inches = [0, 0]
for i, group in enumerate(groups):
for raw_val in group:
if raw_val == None:
continue
if '"' in raw_val:
result_inches[i] += int(raw_val[:-1])
elif "'" in raw_val:
result_inches[i] += int(raw_val[:-1])*12
else:
result_inches[i] += int(raw_val)*12
sub_output.append(result_inches)
print([f"{x}x{y}" for x, y in sub_output])
Output:
['108x132']
['60x72']
['60x96', '60x96', '60x92']
['106x144']
I saw your edit and included the ["8'1x10'1"] case :)
I rewrote the entire thing, but this seems to work:
input_ = ["8'x10'", "60\" x 72\"", "5'x8'","5x8","60\"x92\"", "8'10\"x12'", "8'1x10'1\""]
inches_only = []
for s in input_:
s.replace(" ", "")
sides = s.split("x")
new_sides = []
for side in sides:
inches = 0
split1 = side.split("'")
if len(split1) > 1 or (len(split1) == 1 and not side.__contains__('"')):
inches = int(split1[0]) * 12
split2 = side.split('"')
if len(split2) > 1:
inches += int(split2[0].split("'")[-1])
elif len(split2) == 1 and len(split1) > 1 and len(split1[1]) > 0:
inches += int(split1[1])
new_sides.append(str(inches) + '"')
inches_only.append("x".join(new_sides))
print(inches_only)
Output:
['96"x120"', '60"x72"', '60"x96"', '60"x96"', '60"x92"', '106"x144"', '97"x121"']

How to add or remove Chrome Extensions "after" selenium web-driver has been instantiated / defined

The title says it all - I am looking for a way (or ways) to load, enable, add (and likewise: disable / remove) extensions after the webdriver has been created.
Context: Python, selenium (per tags). Pyautogui for certain parts would be unavoidable, but would need to be robust. I have a draft working soln but its rough and a little GPU dependent (point: can/will not accept "this cannot be done with Chrome" as I know it can be done, but would like to see some soln/code to this effect).
I am perfectly aware of the various methods to load an extension prior to the driver being instantiated / created. i.e.
o.add_extension(crx file location)
o.add_argument(unpacked folder loc)
o.add_argument('--user-data-dir=' + profileX)
where o = Options, profileX has extensions pre-installed and so forth. So will be clear - I am completely uninterested in proposals to this effect.
Any ideas/proposals in regards to the question in the title/above?
Ideally (but not absolutely critical) would be a programmatic solution that is not entirely GUI based (robotic/PyAutogui dependent).
You can assume the extension is available on the chrome store for this exercise.
Use-case: The extension I'm testing involves registering points and to protect fair / intended usage terms, its designed to cease functioning whenever it recognises automated manipulation (which is perfectly possible with 'headed' chrome, e.g. you just assign it a hotkey in chrome settings, and use Pyautogui to activate, or locate it's html page and interact directly etc.). GIVEN this, and the very many, many tests I have, it seems a waste of resource me having to reload the tests, or set up profiles, or stop and start the tests every so often so that I can include 'fresh' copies of the crx files or deploy one of the other methods I mention above. To date / my best knowledge, there is no solution for this. Happy to be pleasantly surprised if someone can point me to a 'duplicate' Q in this regard.
NOTES
Problem addressed with three possible approaches (thus soln. appears lengthy, but individual methods are not excessive/particular lengthy; what's more, code can be easily adapted as req.)
Further, this starts in the context of a single-browser environment / setup;
Ensues with variable and method definitions that extend the premise / thinking to encompass implementation within a multi-threaded / multi-browser environment
PRELIMINARY
import glob2,itertools,os, pyautogui, shutil, time, pyperclip, subprocess, keyboard as kb
from datetime import datetime
from zipfile import ZipFile
now = datetime.now()
dt_string: str = now.strftime("%d-%b-%Y, %H:%M:%S")
print(dt_string)
from selenium import webdriver
from selenium.webdriver import DesiredCapabilities
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.wait import WebDriverWait
from concurrent.futures import ThreadPoolExecutor
from os import path
#references: date-time format: https://www.programiz.com/python-programming/datetime/current-datetime
datetime reference
METHODS
Method 1: add after chrome launches via Chrome-store
def ext_update_method1(ps, section=''):
global w, p2s
text_temp, p2s = [''] * len(ps), []
def button_click(p, parms = ['',True]):
#parms[0] = ID, parms[1] = click?
ID,click = parms[0], parms[1]
global text_temp
text_temp[p] = ''
ID = ['omghfjlpggmjjaagoclmmobgdodcjboh'] if ID == '' else ID #default i= Browsec if no ID entered
d[p].get(f'https://chrome.google.com/webstore/detail/{ID[0]}')
w[p] = WebDriverWait(d[p], 10)
w[p].until(lambda x: x.execute_script("return document.readyState") == "complete")
button = w[p].until(lambda x: x.find_element_by_class_name('g-c-R'))
text_temp[p] = button.text
if click == True: button.click()
def add_remove():
global p2s
for i, y in enumerate(ys): activ(i, ys), (ss, 0.5), keys([(pr, 'tab'), (pr, 'space')])
after2, ys2 = gwwt(''), []
for x in after2:
if (x not in before) and (x not in ys_remove): ys2 = ys2 + [x, ]
# ys2 = ys2 + [x,] if (all(x not in before) and (x not in ys_remove)) else ys2
for i, y in enumerate(ys2): activ(i, ys), (ss, 0.5), keys([(pr, 'tab'), (pr, 'space')])
ss(1)
after2, ys2 = gwwt(''), []
for x in after2:
if (x not in before) and (x not in ys_remove) and (x not in a[0] for a in wd): ys2 = ys2 + [x, ]
for i, y in enumerate(ys2):
if all(y != x[0] for x in wd): y.close()
if len(ys_remove) > 0:
for i, y in enumerate(ys_remove):
activ(i, ys_remove), pr('space'), ss(0.5)
p2s = p2s + [i, ]
if section == 1:
return 'complete 2nd iteration' #prevent endless loop (see next comment)
else:
print('removed add-in, now adding back again....')
cc(2)
thread_all(ps, close_extra)
ext_update_method1(p2s, 1) #loop back on self to add
else:
return 'complete 1st iteration'
def close_extra(p):
global w
w_old = w[p]
w[p] = WebDriverWait(d[p], 10)
tabs_close_extra(p)
tabs_close_extra(p)
activ(p), pr('a'), activ(p), pr('enter')
w[p].until(lambda x: x.execute_script("return document.readyState") == "complete")
w[p] = w_old
thread_all(ps, tabs_close_extra)
before = gwwt('')
thread_all(ps, button_click)
cc(2) #cc(5)
after = gwwt('')
ys, ys_remove, p2s = [], [], []
ys_remove = gwwt('remove')
print(f'ys_remove = {ys_remove}')
for x in after:
if (x not in ys_remove) and (x not in before): ys = ys + [x, ]
print(add_remove())
cc(2)
thread_all(ps, close_extra)
thread_all(ps,button_click,['',False])
qs = []
for x in text_temp: qs = qs + [1,] if 'add' in x.lower() else qs
print(f'qs: {qs}')
if section == 2: return #prevent never-ending loop (see next comment)
if len(qs) > 0: ext_update_method1(qs,2) #loop back on self in case 'add extension' still present in web-store
Notes:
Can download multiple versions of same extension on same browser
Caution: 3rd parameter in n_i_c is set to 1 by default: this will
clear your downloads folder. Set to 0 if don't want this to happen
Arguments:
args: n_i_c[0] = number of times you wish to download a given
extension onto the same browser
n_i_c[1] = item of global list: ext_details, see vars()n_i_c2 =
1 to clear folder
n_i_c[3]= 0 => only download unpacked folder (not loading it too)
Requires methods ('Ancillary Code', Vars) below - code can be modified
to exclude these.
Method 2: Download & load .crx file after Chrome launch
def ext_update_method2(ps, n_i_c=[2, 0, 1,1], section = ''): # same order as it would
appear for single set of extensions (iro one tab)...
# parms = [2,0,0,0] =>
# 0. repetitions - e.g. 2 downloads : uBlock
# 1. 0 [index value - e.g. uBlock = 4, below] downloaded and unzipped/installed on profile p
# 2: clear folder
# 3: is_load = 0 => only download unpacked folder (not loading it too)
global start, w, files_old, ev, d, parent, txt
global tabs_before
global files, files_new, index_latest_files, index_redo, index_hks
hks2, index_ext, clear_folder, is_load = n_i_c[0], n_i_c[1], n_i_c[2], n_i_c[3] # ID, alias = cred[0], cred[1], cred[2]
hks2 = hks if hks == '' else hks2
ID, alias = ext_details[index_ext][1], ext_details[index_ext][0]
url_robwu = '''https://robwu.nl/crxviewer/?crx=https://chrome.google.com/webstore/detail/''' + str(ID)
if clear_folder == 1:
folder_clear(del_dir=os.path.join(os.path.expanduser("~"), 'Downloads', '*'))
def thread_all_0(p): #set up stuff
global d, w, index_hks2
if 'error' in str(tabs_close_extra(p)):
tab_close(p)
d[p].implicitly_wait(5)
w[p] = WebDriverWait(d[p], 5)
index_hks2[p] = ''
d[p].get('chrome://extensions')
code_0 = '''var tags = document.querySelector('body').querySelector('extensions-manager')['shadowRoot'].querySelector('cr-view-manager').querySelector('extensions-item-list')["shadowRoot"].querySelector('#container').querySelectorAll('extensions-item'); return tags.length;'''
index_hks[p]=ev[p](code_0)
print(index_hks[p])
#
thread_all(ps, thread_all_0)
#
def thread_all_1(p): #open website to download crx (multi-thread to expedite)
d[p].get(url_robwu)
#
if len(ps) >= 2: #prevent overloading website - only do 3 at a time if more than 2 browsers being used
groups = list(data_mygrouper(2, ps))
for x in groups: thread_all(x, thread_all_1,workers = 3, chunk = 3)
else:
thread_all(ps, thread_all_1)
files_old = glob2.glob(os.path.join(os.path.expanduser("~"), 'Downloads', '*.zip'))
def thread_all_2(p):
try:
w[p].until(lambda x: x.find_element_by_id("download-link")).click()
print('lambda wait passed !!')
except:
print('lambda wait failed :(')
return
start_temp = time.time()
while (time.time() - start_temp <= 90) and (len(glob2.glob(os.path.join(os.path.expanduser("~"), 'Downloads', '*.zip'))) - len(files_old) < hks2 * (len(ps))) or (kb.is_pressed('escape') == True):
if kb.is_pressed('escape') == True: break
thread_all(ps, thread_all_2), ss(1)
files = glob2.glob(os.path.join(os.path.expanduser("~"), 'Downloads', '*.zip'))
files_new = []
for keep in files:
if str(keep) not in files_old: files_new = files_new + [str(keep), ]
# thread_all(files_new, z_extension_unzip, alias)
path_dir_core = os.path.join(os.path.expanduser("~"), 'Downloads')
index_latest_files = [''] * len(files_new)
#
def thread_all_3(j): # unzip
global index_latest_files
index_latest_files[j] = os.path.join(path_dir_core, alias + str(j))
with ZipFile(files_new[j], 'r') as zipObj:
zipObj.extractall(index_latest_files[j])
os.remove(files_new[j])
#
thread_all(list(range(len(files_new))), thread_all_3)
if is_load != 1: return
code1 = '''if(document.querySelector('body').querySelector('extensions-manager')["shadowRoot"].querySelector('extensions-toolbar').attributes.length !=2){document.querySelector("body").querySelector("extensions-manager")["shadowRoot"].querySelector("extensions-toolbar")["shadowRoot"].querySelector("cr-toolbar").querySelector(".more-actions").querySelector("#devMode")["shadowRoot"].querySelector("#knob").click() } else {'dev mode already activated!'}'''
code2 = '''document.querySelector('body').querySelector('extensions-manager')["shadowRoot"].querySelector('extensions-toolbar')["shadowRoot"].querySelector("#loadUnpacked").click()'''
#
def thread_all_4(p):
d[p].get('chrome://extensions/'), ss(1)
ev[p](code1)
for y in range(hks2):
thread_all(ps, thread_all_4)
windows_before = gwwt('Select the extension directory')
for p in ps:
try:
if path.exists(os.path.join(path_dir_core, index_latest_files[p + len(ps) * (y)])):
try:
ev[p](code2)
except:
continue
start_temp = time.time()
while (time.time() - start_temp <= 30) and (
len(gwwt('Select the extension directory')) - len(windows_before)) < 1 and (
'select the extension directory' not in gawt().lower()): pass # len(ps) - len(errors_chrome()): pass
tabs_before = len(d[p].window_handles)
windows_A = gwwt('')
try:
keys([(tw, index_latest_files[p + len(ps) * (y)]), (ss, 0.5), (pr, 'enter'), (pr, 'tab'),(pr, 'space')], 0.75)
if len(windows_A) < len(gwwt('')):
d[p].refresh()
print('would break1')
else:
window_target = gwwt('Select the extension directory')[0]
try:
window_target.activate()
except:
window_target.minimize()
window_target.restore()
finally:
pyperclip.copy(index_latest_files[p + len(ps) * (y)]), ss(0.5)
keys([(hk, 'ctrl', 'l'), (kd, 'shift'), (pr, 'tab', 4), (ku, 'shift'), (hk, 'ctrl', 'v'), (pr, 'enter'), (pr, 'tab'), (pr, 'space')])
except:
d[p].refresh()
pr('escape', 2)
print('would break2')
tabs_close_extra(p)
else: continue
except: continue
def thread_all_5(p):
global qs
d[p].get('chrome://extensions/shortcuts')
code_0 = '''return document.querySelector('body').firstElementChild["shadowRoot"].querySelector("cr-view-manager").querySelector('extensions-keyboard-shortcuts')['shadowRoot'].querySelector('#container').querySelectorAll('.shortcut-card').length'''
index_hks[p] = int(ev[p](code_0)) - index_hks[p]
qs = qs + [p,] if index_hks[p] < hks2 else qs
print(f'index_hks[{p}] = {index_hks[p]}')
index4[p] = 0
qs = []
if clear_folder == 1:
thread_all(ps, thread_all_5)
if section == 1: return
if len(qs) > 0: ext_update_method2(qs, n_i_c = [hks2, index_ext, 0, 1], section = 1)
qs = []
for p in range(len(ps)): qs = qs + [p,]
Method 3: remove programmatically
def ext_remove(ps,ext):
for p in range(len(ps)):
try:
activ(p)
d[p].get('chrome://extensions/')
#pr('f12'),ss(1)
hk('ctrl', 'shift', 'j'), ss(1)
code = '''var tags = document.querySelector('body').querySelector('extensions-manager')['shadowRoot'].querySelector('cr-view-manager').querySelector('extensions-item-list')["shadowRoot"].querySelector('#container').querySelectorAll('extensions-item'); for (i = 0;i <= tags.length; i ++) {try {if(tags[i]['shadowRoot'].querySelector('#a11yAssociation').innerText.toLowerCase().indexOf("''' + str(ext) +'''") > 0) {tags[i]['shadowRoot'].querySelector('#remove-button').click();break} } catch {}}'''
pyperclip.copy(code), ss(0.5)
# pr('tab'), ss(0.5)
temp_rep = 1 if type(ext) == str else len(ext)
for _ in range(temp_rep):
hk('ctrl', 'v'), ss(0.5)
pr('enter'), ss(0.5)
pr('space'), ss(0.5)
tabs_close_extra(p)
pr('f12'), ss(0.5) #hk('ctrl', 'shift', 'j'), ss(0.5)
except: pass
ANCILLARY CODE
Activate window
Shorthand: simulate keyboard strokes
Methods: sub-divide lists, close tabs, thread-pool (multi-threading), and tile windows*
*(java scripts incl. - to be saved in same location as this script
Activate window
pyautogui.FAILSAFE = False
def activ(p, index_wd=''):
global index_activ
try:
if index_wd == '':
index_wd = wd[p][0]
else:
index_wd = index_wd[p]
except:
index_wd = wd[p]
print(f'active {w}')
index_activ[p] = False
try:
index_wd.activate()
index_activ[p] = True
return index_activ[p]
except:
try:
index_wd.minimize()
index_wd.restore()
index_activ[p] = True
return index_activ[p]
except:
index_activ[p] = False
index_activ[p] = False
return index_activ[p]
Quick keys
def keys(actions, delay=0.5):
# global BL3
print(f'def keys()') # {actions}') #, profile {p}')
outcome = []
for action in actions:
print(f'action {action}')
if len(action) == 4:
outcome = outcome + [action[0](action[1], action[2], action[3]), ]
elif len(action) == 3:
outcome = outcome + [action[0](action[1], action[2]), ]
elif (len(action) == 2) and (action[1] != ''):
outcome = outcome + [action[0](action[1]), ]
else:
outcome = outcome + [action[0](), ]
ss(delay) # await ass(delay)
return outcome
Sub-divide lists
def data_mygrouper(n,
iterable):
args = [iter(iterable)] * n
return ([e for e in t if e != None] for t in itertools.zip_longest(*args))
stack overflow reference (data_mygrouper)
ThreadPool
def thread_all(ps, fn, parm='', actions=[], workers=6, chunk=1):
# https://stackoverflow.com/questions/42056738/how-to-pass-a-function-with-more-than-one-argument-to-python-concurrent-futures/42056975
print(f'thread_all({ps}, {fn}, {parm}, {actions}')
if parm == '':
with ThreadPoolExecutor(max_workers=max(1, workers)) as executor:
return executor.map(fn, ps, timeout=90, chunksize=max(1, chunk))
else:
with ThreadPoolExecutor(max_workers=max(1, workers)) as executor:
return executor.map(fn, ps, itertools.repeat(parm, L), timeout=90, chunksize=max(1, chunk))
thread-pool_exector ref: here
close tabs
def tab_close(p):
print(f'def tab_close {p}')
# d[p].switch_to.window(parent[p])
for h in d[p].window_handles:
d[p].switch_to.window(h)
parent[p] = h
[ev[p]] = [d[p].execute_script]
break
# parent[p] = d[p].current_window_handle
for h in d[p].window_handles:
if h != parent[p]:
d[p].switch_to.window(h)
if len(d[p].window_handles) > 1: d[p].close()
else: break
d[p].switch_to.window(parent[p])
def tabs_close_extra(p):
# alternative method (much slower): https://stackoverflow.com/questions/12729265/switch-tabs-using-selenium-webdriver-with-java
try:
for h in d[p].window_handles:
d[p].switch_to.window(h)
parent[p] = h
break
# parent[p] = d[p].current_window_handle
tabs_original = len(d[p].window_handles)
if tabs_original > 1:
for h in d[p].window_handles:
if h != parent[p]:
d[p].switch_to.window(h)
activ(p), hk('ctrl', 'w')
if len(d[p].window_handles) == tabs_original:
d[p].close()
# d[p].switch_to.window(parent[p])
d[p].switch_to.window(parent[p])
except:
print(f'error in tabs_close_extra {p}')
Variables
def vars():
print('def vars()')
global index, index2, index3, index4, index5, index6
global index_activ, index_activ2, hks, pycharm_win
global index_latest_files, index_hks, index_hks2
global parent, d, w, w2
global path_chrome, path_exec, path_core, path_temp, profile, done, caps, pycharm_win
global ps, p2s, qs
global L, tile_type, compact, outcome
global kd, ku, hk, pr, tw, wr, cl
global gats, gaws, gwwt, gawt, gaw
global cc, ss, start, start2, start_overall
global wd, wd2, ev, errors, errors2, errors3
global ext_0, ext_1, ext_2, ext_3,ext_details
caps = DesiredCapabilities.CHROME.copy()
[cc, ss, kd, ku, hk, pr, tw, wr, cl] = [pyautogui.countdown, time.sleep,
pyautogui.keyDown, pyautogui.keyUp, pyautogui.hotkey, pyautogui.press,,pyautogui.typewrite, pyautogui.write, pyautogui.click]
[gats, gaws, gwwt] = [pyautogui.getAllTitles, pyautogui.getAllWindows, pyautogui.getWindowsWithTitle]
[gawt, gaw] = [pyautogui.getActiveWindowTitle, pyautogui.getActiveWindow]
L = 4
qs, p2s, ps, = list(range(L)), list(range(L)), list(range(L))
text_temp, start = [''] * L, [0] * L
index_hks, index_hks2 = [hks] * L, [0] * L
index_latest_files = ['']
parent, w, ev, d, wd = [''] * L, [''] * L, [''] * L, [''] * (L + 1), [['']]*L
start_overall, outcome = '', ''
try: pycharm_win = [gaw()]
except: pass
path_chrome = "C:\Program Files\Google\Chrome\Application\chrome.exe"
path_core = os.path.join(os.path.expanduser("~"), 'PyCharmProjects', 'Parallel')
path_exec = os.path.join(path_core, "chromedriver.exe")
ext_details = [ ['ublock', 'cjpalhdlnbpafiamejdnhcphjbkeiagm'], ['keyboard_shortcuts', 'dkoadhojigekhckndaehenfbhcgfeepl'], ['browsec', 'omghfjlpggmjjaagoclmmobgdodcjboh'], ['itrace', 'njkmjblmcfiobddjgebnoeldkjcplfjb']]
ext_0= os.path.join(path_core, "Browsec")
ext_1 = os.path.join(path_core, "Keyboard")
ext_2 = os.path.join(path_core, "itrace")
ext_3 = os.path.join(path_core, "ublock")
MAIN CODE
if __name__ == '__main__':
ps =''
vars()
if len(ps) > 3:
ps_new = list(data_mygrouper(int(round(len(ps) / 2, ndigits=0)), ps))
for x in range(2): thread_all(ps_new[x], new_profile, workers=len(ps_new[x]) + 1, chunk=len(ps_new[x]) + 1), cc(5)
# new_profile
else: thread_all(ps, new_profile, workers=L + 1, chunk=L+1)
#thread_all(ps,new_profile)
tile_windows('v')
ext_update_method1(ps)
ext_remove(ps,'browsec')
ext_update_method2(ps)

DNS Server doesnt response

The dns doesnt work if i do this it gives this error and idk whats the matter it just gives me this error:
Traceback (most recent call last):
File "c:\Users\engin\Downloads\All files\dns.py", line 160, in <module>
r = buildresponse(data)
File "c:\Users\engin\Downloads\All files\dns.py", line 155, in buildresponse
dnsbody += rectobytes(domainname, rectype, record["ttl"], record["value"])
TypeError: string indices must be integers
and i did write this code for my DNS Server:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((ip, port))
def load_zone():
jsonzone = {}
zonefiles = glob.glob('zones/*.zone')
for zone in zonefiles:
with open(zone) as zonedata:
data = json.load(zonedata)
zonename = data["$origin"]
jsonzone[zonename] = data
return jsonzone
zonedata = load_zone()
def getFlags(flags):
byte1 = bytes(flags[:1])
byte2 = bytes(flags[1:2])
rflags = ''
QR = '1'
OPCODE = ''
for bit in range(1,5):
OPCODE += str(ord(byte1) & (1<<bit))
AA = '1'
TC = '0'
RD = '0'
RA = '0'
Z= '000'
RCODE = '0000'
return(int(QR + OPCODE + AA + TC + RD, 2).to_bytes(1, byteorder='big') + int(RA + Z + RCODE, 2).to_bytes(1, byteorder='big'))
def getquestiondomain(data):
state = 0
expectedlenght = 0
domainsting = ''
domainparts = []
x = 0
y = 0
for byte in data:
if state == 1:
if byte != 0:
domainsting += chr(byte)
x += 1
if x == expectedlenght:
domainparts.append(domainsting)
domainsting = ''
state = 0
x = 0
if byte == 0:
domainparts.append(domainsting)
break
else:
state = 1
expectedlenght = byte
# x += 1
y += 1
questiontype = data[y + 1 : y + 3]
return(domainparts, questiontype)
def getzone(domain):
global zonedata
zone_name = '.'.join(domain)
return zonedata[zone_name]
def getrecs(data):
domain, questiontype = getquestiondomain(data)
qt = ''
if questiontype == b'\x00\x01':
qt = 'a'
zone = getzone(domain)
return (zone, qt, domain)
def rectobytes(domainname, rectype, recttl, recval):
rbytes = b'\xc0\x0c'
if rectype == 'a':
rbytes = rbytes + bytes([0]) + bytes([1])
rbytes = rbytes + bytes([0]) + bytes([1])
rbytes += int(recttl).to_bytes(4, byteorder='big')
if rectype == 'a':
rbytes = rbytes + bytes([0]) + bytes([4])
for part in recval.split('.'):
rbytes += bytes([int(part)])
return rbytes
def buildquestion(domainname, rectype):
qbytes = b''
for part in domainname:
lenght = len (part)
qbytes += bytes([lenght])
for char in part:
qbytes += ord(char).to_bytes(1, byteorder='big')
if rectype == 'a':
qbytes += (1).to_bytes(2, byteorder='big')
qbytes += (1).to_bytes(2, byteorder='big')
return qbytes
def buildresponse(data):
TransactionID = data[:2]
# TID = ''
# for byte in TransactionID:
# TID += hex(byte)
Flags = getFlags(data[2:4])
QDCOUNT = b'\x00\x01'
# getquestiondomain(data[12:])
ANCOUNT = len(getrecs(data[12:])[0]).to_bytes(2, byteorder='big')
NSCOUNT = (0).to_bytes(2, byteorder='big')
ARCOUNT = (0).to_bytes(2, byteorder='big')
dnsheader = TransactionID + Flags + QDCOUNT + ANCOUNT + NSCOUNT + ARCOUNT
dnsbody = b''
records, rectype, domainname = getrecs(data[12:])
dnsquestion = buildquestion(domainname, rectype)
for record in records:
dnsbody += rectobytes(domainname, rectype, record["ttl"], record["value"])
return dnsheader + dnsquestion + dnsbody
while 1:
data, addr = sock.recvfrom(512)
r = buildresponse(data)
sock.sendto(r, addr)
and this value record in the for at the very bottom of buildresponse it just prints out #origin
Idk whats the problem or so and then i created this Post and pls help.
pls help!
Okay so now you've shown that your records value is the following dictionary:
records = {'$origin': 'status.minecraft.de.', '$ttl': 3600, 'soa': {'mname': 'ns1.status.minecraft.de.', 'rname': 'admin.status.minecraft.de.', 'serial': '{time}', 'refresh': 3600, 'retry': 600, 'expire': 604800, 'minimum': 86400}, 'ns': [{'host': 'ns1.status.minecraft.de.'}, {'host': 'ns2.status.minecraft.de.'}], 'a': [{'name': '#', 'ttl': 400, 'value': '255.255.255.255'}, {'name': '#', 'ttl': 400, 'value': '127.0.0.1'}, {'name': '#', 'ttl': 400, 'value': '127.0.0.1'}]}
This means that if you were to loop through it how you currently do - for record in records - we know that, since it's a dictionary, each record will be a key of that dictionary (as per this). So, the following code:
for record in records:
print(record)
print(type(record))
Gives the following outpupt - which is just all the keys in the dictionary:
$origin
<class 'str'>
$ttl
<class 'str'>
soa
<class 'str'>
ns
<class 'str'>
a
<class 'str'>
So, that means that if you try to access record["ttl"] or record["value"], since record is a string, this will be like trying to do something like "$ttl"["ttl"], which would give the error string indices must be integers.
However, the issue wouldn't be solved just be replacing record with records, since the records object has no "value" or "ttl" key. It appears that you're actually trying to loop through each value in the "a" key in your records dictionary, since its value is an array of dictionaries that have both a "ttl" and "value" key:
[{'name': '#', 'ttl': 400, 'value': '255.255.255.255'}, {'name': '#', 'ttl': 400, 'value': '127.0.0.1'}, {'name': '#', 'ttl': 400, 'value': '127.0.0.1'}]
Therefore, your fix would simply be:
for record in records["a"]:
dnsbody += rectobytes(domainname, rectype, record["ttl"], record["value"])

KeyError for key that exists in dictionary [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I have a piece of code that has an array that loops through an array of keys for a dictionary. It gets each of these keys, applies it to the dictionary and then gets the returned value and uses it for spacing out my unicode table. Example:
sizeDict = {
"Name": 16,
"Mobile": 11,
"Pizza": 7,
"Drink": 7,
"Dessert": 7,
"Total": 7
}
header = ['name', 'mobile', 'pizza', 'drink', 'dessert', 'total']
def printRow(firstChar, endChar, space, specialChar, spaceArray, spaceDict):
output = firstChar
for i in range(0, len(spaceArray)):
if(i == len(spaceArray) - 1):
specialChar = endChar
output = output + space * spaceDict[spaceArray[i].title()] + specialChar
return output
print(printRow("┏", "┓", "━", "┳", header, sizeDict))
#Returns ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┓
The problem for some reason, is that it doesn't recognise some of the values from the array as actual keys in the dictionary, even though both strings are exactly alike. Here is the specific array, dictionary and error message where the error occured.
statHeader = ['Average Total', 'Earned', '% of Total']
statSizeDict = {
"Average Total": 15,
"Earned": 10,
"% of Total": 20
}
statSizeArray = [15,10,20]
"""
<ipython-input-3-5c5f25401e4d> in statOrders(statData)
272 for i in range(0, len(statHeader)):
273 tempString += spaceVal(statHeader[i], statSizeDict[statHeader[i]])
--> 274 print(printRow("┏", "┓", "━", "┳", statHeader, statSizeDict))
275 print(tempString)
276 print(printRow("┣", "┫", "━", "╋", statHeader, statSizeDict))
<ipython-input-3-5c5f25401e4d> in printRow(firstChar, endChar, space, specialChar, spaceArray, spaceDict)
51 if(i == len(spaceArray) - 1):
52 specialChar = endChar
---> 53 output = output + space * spaceDict[spaceArray[i].title()] + specialChar
54 return output
55 # ========================================================================================================================== #
KeyError: '% Of Total'
"""
Here is the complete code for reference:
import csv
import os
# ========================================================================================================================== #
data = []
testData = [8001, 499382, 'int', 'int', 'float']
header = ['name', 'mobile', 'pizza', 'drink', 'dessert', 'total']
statHeader = ['Average Total', 'Earned', '% of Total']
# ========================================================================================================================== #
orderDict = {
"Small cheese pizza": ['pizza', 5],
"Big cheese pizza": ['pizza', 10],
"Small drink": ['drink', 1],
"Large drink": ['drink', 1.5],
"Small dessert": ['dessert', 0.5],
"Large dessert": ['dessert', 1]
}
posDict = {
"Pizza Total": 2,
"Drink Total": 3,
"Dessert Total": 4
}
returnDict = {
1: 'Task completed succesfully.',
2: 'Task encountered an unexpected error.',
3: 'No file data was found.',
4: 'Value does not exist or is out of range.',
5: 'Value type is invalid or does not exist in current range.',
6: 'Value length was to large for function.'
}
sizeDict = {
"Name": 16,
"Mobile": 11,
"Pizza": 7,
"Drink": 7,
"Dessert": 7,
"Total": 7
}
statSizeDict = {
"Average Total": 15,
"Earned": 10,
"% of Total": 20
}
statSizeArray = [15,10,20]
def spaceVal(value, size):
return str(value)[:size] + " " * (size-len(str(value))) + '┃'
def printRow(firstChar, endChar, space, specialChar, spaceArray, spaceDict):
output = firstChar
for i in range(0, len(spaceArray)):
if(i == len(spaceArray) - 1):
specialChar = endChar
output = output + space * spaceDict[spaceArray[i].title()] + specialChar
return output
# ========================================================================================================================== #
def newOrderCash(appendData, name, mobile, pizza=0, drink=0, dessert=0):
"""
Appends the formatted order to the data list and returns
the name of the customer and the total of their order.
Args:
appendData - a list which has the order
appended to the end of it.
name - a string value containing the customer's name.
mobile - a string or integer value which contains
the mobile number of the person making the order.
pizza - the total cost of the ordered pizza which
defaults to zero if no pizza was ordered.
drink - the total cost of the ordered pizza which
defaults to zero if no pizza was ordered.
dessert - the total cost of the ordered pizza which
defaults to zero if no pizza was ordered.
Returns:
A list containing the name of the customer and the
total cost of their order.
None - If name or mobile is not provided.
"""
if(name is None or name == "" or mobile is None or mobile == ""):
return None
if(len(name) > 21 or len(str(mobile)) > 10):
return 6
total = float(pizza) + float(drink) + float(dessert)
appendData.append([name, str(mobile), float(pizza), float(drink), float(dessert), total])
returnData = name, total
return list(returnData)
def newOrderItems(appendData, name, mobile, items):
"""
Appends the formatted order to the data list and returns
the name of the customer and the total of their order.
Args:
appendData - a list which has the order
appended to the end of it.
name - a string value containing the customer's name.
mobile - a string or integer value which contains
the mobile number of the person making the order.
items - a list which contains the items the
customer has ordered.
Returns:
A list containing the name of the customer and the
total cost of their order.
None - If name or mobile is not provided.
"""
if(name is None or name == "" or mobile is None or mobile == ""):
return None
total = 0
drink = 0
dessert = 0
pizza = 0
for i in items:
total += float(orderDict[i][1])
if(orderDict[i][0] == 'pizza'):
pizza += float(orderDict[i][1])
elif(orderDict[i][0] == 'drink'):
drink += float(orderDict[i][1])
elif(orderDict[i][0] == 'dessert'):
dessert += float(orderDict[i][1])
tempArray = name, str(mobile), pizza, drink, dessert, total
appendData.append(list(tempArray))
returnData = name, total
return list(returnData)
def newBulkOrders(appendData, names, mobiles, items):
"""
Appends the formatted order to the data list and returns
the names of the customer and the totals of their order.
Args:
appendData - a list which has the order
appended to the end of it.
name - a list containing the customers' names.
mobiles - a list containing the customers' mobiles.
items - a list of lists containing.
Returns:
A list containing the names of the customers
and the totals of their orders.
None - If name or mobile is not provided.
Task Code 4 - If a type error occurs.
"""
if(names is None or names == "" or mobiles is None or mobiles == ""):
return None
try:
returnTotals = []
returnNames = []
errorArray = []
returnList = []
for l in range(0, len(names)):
total = 0
drink = 0
dessert = 0
pizza = 0
tempItems = items[l]
for i in tempItems:
total += float(orderDict[i][1])
if(orderDict[i][0] == 'pizza'):
pizza += float(orderDict[i][1])
elif(orderDict[i][0] == 'drink'):
drink += float(orderDict[i][1])
elif(orderDict[i][0] == 'dessert'):
dessert += float(orderDict[i][1])
tempArray = names[l], str(mobiles[l]), float(pizza), drink, dessert, total
returnTotals.append(total)
returnNames.append(names[l])
errorArray.append(list(tempArray))
for x in range(0, len(errorArray)):
appendData.append(errorArray[x])
returnList = returnNames, returnTotals
return list(returnList)
except IndexError:
return 4
# ========================================================================================================================== #
def saveOrder(saveData, filename):
"""
Opens a file with name filename, and writes
saveData to it.
Args:
saveData - the list of orders which will be
written to the file.
filename - a string value which gives the name
of the file to be written to.
Returns:
Task Code 1 - If the task is complete successfully.
"""
writeFile = csv.writer(open(filename, 'w', newline=''))
writeFile.writerow(header)
for i in range(0, len(saveData)):
writeFile.writerow(saveData[i])
return 1
def getOrders(writeData, filename):
"""
Opens a file with name filename, and writes
saveData to it.
Args:
saveData - the list of orders which will be
written to the file.
filename - a string value which gives the name
of the file to be written to.
Returns:
Task Code 1 - If the task is complete successfully.
"""
if os.path.isfile("pythoncsv.csv"):
getFile = csv.reader(open(filename, 'r+', newline=''))
for i in getFile:
writeData.append(i)
# Getting rid of header row so that we don't get a bunch of TypeErrors.
writeData.pop(0)
for i in writeData:
i[2] = float(i[2])
i[3] = float(i[3])
i[4] = float(i[4])
i[5] = float(i[5])
print(writeData)
else:
# Creates file as above if statement tests whether it exists or not.
getFile = csv.reader(open(filename, 'w', newline=''))
return 1
# ========================================================================================================================== #
def printOrders(printData):
# Purpose of first for loop is to ensure that longer names do not cause printing errors.
space = 0
tempString = "┃"
for i in range(0, len(header)):
tempString += spaceVal(header[i].title(), sizeDict[header[i].title()])
print(printRow("┏", "┓", "━", "┳", header, sizeDict))
print(tempString)
print(printRow("┣", "┫", "━", "╋", header, sizeDict))
tempString = ""
for i in range(0, len(printData)):
tempString = "┃"
for x in range(0, len(printData[i])):
tempString += spaceVal(printData[i][x], sizeDict[header[x].title()])
print(tempString)
print(printRow("┗", "┛", "━", "┻", header, sizeDict))
print('\n')
return 1
# ========================================================================================================================== #
def statOrders(statData):
#try:
statArray = [[0, 'Pizzas'], [0, 'Drinks'], [0, 'Desserts'], [0, 'Overall']]
for i in range(0, len(statData)):
statArray[0][0] += statData[i][2]
statArray[1][0] += statData[i][3]
statArray[2][0] += statData[i][4]
statArray[3][0] += statData[i][5]
space = 0
tempString = "┃"
for i in range(0, len(statHeader)):
tempString += spaceVal(statHeader[i], statSizeDict[statHeader[i]])
print(printRow("┏", "┓", "━", "┳", statHeader, statSizeDict))
print(tempString)
print(printRow("┣", "┫", "━", "╋", statHeader, statSizeDict))
tempString = ""
for i in range(0, len(statArray)):
tempString = "┃"
tempString = tempString + spaceVal(statArray[i][1], statSizeArray[0]) + spaceVal(str(statArray[i][0]), statSizeArray[1]) + spaceVal(str(int(100 * statArray[i][0] / statArray[3][0])) + '%', statSizeArray[2])
print(tempString)
print(printRow("┗", "┛", "━", "┻", statHeader, statSizeDict))
print('\n')
return 1
#except (IndexError, TypeError):
# return 5
# ========================================================================================================================== #
def modifyOrder(modifyData, orderName, modifyValueType, newValue):
try:
for i in range(0, len(modifyData)):
if(modifyData[i][0] == orderName):
modifyData[i][posDict[modifyValueType]] = float(newValue)
modifyData[i][5] = float(sum(modifyData[i][2:5]))
return modifyData[i][5]
return 4
except (TypeError, IndexError):
return 2
# ========================================================================================================================== #
# End of Asserts: Task Failed Succesfully
# ========================================================================================================================== #
And the specific function where the error occurs:
def statOrders(statData):
#try:
statArray = [[0, 'Pizzas'], [0, 'Drinks'], [0, 'Desserts'], [0, 'Overall']]
for i in range(0, len(statData)):
statArray[0][0] += statData[i][2]
statArray[1][0] += statData[i][3]
statArray[2][0] += statData[i][4]
statArray[3][0] += statData[i][5]
space = 0
tempString = "┃"
for i in range(0, len(statHeader)):
tempString += spaceVal(statHeader[i], statSizeDict[statHeader[i]])
print(printRow("┏", "┓", "━", "┳", statHeader, statSizeDict))
print(tempString)
print(printRow("┣", "┫", "━", "╋", statHeader, statSizeDict))
tempString = ""
for i in range(0, len(statArray)):
tempString = "┃"
tempString = tempString + spaceVal(statArray[i][1], statSizeArray[0]) + spaceVal(str(statArray[i][0]), statSizeArray[1]) + spaceVal(str(int(100 * statArray[i][0] / statArray[3][0])) + '%', statSizeArray[2])
print(tempString)
print(printRow("┗", "┛", "━", "┻", statHeader, statSizeDict))
print('\n')
return 1
#except (IndexError, TypeError):
# return 5
# ========================================================================================================================== #
In fact
"% of Total".title() returns % Of Total.
This explains your error

Unable to break infinite loop

There are various posts related to infinite loops on here but none reflect my particular predicament (they deal with Java or they do not match my code format etc). The code I have used is actually source code or 'answer code' to an exercise aimed at new students such as myself and it only supplies the 'correct code without correct format' which for an independent student can complicate things but also provide a more productive challenge.
The code makes solid use of 'functions' and 'calling functions from within other functions' which leaves very little 'global code' as a result, this may make things slightly more complicated but hopefully experienced programmers won't be phased by this.
I think the loop is either an issue with my 'while loop code indentation' or the 'while loop condition/counter code itself'. The loop code takes and uses data from other parts of the program code and shouldn't be completely ruled out but realistically I suspect the problem is one of the two former possible issues of either indentation or internal loop code itself, I have already tried multiple variations of 'indentation layout' as well as making quick fixes (misstyped syntax etc).
The code in question can be found towards the end of the program code (there is only one 'while loop' in the program code) it is in the 'menu options' section of code under '# Loop through quotes selecting those referencing the appropriate month and store the data in the summary dictionary'.
I have included two separate code windows, one highlighting the suspected 'problem code' and the the other with 'full program code'. Any help in any aspect will be appreciated.
Code segment most likely to hold error
def monthlyReport():
file = open(QUOTES_TO_DATE_FILE, 'r')
text = file.read()
file.close()
quotes = text.split()
month = input('Enter month: ')
summary = {'Lawn':{'Quantity' : 0.0, 'Value' : 0.0}, 'Patio' :{'Quantity' : 0.0, 'Value' : 0.0}, 'Water Feature' :{'Quantity' : 0.0, 'Value' : 0.0}}
# Loop through quotes selecting those referencing the appropriate month and
#store the data in summary dictionary
index = 0
while True:
if quotes[index] == month:
inputQuotesFromFile2(quotes[index+1])
summary['Lawn']['Quantity'] = summary['Lawn']['Quantity'] + quote['Lawn']['Width'] * quote['Lawn']['Length']
summary['Lawn']['Value'] = summary['Lawn']['Value'] + quote ['Lawn']['Cost']
summary['Patio']['Quantity'] = summary['Patio']['Quantity'] + quote['Patio']['Width'] * quote['Patio']['Length']
summary['Patio']['Value'] = summary['Patio']['Value'] + quote['Patio']['Cost']
summary['Water Feature']['Quantity'] = summary['Water Feature']['Quantity'] + quote['Water Feature']['Quantity']
summary['Water Feature']['Value'] = summary['Water Feature']['Value'] + quote['Water Feature']['Cost']
index = index + 2
if (index >= len(quotes)):
break
totalValue = summary['Lawn']['Value'] + summary['Patio']['Value'] + summary['Water Feature']['Value']
outputSummaryDictionary(summary, month, totalValue)
Full program code
# `Dictionary containing time values (mins) per square metre/ per feature
##lawn:20 patio:20 water feature:60
TIME = {'Lawn': 20, 'Patio': 20, 'Water Feature': 60}
# Constant for labour cost
##16.49
LABOUR_COST = 16.49
# Variable for filename of list of quotes made to date
##quotesToDateFile
QUOTES_TO_DATE_FILE = 'quotesToDateFile.txt'
# 'Global variables'
# A dictionary that stores quote data temporarily, contains sub dicts for each
#material type including keys for length, width, cost, time/quantity,cost, time
quote = {'Lawn':{'Length': 0 , 'Width': 0 , 'Cost': 0.0 , 'Time': 0.0},
'Patio':{'Length': 0 , 'Width': 0, 'Cost': 0.0 , 'Time': 0.0 },
'Water Feature':{'Quantity': 0 , 'Cost': 0.0 , 'Time': 0.0}}
# A dictionary storing material costs of individual items (can be updated)
materialCost = {'Lawn': 15.5, 'Patio': 20.99, 'Water Feature': 150}
# 'Input'
# Function to input material info defined by a length
##create function with named parameter for 'item'
def inputItemDimensions(item):
s = 'Enter length of ' + item + ':'
length = int(input('Enter length of material: '))
s = 'Enter width of ' + item + ':'
width = int(input('Enter width of material: '))
return length, width
# Function to input material info defined by quantity
##create function with named parameter 'item
def inputItemQuantity(item):
s = 'Enter quantity of ' + item + ':'
quantity = int(input('Enter quantity of items: '))
return quantity
# Function for input of area and quantity
def itemInput():
global quote
quote['Lawn']['Length'], quote['Lawn']['Width'] = inputItemDimensions('lawn')
quote['Patio']['Length'], quote['Patio']['Width'] = inputItemDimensions('concrete patio')
quote['Water Feature']['Quantity'] = inputItemQuantity('water feature')
# 'Cost calculation'
# Function to calculate, output to screen, return the material cost and time
#to install a landscape item installed by length and width
def costCalculation1(num, item, length, width, cost, time):
print('[{0}]'.format(num))
print('Length and width of the {0} = {1} x {2}m'.format(item, length, width))
area = length * width
print('Total area of {0} = {1:.2f}m^2'.format(item, area))
print('Cost of {0} per m^2 = £{1:.2f}'.format(item, cost))
totalCost = area * cost
print('Total cost of {0} = £{1}\n'.format(item, totalCost))
totalTime = area * time
return totalCost, totalTime
# Function to calculate, output to screen and return the material cost and time
#to install a landscape item installed by quantity
def costCalculation2(num, item, quantity, cost, time):
print('[{0}]'.format(num))
print('Quantity of {0} = {1} items'.format(item, quantity))
print('Cost of one {0} = £{1:.2f}'.format(item, cost))
totalCost = quantity * cost
print("Total cost of {0} {1} = £{2}\n".format(quantity, item, totalCost))
totalTime = quantity * time
return totalCost, totalTime
# Function to calculate individual costs of items
def calculateItemCosts():
global quote
quote['Lawn']['Cost'], quote['Lawn']['Time'] = costCalculation1('1', 'lawn', quote['Lawn']['Length'], quote['Lawn']['Width'], materialCost['Lawn'], TIME['Lawn'])
quote['Patio']['Cost'], quote['Patio']['Time'] = costCalculation1('2', 'patio', quote['Patio']['Length'], quote['Patio']['Width'], materialCost['Patio'], TIME['Patio'])
quote['Water Feature']['Cost'], quote['Water Feature']['Time'] = costCalculation2('3', 'water features', quote['Water Feature']['Quantity'], materialCost['Water Feature'], TIME['Water Feature'])
# Function to calculate workimg costs and output them
def workingCost():
print('Working costs:')
totalTime = (quote['Lawn']['Time'] + quote['Patio']['Time'] + quote['Water Feature']['Time']) / 60
labourCost = totalTime * LABOUR_COST
print('Total time to complete work = {0} mins'.format(totalTime))
print('Cost of work per hour = £{0}'.format(LABOUR_COST))
print('Total cost of work = £{0}\n'.format(labourCost))
# Calculate total fee payable by customer, output to screen and file
materialCost = quote['Lawn']['Cost'] + quote['Patio']['Cost'] + quote['Water Feature']['Cost']
totalCost = materialCost + labourCost
print('Total cost to pay = £{0}\n'.format(totalCost))
# 'Output functions'
# Output details concerning item
def outputItems():
outputItems1('1', 'Lawn', quote['Lawn'])
outputItems1('2', 'Patio', quote['Patio'])
outputItems2('3', 'Water Feature', quote['Water Feature'])
# Output dimensions and cost for certain item
def outputItems1(num, item, itemDict):
print('[{0}]'.format(num))
print('Length of width of {0} = {1}m x {2}m'.format(item, itemDict['Length'], itemDict['Width']))
print('Total cost of {0} = £{1}'.format(item, itemDict['Cost']))
print('Time to install {0} = {1}mins\n'.format(item, itemDict['Time'] / 60))
# Output quantity and cost for item
def outputItems2(num, item, itemDict):
print('[{0}]'.format(num))
print('Quantity of {0} = {1} items'.format(item, itemDict['Quantity']))
print('Cost of one {0} = £{1:.2f}'.format(item, itemDict['Cost']))
print('Time to install {0} = {1:.2f} hours\n'.format(item, itemDict['Time'] / 60))
# Output material cost dictionary
def outputMaterialCostDictionary():
for key, value in materialCost.items():
print('{0} = {1}'.format(key, value))
print('\n')
# Output summary dictionary
def outputSummaryDictionary(summaryD, month, totalV):
outputSummaryItem1(['Month', month, '', '', ''])
outputSummaryItem1(['Total', '', 'Total', 'Total', 'Total'])
outputSummaryItem1(['Working', 'Item', 'Square metre', 'Number', 'Monthly'])
outputSummaryItem1(['Costs', '', 'Purchased', 'Purchased', 'Value'])
outputSummaryItem2('Lawn', summaryD['Lawn'])
outputSummaryItem2('Patio', summaryD['Patio'])
outputSummaryItem3('Water Feature', summaryD['Water Feature'])
outputSummaryItem4(totalV)
# Output summary dictionary item ver 1
def outputSummaryItem1(sList):
print('|{0:^13}|{1:^13}|{2:^13}|{3:^13}|{4:^13}|'.format(sList[0], sList[1], sList[2], sList[3], sList[4]))
# Output summary dictionary item ver 2
def outputSummaryItem2(name, item):
print('|{0:^13}|{1:^13}|{2:13.2f}|{3:^13}|{4:13.2f}|'.format('', name, item['Quantity'], '', item['Value']))
# Output summary dictionary item ver 3
def outputSummaryItem3(name, item):
print('|{0:^13}|{1:^13}|{2:^13}|{3:13.0f}|{4:13.2f}|'.format('', name, '', item['Quantity'], item['Value']))
# Output summary dictionary item ver 4
def outputSummaryItem4(totalValue):
print('|{0:^13}|{1:^13}|{2:^13}|{3:^13}|{4:13.2f}|'.format('Total', '', '', '', totalValue))
# 'File handling'
# Function to output file
def outputToFile():
filename = input('Enter file name: ')
file = open(filename, 'w')
month = input('Enter month:' )
print('Filename = {0}....Month = {1}\n'.format(filename, month))
file.write('{0}\n'.format(month))
s = '{0} {1} {2} {3}\n'.format(quote['Lawn']['Length'], quote['Lawn']['Width'], quote['Lawn']['Cost'], quote['Lawn']['Time'])
file.write(s)
s = '{0} {1} {2} {3}\n'.format(quote['Patio']['Length'], quote['Patio']['Width'], quote['Patio']['Cost'], quote['Patio']['Time'])
file.write(s)
s = '{0} {1} {2}\n'.format(quote['Water Feature']['Quantity'], quote['Water Feature']['Cost'], quote['Water Feature']['Time'])
file.write(s)
file.close()
# Update quotes to date file
file = open(QUOTES_TO_DATE_FILE, 'a')
s = '{0} {1}\n'.format(month, filename)
file.write(s)
file.close()
# Function to input quote from file where file name is not known
def inputQuoteFromFile1():
filename = input('Enter name for input file: ')
inputQuoteFromFile2(filename)
# Function to input quote from file when file IS known
def inputQuoteFromFile2(filename):
file = open(filename, 'r')
text = file.read()
list1 = text.split()
file.close()
# Process the data (ignore first item which is the month)
##declare 'quote' dict as global (this might mean this code is within function)
global quote
subDictionary = {'Length' : float(list1[1]), 'Width' : float(list1[2]), 'Cost' : float(list1[3]), 'Time' : float(list1[4])}
quote['Lawn'] = subDictionary
subDictionary = {'Length' : float(list1[5]), 'Width' : float(list1[6]), 'Cost' : float(list1[7]), 'Time' : float(list1[8])}
quote['Patio'] = subDictionary
subDictionary = {'Quantity' : float(list1[9]), 'Cost' : float(list1[10]), 'Time' : float(list1[11])}
quote['Water Feature'] = subDictionary
file.close()
# 'Menu options'
# Function to allow preperation of a new quote
def prepareANewQuote():
itemInput()
calculateItemCosts()
workingCost()
outputToFile()
# Function to load new material costs
def loadNewMaterialCosts():
filename = input('Enter filename: ')
file = open(filename, 'r')
text = file.read()
file.close()
newMaterialCosts = text.split()
# Assign costs to material cost dictionary
index = 0
for key in materialCost.keys():
materialCost['Key'] = float(newMaterialCosts['index'])
index = index + 1
# Output new material costs # NOTE MAY NEED TO BE INDENTED FURTHER
outputMaterialCostDictionary()
# Function to view and load existing quote
def viewExistingQuote():
inputQuoteFromFile1()
outputItems()
workingCost()
# Function to generate monthly report summary
def monthlyReport():
file = open(QUOTES_TO_DATE_FILE, 'r')
text = file.read()
file.close()
quotes = text.split()
month = input('Enter month: ')
summary = {'Lawn':{'Quantity' : 0.0, 'Value' : 0.0}, 'Patio' :{'Quantity' : 0.0, 'Value' : 0.0}, 'Water Feature' :{'Quantity' : 0.0, 'Value' : 0.0}}
# Loop through quotes selecting those referencing the appropriate month and
#store the data in summary dictionary
index = 0
while True:
if quotes[index] == month:
inputQuotesFromFile2(quotes[index+1])
summary['Lawn']['Quantity'] = summary['Lawn']['Quantity'] + quote['Lawn']['Width'] * quote['Lawn']['Length']
summary['Lawn']['Value'] = summary['Lawn']['Value'] + quote ['Lawn']['Cost']
summary['Patio']['Quantity'] = summary['Patio']['Quantity'] + quote['Patio']['Width'] * quote['Patio']['Length']
summary['Patio']['Value'] = summary['Patio']['Value'] + quote['Patio']['Cost']
summary['Water Feature']['Quantity'] = summary['Water Feature']['Quantity'] + quote['Water Feature']['Quantity']
summary['Water Feature']['Value'] = summary['Water Feature']['Value'] + quote['Water Feature']['Cost']
index = index + 2
if (index >= len(quotes)):
break
totalValue = summary['Lawn']['Value'] + summary['Patio']['Value'] + summary['Water Feature']['Value']
outputSummaryDictionary(summary, month, totalValue)
# 'Main' (initialisation)
# Top level function
def start():
while True :
print('Select one of following options')
print('(1) Prepare new quote')
print('(2) Load new cost data')
print('(3) Load and view existing quote')
print('(4) Generate monthly report summary')
print('(5) Exit')
selection = int(input())
if selection == 1:
prepareANewQuote()
elif selection == 2:
loadNewMaterialCosts()
elif selection == 3:
viewExistingQuote()
elif selection == 4:
monthlyReport()
elif selection == 5:
quit()
else:
print('Error unrecognised command')
# Start
start()
index never gets modified if quotes[index] does not equal month, so the code will keep checking the same value over and over again and never proceed.
You should unindent that assignment of index by one level. But really this is not an appropriate use of a while loop; you should use for to iterate over quotes:
for quote in quotes:
(Also note there are two while loops in this code; and actually far too much use of global.)

Categories