Crea un objeto python desde la dirección de memoria (usando gi.repository)

A veces necesito llamar a una función gtk / gobject que solo existe en C, pero devuelve un objeto que tiene un envoltorio de python. Anteriormente utilicé una solución basada en ctypes que funcionaba bien:

http://faq.pygtk.org/index.py?req=show&file=faq23.041.htp

Ahora que cambié de PyGtk (“import gtk”) a GObject-introspection (“from gi.repository import Gtk”), ¿qué puedo usar en su lugar?

La interfaz _PyGObject_API ha cambiado en algún momento. Necesitaba descartar la función register_sinkfunc . Los siguientes trabajos:

 from gi.repository import Gio, GLib import gi import ctypes 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)), ('lookup_class', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)), ('newgobj', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)), ] class PyGObjectCPAI(object): def __init__(self): PyCObject_AsVoidPtr = ctypes.pythonapi.PyCObject_AsVoidPtr PyCObject_AsVoidPtr.restype = ctypes.c_void_p PyCObject_AsVoidPtr.argtypes = [ctypes.py_object] addr = PyCObject_AsVoidPtr(ctypes.py_object( gi._gobject._PyGObject_API)) self._api = _PyGObject_Functions.from_address(addr) def pygobject_new(self, addr): return self._api.newgobj(addr) capi = PyGObjectCPAI() 

Para obtener un objeto de un puntero:

 obj = capi.pygobject_new(pointer) 

para obtener un puntero de un objeto (g):

 pointer = hash(obj) 

Tengo que agregar, en mi caso, esto no me ayudó a resolver mi problema real. Estaba intentando establecer una interfaz con dconf, pero dconf devuelve valores de tipo GVariant, que no se heredan de GObject. Parece que PyGI / GObject desafortunadamente no expone las funciones necesarias para convertir una C (* GVariant) en una Python GLib.Variant. Supongo que es en esos momentos en los que tienes que deshacerte de tu enfoque inicial y probar algo diferente.

El código en la respuesta de jdm no es compatible con Python 3. Como CObject está en desuso en Python 2.7 y 3.1, y se eliminó a partir de la versión 3.2, modifiqué el código para usar Capsule ( disponible en 2.7 y desde la versión 3.1):

 import ctypes, gi 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)), ('lookup_class', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)), ('newgobj', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)), ] class PyGObjectCAPI(object): def __init__(self): self._as_void_ptr.restype = ctypes.c_void_p self._as_void_ptr.argtypes = [ctypes.py_object] addr = self._as_void_ptr(ctypes.py_object( gi._gobject._PyGObject_API)) self._api = _PyGObject_Functions.from_address(addr) @staticmethod def _as_void_ptr(obj): name = ctypes.pythonapi.PyCapsule_GetName(obj) return ctypes.pythonapi.PyCapsule_GetPointer(obj, name) def pygobject_new(self, addr): return self._api.newgobj(addr) capi = PyGObjectCAPI() 

(También lo renombré a la API de PyGobjectC, no estoy seguro de si CPAI representaba algo, pero tenía más sentido para mí de esta manera).

La API de PyGOject cambió desde la actualización de AlliedEnvy

 import gi import ctypes from ctypes import pythonapi class _PyGObject_Functions(ctypes.Structure): _fields_ = [ ('pygobject_register_class', ctypes.PYFUNCTYPE(ctypes.c_void_p)), ('pygobject_register_wrapper', ctypes.PYFUNCTYPE(ctypes.c_void_p)), ('pygobject_lookup_class', ctypes.PYFUNCTYPE(ctypes.c_void_p)), ('pygobject_new', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)), ] class PyGObjectCAPI(object): def __init__(self): addr = self._as_void_ptr(gi._gobject._PyGObject_API) self._api = _PyGObject_Functions.from_address(addr) @classmethod def _capsule_name(cls, capsule): pythonapi.PyCapsule_GetName.restype = ctypes.c_char_p pythonapi.PyCapsule_GetName.argtypes = [ctypes.py_object] return pythonapi.PyCapsule_GetName(capsule) @classmethod def _as_void_ptr(cls, capsule): name = cls._capsule_name(capsule) pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p pythonapi.PyCapsule_GetPointer.argtypes = [ ctypes.py_object, ctypes.c_char_p] return pythonapi.PyCapsule_GetPointer(capsule, name) def to_object(self, addr): return self._api.pygobject_new(addr) capi = PyGObjectCAPI() 

Con la llegada de los archivos de instalación ( .typelib , .gir ), la misma API debería estar disponible, independientemente del idioma que se use, es decir, si está usando una función C que no está en la API, probablemente esté usando una función destinado a ser utilizado sólo internamente.