Question

I have a plugin written entirely in Python using PyObjC whose core classes I need to convert to Objective-C. One of them basically just loads up a Python module and executes a specific function, passing it keyword arguments. In PyObjC, this was extremely.

However, I'm having difficulty figuring out how to do the same thing using the Python C API. In particular, I'm unsure how best to convert an NSDictionary (which might hold integers, strings, booleans, or all of the above) into a format that I can then pass on to Python as keyword arguments.

Anyone have pointers on how to accomplish something like this? Thanks in advance!

Edit: just to clarify, I'm converting my existing class which was formerly Python into Objective-C, and am having trouble figuring out how to move from an NSDictionary in Objective-C to a Python dictionary I can pass on when I invoke the remaining Python scripts. The Objective-C class is basically just a Python loader, but I'm unfamiliar with the Python C API and am having trouble figuring out where to look for examples or functions that will help me.

Was it helpful?

Solution

Oh, looks like I misunderstood your question. Well, going the other direction isn't terribly different. This should be (as least a start of) the function you're looking for (I haven't tested it thoroughly though, so beware of the bugs):

// Returns a new reference
PyObject *ObjcToPyObject(id object)
{
    if (object == nil) {
        // This technically doesn't need to be an extra case, 
        // but you may want to differentiate it for error checking
        return NULL;
    } else if ([object isKindOfClass:[NSString class]]) {
        return PyString_FromString([object UTF8String]);
    } else if ([object isKindOfClass:[NSNumber class]]) {
        // You could probably do some extra checking here if you need to
        // with the -objCType method.
        return PyLong_FromLong([object longValue]);
    } else if ([object isKindOfClass:[NSArray class]]) {
        // You may want to differentiate between NSArray (analagous to tuples) 
        // and NSMutableArray (analagous to lists) here.
        Py_ssize_t i, len = [object count];
        PyObject *list = PyList_New(len);
        for (i = 0; i < len; ++i) {
            PyObject *item = ObjcToPyObject([object objectAtIndex:i]);
            NSCAssert(item != NULL, @"Can't add NULL item to Python List");
            // Note that PyList_SetItem() "steals" the reference to the passed item.
            // (i.e., you do not need to release it)
            PyList_SetItem(list, i, item);
        }
        return list;
    } else if ([object isKindOfClass:[NSDictionary class]]) {
        PyObject *dict = PyDict_New();
        for (id key in object) {
            PyObject *pyKey = ObjcToPyObject(key);
            NSCAssert(pyKey != NULL, @"Can't add NULL key to Python Dictionary");
            PyObject *pyItem = ObjcToPyObject([object objectForKey:key]);
            NSCAssert(pyItem != NULL, @"Can't add NULL item to Python Dictionary");
            PyDict_SetItem(dict, pyKey, pyItem);
            Py_DECREF(pyKey);
            Py_DECREF(pyItem);
        }
        return dict;
    } else {
        NSLog(@"ObjcToPyObject() could not convert Obj-C object to PyObject.");
        return NULL;
    }
}

You may also want to take a look at the Python/C API Reference manual if you haven't already.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top