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

Python 2/3 compat fixes, and first demo apps with bundled python3.5 #32

Merged
merged 14 commits into from Jul 24, 2017

Conversation

anthrotype
Copy link
Member

I based the current py23 branch on the yosemite branch, since the latter seems more advanced than master (see my question at #31).

With this patch, I was able to compile the SimpleApp as well as the TinyTextEditor inside Demos, using the latest Python 3.5.2 from Python.org, the latest pyobjc 3.2.1 (released just today, finally with pre-compiled wheels on PyPI), and the latest py2app.

Here are the two standalone apps, with embedded python3.5:

https://www.dropbox.com/s/errd2truk2r9kja/TinyTextEditor.zip?dl=0
https://www.dropbox.com/s/9y6iquvx9ab3age/SimpleApp.zip?dl=0

Please let me know if this works for you as well,
Thanks.

/cc @typesupply @typemytype @justvanrossum

Cosimo Lupo added 13 commits December 12, 2016 12:33
in Lib/vanilla/test/testAll.py, use `importlib.reload` as the built-in `reload` is no longer available in Python 3
… methods that are only used from Python and never from Objective-C

From https://pythonhosted.org/pyobjc/core/changelog.html, "Version 3.2":

"""
Backward compatibility note: Due to a change in the way the default method signature is calculated PyObjC is now more strict in enforcing the Python<->Objective-C mapping for selectors and a number of code patterns that were allowed before are no longer allowed, in particular the following method definitions raise objc.BadPrototypeError:

class MyObject (NSObject):
   def mymethod(self, a, b): ...
   def method_arg_(self, a, b, c): ...

If these methods are only used from Python and are never used from Objective-C the error can be avoided by decorating these methods with objc.python_method:

class MyObject (NSObject):
   @objc.python_method
   def mymethod(self, a, b): ...

This cannnot be used for methods used from Objective-C, for those you will have to rename the method or you will have to provide an appropriate selector explictly
"""
…examples

I didn't bother adding `from __future__ import print_function` in the docstring examples.
That should be implied (hopefully).
…instead of range(len(...))

Also, replace:

for index in range(len(alist)):
    item = alist[index]

with enumerate():

for index, item in enumerate(alist):
    ...
@justvanrossum
Copy link
Collaborator

Woa Cosimo, that is pretty great! Both apps worked here, on 10.10.2.

@anthrotype
Copy link
Member Author

great!
Somehow I can't run the test suite, though.

I tried doing:

python Lib/vanilla/test/testAll.py

But it seems to enter a sort of infinite loop (it prints nothing, seems like it hangs), and I have to kill the process forcibly.

This does not happen only with Python 3.5, but also when I try using python 2.7 with the same version of pyobjc (3.2.1).

If I use the python 2.7 with the old pyobjc that comes with OS 10.10 (yeah, I'm still using Yosemite!), the test suite works when running from the yosemite branch.

I wonder what pyobjc version does DrawBot or Robofont use?

@anthrotype
Copy link
Member Author

DISCLAIMER: I know nothing about Objective-C or PyObjC... 😁

@justvanrossum
Copy link
Collaborator

I wonder what pyobjc version does DrawBot or Robofont use?

Whatever comes with the OS...

@anthrotype
Copy link
Member Author

which OS then are they built with?
I guess the minimum required one.

@justvanrossum
Copy link
Collaborator

DISCLAIMER: I know nothing about Objective-C or PyObjC... 😁

Your usage of @objc.python_method proves that was a lie :)

@benkiel
Copy link
Member

benkiel commented Dec 12, 2016

Both these run on 10.11.6

@anthrotype
Copy link
Member Author

anthrotype commented Dec 13, 2016

ok, I kind of figured out why the testAll.py module was not showing any window when I run it from the console.

The main window of testAll.Test class which gathers all other tests is a floating NSPanel, which unlike NSWindow is hidden by default when the parent app is not active; as you may have noticed, when running a pyobjc script from the Terminal.app, the GUI starts up in the background and one has to click on a window to activate the app. The problem with the NSPanel is that it's hidden when the app is in the background, so I can't even click to activate it, neither the temporary NSApplication show a dock icon to click on...

If instead I use an NSWindow instead of NSPanel as Test window, then I can click on it with when running testAll.py from the Terminal, and I am able to interact with the GUI tests (they all seem to pass, by the way... except for RBSplitView which might need to be recompiled from source).

The change to make testAll.py work is:

-self.w = FloatingWindow((200, 300, 120, 340))
+self.w = Window((200, 300, 120, 340))

Could someone (@typesupply, @typemytype, etc.) explain how you normally would execute vanilla test suite? Maybe you run it from inside Robofont.app?


About the RBSplitView, why isn't SplitView2 module the default one? Unlike SplitView which uses that third-party framework, the latter works just fine with my python3.5 setup.
I wonder if we could/should drop it?

Thanks

@typesupply
Copy link
Member

Could someone (@typesupply, @typemytype, etc.) explain how you normally would execute vanilla test suite?

I used to run testAll.py from Terminal. That would launch a "Python" app and give it focus and that would make the panel show up. Still works in 10.10, but Apple may have changed launching behavior in a more recent OS.

About the RBSplitView, why isn't SplitView2 module the default one?

NSSplitView used to be nearly useless and RBSplitView was written to do stuff that needed to be done, like nesting. RBSplitView became the de facto standard for, like, a decade. Apple made changes to NSSplitView to cover the most common behaviors, but the API was weird and took a lot of configuring. SplitView2 was me trying to make a drop in replacement for vanilla.SplitView that behaved exactly the same way with NSSplitView being the wrapped class instead of RBSplitView. I didn't do a full switch because they aren't 1:1 compatible. I called it SplitView2 and the plan was for everyone to switch to that, isolate bugs and then we'd drop the RBSplitView backend and change "SplitView2" to "SplitView". That was in 2011. I haven't thought about it much since then. I have no idea if it is ready to replace the old one.

@benkiel
Copy link
Member

benkiel commented Dec 13, 2016

Sample apps open and run in 10.12.1

@anthrotype
Copy link
Member Author

anthrotype commented Dec 13, 2016

Thanks for the explanation, Tal.
I guess this is the source code for RBSplitView?
https://github.com/JanX2/RBSplitView
I'll try to recompile with the version of python 3 and pyobjc 3.2.1 I'm using and see if I make it work.

Yes, it seems like when using python2.7 with the built-in pyobjc (Yosemite comes with 2.5.1), the testAll.py module creates a new "app" called Python, with its own icon in the dock, whereas when I run it with the latest pyobjc (3.2.1), whether I use py27 or 35, I don't get any dock icon or menu bar, and the floating NSPanel is invisible so I can't interact with it.
I don't actually know why.
It could be that the initialization code in executeVanillaTest function, where it creates a MainMenu from code rather than from InterfaceBuilder file, is no longer enough to create the mini app on the fly?

The only way I can manage to make the testAll window active is by replacing with a vanilla Window class instead of FloatingWindow.

Would you be ok with the latter change?

What else would you recommend me to do? I was thinking maybe add a minimal setup.py for the test suite so I can call py2app to generate a temp .app bundle and launch it from there, instead of running the script from console.

@anthrotype
Copy link
Member Author

alright, alright...
it turns out it's a bug in virtualenv:
pypa/virtualenv#54

using python3's built-in venv module instead of virtualenv to create my virtual environment does the trick.

I can happily run the python Lib/vanilla/test/testAll.py and I get a nice Python dock icon and main menu!

I'm starting to like this GUI thing :)

@anthrotype
Copy link
Member Author

this is the traceback I get when clicking on SplitView button (same error when running from 2.7 or 3.5, both using the latest pyobjc 3.2.1):

$ python Lib/vanilla/test/testAll.py 
2016-12-13 19:16:41.915 Python[8208:6190435] PyObjC: Converting exception to Objective-C:
Traceback (most recent call last):
  File "/Users/cosimolupo/Documents/Github/vanilla/Lib/vanilla/vanillaBase.py", line 212, in action_
    self.callback(sender)
  File "Lib/vanilla/test/testAll.py", line 605, in openTestCallback
    TestSplitView(self.w.drawGrid.get())
  File "Lib/vanilla/test/testAll.py", line 551, in __init__
    self.nestedSplit = SplitView((0, 0, 0, 0), paneDescriptions2, isVertical=True)
  File "/Users/cosimolupo/Documents/Github/vanilla/Lib/vanilla/vanillaSplitView.py", line 92, in __init__
    self._setupView(self.rbSplitViewClass, posSize)
  File "/Users/cosimolupo/Documents/Github/vanilla/Lib/vanilla/vanillaBase.py", line 31, in _setupView
    self._nsObject = cls(self)
  File "/Users/cosimolupo/Documents/Github/vanilla/Lib/vanilla/nsSubclasses.py", line 10, in __new__
    self = cls.alloc().init()
  File "/Users/cosimolupo/Documents/Github/vanilla/Lib/vanilla/vanillaSplitView.py", line 9, in init
    self = super(VanillaRBSplitView, self).initWithFrame_(((0, 0), (0, 0)))
AttributeError: 'super' object has no attribute 'initWithFrame_'
2016-12-13 19:16:41.916 Python[8208:6190435] <class 'AttributeError'>: 'super' object has no attribute 'initWithFrame_'
2016-12-13 19:16:41.917 Python[8208:6190435] (
	0   CoreFoundation                      0x00007fff8cb5703c __exceptionPreprocess + 172
	1   libobjc.A.dylib                     0x00007fff8b09d76e objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff8cb56bd9 -[NSException raise] + 9
	3   _objc.cpython-35m-darwin.so         0x0000000101d2c4ce PyObjCErr_ToObjCWithGILState + 46
	4   _objc.cpython-35m-darwin.so         0x0000000101d149ce method_stub + 5070
	5   _objc.cpython-35m-darwin.so         0x0000000101d41512 ffi_closure_unix64_inner + 674
	6   _objc.cpython-35m-darwin.so         0x0000000101d40a46 ffi_closure_unix64 + 70
	7   AppKit                              0x00007fff8ba47eb1 -[NSApplication sendAction:to:from:] + 452
	8   AppKit                              0x00007fff8ba5d946 -[NSControl sendAction:to:] + 86
	9   AppKit                              0x00007fff8ba5d862 __26-[NSCell _sendActionFrom:]_block_invoke + 131
	10  libsystem_trace.dylib               0x00007fff847bfcd7 _os_activity_initiate + 75
	11  AppKit                              0x00007fff8ba5d7bf -[NSCell _sendActionFrom:] + 144
	12  libsystem_trace.dylib               0x00007fff847bfcd7 _os_activity_initiate + 75
	13  AppKit                              0x00007fff8ba5bcb3 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2821
	14  AppKit                              0x00007fff8bab434f -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 770
	15  AppKit                              0x00007fff8ba5a366 -[NSControl mouseDown:] + 714
	16  AppKit                              0x00007fff8bfc42dc -[NSWindow _reallySendEvent:isDelayedEvent:] + 14125
	17  AppKit                              0x00007fff8b953c86 -[NSWindow sendEvent:] + 470
	18  AppKit                              0x00007fff8b950212 -[NSApplication sendEvent:] + 2504
	19  AppKit                              0x00007fff8b879b68 -[NSApplication run] + 711
	20  _objc.cpython-35m-darwin.so         0x0000000101d408c7 ffi_call_unix64 + 79
	21  Python                              0x00007fff5bffde80 Python + 140730441916032
)

I had a look at the source file for RBSplitView but I have no idea how to make it compile. I did try to throw it at Xcode but it barfed on me (can't really use Xcode, sorry).

So, I guess, we'll have to fix the pure pyobjc implementation of SplitView2 to replace the RBSplitView one. By the way, the code is really old, last commit was 7 years ago..

How do we check/ensure that SplitView2 is fully functional replacement?

@anthrotype
Copy link
Member Author

aargh... defconAppKit just threw this error:

ImportError: cannot import name NibClassBuilder

The pyobjc docs say it's deprecated since 2.4. I guess at some point they dropped it altogether.
https://pythonhosted.org/pyobjc/api/module-PyObjCTools.NibClassBuilder.html

Found this on the Pythonmac-SIG:

Ronald Oussoren ronaldoussoren at mac.com 
Thu Aug 21 14:13:12 CEST 2008

[...]

A signficant subset of the examples in the repository still use  
PyObjCTools.NibClassBuilder. That module is deprecated and shouldn't  
be used in new code (and doesn't work with IB3 at all), all examples  
should be modified to work without NibClassBuilder. This means:

- Add explicit base classes instead of NibClassBuilder.AutoBaseClass
- Add outlet definitions (objc.IBOutlet definitions)
- Add @objc.IBAction decorator to actions (needed for IB3)

I have no idea what that means.

I guess we reached a stalemate here. Either we modernize vanilla based apps to use current PyObjC versions, or we can't use Python 3 with old PyObjc versions that are still compatible with vanilla... :(

@justvanrossum
Copy link
Collaborator

I only see NibClassBuilder in the test app, so the test app hasn't been tested for a while. Try to just remove any references to NibClassBuilder and it might just work, actually. At least it should be a shallow problem.

@miguelsousa
Copy link
Contributor

@anthrotype have a look at robotools/defconAppKit#14

@anthrotype
Copy link
Member Author

Thanks Miguel! That did the trick :)
I noticed though that the commits in that PR are no longer in the master branch, for some reasons...
Do you know why?

@typesupply
Copy link
Member

How do we check/ensure that SplitView2 is fully functional replacement?

Probably replace SplitView with SplitView2 and wait for bug reports. :) If @typemytype doesn't object to that strategy, I'm fine with being a little reckless.

@miguelsousa
Copy link
Contributor

@anthrotype I think that PR was never merged because Frederik had a different solution

@typemytype
Copy link
Member

both apps work on 10.9 and up. Well done!

@miguelsousa Im unaware of a different solution for the nibclass thingy, this is just old stuff :) that is not necessary anymore, probably somewhere a PR got it mixed up...

splitview

I guess its just legacy issues why there was no switch to the pure python and pyobjc splitview2.
This has to be tested. Important test: multiple nested splitviews in different directions with all contrains on.

I could write something up and add it to the test cases: testSplitview.py?

@justvanrossum
Copy link
Collaborator

Can this be merged?

@anthrotype
Copy link
Member Author

I think so, though I haven't had the time to play with this in months. Feel free to merge if you like (I don't have push access).

@typesupply typesupply merged commit d515a0b into robotools:yosemite Jul 24, 2017
@anthrotype anthrotype deleted the py23 branch July 26, 2017 10:47
@anthrotype
Copy link
Member Author

anthrotype commented Jul 26, 2017

Note that I haven't checked if theses changes here would break compatibility with the pre-installed (and outdated) PyObjC that ships with macOS Python (the one in Extras folder). Back when I worked on this, my concern was to be able to run vanilla with the current PyObjC version. Before merging this to master, it would make sense to see if these changes require a more recent PyObjC version than the one pre-installed on macOS, so that it won't break applications relying it.

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

Successfully merging this pull request may close these issues.

None yet

6 participants