Sound import prevents input() from functioning properly

I recently transitioned to psychopy3, and now I’m having issues gathering user input using input(), but only after I import the sound module from psychopy. This worked in the previous version of psychopy using raw_input(). The script below tests this odd behavior.

input("Testing? ") #this line produces a prompt in the terminal 
from psychopy.sound import Sound
input("Testing? ") #this line will not 

Interestingly, I’m still capable of passing an input via the terminal but the prompt will not show after the sound import.

Ideas as to why this would be? I suppose that I could use a dialog instead, which will work, but that seems a bit bulky. I appreciate your help.

Hey,

Does it show any error message, or does the command prompt not ever show up again?

If you are using coder mode, and running the following line, you might want to check your Psychopy audio preference.
I think the defaults are [‘pyo’, ‘pygame’, ‘soundlib’], and I find ‘pygame’ to be most stable for use. Try switching the order of the sound libraries, and see if they work. PsychoPy prioritizes from left most item. There’s a more detailed documentation at https://www.psychopy.org/api/sound.html.

If you are simply trying to test it using terminal, you can first set library preference by

from psychopy import prefs
prefs.general['audioLib'] = ['pygame','pyo']

and then try:

input("Testing? ") #this line produces a prompt in the terminal 
from psychopy.sound import Sound
input("Testing? ") #this line will not 

I’m using a python script and calling it from the terminal. The prompt for the input doesn’t show after I import the sound module (and only the sound module, works fine if I import others), but I can enter a value and it is stored. There is no error message.

This behavior persists with all of the audio library backends.

This behavior even persists if I rename the input function from python 3 (thought that there might be a namespace conflict). This suggests to me some serious coding issue at a basic level, considering that the behavior of base functions in python are being corrupted. I’ll open a pull request.

from psychopy import prefs
prefs.general['audioLib'] = ['pygame','pyo']
from builtins import input as new_input #renaming the builtin input function for python 
new_input("Testing? ") #this line produces a prompt in the terminal 
from psychopy.sound import Sound
test_input=new_input("Testing? ") #this line will not 
print(test_input) #but the value entered after the line above is run is stored 

This very much sounds like an open issue from the sounddevice module: https://github.com/spatialaudio/python-sounddevice/issues/61.

This is a possible work-around:

import readline

I’ve tried stock python (not conda python) 2.7 and 3.6.1 installations on 4 different machines today (spanning Mac, Ubuntu 18.04, Win10) and I can’t reproduce the error.

Is it purely a conda Python thing?

But it’s easy for us to add import readline to the sound module if that’s likely to help! :slight_smile:

No, it’s unrelated to conda.

I guess it depends on what exactly the Python interpreter is loading on startup, it might be importing readline already on your system(s)?

I just tested it with this minimal script:

import sounddevice as sd
input("Hello, world!")

If I run it (on Debian Linux, without conda) with:

python3 input.py

… I get no output, if I run:

python3 -i input.py

… I do get the output.

OK thanks Matthias. Although I appreciate that it’s good to get rid of the excessive portaudio messages, it sounds like permanently redirecting stderr is a bad idea. I will add readline to our sound import, so that our users might not notice the hack, but it feels like this is a hint that the issue needs revisiting in sounddevice? Maybe just making the redirect briefly during the portaudio calls (as you once suggested)

Cheers to all for working it out.

1 Like

I’m open for suggestions on how to improve this situation, ideally in the form of a pull request!

But it is probably not as bad as you might think. I’m not actually redirecting all of stderr. It’s only a part of it, but TBH, I don’t really know in which situation this could unintentionally silence the output of some other module. I guess it could be a problem with C extensions? But those shouldn’t generate any raw stderr messages anyway, right?

Python’s sys.stderr is not affected, nor is the stderr from an external process, as can be seen in this example:

import subprocess
import sys

import sounddevice as sd

print('no output, please press <return>')
input("I'm not visible!")
print('I am visible!', file=sys.stderr)
print('stderr from external program:')
subprocess.run(['cat', 'nonexisting-file.txt'])

BTW, the redirection of stderr is only done on Linux and macOS, so if you try this on Windows, the input prompt should be visible, whether sounddevice is imported or not. And cat will probably not be a valid command.

If anybody can come up with an example where stderr output is unintentionally hidden, please tell me!