iokit.IOServiceGetMatchingServices broken under Python3?

694 views Asked by At

I just got a mac mini running Yosemite (I normally use linux). I was trying to get serial.tools.list_ports.comports() to work under Python3.

I've narrowed down the problem to the following snippet of code (extracted from pyserial):

import ctypes
from ctypes import util

iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit'))

kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault")

iokit.IOServiceMatching.restype = ctypes.c_void_p

iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
iokit.IOServiceGetMatchingServices.restype = ctypes.c_void_p

serial_port_iterator = ctypes.c_void_p()

print('kIOMasterPortDefault =', kIOMasterPortDefault)

response = iokit.IOServiceGetMatchingServices(
    kIOMasterPortDefault,
    iokit.IOServiceMatching('IOSerialBSDClient'),
    ctypes.byref(serial_port_iterator)
)
print('serial_port_iterator =', serial_port_iterator)

If I run this under python2, then it works properly:

382 >python bug.py 
('kIOMasterPortDefault =', c_void_p(None))
('serial_port_iterator =', c_void_p(4355))

However, when I run it under Python3, it fails (serial_port_iterator stays as c_void_p(None))

383 >python3 bug.py
kIOMasterPortDefault = c_void_p(None)
serial_port_iterator = c_void_p(None)

Does anybody know why this would be failing under Python3, and perhaps how to fix it?

1

There are 1 answers

0
Dave Hylands On

ok - figured it out.

Python3 passes strings as unicode (wide) strings, whereas Python2 passes strings as narrow strings.

So changing this line

iokit.IOServiceMatching('IOSerialBSDClient'),

to read

iokit.IOServiceMatching(b'IOSerialBSDClient'),

makes it work for Python2 and 3.

Now to see if I can get the change into pyserial.