nonetype object not subscriptable pysimplegui

Question:

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()
Asked By: Trevor O'Connell

||

Answers:

There’re something not good,

  1. 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()
  1. 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 !
  1. 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
Answered By: Jason Yang

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.

Answered By: jwal

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.

Answered By: Lenka Čížková

It happens when the value is not given and you closed the program. The easiest way is to give a random value.

input_box = sg.InputText(tooltip="Enter text", key='text')

while True:
    event, value = window.read()
    match event:
        case WIN_CLOSED:
            value['text'] = 1 # <- a random value
            break
Answered By: Hardliner
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.