Editing PyMaemo/Accessing APIs without Python bindings
Warning: You are not logged in.
Your IP address will be recorded in this page's edit history.
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 11: | Line 11: | ||
== Basic Usage == | == Basic Usage == | ||
- | Let's say you want to use | + | Let's say you want to use printf() from the GNU C Library. All you need in Python is: |
- | + | ||
- | import ctypes | + | import ctypes |
- | libc = ctypes.CDLL('libc.so.6') | + | libc = ctypes.CDLL('libc.so.6') |
- | libc.printf('Hello world!') | + | libc.printf('Hello world!') |
- | + | ||
In a few words, you create an object correspondent to the library you need and use it to call the function directly. You can also store the functions in plain python objects to use them easily later: | In a few words, you create an object correspondent to the library you need and use it to call the function directly. You can also store the functions in plain python objects to use them easily later: | ||
- | + | ||
- | c_printf = libc.printf | + | c_printf = libc.printf |
- | c_printf('Hello libc') | + | c_printf('Hello libc') |
- | + | ||
Remember that those are C functions, not Python ones, so you must supply arguments of the correct type to avoid undefined behavior (such as segmentation faults). As an example, if an integer is passed to the above function, you get | Remember that those are C functions, not Python ones, so you must supply arguments of the correct type to avoid undefined behavior (such as segmentation faults). As an example, if an integer is passed to the above function, you get | ||
Line 29: | Line 29: | ||
== Initializing libosso-abook == | == Initializing libosso-abook == | ||
- | libosso-abook needs to be initialized by calling [http://maemo.org/api_refs/5.0/5.0-final/libosso-abook/libosso-abook-osso-abook-init.html#osso-abook-init osso-abook-init()]. This is similar to the example above, but a little more complex because the function takes three pointers: argc, argv and the OSSO context. First of all, you must create a | + | libosso-abook needs to be initialized by calling [http://maemo.org/api_refs/5.0/5.0-final/libosso-abook/libosso-abook-osso-abook-init.html#osso-abook-init osso-abook-init()]. This is similar to the example above, but a little more complex because the function takes three pointers: argc, argv and the OSSO context. First of all, you must create a osso.Context instance using the "osso" module (provided python-osso): |
- | + | ||
- | import osso | + | import osso |
+ | |||
+ | osso_ctx = osso.Context("test_abook", "0.1") | ||
- | |||
- | |||
Note: there is no documentation for python-osso yet, so see the C documentation for [http://maemo.org/api_refs/5.0/5.0-final/libosso/group__Init.html#g05d45d1e72c2cd74f665086225141431 osso_initialize()] for details about osso.Context() arguments. Note that only "application" and "version" attributes are used in Python. | Note: there is no documentation for python-osso yet, so see the C documentation for [http://maemo.org/api_refs/5.0/5.0-final/libosso/group__Init.html#g05d45d1e72c2cd74f665086225141431 osso_initialize()] for details about osso.Context() arguments. Note that only "application" and "version" attributes are used in Python. | ||
Next, load and initialize libosso-abook library: | Next, load and initialize libosso-abook library: | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | osso_abook = ctypes.CDLL('libosso-abook-1.0.so.0') | + | import sys |
- | argv_type = ctypes.c_char_p * len(sys.argv) | + | import ctypes |
- | argv = argv_type(*sys.argv) | + | # be sure to import gtk before calling osso_abook_init() |
- | argc = ctypes.c_int(len(sys.argv)) | + | import gtk |
- | osso_abook.osso_abook_init(ctypes.byref(argc), ctypes.byref(argv), hash(osso_ctx)) | + | |
- | + | osso_abook = ctypes.CDLL('libosso-abook-1.0.so.0') | |
+ | argv_type = ctypes.c_char_p * len(sys.argv) | ||
+ | argv = argv_type(*sys.argv) | ||
+ | argc = ctypes.c_int(len(sys.argv)) | ||
+ | osso_abook.osso_abook_init(ctypes.byref(argc), ctypes.byref(argv), hash(osso_ctx)) | ||
+ | |||
The byref() function returns a pointer to the given data. The hash() function returns the memory address of the argument. | The byref() function returns a pointer to the given data. The hash() function returns the memory address of the argument. | ||
Line 55: | Line 55: | ||
Every GObject instance created by a C library must have a corresponding Python object, so that it can be manipulated on Python code. This object, which acts like a "wrapper" around the C pointer, is created using the pygobject_new() C function. Unfortunately, pygobject_new() is not a plain function, but a macro which points to a function pointer in a struct (see /usr/include/pygtk-2.0/pygobject.h on the "#define pygobject_new ..." line), making it a little more complex to be called from Python. The snippet of code below, borrowed from [http://faq.pygtk.org/index.py?req=show&file=faq23.041.htp PyGTK FAQ], will take care of this: | Every GObject instance created by a C library must have a corresponding Python object, so that it can be manipulated on Python code. This object, which acts like a "wrapper" around the C pointer, is created using the pygobject_new() C function. Unfortunately, pygobject_new() is not a plain function, but a macro which points to a function pointer in a struct (see /usr/include/pygtk-2.0/pygobject.h on the "#define pygobject_new ..." line), making it a little more complex to be called from Python. The snippet of code below, borrowed from [http://faq.pygtk.org/index.py?req=show&file=faq23.041.htp PyGTK FAQ], will take care of this: | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | class PyGObjectCPAI(object): | + | # ctypes wrapper for pygobject_new(), based on code snippet from |
- | + | # http://faq.pygtk.org/index.py?req=show&file=faq23.041.htp | |
- | + | class _PyGObject_Functions(ctypes.Structure): | |
- | + | _fields_ = [ | |
- | + | ('register_class', | |
- | + | ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p, | |
+ | ctypes.c_int, ctypes.py_object, ctypes.py_object)), | ||
+ | ('register_wrapper', | ||
+ | ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.py_object)), | ||
+ | ('register_sinkfunc', | ||
+ | ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)), | ||
+ | ('lookupclass', | ||
+ | ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)), | ||
+ | ('newgobj', | ||
+ | ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)), | ||
+ | ] | ||
+ | |||
+ | class PyGObjectCPAI(object): | ||
+ | def __init__(self): | ||
+ | import gobject | ||
+ | py_obj = ctypes.py_object(gobject._PyGObject_API) | ||
+ | addr = ctypes.pythonapi.PyCObject_AsVoidPtr(py_obj) | ||
+ | self._api = _PyGObject_Functions.from_address(addr) | ||
+ | |||
+ | def pygobject_new(self, addr): | ||
+ | return self._api.newgobj(addr) | ||
- | |||
- | |||
- | |||
Adding this to your code, you will be able to create Python objects from an arbitrary GObject pointer, simply using something like: | Adding this to your code, you will be able to create Python objects from an arbitrary GObject pointer, simply using something like: | ||
- | + | ||
- | capi = PyGObjectCPAI() | + | capi = PyGObjectCPAI() |
- | c_obj = c_function_returning_gobject(...) | + | c_obj = c_function_returning_gobject(...) |
- | obj = capi.pygobject_new(c_obj) | + | obj = capi.pygobject_new(c_obj) |
- | + | ||
== Creating a OssoABookContactChooser Instance == | == Creating a OssoABookContactChooser Instance == | ||
- | As an example of a GObject instantiation, let's call the | + | As an example of a GObject instantiation, let's call the osso_abook_contact_chooser_new() constructor from Python, which creates a "contact chooser" dialog useful to select one of more contacts: |
- | + | ||
- | capi = PyGObjectCPAI() | + | capi = PyGObjectCPAI() |
- | c_chooser = osso_abook.osso_abook_contact_chooser_new(None, "Choose a contact") | + | c_chooser = osso_abook.osso_abook_contact_chooser_new(None, "Choose a contact") |
- | chooser = capi.pygobject_new(c_chooser) | + | chooser = capi.pygobject_new(c_chooser) |
- | + | ||
After this, you can use <code>chooser</code> like any other GObject in Python, including calling inherited methods: | After this, you can use <code>chooser</code> like any other GObject in Python, including calling inherited methods: | ||
- | + | ||
- | chooser.run() | + | chooser.run() |
- | chooser.hide() | + | chooser.hide() |
- | + | ||
== Accessing Items in a GList == | == Accessing Items in a GList == | ||
Once the "contact chooser" dialog has run, you can get the selected contacts using: | Once the "contact chooser" dialog has run, you can get the selected contacts using: | ||
- | |||
- | |||
- | |||
- | |||
- | the <code>contacts</code> variable now holds a | + | contacts = osso_abook.osso_abook_contact_chooser_get_selection(c_chooser) |
- | + | ||
- | glib = ctypes.CDLL('libglib-2.0.so.0') | + | Note that you must pass the <b>C Pointer</b> to [http://maemo.org/api_refs/5.0/5.0-final/libosso-abook/OssoABookContactChooser.html#osso-abook-contact-chooser-get-selection osso_abook_contact_chooser_get_selection()], not the Python object. |
- | def glist(addr): | + | |
- | + | the <code>contacts</code> variable now holds a GList pointer. In order to access the items stored on this list, you need some Python code: | |
- | + | ||
- | + | glib = ctypes.CDLL('libglib-2.0.so.0') | |
- | + | def glist(addr): | |
- | + | class _GList(ctypes.Structure): | |
- | + | _fields_ = [('data', ctypes.c_void_p), | |
- | + | ('next', ctypes.c_void_p)] | |
- | + | l = addr | |
- | + | while l: | |
+ | l = _GList.from_address(l) | ||
+ | yield l.data | ||
+ | l = l.next | ||
+ | |||
This function uses the yield statement to construct a so called [http://docs.python.org/tutorial/classes.html#generators generator]. The actual GList manipulation is made using functions from libglib library. This generator makes it very easy to iterate over the items: | This function uses the yield statement to construct a so called [http://docs.python.org/tutorial/classes.html#generators generator]. The actual GList manipulation is made using functions from libglib library. This generator makes it very easy to iterate over the items: | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | + | for i in glist(contacts): | |
+ | get_display_name = osso_abook.osso_abook_contact_get_display_name | ||
+ | get_display_name.restype = ctypes.c_char_p | ||
+ | print "%s\n" % get_display_name(i) | ||
- | + | Here, we use [http://maemo.org/api_refs/5.0/5.0-final/libosso-abook/OssoABookContact.html#osso-abook-contact-get-display-name osso_abook_contact_get_display_name()] to get the contact's display name, but you can call virtually any function using the same approach. | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | Once you are done with the GList manipulation, you should free its memory: | |
- | + | ||
- | glib.g_list_free(contacts) | + | glib.g_list_free(contacts) |
- | + | ||
== Final Words == | == Final Words == | ||
This document purpose is to give a basic understanding necessary to use ctypes to explore C libraries, specially ones that manipulate GObject. Notably, we do not describe how to define callbacks, but this is left as an exercise for the reader. Again, be sure to read the [http://docs.python.org/library/ctypes.html#callback-functions ctypes documentation] if you are interested in more advanced techniques. | This document purpose is to give a basic understanding necessary to use ctypes to explore C libraries, specially ones that manipulate GObject. Notably, we do not describe how to define callbacks, but this is left as an exercise for the reader. Again, be sure to read the [http://docs.python.org/library/ctypes.html#callback-functions ctypes documentation] if you are interested in more advanced techniques. | ||
+ | |||
+ | ==Related Links:== | ||
+ | |||
+ | [http://www.bodybuildingrevealed.com/'''body building'''] | ||
See also more usage examples [[/More examples|here]]. | See also more usage examples [[/More examples|here]]. | ||
[[Category:Python]] | [[Category:Python]] |
Learn more about Contributing to the wiki.