Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filechooser on mac: using path, crashes python #524

Closed
ElliotGarbus opened this issue Nov 20, 2019 · 8 comments · Fixed by Mulugruntz/plyer#1 or #565
Closed

Filechooser on mac: using path, crashes python #524

ElliotGarbus opened this issue Nov 20, 2019 · 8 comments · Fixed by Mulugruntz/plyer#1 or #565

Comments

@ElliotGarbus
Copy link

ElliotGarbus commented Nov 20, 2019

MacOS 10.14.6

using the path parameter causes python to crash (not just the app).
Using the use_extensions with path causes an uncaught exception.

Test case:

from pathlib import Path

from kivy.app import App
from kivy.lang.builder import Builder
from plyer import filechooser

kv = '''
BoxLayout:
    orientation: 'vertical'
    Button:
        text: 'Test: Open, filters=["*.pdf"]; this will crash python'
        on_release: app.ft.open(filters=['*.pdf'])
    Button:
        text: 'Test: Open, filters=["*.pdf"] use_extensions=True; throws exception '
        on_release: app.ft.open(filters=['*.pdf'], use_extensions=True)
    Button:
        text: 'Test: Open, filters=[] this will work as expected'
        on_release: app.ft.open()
    Label:
        text: 'plyer.filechooser.open_file() with a filter will crash on mac'
'''


class FileTest:
    def __init__(self):
        self.file_name = ''

    def open(self, **kwargs):
        filechooser.open_file(title='Open Patch File',
                              on_selection=self._open_selection, **kwargs)

    def _open_selection(self, selection):
        try:
            self.file_name = Path(selection[0]).name
        except (ValueError, IndexError):  # The user did not select a file
            print('open canceled')
        else:
            print(f'open file: {self.file_name}')


class PlyerFilechooserTestApp(App):
    ft = FileTest()

    def build(self):
        return Builder.load_string(kv)


if __name__ == '__main__':
    PlyerFilechooserTestApp().run()



@matham
Copy link
Member

matham commented May 27, 2020

I ran into this issue, where if I specified filers it would crash.

@Mulugruntz
Copy link
Contributor

Mulugruntz commented Jun 30, 2020

Same here.

This crashes here:
https://github.com/kivy/plyer/blob/11b6b4b/plyer/platforms/macosx/filechooser.py#L96

2020-06-30 22:21:01.316 python[92472:38636130] -[__NSSingleObjectArrayI _getCString:maxLength:encoding:]: unrecognized selector sent to instance 0x7fbbf1f74820
2020-06-30 22:21:01.335 python[92472:38636130] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI _getCString:maxLength:encoding:]: unrecognized selector sent to instance 0x7fbbf1f74820'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff4c94dcfd __exceptionPreprocess + 256
	1   libobjc.A.dylib                     0x00007fff76ff3a17 objc_exception_throw + 48
	2   CoreFoundation                      0x00007fff4c9c7b06 -[NSObject(NSObject) __retain_OA] + 0
	3   CoreFoundation                      0x00007fff4c8efb8f ___forwarding___ + 1485
	4   CoreFoundation                      0x00007fff4c8ef538 _CF_forwarding_prep_0 + 120
	5   CoreFoundation                      0x00007fff4c86611c CFStringGetCString + 140
	6   Foundation                          0x00007fff4ebb9d1f NSHFSTypeCodeFromFileType + 45
	7   AppKit                              0x00007fff4a673bc2 -[NSSavePanel _setEnabledFileTypes:] + 317
	8   AppKit                              0x00007fff4a673847 -[NSSavePanel setAllowedFileTypes:] + 400
	9   libffi.dylib                        0x00007fff7636af6c ffi_call_unix64 + 76
	10  ???                                 0x00007fbbf42d1570 0x0 + 140445232207216
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Please note that I believe there's another bug on line 90 and 92 where it uses f.strip() when it made sure beforehand that it wouldn't be a string. The expected behaviour would be to use the _ variable from line 88 (but renamed) to perform the .strip() on.

If this bug is fixed, it will still not fix the NSException from above.

@Mulugruntz
Copy link
Contributor

The weird thing is that it's an NSOpenPanel but the throw call stack mentions NSSavePanel. I'll dig into that direction.

@matham
Copy link
Member

matham commented Jun 30, 2020

If you figure it out a PR is always welcome!

@Mulugruntz
Copy link
Contributor

Mulugruntz commented Jun 30, 2020

I'm still digging but it's likely to be an issue on https://github.com/kivy/pyobjus or even below... :-/
And I'm not well-versed in Cython.

I tried both with
pipenv install -e "git+https://github.com/kivy/pyobjus.git@672ed61#egg=pyobjus"
and
pipenv install pyobjus==1.1.0

and the result is exactly the same.

So I'd imagine it has not been fixed yet.

@Mulugruntz
Copy link
Contributor

Mulugruntz commented Jun 30, 2020

This minimal code reproduces the crash:

from pyobjus import autoclass, objc_arr, objc_str
from pyobjus.dylib_manager import load_framework, INCLUDE

load_framework(INCLUDE.AppKit)

NSOpenPanel = autoclass('NSOpenPanel')
panel = NSOpenPanel.openPanel()

ftypes_arr = objc_arr([objc_str('jpg')])
panel.setAllowedFileTypes_(ftypes_arr)

If I do a print(panel), I get <__main__.NSKVONotifying_NSOpenPanel object at 0x116b6e450> which shows it's an NSOpenPanel. Even though it seems to be bound to the NSSavePanel implementation underneath.

@Mulugruntz
Copy link
Contributor

Found the issue!
I'll do a PR.

Mulugruntz added a commit to Mulugruntz/plyer that referenced this issue Jun 30, 2020
Mulugruntz added a commit to Mulugruntz/plyer that referenced this issue Jun 30, 2020
@Mulugruntz
Copy link
Contributor

The thing was that objc_arr was expecting positional arguments.
https://github.com/kivy/pyobjus/blob/3f6314152ea850bff8a218fb3dbc4df22431a4f2/pyobjus/pyobjus_types.pxi#L371

And the list was given as an argument.
In Objective-C, there's this thing where when you initialize with a list, the last element must have nil. And objc_arr is adding a None at the end of the positional arguments.

So, instead of having ('jpg', 'JPG', None), it had (['jpg', 'JPG'], None).
The setAllowedFileTypes() method was expecting to work on strings and received a list. Crash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants