-
Notifications
You must be signed in to change notification settings - Fork 51
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
pyobjc==10.3 breakage #610
Comments
What's your use case for this? I've disabled calling class MyDocument(NSDocument):
def __init__(self, *args, **kwds): pass
document = MyDocument() # __init__ gets called
document, error = MyDocument(type="mytype", error=None). # __init__ does not get called I've chosen to disable |
My use case was this: I'd like to instantiate my NSObject subclass as if it's a Python class, by just calling it with arguments. |
That's already possible, but you have to implement one or more init methods for this. What doesn't work is writing a single intermediate subclass and than implemented its classes as if they are plain python classes. TBH, that's not something I had considered. The changelog mentions this a bit too concisely, https://pyobjc.readthedocs.io/en/latest/notes/instantiating.html is a bit clearer. class MyObject(NSObject):
init = None # Calling MyOjbect() is not allowed
def initWithX_y_(self, x_value, y_value):
self = super.init()
self.x = x_value
self.y = y_value
return self
value = MyValue(x=42, y=24) One limitation is that the order or keywords is currently important. I'm not convinced that this is the right design, but it was easier to start with this limitation than to introduce it later when I run into system frameworks where the order is important. I'll probably drop the restriction during the summer, but only after I've checked the framework bindings and have hammered out a design for a similar feature for calling other methods in a nicer way. |
But what about the aspect of the 10.3 update unnecessarily breaking working code? |
I'll revert the change that broke |
Idea: only call |
I like the idea, but have to check how hard it will be to implement this in the current setup. In a very real sense every class now implements its own That said, I already detect if a user has written the |
For completeness sake: the |
Thanks for the reference to cocoa-vanilla, I'll test my changes with that library as well. I shortly commit some changes that ensure that the following tests pass: class OC_DunderInitBase(NSObject):
# Helper for ``TestUsingDunderInit``
def __new__(cls, *args, **kwds):
return cls.alloc().init()
class TestUsingDunderInit(TestCase):
# Some users have an intermediate class
# which implements ``__new__`` to be able
# to create Cocoa sublcasses using a similar
# interface as normal Python subclasses, e.g.
# with ``__init__`` for initializing the instance.
#
# This should continue to work.
def test_using_dunder_init(self):
class OC_DunderInitSub1(OC_DunderInitBase):
def __init__(self, x, y=2):
self.x = x
self.y = y
o = OC_DunderInitSub1(x=1)
self.assertIsInstance(o, OC_DunderInitSub1)
self.assertEqual(o.x, 1)
self.assertEqual(o.y, 2)
with self.assertRaises(TypeError):
OC_DunderInitSub1()
with self.assertRaises(TypeError):
OC_DunderInitSub1(9, z=4)
def test_multipe_generations(self):
class OC_DunderInitSub2(OC_DunderInitBase):
def __init__(self, x, y):
self.x = x
self.y = y
class OC_DunderInitSub3(OC_DunderInitSub2):
def __init__(self, x, y, z):
super().__init__(x, y)
self.z = z
o = OC_DunderInitSub3(1, 2, 3)
self.assertIsInstance(o, OC_DunderInitSub3)
self.assertEqual(o.x, 1)
self.assertEqual(o.y, 2)
self.assertEqual(o.z, 3) That is, |
As mentioned in the changelog update a number of popular libraries use ``__new__`` and ``__init__`` in their code and the 10.3 change w.r.t. not calling ``__init__`` broke those libraries.
I've clicked around a little in I did have a crash when using vanillaBrowser, but that seems to be related to Python 3.12 support in cocoa-vanilla:
|
There will be a release of 10.3.1 later this weekend unless I run into unexpected issues when running the full test suite using the latest python updates. |
Thank you! |
Just for the record, the Glyphs.app python wrapper uses a pattern like this to make the objc API more pythonic:
|
... or unless my build VM crashes. I've restarted a test run and expect to release later today. |
That should work again in 10.3.1. The change in 10.3.1 is to only disable calling |
PyObjC 10.3.1 is now available on PyPI with this fix. |
I can confirm that my code works again with the 10.3.1 update. Thank you so much! |
10.3 breaks vanilla, 10.3.1 fixes it. GlyphsPython users will have 10.2 for now, but if user switches to another Python and has 10.3, it will crash TalkingLeaves. See ronaldoussoren/pyobjc#610
I finally got to test this with my code. And it is still not working as before. I added some "convenience" to often used Cocoa classes like this:
I get this error:
And if I do
it fails, too. I need to add:
I can deal with second problem, but it would be great to be able to amend Cocoa classes like this. |
I'm trying to reproduce the first problem, but so far without success. The traceback indicates that my Is the code below similar enough to what you're doing? from Foundation import NSURL
from objc import python_method
def override__new__(self, *args, **kwds):
return self.alloc().initWithString_("https://www.python.org")
def override__init__(self, *args, **kwds):
print(self, args, kwds)
NSURL.__new__ = staticmethod(override__new__)
NSURL.__init__ = python_method(override__init__)
o = NSURL()
print(o, type(o)) The second issue is a consequence of how the new feature is implemented: Every (native) class gets its own It might be possible to avoid the second problem in your code by carefully calling I'm afraid there's no good solution for the second problem, other then giving up on good help on my end or explicitly setting |
I can fix the second problem on my end. I just need to copy paste that line a few times. So don’t worry about it. NSURL is not a good sample, it would need to parse the args in
The NSURL could be "wrapped" like this:
|
The annoying bit is that both work for me. That is, given a virtualenv named "pydotorg" in which I installed PyObjC 10.3.1 from PyPI ("pip install pyobjc"):
The current development version (what will be 11.0 later this year) behaves the same. I do get a |
You are right. It works when run in plain python. But it doesn't when run inside my app. I’ll dig a bit. |
I have narrowed it down. It seems only to happen when two python files are executed in the same context. (e.g. two plugins that are based on py2app running inside my app) Both do:
The first time first time all is fine, NSMenuItem is imported, and then the myWrapper is loaded and the methods are assigned. But when the second file imports NSMenuItem, the import seems to overwrite my |
I found more issues with this change that breaks scripting in Glyphs. Now some of my own classes will throw this error. And only on the second run of a script. I report back as soom as I find more details. |
Describe the bug
There's a regression for a code pattern like this:
With pyobjc==10.2 this outputs this:
However, with pyobjc==10.3,
__init__
doesn't get called, and this is the output:The text was updated successfully, but these errors were encountered: