I'm trying to use a private framework with PyObjC. I've got this so far:
from AppKit import *
from Foundation import *
import objc
framework="/System/Library/PrivateFrameworks/DSObjCWrappers.framework"
objc.loadBundle("DSObjCWrapper", globals(), framework)
directory = DSoDirectory.alloc()
directory.initWithHost_user_password_("server", "diradmin", "password")
eDSStartsWith = 0x2002
node = directory.findNode_matchType_(u"/LDAPv3", eDSStartsWith)
That works fine. Now, I want to call a method on my node (of class DSoNode), with this objective-c signature.
The most obvious way doesn't know how to take a string and pass it to a char*:
node.hasRecordsOfType_("dsRecTypeStandard:ComputerLists")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/Users/clinton/<ipython console> in <module>()
ValueError: depythonifying 'char', got 'str' of 31
It looks like it is possible to change the signature as python sees it. I tried some variations on:
objc.registerMetaDataForSelector("DSoNode", "hasRecordsOfType_", dict( arguments={ 2+0: dict(type_modifier='n', type='^C') }))
but--and frankly I don't know how the registerMetaDataForSelector function works, and haven't found docs on it--I still get the same error when I invoke my selector on the node. How do I tell PyObjC to convert a string to a char*? (Or is there a better way to do it, as these strings are C constants #defined in a header file.)
Update: I tried using gen_bridge_metadata
(as mentioned in this blog post), and, after consulting the man page, tried it as follows:
sudo mkdir -p /System/Library/PrivateFrameworks/DSObjCWrappers.framework/Resources/BridgeSupport
sudo gen_bridge_metadata --framework ~/Downloads/DSTools-112.1/build/Deployment/DSObjCWrappers.framework/ --output /System/Library/PrivateFrameworks/DSObjCWrappers.framework/Resources/BridgeSupport/DSObjCWrappers.bridgesupport
I still get the same error; there is no indication that this was even noticed, except that if I type:
help(modules)
I get:
/System/Library/PrivateFrameworks/DSObjCWrappers.framework/Versions/A/Resources/<ipython console> in <module>()
NameError: name 'modules' is not defined
I should also mention that I found a list of types that I believe would be understood by the registerMetaDataForSelector function; objective-C type encodings. Note that the XML for the particular function I'm after says:
<method selector='hasRecordsOfType:'>
<retval type='B'/>
</method>
I would've expected something explaining the input parameter, too.
I believe you want the following and then should pass a non-unicode string:
objc.registerMetaDataForSelector("DSoNode",
"hasRecordsOfType:",
dict(
arguments =
{
2: dict(type=objc._C_PTR + objc._C_CHAR_AS_TEXT,
c_array_delimited_by_null=True,
type_modifier=objc._C_IN)
}
))
A more complete NSString example follows:
from AppKit import *
from Foundation import *
import objc
def setupMetadata():
objc.registerMetaDataForSelector("NSString", "stringWithCString:",
dict(
arguments =
{
2: dict(type=objc._C_PTR + objc._C_CHAR_AS_TEXT,
c_array_delimited_by_null=True,
type_modifier=objc._C_IN)
}
))
def doTest():
s = NSMutableString.stringWithString_(u"foo");
NSLog(u"string[" + s + "]")
s2 = NSString.stringWithCString_("bar")
NSLog(u"string[" + s2 + "]")
setupMetadata()
doTest()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With