Question

First, some context: I'm a Python developer who has written a medium-sized application using PyGObject, taking advantage of GObject Introspection to access things like GSettings, etc. Some of my Python objects actually subclass GObject.GObject, so I'm using GObject quite extensively.

Recently, a certain library has come to my attention that wraps a C library in GObject (gexiv2, used by Shotwell/Vala), however it doesn't currently support introspection. I'm interested in adding introspection support to gexiv2 so that I can access it from Python, but I don't even know where to begin on this topic.

When I research introspection and VAPI, I see lots of documentation referencing the fact that the VAPI can be automatically generated from the introspection annotations... but what about a project that already has a VAPI, but no introspection? Is it possible to automatically generate the introspection annotations given the VAPI?

Thanks.

Was it helpful?

Solution 2

Well, after getting sick of the tediousness of hand-copying VAPI definitions into introspection annotations, I wrote this (crude) script to do it for me:

#!/bin/env python

import sys

from collections import defaultdict

ANNOTATION = """/**
 * %s:
%s *
 * Returns:%s
 */
"""

PARAMETER = """ * @%s:%s
"""

methods = defaultdict(set)

attrs = defaultdict(dict)

with open(sys.argv[1]) as vapi:
    for line in vapi:
        tokens = line.split()
        try:
            names = tuple(tokens[0].split('.'))
        except IndexError:
            continue

        attrs[names] = {}
        for attribute in tokens[1:]:
            key, val = attribute.split('=')
            if val == '"1"': val = True
            if val == '"0"': val = False
            attrs[names][key] = val

        methods[names[0]]
        if len(names) > 1:
            methods[names[0]].add(names[-1])

for method in methods:
    params = ''
    for param in methods[method]:
        param_attributes = ''
        param_attrs = attrs[(method, param)]
        if param_attrs.get('hidden'):
            param_attributes += ' (skip)'
        if param_attrs.get('is_out'):
            param_attributes += ' (out)'
        if param_attrs.get('transfer_ownership'):
            param_attributes += ' (transfer full)'
        elif 'transfer_ownership' in param_attrs:
            param_attributes += ' (transfer none)'
        if param_attrs.get('array_null_terminated'):
            param_attributes += ' (array zero-terminated=1)'
        if param_attrs.get('array_length_pos'):
            param_attributes += ' (array length=FIXME)'
        if param_attributes:
            param_attributes += ':'
        params += PARAMETER % (param, param_attributes)

    attributes = ''
    method_attrs = attrs[(method,)]
    if method_attrs.get('transfer_ownership'):
        attributes += ' (transfer full)'
    elif 'transfer_ownership' in method_attrs:
        attributes += ' (transfer none)'
    if method_attrs.get('nullable'):
        attributes += ' (allow-none)'
    if method_attrs.get('array_null_terminated'):
        attributes += ' (array zero-terminated=1)'
    if attributes:
        attributes += ':'

    print ANNOTATION % (method, params, attributes)

This obviously has some disadvantages: It doesn't insert the annotations into the code, it simply prints them, so you have to do quite a bit of copy & pasting to get everything into the right place. It also doesn't handle arrays very well, but it at least lets you know when there's an array you need to fix manually. All in all, it was significantly less work to run this script and then massage the results than it was to parse by hand. I'm posting it here in the hopes that it gets picked up by google and somebody else may benefit one day (although I dearly hope that all GObject-based projects from here on out simply start with annotations and then use vapigen).

OTHER TIPS

VAPI bindings are not necessarily related to GObject introspection. For instance, there are VAPI bindings for POSIX, Linux, libudev, and other things that are definitely not GObject-based. There isn't a direct way to convert a VAPI to a GObject binding.

However, if you have C header files and a working library, then you can generally build a GObject introspection file from the library. For gexiv2, download and build the source, then execute:

g-ir-scanner -I gexiv2 gexiv2/gexiv2-{metadata,managed-stream,preview-properties,preview-image,log,startup}.h -n GExiv2 --library libgexiv2.la --pkg gobject-2.0

And this will produce a GIR binding (XML) that you can use in Python.

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