pyobjus icon indicating copy to clipboard operation
pyobjus copied to clipboard

Use `method_getNumberOfArguments`, `method_copyArgumentType` and `method_copyReturnType` to define argument and return types

Open misl6 opened this issue 2 years ago • 0 comments

I'm upgrading the iOS and macOS camera support on Kivy, and after a few tests I decided to use pyobjus sometimes, so the user can easily interact with AVCaptureDevice and AVCaptureSession, without writing a specific API.

Unfortunately, during development, something took my attention:

   File "/Users/mirko/Documents/projects/kivy/kivy/uix/camera.py", line 116, in on_play
     self._camera.start()
   File "kivy/core/camera/camera_avfoundation.pyx", line 135, in kivy.core.camera.camera_avfoundation.CameraAVFoundation.start
     self.set_preset("AVCaptureSessionPresetHigh")
 
   File "kivy/core/camera/camera_avfoundation.pyx", line 158, in kivy.core.camera.camera_avfoundation.CameraAVFoundation.set_preset
     if self._kivyavfcamera.mCaptureSession.canSetSessionPreset_(preset):
 
   File "pyobjus/pyobjus_types.pxi", line 647, in pyobjus.ObjcClassInstance.__getattribute__
   File "pyobjus/pyobjus.pyx", line 500, in pyobjus.ObjcMethod.__call__
   File "pyobjus/pyobjus.pyx", line 240, in pyobjus.ObjcMethod.__init__
   File "pyobjus/pyobjus_conversions.pxi", line 181, in pyobjus.convert_to_cy_cls_instance
   File "pyobjus/pyobjus.pyx", line 736, in pyobjus.autoclass
   File "pyobjus/pyobjus.pyx", line 539, in pyobjus.class_get_methods
   File "pyobjus/pyobjus.pyx", line 531, in pyobjus.objc_method_to_py
   File "pyobjus/pyobjus.pyx", line 240, in pyobjus.ObjcMethod.__init__
   File "pyobjus/type_enc.pxi", line 13, in pyobjus.parse_signature
   File "pyobjus/type_enc.pxi", line 2, in pyobjus.seperate_encoding
 IndexError: list index out of range

So, I added some debug in pyobjus, and I found out that sometimes (E.g. (b'b@:@', b'conformsToProtocol:')), the signature does not contain any stack layout info. (See: https://stackoverflow.com/questions/11527385/how-are-the-digits-in-objc-method-type-encoding-calculated)

Our previous logic took the return value from method_getTypeEncoding and then parsed the signature, by using a regex to split it. Unfortunately, the regex works thanks to the stack layout info digits.

Thankfully 🎉, Apple provides method_getNumberOfArguments, method_copyArgumentType and method_copyReturnType (https://developer.apple.com/documentation/objectivec/objective-c_functions?language=objc), so we can avoid implementing any extra logic or specific patches on our side, while also cleaning-up some complexity.

⚠️ But, there's an issue ⚠️ While doing these changes, I needed to change the positional arguments of the ObjcMethod init method. Even if the risk of someone who used it directly is quite low, I'm still breaking the API, so we likely need a new major release bump and a warning should be added in the release notes.

💡Also likely fixes issue: https://github.com/kivy/pyobjus/issues/21

misl6 avatar Dec 04 '22 09:12 misl6