Re: [Pyobjc-dev] Calling Python From ObjC
Brought to you by:
ronaldoussoren
From: Bob I. <bo...@re...> - 2005-06-03 20:57:45
|
The message ends with a @ because there is a typo in the format string, it should be %@ not @%. That's what I get for writing code in Mail (take similar heed for the code snippets below). As for the class not found, it's because you're looking for the bundle in the wrong place. Again, I didn't look at your code hard enough. It's semantically wrong. Since you have developed a plug- in, it is not the main bundle, so you can't look for resources there. You need to find the bundle for your plugin. There are three ways to find a plugin's bundle: (1) Use some known memory address in the bundle (ideally a class, but it can be done with anything given more work) (2) Use the bundle's identifier (3) Know the bundle's path in advance .. generally I try and use (1), because it can be "cut&pasted" elsewhere and still works. The easiest way to do that is to use: // where FuBar is some class you've defined in that bundle NSBundle *pluginBundle = [NSBundle bundleForClass:FuBar]; The alternative from-memory approach that does not require a class is demonstrated in <http://svn.red-bean.com/bob/py2app/trunk/src/py2app/ bundletemplate/src/main.m>, take a look at the functions bundlePath() and bundleBundle() ... they can be copied verbatim to any bundle and it should work fine. As for (2), you would simply to: NSBundle *pluginBundle = [NSBundle bundleWithIdentifier:@"my.bundle.identifier.that.must.have.already.been. instantiated.in.this.app"]; .. and (3) is the obvious, but terrible: NSBundle *pluginBundle = [NSBundle bundleWithPath:@"/Some/Known/ Location/Dont/Do/This"]; -bob On Jun 3, 2005, at 12:15 PM, Nathan R. Yergler wrote: > Thanks for the code, Bob. That makes perfect sense. I've been able > to build my plugin (doing python setup.py py2app first, then building > the plugin in XCode), and when I attempt to do mdimport (in order to > import the metadata to Spotlight, and execute the code), I see the > "PyMetadataImport class not found in ..." message. My concern is that > the message ends with @. Am I interpretting that correctly to this > it's not finding the correct path (or the value of pluginPath is an > empty string)? I looked inside the plugin the build creates, and the > PyMetadataImport.plugin is being copied into the Resources directory. > > Any ideas where to start looking? > > Thanks again for all you help. > > Nathan > > > On 6/3/05, Bob Ippolito <bo...@re...> wrote: > >> Remove the @class statement. The @class statement is a forward >> reference to a class that the Objective-C linker must see before >> linking everything together. Since it won't, you can't use that. I >> missed the fact that the @class statement was in there the first >> time, that was an error. >> >> You also need to put this (or equivalent) back in: >> Class PyMetadataImport = NSClassFromString(@"PyMetadataImport"); >> >> I would probably also do the bundle loading once.. anyway, here's how >> I would write that: >> >> Boolean GetMetadataForFile(void *thisInterface, NSMutableDictionary >> *attributes, NSString *contentTypeUTI, NSString *pathToFile) >> { >> static BOOL PluginLoaded = NO; >> static Class PyMetadataImport = nil; >> >> NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; >> >> if (!pluginLoaded) { >> NSString *pluginPath = [[NSBundle mainBundle] >> pathForResource:@"PyMetadataImporter" >> ofType:@"plugin"]; >> NSBundle *pluginBundle = [NSBundle >> bundleWithPath:pluginPath]; >> PyMetadataImport = [pluginBundle >> classNamed:@"PyMetadataImport"]; >> if (!PyMetadataImport) { >> NSLog(@"PyMetadataImport class not found in @%", >> pluginPath); >> } >> pluginLoaded = YES; >> } >> >> id foo = [[PyMetadataImporter alloc] init]; >> [foo aMethod]; >> >> [pool release]; >> >> return TRUE; >> } >> >> >> -bob >> >> On Jun 3, 2005, at 11:32 AM, Nathan R. Yergler wrote: >> >> >>> OK, so that makes sense. I'm actually writing an Objective-C plugin >>> which is partially implemented in Python (in order to reuse some >>> code >>> we already have). Here's how I've updated my objective-C file: >>> >>> @class PyMetadataImporter; >>> >>> Boolean GetMetadataForFile(void *thisInterface, NSMutableDictionary >>> *attributes, NSString *contentTypeUTI, NSString *pathToFile) >>> { >>> >>> >>> NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; >>> NSString *pluginPath = [[NSBundle mainBundle] >>> >>> pathForResource:@"PyMetadataImporter" >>> ofType:@"plugin"]; >>> NSBundle *pluginBundle = [NSBundle bundleWithPath:pluginPath]; >>> [pluginBundle load]; >>> [pool release]; >>> >>> >>> BOOL theResult = YES; >>> NSAutoreleasePool *theAutoreleasePool = [[NSAutoreleasePool >>> alloc] init]; >>> >>> id foo = [[PyMetadataImporter alloc] init]; >>> [foo aMethod]; >>> >>> return theResult; >>> } >>> >>> So it compiles successfully, but when it attempts to link complains >>> about an undefined symbol: .objc_class_name_PyMetadataImporter >>> >>> Thoughts? Do I need a header of some sort? >>> >>> Thanks, >>> Nathan >>> >>> >>> On 6/3/05, Bob Ippolito <bo...@re...> wrote: >>> >>> >>>> >>>> On Jun 3, 2005, at 10:20 AM, Nathan R. Yergler wrote: >>>> >>>> >>>> >>>>> I've seen some questions about this in the mailing list >>>>> archive, but >>>>> haven't been able to get any traction. I'm familiar with Python, >>>>> but >>>>> new (relatively) to Objective-C. Here's the situation: I have a >>>>> Python class which inherits from NSObject, and want to use it >>>>> in an >>>>> Objective-C function. For example, the Python class looks like >>>>> this: >>>>> >>>>> from Foundation import * >>>>> >>>>> class PyMetadataImport (NSObject): >>>>> def getMeta_(self, attributes): >>>>> // note that attributes should be a >>>>> NSMutableDictionary >>>>> attributes = {'org_cc_license':'foo'} >>>>> return True >>>>> >>>>> def testMethod_(self): >>>>> NSLog("foo!") >>>>> >>>>> >>>>> I found some documentation at http://www.devoesquared.com/Blog/4 >>>>> which >>>>> indicated I need to do something like in Objective-C: >>>>> >>>>> @class PyMetadataImport; >>>>> >>>>> @interface FuBar : NSObject >>>>> { } >>>>> -(void)aMethod; >>>>> @end; >>>>> >>>>> @implementation FuBar >>>>> >>>>> -(void)aMethod >>>>> { >>>>> Class PyMetadataImport = NSClassFromString >>>>> (@"PyMetadataImport"); >>>>> id myPythonObj = [[PyMetadataImport alloc] init]; >>>>> [myPythonObj testMethod]; >>>>> } >>>>> >>>>> @end; >>>>> >>>>> and then use the FuBar class to proxy calls to the Python class. >>>>> This >>>>> doesn't work. And it seems just a little too difficult given the >>>>> demos I've seen given of Objective-C. Am I missing something >>>>> simple? >>>>> Can anyone give me some direction on how I can instantiate >>>>> PyMetadataImport from Objective-C, and then call it's methods? >>>>> >>>>> >>>> >>>> That code should work, assuming the Python code is loaded. You >>>> didn't say how you were putting the Objective-C and Python code >>>> into >>>> the same app. There are two good ways of doing that, either >>>> write a >>>> Python application that loads an Objective-C plugin (or framework), >>>> or write an Objective-C app that loads a Python plugin. It looks >>>> like you're trying to do the latter, and the example for that is >>>> the >>>> embedding tutorial <http://pyobjc.sourceforge.net/doc/ >>>> extending_objc_with_python.php>. >>>> >>>> -bob >>>> >>>> >>>> >>> >>> >> >> >> > > > ------------------------------------------------------- > This SF.Net email is sponsored by: NEC IT Guy Games. How far can > you shotput > a projector? How fast can you ride your desk chair down the office > luge track? > If you want to score the big prize, get to know the little guy. > Play to win an NEC 61" plasma display: http://www.necitguy.com/?r > _______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev > |