Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Python Objective-C Bridge
-
Hi
First of all, great product!
I'm pretty sure I can call back into Objective-C by writing a statically compiled python library with the functions I want in it (I can see examples of this in places like scene.py and canvas.py (e.g. import _canvas)). BTW, an example would be great, since those libs are compiled into the libpythonista.a lib I can't see what they look like, but I can probably figure it out.
My question is - is the reverse possible ? I want to call a python function from Objective-C. In the PyObjC world I would have imported objc and then created a python subclass of a NSObject. I was hoping you could provide any pointers on how I would go about this.
Also, how would global variables work ? If I were to call a python function and it declared a globalvariable then returned and then I was to call another function that used the same global variable, would it be available ? Would python keep its memory space around between calls ?
Any info you have would be much appreciated.
-
The 'native' modules of Pythonista basically work like this:
→ Python documentation: Extending Python with C or C++
If you use the Xcode template, it would generally be possible to add additional native functionality that is accessible from Python in the same way, but it would NOT be possible to add such functionality to the Pythonista app itself.
As an example, this is an abridged and simplified version of the
_clipboard
module://clipboardmodule.m #import "Python.h" PyObject* clipboard_get(PyObject* self, PyObject* pArgs) { NSString *stringValue = [[UIPasteboard generalPasteboard] string]; if (!stringValue) { return PyUnicode_FromString(""); } return PyUnicode_FromString([stringValue UTF8String]); } static PyMethodDef clipboardMethods[] = { {"get", clipboard_get, METH_NOARGS, "get() -- Get the clipboard's text content as a string"}, // [...] {NULL, NULL, 0, NULL} //sentinel }; PyMODINIT_FUNC init_clipboard(void) { Py_InitModule("_clipboard", clipboardMethods); }
-
This is excellent. Thankyou!
-
Sorry for the naive question, but I :
- Included the “Python.h”- directory to the header include option
- Implemented such a coding like the clipboard example , called the module “_sensors”
Compiling and linking was done without any errors.
Then I added “import sensors” to my main.py file and got the error during runtime that the module is not defined.
What is missing ?
For any suggestions grateful
Stefan -
Did you write a corresponding
sensors.py
file? If you implement_sensors
in C (or in Python, it doesn't really matter) that doesn't automatically create asensors
module. The point of having a native C module and a separate Python wrapper is so you can write parts of your library in Python, and so you can change the C interface without worrying about breaking user code. (Of course you'd still need to provide some backwards compatibility in the Python module.) The C library is still normally available to Python code as_sensors
, the underscore is used as a convention to indicate that it is a "private" library that external code should not depend on. -
Thanks, for the reply, but it's still not working.
This my test coding of _sensor.m :
// // _sensor.m // PilotsApp // // // #import <Foundation/Foundation.h> #import "Python.h" PyObject* sensor_get(PyObject* self, PyObject* pArgs) { NSString *stringValue = @"done"; return PyUnicode_FromString([stringValue UTF8String]); } static PyMethodDef Methods[] = { {"get", sensor_get, METH_NOARGS, "get() -- Get the clipboard's text content as a string"}, // [...] {NULL, NULL, 0, NULL} //sentinel }; PyMODINIT_FUNC init_sensor() { Py_InitModule("_sensor", Methods); }
Then I implemented the file sensor.py :
from _sensor import *
And extacly this statement ends in "No module named _sensor"
Do I have to change any compiling or linking flags ?
-
You have to "register" the module with the Python interpreter during startup, e.g. by calling
PyImport_ExtendInittab
.This has to happen before the interpreter is initialized, e.g. in
applicationDidFinishLaunching:
(AppDelegate). -
This post is deleted! -
Wow. It works. Thanks, Ole!
The coding changes are indicated by ">>> Bridge":
// // AppDelegate.m // Pythonista // // Created by Ole Zorn on 1/19/15. // // #import "AppDelegate.h" #import "PythonistaAppViewController.h" // >>> Bridge #import "Python.h" // <<< Bridge PyMODINIT_FUNC init_sensor(void); @implementation AppDelegate - (void)applicationDidFinishLaunching:(UIApplication *)application { // >>> Bridge struct _inittab pyqt_inittab[] = { {"_sensor", init_sensor},{0,0}}; PyImport_ExtendInittab( pyqt_inittab); // <<< Bridge NSFileManager *fm = [NSFileManager defaultManager]; NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];