Permalink
Browse files

Python manager finally works. Custom ObjC objects may now be passed a…

…ppropriately between across the bridge.
  • Loading branch information...
1 parent e9d8ff2 commit a3ed7b469c25a771ce235784b6a3e92a30aa1d5b @Grayson committed Mar 16, 2009
Showing with 47 additions and 5 deletions.
  1. +24 −1 src/PythonPluginManager.h
  2. +23 −4 src/PythonPluginManager.m
@@ -18,6 +18,29 @@ typedef struct {
int flags;
} PyObjCObject;
+struct pyobjc_api {
+ int api_version;
+ size_t struct_len;
+ PyTypeObject* class_type;
+ PyTypeObject* object_type;
+ PyTypeObject* select_type;
+ void *register_method_mapping;
+ int (*register_signature_mapping)(char*, PyObject *(*)(PyObject*, PyObject*, PyObject*), void (*)(void*, void*, void**, void*));
+ id (*obj_get_object)(PyObject*);
+ void (*obj_clear_object)(PyObject*);
+ Class (*cls_get_class)(PyObject*);
+ PyObject* (*cls_to_python)(Class cls);
+ id (*python_to_id)(PyObject*);
+ PyObject* (*id_to_python)(id);
+};
+
+
+typedef id(*PythonToId_t)(PyObject*);
+typedef PyObject*(*IdToPython_t)(id);
+
+PythonToId_t PythonToId;
+IdToPython_t IdToPython;
+
@interface PythonPluginManager : NSObject <PluginManagerProtocol> {
NSMutableDictionary *_plugins;
}
@@ -40,4 +63,4 @@ PyObject *guaranteedTuple(PyObject *value);
// around calling into a Python module.
@interface PythonPluginManager (PrivateMethods)
- (id)callFunction:(NSString *)functionName ofModule:(PyObject *)module arguments:(NSArray *)args;
-@end
+@end
@@ -10,6 +10,8 @@
// depythonify attempts to turn a PyObject value into its id/Cocoa counterpart.
id depythonify(PyObject *value) {
+ return PythonToId(value);
+
if (value == nil) return nil;
if (PyInt_Check(value) || PyLong_Check(value) || PyBool_Check(value))
return [NSNumber numberWithLong:PyInt_AsLong(value)];
@@ -46,7 +48,9 @@ id depythonify(PyObject *value) {
for (idx = 0; idx < size; idx++) {
PyObject *key = PyList_GetItem(keys, idx);
PyObject *obj = PyDict_GetItem(value, key);
- [dict setObject:depythonify(obj) forKey:depythonify(key)];
+ id convertedObj = depythonify(obj);
+ id convertedKey = depythonify(key);
+ if (convertedKey && convertedObj) [dict setObject:convertedObj forKey:convertedKey];
}
return dict;
}
@@ -71,6 +75,7 @@ id depythonify(PyObject *value) {
// pythonify converts ids to their PyObject values.
typedef PyObject *(*pyobjcobject_new_t)(id, int, int); // Function signature for PyObjCObject_New. Used in dynamic lookup.
PyObject *pythonify(id value) {
+ return IdToPython(value);
if (value == nil) return nil;
if ([value isKindOfClass:[NSString class]]) return PyString_FromString([value UTF8String]);
else if ([value isKindOfClass:[NSNumber class]]) return PyFloat_FromDouble([value doubleValue]);
@@ -107,7 +112,7 @@ id depythonify(PyObject *value) {
// On OS X 10.5, the included PyObjC does not expose PyObjCObject_New so we're going to locate it
// dynamically using dlsym.
pyobjcobject_new_t func;
- func = (pyobjcobject_new_t)dlsym(RTLD_DEFAULT, "PyObjCObject_New");
+ func = (pyobjcobject_new_t)dlsym(RTLD_NEXT, "PyObjCObject_New");
if (!func) {
NSLog(@"Could not find PyObjCObject_New. Error: %s", dlerror());
return Py_None;
@@ -177,8 +182,21 @@ - (void)build
// Load the Python file using PyRun_File and then call the actionProperty() function
PyRun_File(pyFile, [path UTF8String], Py_file_input, globals, globals);
+
+ if (PythonToId == nil) {
+ PyObject *objcModule = PyImport_Import(PyString_FromString("objc"));
+ Py_DECREF(objcModule);
+ if (objcModule == NULL) NSLog(@"%s WTF?", _cmd);
+ PyObject *objcGlobals = PyModule_GetDict(objcModule);
+ PyObject *apiObj = PyDict_GetItemString(objcGlobals, "__C_API__");
+ struct pyobjc_api *pyobjc = PyCObject_AsVoidPtr(apiObj);
+ PythonToId = pyobjc->python_to_id;
+ IdToPython = pyobjc->id_to_python;
+ }
+
NSString *property = [self callFunction:@"actionProperty" ofModule:mainModule arguments:nil];
-
+ if (!property) continue;
+
NSMutableArray *arr = [plugins objectForKey:property];
if (!arr) arr = [NSMutableArray array];
[arr addObject:[NSValue valueWithPointer:mainModule]];
@@ -233,6 +251,7 @@ -(id)runScriptAtPath:(NSString *)path
// Note that this hasn't been tested. Due to the GIL state, it's possible that this could cause a crash.
// More information on GIL states are documented in callFunction:ofModule:arguments:.
FILE *pyFile = fopen([path UTF8String], "r");
+ PyImport_ImportModule("objc");
PyObject *mainModule = PyImport_AddModule("__main__");
PyObject *globals = PyModule_GetDict(mainModule);
return depythonify(PyRun_File(pyFile, [path UTF8String], Py_file_input, globals, globals));
@@ -251,7 +270,7 @@ - (id)callFunction:(NSString *)functionName ofModule:(PyObject *)module argument
// will crash with some GIL state error. Simply using PyGILState_Ensure() and releasing the GIL state after
// seems to resolve this issue.
PyGILState_STATE state = PyGILState_Ensure();
- PyObject *pValue = PyObject_CallObject(pFunc, args ? guaranteedTuple(pythonify([NSArray arrayWithObjects:@"", @"", nil])) : nil);
+ PyObject *pValue = PyObject_CallObject(pFunc, args ? guaranteedTuple(pythonify(args)) : nil);
if (pValue == nil) PyErr_Print();
else ret = depythonify(pValue);
Py_XDECREF(pFunc);

0 comments on commit a3ed7b4

Please sign in to comment.