Fun With PyObjc: Growl Notification Hell

Most of the time PyObjc is wonderful to work in, I love the python libraries and language.

Other times it just makes me angry.

It seems, at least initially, that PyObjc (2.2b3, the default installation with 10.6 snow leopard) does not work with the Growl framework. You can register your application with growl fine, but if you try to push notifications to growl nothing happens.

Here is what I tried initially to post a growl notification in pyobjc:

GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(u"Notification", "A description.", u"Notification", objc.nil, 0, objc.NO, objc.nil)

This does not work, and for a minute I thought I was the only one experiencing this problem (all open source pyobjc projects using growl had almost identical growl notification code) until I found this commit message on github. I found an associated discussion on the growl discussion group and was disheartened that the developer resorted using a command line version of growl to post notifications. However I decided to try one last thing, and checked the className of python objects passed through the objc bridge.

Here is a table of the objc className of different string creation methods in python:

  • unicode(“a string”) or u”a string”: OC_PythonUnicode
  • str(“a string”) or “a string”: OC_PythonString
  • r”a string”: OC_PythonString

Interestingly enough a python string (unicode, str, raw) is not ‘toll free’ bridged like CFString & NSString are. I guess this is to be expected and shouldn’t cause any problems since both OC_PythonString and OC_PythonUnicode are subclasses of NSString, the documentation even states “A Python unicode may be used anywhere a NSString is expected”. It seems that this is not always the case though. I tried one last thing before resorting to rewriting the code in objc:

GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(NSString.stringWithString_("Notification"), NSString.stringWithString_("A description."), NSString.stringWithString_("Notification"), objc.nil, 0, objc.NO, objc.nil)

And it worked. Note that the created NSString’s don’t get converted by the bridge into a OC_PythonString object, they pass through as regular NSString’s. Note that you also write the above as the more python native:

GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_(NSString.stringWithString_("Notification"), NSString.stringWithString_("A description."), NSString.stringWithString_("Notification"), False, 0, False, None)

One other interesting that I found is that bridge throws a memory leak warning when running

NSString.alloc().initWithString_("Notification")

:

UninitializedDeallocWarning: leaking an uninitialized object of type NSPlaceholderString

My only guess is that because initWithString is called instead of

init

the bridge sees it as a uninitialized object (so I would guess that this warning is falsely thown). Unfortunately the PyObjc documentation is too sparse for me to able to determine what the real cause of the error is.

1 Responses to “Fun With PyObjc: Growl Notification Hell”


  • The memory leak warning is because if you call “NSString.stringWithString_” the object is autoreleased, NSString.alloc().initWithString_ is not. So you would need to call NSString.alloc().initWithString_(“XX”).autorelease()

Leave a Reply