[pygobject] [New API] Add gi.require_foreign
- From: Simon Feltman <sfeltman src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] [New API] Add gi.require_foreign
- Date: Tue, 6 May 2014 03:34:18 +0000 (UTC)
commit 22a952ec532cc83c8227861a7d5bfa2957608c3f
Author: Simon Feltman <sfeltman src gnome org>
Date: Mon May 5 19:37:18 2014 -0700
[New API] Add gi.require_foreign
Add gi.require_foreign(namespace, symbol=None) API for determining
if a foreign marshaling module is available. This can be used in an
applications import statement block to verify the existence of a
specific foreign marshaling module (cairo).
Additionally it forces loading of the foreign marshaling module as
well as the GI repository module. This allows non-introspected signal
closures to correctly marshal their arguments (bug 694604).
https://bugzilla.gnome.org/show_bug.cgi?id=707735
gi/__init__.py | 28 +++++++++++++++++++++++
gi/gimodule.c | 2 +
gi/pygi-foreign.c | 60 ++++++++++++++++++++++++++++++++++++++++++++------
gi/pygi-foreign.h | 4 +++
tests/test_cairo.py | 9 +++++++
5 files changed, 95 insertions(+), 8 deletions(-)
---
diff --git a/gi/__init__.py b/gi/__init__.py
index 7c1a279..df6843c 100644
--- a/gi/__init__.py
+++ b/gi/__init__.py
@@ -26,6 +26,7 @@ __path__ = extend_path(__path__, __name__)
import sys
import os
+import importlib
# we can't have pygobject 2 loaded at the same time we load the internal _gobject
if 'gobject' in sys.modules:
@@ -33,6 +34,7 @@ if 'gobject' in sys.modules:
'modules like "gobject". Please change all occurrences '
'of "import gobject" to "from gi.repository import GObject".')
+from . import _gi
from ._gi import _gobject
from ._gi import _API
from ._gi import Repository
@@ -87,3 +89,29 @@ def require_version(namespace, version):
def get_required_version(namespace):
return _versions.get(namespace, None)
+
+
+def require_foreign(namespace, symbol=None):
+ """Ensure the given foreign marshaling module is available and loaded.
+
+ :param str namespace:
+ Introspection namespace of the foreign module (e.g. "cairo")
+ :param symbol:
+ Optional symbol typename to ensure a converter exists.
+ :type symbol: str or None
+ :raises: ImportError
+
+ :Example:
+
+ .. code-block:: python
+
+ import gi
+ import cairo
+ gi.require_foreign('cairo')
+
+ """
+ try:
+ _gi.require_foreign(namespace, symbol)
+ except Exception as e:
+ raise ImportError(str(e))
+ importlib.import_module('gi.repository', namespace)
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 47cd33c..a1779d3 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -28,6 +28,7 @@
#include "pygi.h"
#include "pyglib.h"
#include "pygi-error.h"
+#include "pygi-foreign.h"
#include <pyglib-python-compat.h>
@@ -616,6 +617,7 @@ static PyMethodDef _gi_functions[] = {
{ "source_new", (PyCFunction) _wrap_pyg_source_new, METH_NOARGS },
{ "source_set_callback", (PyCFunction) pyg_source_set_callback, METH_VARARGS },
{ "io_channel_read", (PyCFunction) pyg_channel_read, METH_VARARGS },
+ { "require_foreign", (PyCFunction) pygi_require_foreign, METH_VARARGS | METH_KEYWORDS },
{ NULL, NULL, 0 }
};
diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c
index 8a83c35..82392be 100644
--- a/gi/pygi-foreign.c
+++ b/gi/pygi-foreign.c
@@ -63,20 +63,24 @@ do_lookup (const gchar *namespace, const gchar *name)
return NULL;
}
+static PyObject *
+pygi_struct_foreign_load_module (const char *namespace)
+{
+ gchar *module_name = g_strconcat ("gi._gi_", namespace, NULL);
+ PyObject *module = PyImport_ImportModule (module_name);
+ g_free (module_name);
+ return module;
+}
+
static PyGIForeignStruct *
-pygi_struct_foreign_lookup (GIBaseInfo *base_info)
+pygi_struct_foreign_lookup_by_name (const char *namespace, const char *name)
{
PyGIForeignStruct *result;
- const gchar *namespace = g_base_info_get_namespace (base_info);
- const gchar *name = g_base_info_get_name (base_info);
result = do_lookup (namespace, name);
if (result == NULL) {
- gchar *module_name = g_strconcat ("gi._gi_", namespace, NULL);
- PyObject *module = PyImport_ImportModule (module_name);
-
- g_free (module_name);
+ PyObject *module = pygi_struct_foreign_load_module (namespace);
if (module == NULL)
PyErr_Clear ();
@@ -88,7 +92,7 @@ pygi_struct_foreign_lookup (GIBaseInfo *base_info)
if (result == NULL) {
PyErr_Format (PyExc_TypeError,
- "Couldn't find conversion for foreign struct '%s.%s'",
+ "Couldn't find foreign struct converter for '%s.%s'",
namespace,
name);
}
@@ -96,6 +100,15 @@ pygi_struct_foreign_lookup (GIBaseInfo *base_info)
return result;
}
+static PyGIForeignStruct *
+pygi_struct_foreign_lookup (GIBaseInfo *base_info)
+{
+ const gchar *namespace = g_base_info_get_namespace (base_info);
+ const gchar *name = g_base_info_get_name (base_info);
+
+ return pygi_struct_foreign_lookup_by_name (namespace, name);
+}
+
PyObject *
pygi_struct_foreign_convert_to_g_argument (PyObject *value,
GIInterfaceInfo *interface_info,
@@ -163,6 +176,37 @@ pygi_register_foreign_struct (const char* namespace_,
g_ptr_array_add (foreign_structs, new_struct);
}
+PyObject *
+pygi_require_foreign (PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "namespace", "symbol", NULL };
+ const char *namespace = NULL;
+ const char *symbol = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "s|z:require_foreign",
+ kwlist, &namespace, &symbol)) {
+ return NULL;
+ }
+
+ if (symbol) {
+ PyGIForeignStruct *foreign;
+ foreign = pygi_struct_foreign_lookup_by_name (namespace, symbol);
+ if (foreign == NULL) {
+ return NULL;
+ }
+ } else {
+ PyObject *module = pygi_struct_foreign_load_module (namespace);
+ if (module) {
+ Py_DECREF (module);
+ } else {
+ return NULL;
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
void
pygi_foreign_init (void)
{
diff --git a/gi/pygi-foreign.h b/gi/pygi-foreign.h
index ca4f75b..afa4768 100644
--- a/gi/pygi-foreign.h
+++ b/gi/pygi-foreign.h
@@ -44,6 +44,10 @@ void pygi_register_foreign_struct (const char* namespace_,
PyGIArgOverrideFromGIArgumentFunc from_func,
PyGIArgOverrideReleaseFunc release_func);
+PyObject *pygi_require_foreign (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs);
+
void pygi_foreign_init (void);
#endif /* __PYGI_FOREIGN_H__ */
diff --git a/tests/test_cairo.py b/tests/test_cairo.py
index 4674068..e4ef65a 100644
--- a/tests/test_cairo.py
+++ b/tests/test_cairo.py
@@ -4,6 +4,8 @@
import unittest
+import gi
+
try:
import cairo
from gi.repository import Regress
@@ -53,6 +55,13 @@ class Test(unittest.TestCase):
self.assertEqual(surface.get_width(), 10)
self.assertEqual(surface.get_height(), 10)
+ def test_require_foreign(self):
+ self.assertEqual(gi.require_foreign('cairo'), None)
+ self.assertEqual(gi.require_foreign('cairo', 'Context'), None)
+ self.assertRaises(ImportError, gi.require_foreign, 'invalid_module')
+ self.assertRaises(ImportError, gi.require_foreign, 'invalid_module', 'invalid_symbol')
+ self.assertRaises(ImportError, gi.require_foreign, 'cairo', 'invalid_symbol')
+
@unittest.skipUnless(has_cairo, 'built without cairo support')
@unittest.skipUnless(Gtk, 'Gtk not available')
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]