1

I have trouble parsing dictionary from python to C program using swing module. I have written a wrapper_dict.c and struct.c program.

wrapper.c 
    #include <Python.h>
    #include "struct.h"
    PyObject *dictionary(PyObject *self, PyObject *args) {
            PyObject *dict;
            int result;
            if (!PyArg_ParseTuple(args, "O", &dict))
                     return NULL;
            result = printBook(&dict);
            return Py_BuildValue("i", result);
    }
    static PyMethodDef dictMethods[] = {
             { "printBook", dictionary, 1 },
             { NULL, NULL }
    };
    void initdict() {
            PyObject *m;
            m = Py_InitModule("dict", dictMethods);
    }
Struct.c: 
    #include<stdio.h>
    #include<string.h>
    #include "struct.h"
    int printBook (struct Books *book) {
            printf(" Book title: %s\n", book->title);
            printf(" Book author: %s\n", book->author);
            printf(" Book subject: %s\n", book->subject);
            printf(" Book book_id: %d\n", book->book_id);
            return 1;
    }

Using dynamic loading:

   xyz@M:~/Python/Cprogam/work$ gcc -fpic -c $(pkg-config --cflags --libs python2) wrapper_dict.c struct.c
    xyz@M:~/Python/Cprogam/work$ gcc -shared wrapper_dict.o struct.o -o dictmod.so

When I passed the dictionary to printBook I see the printf statements returns bunch of garbage values.

 xyz@M:~/Python/Cprogam/work$ python
    Python 2.7.6 (default, Mar 22 2014, 22:59:38)
    [GCC 4.8.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import dict
    >>> books= { 'title':'C progamming', 'author' : 'J k', 'subject' : 'telecomm', 'book_id': '345524'}
    >>>
   >>> dict.printBook(books)
   Book title: t?"?/0l?
   Book author: s?D
   Book subject:
   Book book_id: 4
   1

Am I missing something? Kindly let me know. Thanks in advance.

6
  • dict is a poor choice for the name of your module. It shadows the built-in type of the same name. Commented Oct 8, 2014 at 2:13
  • Where is SWIG involved? Looks like a straight Python C extension to me... Commented Oct 8, 2014 at 6:29
  • I don't think that would compile. You're passing a PyObject** to printBook, which takes a Books*. Commented Oct 8, 2014 at 6:33
  • tried changing the module from dict to dictmodule still it didnt work Commented Oct 8, 2014 at 20:38
  • @MarkTolonen yes I'm using straight python C extension. I want to understand how should I pass PyObject** to printBook ? Commented Oct 8, 2014 at 20:40

1 Answer 1

1

You have to convert the Python object to the proper C structure.

Here's a working example. Error checking left out for brevity, and I guessed at struct.h. I also used Python 3.3 x64 and built with a debug build of Python to check reference counting:

wrapper.c

#include <Python.h>
#include "struct.h"
PyObject *wrap_printBook(PyObject *self, PyObject *args)
{
        PyObject *dict,*py_subject,*py_title,*py_author,*py_book_id;
        struct Books book;
        int result;

        // Parse the Python function arguments.  Expect one object.
        if (!PyArg_ParseTuple(args, "O", &dict))
            return NULL;
        // Expect a Python dictionary, retrieve the expected string values.
        // Note PyDict_GetItemString returns a borrowed reference.  Don't DECREF it.
        py_subject = PyDict_GetItemString(dict,"subject");
        py_title = PyDict_GetItemString(dict,"title");
        py_author = PyDict_GetItemString(dict,"author");
        py_book_id = PyDict_GetItemString(dict,"book_id");
        // Copy the strings into the C structure.
        // Unsafe copy, I know.  I'm not doing all the work :)
        strcpy(book.subject,PyUnicode_AsUTF8(py_subject));
        strcpy(book.author,PyUnicode_AsUTF8(py_author));
        strcpy(book.title,PyUnicode_AsUTF8(py_title));
        // I made book_id an int, so convert the PyUnicode string to a PyInt, then an int.
        py_book_id = PyLong_FromUnicodeObject(py_book_id,10); // convert to PyLong (new ref!)
        book.book_id = PyLong_AsLong(py_book_id);
        Py_DECREF(py_book_id); // release ref
        // Now that the PyDict has been converted to a C value, call the function.
        result = printBook(&book);
        return Py_BuildValue("i", result);
}
static PyMethodDef bookMethods[] = {
    {"printBook",  wrap_printBook, METH_VARARGS, "Call printBook."},
    {NULL, NULL, 0, NULL}
};
static struct PyModuleDef bookModule = {
   PyModuleDef_HEAD_INIT, "book", NULL, -1, bookMethods
};
PyMODINIT_FUNC PyInit_book(void) {
    return PyModule_Create(&bookModule);
}

struct.h

#define MAX_STRING 80
struct Books
{
    char title[MAX_STRING];
    char author[MAX_STRING];
    char subject[MAX_STRING];
    int book_id;
};

int printBook (struct Books *book);

Output:

Python 3.3.2 (VS110.diff:bca965c8a064+, Jun  1 2013, 13:52:13) [MSC v.1700 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import book
[64847 refs]
>>> book.printBook({'subject':'subject1','title':'title1','author':'author1','book_id':'123456'})
 Book title: title1
 Book author: author1
 Book subject: subject1
 Book book_id: 123456
1
[64852 refs]
>>> book.printBook({'subject':'subject1','title':'title1','author':'author1','book_id':'123456'})
 Book title: title1
 Book author: author1
 Book subject: subject1
 Book book_id: 123456
1
[64852 refs] # multiple calls, no reference leaks!
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.