Re: [Pyobjc-dev] Proper way to expose custom Obj-C classes to Python?
Brought to you by:
ronaldoussoren
From: Ian M. <ip...@po...> - 2014-02-19 14:05:11
|
Ken & Georg, Thanks for your replies. I've already gotten this far -- i.e. I'm running the interpreter in process, executing arbitrary python scripts in it, and trading objects back and forth via NSClassFromString and other API with provided wrappers. What I was hoping to achieve was "first-class" support for my classes -- like the framework wrappers that ship with PyObjC for the system frameworks. I've made some progress by brute force. I've gotten objective-metadata-tool installed, and I'm currently working through getting it to scan my framework's headers. This process appears under-documented, so my experience is basically, "Try an invocation of objective-metadata-tool in the debugger. See what fails. Figure out why it failed. Adjust invocation to avoid that condition. Repeat." I'll report back with my findings if I have any eventual success. Thanks, Ian On Wed, Feb 19, 2014 at 2:56 AM, Ken Thomases <ke...@co...> wrote: > On Feb 18, 2014, at 5:23 PM, Ian McCullough wrote: > > > I'm trying to determine the best way to expose custom, > > application-specific, non-system-framework (i.e. not in one of the > > framework wrappers provided with PyObjC) classes written in Objective-C > to > > python across the PyObjC bridge. My eventual hope is to develop a > "hybrid" > > application in which some portions of the app are in Objective-C and > others > > are in python, with the two side integrating via the PyObjC bridge. Most > of > > the documentation I've been able to find seems to focus on situations > where > > the goal is to have all the app-specific code be in python, and to have > the > > python call out to AppKit classes, etc via the bridge and the > pre-packaged > > system framework wrappers. > > > > I've not seen any indication that it's possible to expose classes from an > > app. > > It is. I don't know if this is the best way, but one way is to link an > otherwise ordinary Cocoa app, written in Objective-C, to the Python > framework. You would then use the Python embedding API to set up the > Python runtime and load and run some Python code. You might do something > like: > > NSString* pythonPath = /* path within your app bundle to its Python > files */; > setenv("PYTHONPATH", [pythonPath fileSystemRepresentation], 1); > > Py_SetProgramName("/usr/bin/python2.6"); // or whatever version of > Python you link against; don't know how relevant this is > Py_InitializeEx(0); > PyEval_InitThreads(); > PyGILState_STATE gilState = PyGILState_Ensure(); > > NSString* script = /* path to a initialization script in your app > bundle */; > static char* arg0 = strdup([script fileSystemRepresentation]); // > don't deallocate until Python runtime is terminated, if ever > static char** argv = &arg0; // ditto > PySys_SetArgv(1, argv); > > FILE* scriptFile = fopen([script fileSystemRepresentation], "r"); > int result = PyRun_SimpleFileEx(scriptFile, (char *)[[script > lastPathComponent] fileSystemRepresentation], 1); > if (result) /* handle error */; > > PyGILState_Release(gilState); > if (gilState == PyGILState_LOCKED) > { > PyThreadState_Swap(NULL); > PyEval_ReleaseLock(); > } > > The script file mentioned above would just import modules and do > initialization and then exit. It wouldn't be a long-running script. Since > the application keeps running and the Python runtime is persistent, the > state which is set up by the script persists, too. > > After that, you have a few ways of interacting between the Python code and > the Objective-C code. Any Python class which inherits from a Cocoa class > is registered with the Objective-C runtime. It can be looked up with > NSClassFromString(). Then, it's methods can be invoked directly. You can > make that simpler by declaring Objective-C interfaces for those classes. > > The Objective-C code can pass its objects into the methods of the Python > classes and the Python code can then operate on those objects. > > Also, the Python code can find some objects itself, such as NSApp or > various singletons. It can then do things like set itself as delegates or > register for notifications. > > I believe that the classes of your app, since they were registered with > the Objective-C runtime at the time that Python was loaded and your > initialization script was run, can just be used directly in your Python > scripts. If that doesn't work, I'm sure you can use > Foundation.NSClassFromString() to get access. > > I hope that helps. > > Cheers, > Ken > > |