[gnome-builder] pygobject: add Builder.py overrides
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] pygobject: add Builder.py overrides
- Date: Fri, 30 Oct 2015 21:16:04 +0000 (UTC)
commit 7c1d26b5eafd44a97f8e4adb07bab43eea55781c
Author: Christian Hergert <chergert redhat com>
Date: Mon Oct 19 21:12:22 2015 -0700
pygobject: add Builder.py overrides
This allows us to create a GDBus-based service without all of the pain
of multiple dbus implementations in process (python-dbus and GDBus). It
only supports methods currently, and is based on a proposal from Martin
Pitt which can be found on
https://bugzilla.gnome.org/show_bug.cgi?id=656330
This can be used by worker processes to communicate with the parent
Builder process over a soon to be added private bus.
build/Makefile.am | 1 +
configure.ac | 5 ++
src/Builder.py | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/Makefile.am | 5 ++
4 files changed, 165 insertions(+), 0 deletions(-)
---
diff --git a/build/Makefile.am b/build/Makefile.am
index c44cfa2..5b499e8 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -8,6 +8,7 @@ GITIGNOREFILES = \
install-sh \
ltmain.sh \
missing \
+ py-compile \
test-driver \
$(NULL)
diff --git a/configure.ac b/configure.ac
index 4ba8497..8b9dc5a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -258,7 +258,9 @@ dnl Check for Required Python
dnl ***********************************************************************
enable_python_scripting=no
AS_IF([test "x$have_pygobject" = "xyes"],[
+ AM_PATH_PYTHON([3.2.3])
AC_PATH_TOOL(PYTHON3_CONFIG, "python3-config")
+
AS_IF([test -z "${PYTHON3_CONFIG}"],[
AC_MSG_RESULT([Failed to locate python3-config.])
],[
@@ -267,6 +269,9 @@ AS_IF([test "x$have_pygobject" = "xyes"],[
LIBIDE_LDFLAGS="${LIBIDE_LDFLAGS} `${PYTHON3_CONFIG} --ldflags`"
enable_python_scripting=yes
])
+
+ pyoverridesdir="\$(pyexecdir)/gi/overrides"
+ AC_SUBST(pyoverridesdir)
])
diff --git a/src/Builder.py b/src/Builder.py
new file mode 100644
index 0000000..a6784ef
--- /dev/null
+++ b/src/Builder.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+
+#
+# Builder.py
+#
+# Copyright (C) 2015 Christian Hergert <christian hergert me>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from gi.repository import GLib
+from gi.repository import GObject
+from gi.repository import Gio
+import inspect
+
+from ..importer import modules
+
+Builder = modules['Builder']._introspection_module
+__all__ = []
+
+#
+# The following GDBus wrapper is based upon code by Martin Pitt from
+# https://bugzilla.gnome.org/show_bug.cgi?id=656330
+# demo D-Bus server using GDBus
+# (C) 2010 Martin Pitt <martin piware de>
+#
+
+class _Gio_DBusMethodInfo:
+ interface = None
+ in_args = None
+ out_signature = None
+
+def DBusMethod(dbus_interface, in_signature=None, out_signature=None):
+ def decorator(func):
+ func._dbus_method = _Gio_DBusMethodInfo()
+ func._dbus_method.interface = dbus_interface
+ #func._dbus_method.out_signature = '(' + (out_signature or '') + ')'
+ func._dbus_method.out_signature = out_signature or ''
+
+ func._dbus_method.in_args = []
+ in_signature_list = GLib.Variant.split_signature(in_signature)
+ arg_names = inspect.getargspec(func).args
+ arg_names.pop(0) # eat "self" argument
+ if len(in_signature) != len(arg_names):
+ raise TypeError('specified signature %s for method %s does not match length of arguments' %
(str(in_signature_list), func.func_name))
+ for pair in zip(in_signature_list, arg_names):
+ func._dbus_method.in_args.append(pair)
+ return func
+ return decorator
+
+class DBusService:
+ class _DBusInfo:
+ object_path = None
+ connection = None
+ reg_id = None
+ methods = None # interface -> method_name -> info_map
+ # info_map keys: method_name, in_signature, out_signature
+
+ def __init__(self, object_path=None):
+ self.__dbus_info = self.__class__._DBusInfo()
+ self.__dbus_info.object_path = object_path
+
+ # set up the vtable maps, for more efficient lookups at runtime
+ self.__dbus_info.methods = {}
+ for id in dir(self):
+ attr = getattr(self, id)
+ if hasattr(attr, '_dbus_method'):
+ self.__dbus_info.methods.setdefault(attr._dbus_method.interface, {})[id] = {
+ 'in_args': attr._dbus_method.in_args,
+ 'out_signature': attr._dbus_method.out_signature,
+ }
+
+ def export(self, connection, object_path=None):
+ """
+ @connection: A Gio.DBusConnection
+ @object_path: an optional path to register at
+
+ Exports the service onto the Gio.DBusConnection provided.
+
+ If @object_path is None, then the object path registered during object
+ creation will be used.
+ """
+ self.__dbus_info.connection = connection
+ node_info = Gio.DBusNodeInfo.new_for_xml(self.__dbus_introspection_xml())
+ for interface in self.__dbus_info.methods:
+ self.__dbus_info.reg_id = connection.register_object(
+ object_path or self.__dbus_info.object_path,
+ node_info.lookup_interface(interface),
+ self.__dbus_method_call,
+ self.__dbus_get_property,
+ self.__dbus_set_property)
+
+ def unexport(self):
+ """
+ Unregisters a previous registration to a connection using
+ export_object().
+ """
+ self.connection.unregister_object(self.__dbus_info.reg_id)
+ self.__dbus_info.reg_id = None
+ self.__dbus_info.connection = None
+
+ def __dbus_introspection_xml(self):
+ '''Generate introspection XML'''
+ parts = ['<node>']
+ for interface in self.__dbus_info.methods:
+ parts.append(' <interface name="%s">' % interface)
+ for method, data in self.__dbus_info.methods[interface].items():
+ parts.append(' <method name="%s">' % method)
+ for (sig, name) in data['in_args']:
+ parts.append(' <arg type="%s" name="%s" direction="in"/>' % (sig, name))
+ parts.append(' <arg type="%s" name="return" direction="out"/>' % data['out_signature'])
+ parts.append(' </method>')
+ parts.append(' </interface>')
+ parts.append('</node>')
+ return '\n'.join(parts)
+
+ def __dbus_method_call(self, conn, sender, object_path, iface_name, method_name, parameters, invocation):
+ try:
+ info = self.__dbus_info.methods[iface_name][method_name]
+ except KeyError:
+ invocation.return_error_literal(Gio.dbus_error_quark(),
+ Gio.DBusError.UNKNOWN_METHOD,
+ 'No such interface or method: %s.%s' % (iface_name, method_name))
+ return
+
+ try:
+ ret = getattr(self, method_name)(*parameters.unpack())
+ invocation.return_value(GLib.Variant('(' + info['out_signature'] + ')', (ret,)))
+ except Exception as e:
+ invocation.return_error_literal(Gio.dbus_error_quark(),
+ Gio.DBusError.IO_ERROR,
+ 'Method %s.%s failed with: %s' % (iface_name, method_name,
str(e)))
+
+ def __dbus_get_property(self, conn, sender, object_path, iface_name, prop_name, error):
+ error = GLib.Error.new_literal(GLib.io_channel_error_quark(), 1, 'Not implemented yet')
+ return None
+
+ def __dbus_set_property(self, conn, sender, object_path, iface_name, prop_name, value, error):
+ error = GLib.Error.new_literal(GLib.io_channel_error_quark(), 1, 'Not implemented yet')
+ return False
+
+Builder.DBusService = DBusService
+Builder.DBusMethod = DBusMethod
diff --git a/src/Makefile.am b/src/Makefile.am
index c3bb3d5..4e90e31 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,11 @@ bin_PROGRAMS = gnome-builder
pkglibdir = $(libdir)/gnome-builder
pkglib_LTLIBRARIES = libgnome-builder.la
+if ENABLE_PYTHON_SCRIPTING
+overridesdir = $(pyoverridesdir)
+overrides_PYTHON = Builder.py
+endif
+
# XXX: Keep in sync with gnome-builder.h
libgnome_builder_public_sources = \
gnome-builder.h \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]