psychopy.org | Reference | Downloads | Github

Python3 compatibility issues


#1

Hi,

I tried PsychoPy with Python3 and found some compatibility issues. My setups are following. PsychoPy is the latest main branch on the master repository.

  • winpython 2.7.10 x86, pyglet 1.3.0, wxpython 3.0.2
  • winpython 3.6.1 x64, pyglet 1.3.0, wxpython 4.0.0b1

1. keyname inconpatibility
In Python2, psychopy.core.event.getKeys() returns 'return' when Enter key is pressed. On the other hand, it returns 'enter' in Python3. Should we fix getKeys() to return ‘return’ both in Python2 and 3? Or should we leave this as it is and call users’ attention to this change?

2. dict incompatibility
Builder’s “branchedExp” demo doesn’t run in Python3. Error message is following.

Traceback (most recent call last):
  File "C:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\builder\builder.py", line 1972, in runFile
    script = self.generateScript(self.exp.expPath)
  File "C:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\builder\builder.py", line 2179, in generateScript
    target=target)
  File "C:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\builder\experiment.py", line 221, in writeScript
    self.flow._prescreenValues()
  File "C:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\builder\experiment.py", line 1722, in _prescreenValues
    for field, key in self._dubiousConstantUpdates(component):
  File "C:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\builder\experiment.py", line 1664, in _dubiousConstantUpdates
    expInfo = eval(self.exp.settings.params['Experiment info'].val)
  File "<string>", line 1
    {'participant':'ID01', 'session':001}
                                       ^
SyntaxError: invalid token

Expression of {'session':001} is not error in Python2, but it is not in Python3. I think that we need not to support such expressions, but many experiments created by users may be affected if we don’t support such expressions. Improving error message may be a good solution for this. The current error message is too difficult for beginners.

What do you think about these issues?
I’d appreciate your comments.


#2

Issue 1. I think we should make it the same on both. Actually, specifically, I think the key on the number pad should be “enter” and the other one should be “return” (abbrieviated from a “carriage return” on a typewriter and giving rise the down-an-left arrow)

Issue 2. I’ve seen this myself and corrected it in a couple of places (https://github.com/psychopy/psychopy/commit/046705e7437a9b0f021fb8c10ee683dfc489f100#diff-26a01c2b623f4bab5bf46b330f6aaf71) but must have missed that one.


#3

Issue 1.
Thank you for your reply. I’ll try to fix codes to return the same key name both in Python 2 and 3.

Distinguishing numpad’s ‘enter’ from ‘return’ is a nice idea, but pyglet recognizes both keys as 0xFF0D in my Windows10 PCs…:disappointed_relieved:

By the way, I found the reason why key name is different between Python2 and 3. Pyglet’s converts key code to key name using a dict object named _key_name, which in built at pyglet/window/key.py. The code for building _key_name works differently in Python3 from in Python2.

Issue2
I see. I’ll simply fix “branchedExp” demo.


#4

I noticed that Builder cannot read *.pkl file as conditions in Python3.

Traceback (most recent call last):
  File "C:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\data\utils.py", line 325, in importConditions
    trialsArr = pickle.load(f)
TypeError: a bytes-like object is required, not 'str'

To avoid this error, we have to read condition file in binary mode; however, in that case, we have to convert newline characters manually like below.

        f = open(fileName, 'rb')
        # Converting newline characters.
        if PY3:
            # 'b' is necessary in Python3 because byte object is 
            # returned when file is opened in binary mode.
            buffer = f.read().replace(b'\r\n',b'\n').replace(b'\r',b'\n')
        else:
            buffer = f.read().replace('\r\n','\n').replace('\r','\n')
        try:
            trialsArr = pickle.loads(buffer)
        except Exception:
            raise IOError('Could not open %s as conditions' % fileName)

Applying this fix, I got following error.

Traceback (most recent call last):
  File "C:\Users\Hiroyuki\Desktop\pickletest_lastrun.py" line 83, in <module>
    trialList=data.importConditions('C:\\Users\\Hiroyuki\\Desktop\\conditions.pkl')
  File "C:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\data\utils.py", line 343, in importConditions
    thisTrial[fieldName] = row[fieldN]
TypeError: unhashable type: 'newstr'

It seems that the current PsychoPy “pickling” string using future.types.newstr class in Python2, and that newstr cannot be used as a hash key in Python3. Inserting following lines after trialsArr = pickle.loads(buffer), *.pkl condition file can be imported in Python3.

        if PY3:
            # In Python3, strings returned by pickle() is unhashable.
            # So, we have to convert them to str.
            trialsArr = [[str(item) if isinstance(item, str) else item
                          for item in row] for row in trialsArr]

#5

Ok I knew that there was an error trying to load pickled files (i was looking at data files) but I didn’t know there was a potential fix as simple as this! was thinking we just couldn’t do it at all but this is very exciting! Will it will for data file too?


#6

I tried to read psydat files in psychopy/tests/data folder.
Unfortunately, I couldn’t read any of these psydat files.

The problem is that attributes of object unpickled by this method is corrupted. For example, dataFileName attribute of psychopy.data.Experiment object is unpickled as b'dataFileName', which cannot be accessed in a normal way. I’ll search for a way to read psydat files.

Note:
I can read psydat file generated by Python 3. So, the problem is to read psydat files generated by Python 2.


#7

I found that pickle.loads() can read psydat files in python 3.5 and 3.6 when encoding='latin-1'. Following code can read psydat files in psychopy/tests/data folder without error.

import pickle
import os

for file in os.listdir('.'): # set path to psydat folder
    if file[-7:].lower()=='.psydat':
        contents = None
        print('========{}================================'.format(file))
        f = open(file, 'rb')
        buff = f.read()
        try:
            contents = pickle.loads(buff, encoding='latin-1')
        except TypeError as err:
            print('TypeError: {0}'.format(err))
            print('counld not unpickle {}'.format(file))
            continue
        print(type(contents), dir(contents))

However, inserting encoding='latin-1' to pickle.load() in psychopy.tools.filetools.fromfile() doesn’t work as expected. I suspect that something like future package may affect behavior of pickle.load(), but I cannot specify which package does.

I also found that 'latin-1' solution has problem in reading psydat files containing non-ASCII characters. I think that full support of old psydat files in Python3 is quite hard task.


#8

All very good info. Thanks Hiroyuki. Yes, it might be hard to support all forms of previous studies but I was thinking we wouldn’t be able to support loading of any previous data files after the switch, so this is at least a start!

thanks for your help


#9

By the way, although this issue could be resolved by altering the demo, that won’t work for people who’ve already unpacked the demos themselves. I’ve added code to check the syntax and, if necessary, convert the disallowed integer 001 to be a string "001". If you’re interested in the details see the new getInfo() method in https://github.com/psychopy/psychopy/commit/ba81f11da808cbe245a8af82db9d9228b55a2535


#10

I tried to run PsychoPy on a new Windows10 PC and noticed that the firstrun wizard cannot be started in Python3.

Traceback (most recent call last):
  File "C:\Users\Hiroyuki\Desktop\WinPython-64bit-3.6.1.0Qt5\python-3.6.1.amd64\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Users\Hiroyuki\Desktop\WinPython-64bit-3.6.1.0Qt5\python-3.6.1.amd64\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "c:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\psychopyApp.py", line 96, in <module>
    start_app()
  File "c:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\psychopyApp.py", line 28, in start_app
    app = PsychoPyApp(0, showSplash=showSplash)
  File "c:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\_psychopyApp.py", line 138, in __init__
    self.onInit(**kwargs)
  File "c:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\_psychopyApp.py", line 205, in onInit
    self.firstrunWizard()
  File "c:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\_psychopyApp.py", line 358, in firstrunWizard
    self._wizard('--config', '--firstrun')
  File "c:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\app\_psychopyApp.py", line 353, in _wizard
    [sys.executable, wizard, selector, arg], stderr=True)
  File "c:\Users\Hiroyuki\Dropbox\git-repository\psychopy\psychopy\core.py", line 150, in shellCall
    encoding=encoding, env=env)
  File "C:\Users\Hiroyuki\Desktop\WinPython-64bit-3.6.1.0Qt5\python-3.6.1.amd64\lib\subprocess.py", line 707, in __init__
    restore_signals, start_new_session)
  File "C:\Users\Hiroyuki\Desktop\WinPython-64bit-3.6.1.0Qt5\python-3.6.1.amd64\lib\subprocess.py", line 964, in _execute_child
    args = list2cmdline(args)
  File "C:\Users\Hiroyuki\Desktop\WinPython-64bit-3.6.1.0Qt5\python-3.6.1.amd64\lib\subprocess.py", line 461, in list2cmdline
    needquote = (" " in arg) or ("\t" in arg) or not arg
TypeError: a bytes-like object is required, not 'str'

Lines 454-463 of subprocess.py is following:

    for arg in seq:
        bs_buf = []

        # Add a space to separate this argument from the others
        if result:
            result.append(' ')

        needquote = (" " in arg) or ("\t" in arg) or not arg  # line 461
        if needquote:
            result.append('"')

Note that type of the right operand of in operator is str in line 461.
And value of seq is the first parameter of psychopy.core.shellCall(); that is:

[b'C:\\Users\\Hiroyuki\\Desktop\\WinPython-64bit-3.6.1.0Qt5\\python-3.6.1.amd64\\python.exe', b'c:\\Users\\Hiroyuki\\Dropbox\\git-repository\\psychopy\\psychopy\\tools\\wizard.py', b'--config', b'--firstrun']

In Python3, the left operand of in operator must be str if the right operand is str. So, we have to pass a list of str to psychopy.core.shellCall().


#11

I noticed that line 461 of subprocess.py is called only in MS Windows. This line is included in subprocess.Popen.list2cmdline() and this method is called by subprocess.Popen._execute_child(). _execute_child() is defined only in MS Windows (definition of this method is included in if _mswindows sentence). Therefore, the problem of bytes-like object is Windows specific. I confirmed that Python3.6.3+Ubuntu16.04LTS doesn’t show this problem. I think that command line should not be converted to bytes in Windows.

I found another problem. After applying above fix, still I can’t run firstrun Wizard. In Windows10, child process is crashed immediately after started. In Ubuntu16.04LTS, firstrun process seems to be started. In both setup, this problem disappears by removing lines 117-118 of psychopy/core.py.

def shellCall(shellCmd, stdin='', stderr=False, env=None, encoding='utf-8'):
    """
    (snip)
    """
    if env is None:    # line 117
        env = dict()   # line 118

What is the purpose of these lines? Is there any environment where replacing None with dict()? is necessary?

EDIT:
Sorry, there is one more problem. In Japanese Windows10, encoding of Popen() must be 'cp932' or its variant even if using Python 3.6. To make matters worse, sys.getfilesystemencoding() and sys.getdefaultencoding() return 'utf-8' in Python 3.6 in Japanese Windows. We have to find appropriate encoding without using these functions (locale.getpreferredencoding() seems to be suitable for this purpose).


#12

I fixed the bytes-like error in shellCall() is by sending commands in str (not bytes) object and specifying encoding using locale.getpreferredencoding(). Please see following pull request for detail.

https://github.com/psychopy/psychopy/pull/1636

The next issue is about pyo. Recent versions of pyo have UnicodeDecodeError in Python 2.7.

Unicode{En,De}codeErrors in fresh install #1525

I had expected that this issue would be resolved in Python 3, but it wasn’t. In Python3, pa_get_devices_infos() crashes with following error on my Japanese Windows10 PC.
Pyo’s version is 0.8.8.

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 10: invalid start byte

The above exception was the direct cause of the following exception:

SystemError: <class 'UnicodeDecodeError'> returned a result with an error set

The above exception was the direct cause of the following exception:

SystemError: <class 'UnicodeDecodeError'> returned a result with an error set

The above exception was the direct cause of the following exception:

SystemError: <class 'UnicodeDecodeError'> returned a result with an error set

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: <built-in function pa_get_devices_infos> returned a result with an error set

On the same machine, pa_get_devices_infos() returns following result in Python 2. Again, pyo is 0.8.8. There seems to be no problem, but name of device 0, 1, 3, 4 are corrupted (shown as u'???').

({
10: {'host api index': 4, 'latency': 0.009999999776482582, 'default sr': 44100, 'name': u'\u30b9\u30c6\u30ec\u30aa \u30df\u30ad\u30b5\u30fc (Realtek HD Audio Stereo input)'}, 
11: {'host api index': 4, 'latency': 0.009999999776482582, 'default sr': 44100, 'name': u'\u30de\u30a4\u30af (Realtek HD Audio Mic input)'}, 
12: {'host api index': 4, 'latency': 0.009999999776482582, 'default sr': 44100, 'name': u'\u30e9\u30a4\u30f3\u5165\u529b (Realtek HD Audio Line input)'}, 
6: {'host api index': 2, 'latency': 0.01160997711122036, 'default sr': 44100, 'name': u'ASIO4ALL v2'}
}, {
0: {'host api index': 0, 'latency': 0.09000000357627869, 'default sr': 44100, 'name': u'???'}, 
1: {'host api index': 0, 'latency': 0.09000000357627869, 'default sr': 44100, 'name': u'???'}, 
2: {'host api index': 0, 'latency': 0.09000000357627869, 'default sr': 44100, 'name': u'Realtek Digital Output (Realtek'}, 
3: {'host api index': 1, 'latency': 0.11999999731779099, 'default sr': 44100, 'name': u'???'}, 
4: {'host api index': 1, 'latency': 0.11999999731779099, 'default sr': 44100, 'name': u'???'}, 
5: {'host api index': 1, 'latency': 0.11999999731779099, 'default sr': 44100, 'name': u'Realtek Digital Output (Realtek High Definition Audio)'}, 6: {'host api index': 2, 'latency': 0.01160997711122036, 'default sr': 44100, 'name': u'ASIO4ALL v2'}, 
7: {'host api index': 3, 'latency': 0.003000000026077032, 'default sr': 48000, 'name': u'Realtek Digital Output (Realtek High Definition Audio)'}, 
8: {'host api index': 3, 'latency': 0.003000000026077032, 'default sr': 48000, 'name': u'\u30b9\u30d4\u30fc\u30ab\u30fc (Realtek High Definition Audio)'}, 
9: {'host api index': 4, 'latency': 0.009999999776482582, 'default sr': 44100, 'name': u'Speakers (Realtek HD Audio output)'}, 
13: {'host api index': 4, 'latency': 0.009999999776482582, 'default sr': 44100, 'name': u'SPDIF Out (Realtek HDA SPDIF Out)'}
})

I tried pa_get_input_devices(), pa_get_output_devices() on the same machine. The result was that pa_get_input_devices() shows UnicodeDecodeError in Python2, while
pa_get_output_devices() shows UnicodeDecodeError in Python3 ! I suspect that the name of some devices are encoded in cp932, while the other are encoded in utf-8 :worried:.

pa_list_devices() works better. In Python 3, all devices are correctly shown :smile:.

AUDIO devices:
0: OUT, name: Microsoft サウンド マッパー - Output, host api index: 0, default sr: 44100 Hz, latency: 0.090000 s
1: OUT, name: スピーカー (Realtek High Defini, host api index: 0, default sr: 44100 Hz, latency: 0.090000 s
2: OUT, name: Realtek Digital Output (Realtek, host api index: 0, default sr: 44100 Hz, latency: 0.090000 s
3: OUT, name: プライマリ サウンド ドライバー, host api index: 1, default sr: 44100 Hz, latency: 0.120000 s
4: OUT, name: スピーカー (Realtek High Definition Audio), host api index: 1, default sr: 44100 Hz, latency: 0.120000 s
5: OUT, name: Realtek Digital Output (Realtek High Definition Audio), host api index: 1, default sr: 44100 Hz, latency: 0.120000 s
6: IN, name: ASIO4ALL v2, host api index: 2, default sr: 44100 Hz, latency: 0.011610 s
6: OUT, name: ASIO4ALL v2, host api index: 2, default sr: 44100 Hz, latency: 0.011610 s
7: OUT, name: Realtek Digital Output (Realtek High Definition Audio), host api index: 3, default sr: 48000 Hz, latency: 0.003000 s
8: OUT, name: スピーカー (Realtek High Definition Audio), host api index: 3, default sr: 48000 Hz, latency: 0.003000 s
9: OUT, name: Speakers (Realtek HD Audio output), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
10: IN, name: ステレオ ミキサー (Realtek HD Audio Stereo input), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
11: IN, name: マイク (Realtek HD Audio Mic input), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
12: IN, name: ライン入力 (Realtek HD Audio Line input), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
13: OUT, name: SPDIF Out (Realtek HDA SPDIF Out), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s

In python 2, pa_list_devices() runs without UnicodeDecodeError though name of some devices are corrupted (i.e., 8, 10, 11, 12).

AUDIO devices:
0: OUT, name: Microsoft サウンド マッパー - Output, host api index: 0, default sr: 44100 Hz, latency: 0.090000 s
1: OUT, name: スピーカー (Realtek High Defini, host api index: 0, default sr: 44100 Hz, latency: 0.090000 s
2: OUT, name: Realtek Digital Output (Realtek, host api index: 0, default sr: 44100 Hz, latency: 0.090000 s
3: OUT, name: プライマリ サウンド ドライバー, host api index: 1, default sr: 44100 Hz, latency: 0.120000 s
4: OUT, name: スピーカー (Realtek High Definition Audio), host api index: 1, default sr: 44100 Hz, latency: 0.120000 s
5: OUT, name: Realtek Digital Output (Realtek High Definition Audio), host api index: 1, default sr: 44100 Hz, latency: 0.120000 s
6: IN, name: ASIO4ALL v2, host api index: 2, default sr: 44100 Hz, latency: 0.011610 s
6: OUT, name: ASIO4ALL v2, host api index: 2, default sr: 44100 Hz, latency: 0.011610 s
7: OUT, name: Realtek Digital Output (Realtek High Definition Audio), host api index: 3, default sr: 48000 Hz, latency: 0.003000 s
8: OUT, name: 繧ケ繝斐・繧ォ繝シ (Realtek High Definition Audio), host api index: 3, default sr: 48000 Hz, latency: 0.003000 s
9: OUT, name: Speakers (Realtek HD Audio output), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
10: IN, name: 繧ケ繝・Ξ繧ェ 繝溘く繧オ繝シ (Realtek HD Audio Stereo input), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
11: IN, name: 繝槭う繧ッ (Realtek HD Audio Mic input), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
12: IN, name: 繝ゥ繧、繝ウ蜈・蜉・(Realtek HD Audio Line input), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s
13: OUT, name: SPDIF Out (Realtek HDA SPDIF Out), host api index: 4, default sr: 44100 Hz, latency: 0.010000 s

pa_list_devices() seems to be the most promising among these functions, but the output cannot be obtained as a return value.

I read pyo’s source code and noticed that pa_get_devices_infos() simply calls DLL function in portaudio.dll. I think that we can get information directly from DLL function by using ctypes. I’ll give it a try.


#13

Calling shared library functions using ctypes worked as expected both in python 2.7 and 3.6.
However, loading portaudio.dll in Windows 10 was somewhat tricky. portaudio.dll which is included pyo 0.8.8 installer requires libgcc_s_dw2-1.dll and libstdc++-6.dll. So we have to set environment variables to make OS to find these DLLs (pyo doesn’t use ctypes to load DLLs). Here attached my code.

pa_get_devices.py (3.9 KB)

I read source code of pySoundCard and sounddevice to learn how these packages call portaudio functions and noticed that these packages install their own portaudio.dll to site-packages directory, which doesn’t depend on other DLLs. If you don’t hesitate to make sound/backend_pyo.py depend on these modules, replacing pyo.pa_get_devices_infos() with equivalent functions in these packages may be a handy solution.


#14

I got an old Macintosh and tested my code (i.e. pa_get_devices.py attached in my previous post). This code didn’t work in Standalone PsychoPy 1.85.4. In Standalone PsychoPy, libportaudio.dylib is not included in python’s sys.path but in /Applications/PsychoPy2.app/Contents/Frameworks. It would be possible to modify my code to search this path, but I think such an ad hoc solution may cause trouble in other environment than Standalone PsychoPy.

So, I tried to replace pyo’s pa_get_devices_infos(), pa_get_input_devices() and pa_get_output_devices() with query_devices() in sounddevice package. I added get_devices_infos(), get_input_devices() and get_output_devices() functions to psychopy/sound/backend_pyo.py, which convert output of sounddevice.query_devices() to that of pyo’s corresponding function. I pushed these modifications to my repository.

Here is a test code. It gets device information using pyo and newly added function.

import psychopy
psychopy.prefs.general['audioLib'] = ['pyo']
import psychopy.sound
import pyo

def print_devices(pyo_obj, mod_obj):
    """
    pyo_obj is a dict object returned by pyo.pa_get_devices_infos()
    mod_obj is a dict object returned by newly added get_devices_infos()
    """
    for dev_key in pyo_obj.keys():
        print('Device {}'.format(dev_key))
        for param_key in pyo_obj[dev_key].keys():
            print('  {:<14}: {:>20} {:>20}'.format(param_key,
                pyo_obj[dev_key][param_key],
                mod_obj[dev_key][param_key])) # mod_obj and pyo_obj have the same key

pyo_in, pyo_out = pyo.pa_get_devices_infos()
mod_in, mod_out = psychopy.sound.backend.get_devices_infos()

print('======== Output ========')
print_devices(pyo_out, mod_out)

print('======== Input ========')
print_devices(pyo_in, mod_in)

Here is the result. Testing environment is Japanese Ubuntu 16.04 LTS + Python 2.7 + pyo 0.7.8 + sounddevice 0.3.7. The values of latency are slightly different (diffrence is less than 10^{-8}), but other parameters are the same.

======== Output ========
Device 0
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          : HDA Intel PCH: ALC892 Analog (hw:0,0) HDA Intel PCH: ALC892 Analog (hw:0,0)
Device 1
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          : HDA Intel PCH: ALC892 Digital (hw:0,1) HDA Intel PCH: ALC892 Digital (hw:0,1)
Device 3
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          : HDA NVidia: HDMI 0 (hw:1,3) HDA NVidia: HDMI 0 (hw:1,3)
Device 4
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          : HDA NVidia: HDMI 1 (hw:1,7) HDA NVidia: HDMI 1 (hw:1,7)
Device 5
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          : HDA NVidia: HDMI 2 (hw:1,8) HDA NVidia: HDMI 2 (hw:1,8)
Device 6
  host api index:                    0                    0
  latency       :      0.0213333331048      0.0213333333333
  default sr    :                48000                48000
  name          :           sysdefault           sysdefault
Device 7
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :                front                front
Device 8
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :           surround21           surround21
Device 9
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :           surround40           surround40
Device 10
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :           surround41           surround41
Device 11
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :           surround50           surround50
Device 12
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :           surround51           surround51
Device 13
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :           surround71           surround71
Device 14
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :               iec958               iec958
Device 15
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :                spdif                spdif
Device 16
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :                pulse                pulse
Device 17
  host api index:                    0                    0
  latency       :      0.0213333331048      0.0213333333333
  default sr    :                48000                48000
  name          :                 dmix                 dmix
Device 18
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :              default              default
======== Input ========
Device 0
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          : HDA Intel PCH: ALC892 Analog (hw:0,0) HDA Intel PCH: ALC892 Analog (hw:0,0)
Device 16
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :                pulse                pulse
Device 2
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          : HDA Intel PCH: ALC892 Alt Analog (hw:0,2) HDA Intel PCH: ALC892 Alt Analog (hw:0,2)
Device 18
  host api index:                    0                    0
  latency       :     0.00870748329908      0.0087074829932
  default sr    :                44100                44100
  name          :              default              default
Device 6
  host api index:                    0                    0
  latency       :      0.0213333331048      0.0213333333333
  default sr    :                48000                48000
  name          :           sysdefault           sysdefault

I also tested in following environment. The results were similar to above in Ubuntu and MacOS X.
In Windows 10 and 7, I couldn’t compare outputs because pyo 0.8.x doesn’t run in Japanese Windows; however, newly added functions properly return device information even in Japanese Windows.

  • Japanese Ubuntu 16.04 LTS + Python 3.6 + pyo 0.8.8 + sounddevice 0.3.9
  • Japanese MacOS X 10.11.6 + Python 2.7 + pyo 0.8.6 + sounddevice 0.3.4
  • Japanese Windows 10 + Python 2.7 + pyo 0.8.8 + sounddevice 0.3.9
  • Japanese Windows 10 + Python 3.6 + pyo 0.8.8 + sounddevice 0.3.9
  • Japanese Windows 7 + Python 2.7 + pyo 0.8.7 + sounddevice 0.3.8

The sounddevice package is included in “required” packages in setup.py. So I think using sounddevice.query_devices() to resolve pyo’s Unicode problem is not that bad. It is easy to revert modification when pyo’s Unicode problem is resolved. What do you think?