Re: Proper way to expose custom Obj-C classes to Python?

Ian McCullough <[email protected]> Wed, 19 Feb 2014 09:04:39 -0500
Newsgroups gmane.comp.python.pyobjc.devel
Message-ID <CADa4atVsEWkbY2vQWU3qXyxomXXhxJ9jom2Axh4eprb9nN3zNg@mail.gmail.com>
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 <[email protected]> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/pyobjc-dev