Unhashable types & replacing inputs - python

The goal is simple: show a dialog with options, then when a option is selected it will automatically replace some values (to decrease the possibility of making an error while typing the values manually). The following code is part of a larger code, but this is the most important part. The larger piece of code was written by someone else. I wrote the following block:
if expInfo2['quadrant'] == 'UL':
expInfo['refOrientation':'45','x':'-4.24','y':'4.24']
elif expInfo2['quadrant'] == 'LL':
expInfo['refOrientation':'-45','x':'-4.24','y':'-4.24']
elif expInfo2['quadrant'] == 'UR':
expInfo['refOrientation':'-45','x':'4.24','y':'4.24']
elif expInfo2['quadrant'] == 'LR':
expInfo['refOrientation':'45','x':'4.24','y':'-4.24']
The code works fine until it reads the second line, and gives the following error:
Traceback (most recent call last):
File "D:\User\File\Experiment.py", line 48, in <module>
expInfo['refOrientation':'45','x':'-4.24','y':'4.24']
TypeError: unhashable type
()
My experience with programming is limited, but I understand that the things I put in that second line do not fit together. However, I was thinking of splitting them piece by piece but I do not think that will work, like in the following:
if expInfo2['quadrant'] == 'UL':
expInfo['refOrientation':'45']
expInfo['x':'-4.24']
expInfo['y':'4.24']
et cetera...
The full code:
#present a dialogue to chose lab room and whether eyetracker is on or not
expInfo2 = {'lab':'2','eyetracker': '0','quadrant':''}
dlg = gui.Dlg(title="Info", pos=(200, 400))
dlg.addField('Which lab are you in? 2 for lab-2, 3 for lab-3',expInfo2['eyelab'])
dlg.addField('Do you want the eyetracker on? 0 for yes, 1 for no',expInfo2['eyetracker'])
dlg.addField('What quadrant is used? UL=Upper Left, LL=Lower Left, UR=Upper Right, LR=Lower Right',expInfo2['quadrant'])
inf = dlg.show()
expInfo2['lab']=inf[0]
expInfo2['eyetracker'] = inf[1]
expInfo2['quadrant'] = inf[2]
############################## THIS IS THE CODE FOR LAB 2 ###########################################
if expInfo2['lab'] == '2':
expInfo = {'observer':'insert','typeofstaircase':'insert','refOrientation':'','startorient':'insert','x':'','y':'','numstair':4,}
dateStr = time.strftime("%b_%d_%H%M", time.localtime())#add the current time
if expInfo2['quadrant'] == 'UL':
expInfo['refOrientation':'45','x':'-4.24','y':'4.24']
elif expInfo2['quadrant'] == 'LL':
expInfo['refOrientation':'-45','x':'-4.24','y':'-4.24']
elif expInfo2['quadrant'] == 'UR':
expInfo['refOrientation':'-45','x':'4.24','y':'4.24']
elif expInfo2['quadrant'] == 'LR':
expInfo['refOrientation':'45','x':'4.24','y':'-4.24']
#present a dialogue to change params
dlg = gui.Dlg(title="Info", pos=(200, 400))
dlg.addField('Observer:',expInfo['observer'])
dlg.addField('Type of staircase?', expInfo['typeofstaircase'])
dlg.addField('Start Orientation Increment:',expInfo['startorient'])
dlg.addField('X:',expInfo['x'])
dlg.addField('Y:',expInfo['y'])
dlg.addField('Ref. Orienation:',expInfo['refOrientation'])
#dlg.addField('Number of Staircases',expInfo['numstair'])
inf = dlg.show()
expInfo['observer']=inf[0]
expInfo['typeofstaircase'] = inf[1]
expInfo['startorient']=inf[2]
expInfo['x']=inf[3]
expInfo['y']=inf[4]
expInfo['refOrientation']=inf[5]
#expInfo['numstair'] = inf[6]
#dlg = gui.DlgFromDict(expInfo, title='info', fixed=['date'])
#if dlg.OK:
# print(expInfo)
#else:
# core.quit()#the user hit cancel so exit
Any suggestions?

expInfo['refOrientation':'-45','x':'-4.24','y':'-4.24']
So this is interpreted as
expInfo.__getitem__((
slice('refOrientation', '-45', None),
slice('x', '-4.24', None),
slice('y', '-4.24', None)
))
, a 3-tuple of slice objects. expInfo is a dictionary, and only takes hashable types and
hash((
slice('refOrientation', '-45', None),
slice('x', '-4.24', None),
slice('y', '-4.24', None)
))
raises the error
TypeError: unhashable type: 'slice'
because, well, they aren't hashable. It's very, very weird to use strings in slices like that so I don't think you are inputting the key in the correct way.
I think what you are trying to do is update the dictionary. To do this you want:
if expInfo2['quadrant'] == 'UL':
expInfo.update({'refOrientation': '45', 'x': '-4.24', 'y': '4.24'})
elif expInfo2['quadrant'] == 'LL':
...
(note the whitespace I put in to make it more readable. I'd advise reading PEP8 before going any further with python since you throw the style guide out the window).

Related

nonetype object not subscriptable pysimplegui

I'm trying to learn python and pysimplegui at the same time. Also I am old which doesn't help!
I am writing a practice program with my 10 year old son(blind leading the blind) and am running into a problem which i cant fix.
Basically the program lets you enter how many numbers to pick from and how many numbers to pick, then calculates the odds of winning. Hit generate to randomly pick the numbers for you and Print the results to a txt file for a record of your picks.
It all works fine but when i close the window i get a nonetype error which I can't work out.
Can any of ye genius's help?
This is the offending line
n=int(values['--tn--'])
from os import close
import random
from tkinter import Scrollbar
import PySimpleGUI as sg
import datetime
import math
from time import sleep, time
from PySimpleGUI.PySimpleGUI import Open, WIN_CLOSED, main
import sys
sg.theme('Reddit')
layout = [
[sg.In(size=(5,1),k="--tn--" ) ]+[sg.Text('Enter total amount of
numbers',size=(35,1))],
[sg.In(size=(5,1),k="--pn--")]+[sg.Text('Enter how many numbers
you are picking',size=(35,1))],
[sg.Text('Win odds')]+[sg.ML(background_color='light
coral',text_color='white',key='--oddout--',size=(50,2))],
[sg.ML(size=(20,30), key='--main--')],
[sg.Submit('Odds',key='--odds--')]+[sg.Submit('Generate',key='--
gen--')]+ [sg.Cancel('Cancel')]+[sg.Save(key='--save--')]+
[sg.CloseButton('Close',pad=(100,0))]
]
window = sg.Window('Lotto number generator',layout)
while True:
event, values = window.read()
n=int(values['--tn--'])
rr=int(values['--pn--'])
nf = math.factorial(n)
rf = math.factorial(rr)
winodds = (nf/(rf*math.factorial(n-rr)))
winodds = int(winodds)
now = datetime.datetime.now()
if event == WIN_CLOSED:
window['--tn--'].update('1')
break
if event == '--gen--':
r = random.sample(range(1,n),rr)
for i in r:
window['--main--'].print(i)
if event == '--odds--':
window['--oddout--'].print("Your chances of winning are
",f'{winodds:,d}', " to 1, Good Luck")
if event == 'Cancel':
window['--oddout--'].update('')
window['--tn--'].update('')
window['--pn--'].update('')
if event == '--save--':
sys.stdout = open("lotto.txt", "w")
print(values['--main--'])
sys.stdout=close(fd=0)
window.close()
event, values = window.read() is returning None. None['--tn--'] does not exist as it doesn't make sense for None to have a property, hence the error message. You have used the test to avoid this but moved it below an attempt to use the missing property. Hence the error.
It's also worth using a linting tool prompt you to make adjustments to syntax that will break your code and good practice warnings. I use pylint and flake8. The following addresses your specific error message with some tidying for the linter messages. There are still some warnings - good learning exercise :).
"""Learning program."""
from os import close
import random
import PySimpleGUI as sg
import datetime
import math
from PySimpleGUI.PySimpleGUI import Open, WIN_CLOSED, main
import sys
sg.theme('Reddit')
layout = [
[sg.In(size=(5, 1), k="--tn--")] +
[sg.Text('Enter total amount of numbers', size=(35, 1))],
[sg.In(size=(5, 1), k="--pn--")] +
[sg.Text('Enter how many numbers you are picking', size=(35, 1))],
[sg.Text('Win odds')] +
[sg.ML(
background_color='light coral', text_color='white', key='--oddout--', size=(50, 2)
)],
[sg.ML(size=(20, 30), key='--main--')],
[sg.Submit('Odds', key='--odds--')] +
[sg.Submit('Generate', key='--gen--')] +
[sg.Cancel('Cancel')] +
[sg.Save(key='--save--')] +
[sg.CloseButton('Close', pad=(100, 0))]
]
window = sg.Window('Lotto number generator', layout)
while True:
event, values = window.read()
# Moved the next three lines up and commented update which also errors
if event == WIN_CLOSED:
# window['--tn--'].update('1')
break
n = int(values['--tn--'])
rr = int(values['--pn--'])
nf = math.factorial(n)
rf = math.factorial(rr)
winodds = (nf/(rf*math.factorial(n-rr)))
winodds = int(winodds)
now = datetime.datetime.now()
if event == '--gen--':
r = random.sample(range(1, n), rr)
for i in r:
window['--main--'].print(i)
if event == '--odds--':
window['--oddout--'].print(
"Your chances of winning are", f'{winodds:,d}', " to 1, Good Luck"
)
if event == 'Cancel':
window['--oddout--'].update('')
window['--tn--'].update('')
window['--pn--'].update('')
if event == '--save--':
sys.stdout = open("lotto.txt", "w")
print(values['--main--'])
sys.stdout = close(fd=0)
window.close()
Flake8 in particular will prompt you to follow practices that don't have an obvious practical purpose. Later as you use more of the language the benefit of flake8 prompts are good habits that eventually pay large benefits.
There're something not good,
You should check the window close event first, not to processing event, values for other cases first, like following code. You may get event, values as None, None if not, then values['--tn--'] will be same as None['--tn--']. That's why you got TypeError: 'NoneType' object is not subscriptable.
while True:
event, values = window.read()
if event in (sg.WINDOW_CLOSED, 'Close'):
break
# process other events from here
window.close()
In your input fields, values['--tn--'] or values['--pn--'] maybe not with correct format for integer number, so following code may get failure ValueError: invalid literal for int() with base 10
n=int(values['--tn--'])
rr=int(values['--pn--'])
Here's my way to avoid issue,
def integer(string):
try:
value = int(string)
except:
value = None
return value
for string in ("10.5", "", "10"):
value = integer(string)
if value is None:
print(f"{repr(string)} is not a legal integer string !")
else:
print(f"{repr(string)} converted to {value} !")
'10.5' is not a legal integer string !
'' is not a legal integer string !
'10' converted to 10 !
Basically, window destroied after you click close button X of window, so you should not update anything on it.
if event == WIN_CLOSED:
# window['--tn--'].update('1')
break
When you close a window, event and values are not set, see my example below.
While debugging, it's a good practice to print out the current values of event and values to be able to check whether you get what you thought you'd get, like this:
def test():
layout = [[sg.In(size=(5, 1), k="--tn--"), sg.Text('Enter total amount of numbers', size=(35, 1))],
[sg.In(size=(5, 1), k="--pn--"), sg.Text('Enter how many numbers you are picking', size=(35, 1))],
[sg.Text('Win odds'),
sg.ML(background_color='light coral', text_color='white', key='--oddout--', size=(50, 2))],
[sg.ML(size=(20, 30), key='--main--')],
[sg.Submit('Odds', key='--odds--'), sg.Submit('Generate', key='--gen--'),
sg.Cancel('Cancel'), sg.Save(key=' - -save - -'), sg.CloseButton('Close', pad=(100, 0))]
]
window = sg.Window('Lotto number generator', layout)
while True:
event, values = window.read()
print(f'event = {event}, values = {values}')
if event == WIN_CLOSED:
break
window.close()
When you close the window, you get
event = None, values = {'--tn--': None, '--pn--': None, '--oddout--': None, '--main--': None}
so, it is important to start your main loop with if event == WIN_CLOSED: (and break the loop in that case). Only after that, you can go on to process various events and values.

How can I make this a little less hideous? Python

I am creating a simple program that prints a random productive activity. Here is a 'simplified' version of the program.
import random
meditate = ['sitting down meditation','lying down meditation','standing meditation']
exercise = ['go for run','do yoga']
call_text_fam = ['call mom', 'call dad']
activity_list = [meditate, exercise, call_text_fam]
activity_list_spinner = random.randint(0,len(activity_list)-1)
meditate_spinner = random.randint(0,len(meditate)-1)
exercise_spinner = random.randint(0,len(exercise)-1)
call_text_fam_spinner = random.randint(0,len(call_text_fam)-1)
if activity_list[activity_list_spinner] == meditate:
print(activity_list[activity_list_spinner][meditate_spinner])
elif activity_list[activity_list_spinner] == exercise:
print(activity_list[activity_list_spinner][exercise_spinner])
elif activity_list[activity_list_spinner] == call_text_fam:
print(activity_list[activity_list_spinner][call_text_fam_spinner])
This is going to get huge quickly so any ideas on how to clean this up would be awesome.
To illustrate Chris's comment, the second half can be reduced to just:
activity_list = [...]
print(random.choice(random.choice(activity_list)))

Tab/Indent Error in Python Command Prompt

New to Python & taking a course where teacher provided a code snippet to work on. The provided snippet is giving me a TabError as below, but I cannot seem to figure out why. I was hoping someone here could point out the issue.
Error Received:
Error Received
Code where error occurs (Updated to have code lines instead of screen shot):
def filterResultsAcc(self, qcoverage=0.6, scoverage=0.6, evalue=0.01, best_taxon=False):
results = []
hits_by_taxon = {}
for(qstart,qend,sacc,staxid,slen,sstart,send,evalu) in self.blasthits:
qcov = ((qend-qstart) + 1.0) / float(self.querylen)
scov = ((send-sstart) + 1.0 / float(slen)
if qcov >= qcoverage and scov >= scoverage and evalu <= evalue:
if best_taxon:
if staxid in hits_by_taxon.keys():
(sid,e,qc,sc) = hits_by_taxon[staxid]
if evalu < e:
hits_by_taxon[staxid] = (sacc,evalu,qcov,scov)
elif evalu == e:
if qcov > qc:
hits_by_taxon[staxid] = (sacc,evalu,qcov,scov)
elif qvoc == qc:
if scov > sc:
hits_by_taxon[staxid] = (sacc,evalu,qcov,scov)
else:
hits_by_taxon[staxid] = (sacc,evalu,qcov,scov)
else:
results.append(sacc)
if best_taxon:
for taxid in hits_by_taxon.keys():
(sac,e,qc,sc) = hits_by_taxon[taxid]
results.append(sacc)
results.sort()
return results
The error shows that you've mixed tab and spaces, just as it says.
If your editor supports it – turn something like "show unprintable characters" to see what your whitespaces really is.
Another way is to select all code, usually editors will distinguish between spaces and tabs.

ValueError: not enough values to unpack (expected 6, got 5)

I was trying to make a python game using only characters, honestly I did it, but the end condition was too vague. To make one, I simply assigned startLocation as a normal location, and having finished the objective, I would return to the starting location and quit the game to give new line texts. However:
def locations():
startLocation = random.choice(mapaGrid)
monsterLocation = random.choice(mapaGrid)
wellLocation = random.choice(mapaGrid)
goldLocation = random.choice(mapaGrid)
arrowLocation = random.choice(mapaGrid)
if monsterLocation == goldLocation or monsterLocation == startLocation or goldLocation == startLocation or monsterLocation == arrowLocation or wellLocation == goldLocation or wellLocation == startLocation or wellLocation == monsterLocation:
return locations()
return startLocation, monsterLocation, goldLocation, arrowLocation, wellLocation
#Locais do jogador, monstro, ouro, poco, flecha e entrada.
playerLocation, monsterLocation, goldLocation, arrowLocation, wellLocation, startLocation = locations()
So this is where the code fails. When I assign startLocation to locations() in the end, I get the error in the title, even though adding any other completely made up location didn't result in this error. I did try searching but due to my inexperience I couldn't relate the answers to my code.
You return 5 elements:
return startLocation, monsterLocation, goldLocation, arrowLocation, wellLocation
^1 ^2 ^3 ^4 ^5
While in the values that you try to set from the function - you have six of them:
playerLocation, monsterLocation, goldLocation, arrowLocation, wellLocation, startLocation = locations()
^1 ^2 ^3 ^4 ^5 ^6
What do you expect from python to put in the 6th variable?
The error that you got is that you can't assign into 6 variables, because you returned only 5.

python / urwid ListBox object not callable

I've discovered urwid recently and started to play around with it. I've seen a Menu like tutorial example (which works!) and I've tried to modify the code a bit so I can get back and forth in the menu for starters - without doing anything else.
However I got stuck - and Im at a loss on why its happening.
Running this code:
import urwid
choices = u'Tank_1 Tank_2 Tank_3 Solarkreis Exit'.split()
def menu(title, choices):
body = [urwid.Text(title), urwid.Divider()]
for c in choices:
button = urwid.Button(c)
if c == "Exit":
urwid.connect_signal(button, 'click', exit_program)
else:
urwid.connect_signal(button, 'click', item_chosen, c)
body.append(urwid.AttrMap(button, None, focus_map='reversed'))
return urwid.ListBox(urwid.SimpleFocusListWalker(body))
def item_chosen(button, choice):
response = urwid.Text([u'Uebersicht ', choice, u'\n'])
done = urwid.Button(u'Ok')
urwid.connect_signal(done, 'click', menu(u'Menu', choices))
main.original_widget = urwid.Filler(urwid.Pile([response,
urwid.AttrMap(done, None, focus_map='reversed')]))
def exit_program(button):
raise urwid.ExitMainLoop()
main = urwid.Padding(menu(u'Menu', choices), left=2, right=2)
top = urwid.Overlay(main, urwid.SolidFill(u'\N{MEDIUM SHADE}'),
align='center', width=('relative', 60),
valign='middle', height=('relative', 60),
min_width=20, min_height=9)
urwid.MainLoop(top, palette=[('reversed', 'standout', '')]).run()
Running it I get
TypeError: 'ListBox' object is not callable
And I done quite understand how and why.. Help is much appreciated!
Edit: Forgot to add, the error pops up when I try to go back from the sub - menu to the original menu.
line 22, the third parameter is a ListBox object not a callable function.
urwid.connect_signal(done, 'click', menu(u'Menu', choices))

Categories