I sometimes get the error ‘Python is not responding' and the experiment freezes

Hi,
Apologies for reposting, but I still can’t figure out why the error randomly pops up, even when I do the exact same things (as far as I can tell). I cannot schedule participants in advance because of this!

I am running an experiment where people see a stimulus for at least 60 seconds. After the 60s are over, they can exit the screen by pressing SPACE any time they want to (I have put an upper bound at 300s). Only 3 key inputs are legal, ‘left,’ ‘right,’ and ‘space.’

However, within the first 60s itself, I get a popup error: ‘Python.exe has stopped responding.’ I have updated Psychopy to the latest version (v2023.2.2), and I am using a Windows 10 system (however, the same error occurs on Windows 11, too). The rub is that this happens only occasionally. It also happens when I do not have any other program running, so RAM is not an issue. I suspect it is because I am running 2 loops, but I cannot figure out how else I can code this or why it only happens sometimes.

Reproducible code:

from psychopy.visual import TextStim, ImageStim, Slider, RatingScale, ShapeStim
from psychopy import core, visual

win = visual.Window((800, 650))
kb = keyboard.Keyboard()
trial = [1, 2, 3, 4, 5, 6, 7, 8]
trial_start = core.getTime()

#screen details
def imagine(screen = 1, trial = trial, num = 0):
    if screen == 1:
        TextStim(win, text = "first screen").draw()
        win.flip()
    else:
        TextStim(win, text = "second screen").draw()
        win.flip()    
    return
    
'Imgine screen'
i = 1
imagine(screen=1, trial = trial, num = i + 1)
trial_onset = core.getTime() - trial_start    
delib_keys, delib_rt = [], []
kb.clock.reset()
keys = kb.getKeys(['left', 'right', 'space'])

while kb.clock.getTime() < 300:
    
    if keys:
        for key in keys:
            delib_keys.append(key.name)
            delib_rt.append(key.rt)
            
        if (kb.clock.getTime() > 60):
            imagine(screen = 2, trial = trial, num = i + 1)                
            if ('space' in keys): 
                break  

print(delib_keys, delib_rt)


win.close()
core.quit()

The error looks like this and freezes the experiment. There is no error in the runner.
image

That indicates that it’s not a problem with your code per se, but some kind of code/OS interaction. I suspect this might have something to do with checking the keyboard too often. The code as written is going to check the keyboard basically as fast as the clock speed of your processor can manage, because there’s no win.flip() in your loop. It’s plausible that something is getting out of sync or hitting a race condition and locking up, and that’s what’s causing the error message.

If that’s the case then the solution is to just re-draw everything as part of the loop (without changing screens), whether or not the key has been pressed. That will just make it so that it’s only checking at 60Hz (though the keyboard buffer will still record the timing of the keypress down to the millisecond). You could try that just to see if it still crashes occasionally or if it’s better-behaved.

If it’s not that then I have no clue.

… the solution is to just re-draw everything as part of the loop (without changing screens), whether or not the key has been pressed.

I tried doing this, but no luck. The experiment is still freezing up. Thanks anyway! If you think of anything else to deal with this issue, do let me know :slight_smile:

Plan B, which is not ideal, is to stop using the hardware.keyboard library altogether and switch back to event.getKeys() and a separate clock for checking the keyboard. The timing is less precise and it’s generally not as good, but if it’s the keyboard library then it’ll get around the problem.

If it’s not the keyboard library then I really don’t know what it could be. On my Mac the keyboard library will lock up like this if you have multiple keyboards plugged in, but that shouldn’t be an issue on Windows, and if it were the problem, it would happen every time not intermittently. That said, it’s the only thing your code uses that might generate this kind of behavior, just because it interacts with the OS in a different way than everything else.

Yes, I think this could be caused by trying to poll the keyboard in too “tight” a loop. Am I right in thinking the crash only occurs when the screen isn’t updating (i.e when you aren’t pressing space)? If you try to poll the pyglet keyboard constantly in a tight loop it will also mean that the computer gets no time to do anything else and it thinks your app has crashed

I don’t believe this can be fixed by switching away from iohub keyboard though. The problem is your code not allowing any time to breath. For comparison when your stimulus is being presented (e.g. when clock.getTime()>60) it will not be a problem because the win.flip() is pausing repeatedly on each screen refresh and that allows the time.

So, what you probably need to do here is simply to add in a sleep so that you aren’t checking the key list quite so rapidly. Also, your code isn’t actually checking the keys repeatedly - the keyboard is being polled just once and then your loop checks that (unchanging) list repeatedly.

Combined with Jonathan’s point that you should create your text object only once you get code something like this:

from psychopy.visual import TextStim, ImageStim, Slider, RatingScale, ShapeStim
from psychopy import core, visual

win = visual.Window((800, 650))
kb = keyboard.Keyboard()
trial = [1, 2, 3, 4, 5, 6, 7, 8]
trial_start = core.getTime()
scr1msg = TextStim(win, text = "first screen")
scr1msg = TextStim(win, text = "second screen")

#screen details
def imagine(screen = 1, trial = trial, num = 0):
    if screen == 1:
        scr1msg.draw()
    else:
        scr2msg.draw()
    win.flip()    
    return
    
# 'Imgine screen'
i = 1
imagine(screen=1, trial = trial, num = i + 1)
trial_onset = core.getTime() - trial_start    
delib_keys, delib_rt = [], []
kb.clock.reset()

while kb.clock.getTime() < 300:
    keys = kb.getKeys(['left', 'right', 'space'])  # check keys during loop
    if keys:
        for key in keys:
            delib_keys.append(key.name)
            delib_rt.append(key.rt)
            
        if (kb.clock.getTime() > 60):
            imagine(screen = 2, trial = trial, num = i + 1)                
            if ('space' in keys): 
                break 
    time.sleep(0.001)  # give the computer time to breath

note the time.sleep(0.001) which is the solution to the actual problem I believe

note the time.sleep(0.001) which is the solution to the actual problem I believe

This seems to be working so far! I’ll mark this as the solution after running the code for a couple of days/

Thanks Jon and Jonathan! :slight_smile:

Hi @jon
The code worked fine till the time I received a security update on my Windows 11 machine. Since then it seems to be running into the same problem all over again. I am not sure if the security update has messed up the working of the Psychopy package because the code was running fine till I updated the system. Do you have any suggestions that I could try?

UPDATE
I rolled back the update. The problem still persists.

Are you certain your code is the same? Usually this results from someone making a change and forgetting or thinking it was unimportant.

Also, is there a reason you can’t just use Builder, where we’ve spent the time making sure things don’t lock up with erroneous code?