Re: [Pyobjc-dev] Proper way to expose custom Obj-C classes to Python?
Brought to you by:
ronaldoussoren
From: Ronald O. <ron...@ma...> - 2014-02-19 14:59:33
|
(Sorry about the top posting, I'm posting through iCloud webmail and that tends to mangle mails to mailinglist in interesting ways...) The framework wrappers don't contain that much intelligence, at first approximation a wrapper module for your own code can do something like: # MyClasses.py import objc # ... arrange for loading your code (if necessary) for cls in objc.getClassList(): globals()[cls.name] = cls That way your classes are available in the MyClasses namespace. Then add definitions for globals symbols and the like. The metadata tools are at best under-documented, and is very, very fragile (and didn't work at all for me on the 10.9 headers). I'm trying to rewrite the parsing code using the python interface to clang.cindex, but that is moving forward fairly slowly because there is very little documentation on clang.cindex. At the moment it might be easier to just create an _metadata.py file manually instead of using the metadata tool (assuming your headers don't contain a lot of definitions that need to be added to the metadata file) Ronald On Feb 19, 2014, at 03:07 PM, Ian McCullough <ip...@po...> wrote: 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 ------------------------------------------------------------------------------ Managing the Performance of Cloud-Based Applications Take advantage of what the Cloud has to offer - Avoid Common Pitfalls. Read the Whitepaper. http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk _______________________________________________ Pyobjc-dev mailing list Pyo...@li... https://lists.sourceforge.net/lists/listinfo/pyobjc-dev |