[gnome-builder/wip/chergert/perspective] libide: move DBus helpers to Ide overrides



commit 8e2090b9437dc923b54ef57f4807d9d48fdcb1fa
Author: Christian Hergert <chergert redhat com>
Date:   Sun Nov 15 23:42:00 2015 -0800

    libide: move DBus helpers to Ide overrides

 libide/Ide.py               |  161 +++++++++++++++++++++++++++++++++++++++++++
 libide/Makefile.am          |    6 ++
 plugins/jedi/jedi_plugin.py |    6 +-
 3 files changed, 169 insertions(+), 4 deletions(-)
---
diff --git a/libide/Ide.py b/libide/Ide.py
new file mode 100644
index 0000000..9c070fc
--- /dev/null
+++ b/libide/Ide.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+
+#
+# Ide.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
+
+Ide = modules['Ide']._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, async=False):
+    def decorator(func):
+        func._is_async = async
+
+        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 async: arg_names.pop(0) # eat "invocation"
+        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:
+            func = getattr(self, method_name)
+            if func._is_async:
+                ret = func(invocation, *parameters.unpack())
+            else:
+                ret = func(*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
+
+Ide.DBusService = DBusService
+Ide.DBusMethod = DBusMethod
diff --git a/libide/Makefile.am b/libide/Makefile.am
index cc766e4..3f04bbc 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -510,4 +510,10 @@ DISTCLEANFILES += $(vapi_DATA)
 endif
 
 
+if ENABLE_PYTHON_SCRIPTING
+overridesdir = $(pyoverridesdir)
+overrides_PYTHON = Ide.py
+endif
+
+
 -include $(top_srcdir)/git.mk
diff --git a/plugins/jedi/jedi_plugin.py b/plugins/jedi/jedi_plugin.py
index e0d8594..b100f23 100644
--- a/plugins/jedi/jedi_plugin.py
+++ b/plugins/jedi/jedi_plugin.py
@@ -22,7 +22,6 @@
 
 import gi
 
-gi.require_version('Builder', '1.0')
 gi.require_version('Gtk', '3.0')
 gi.require_version('GtkSource', '3.0')
 gi.require_version('Ide', '1.0')
@@ -33,7 +32,6 @@ from gi.importer import DynamicImporter
 from gi.module import IntrospectionModule
 from gi.module import FunctionInfo
 
-from gi.repository import Builder
 from gi.repository import Gio
 from gi.repository import GLib
 from gi.repository import GObject
@@ -457,7 +455,7 @@ class JediCompletionRequest:
             self.cancelled = True
             self.invocation.return_error_literal(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED, "Operation 
was cancelled")
 
-class JediService(Builder.DBusService):
+class JediService(Ide.DBusService):
     queue = None
     handler_id = None
 
@@ -466,7 +464,7 @@ class JediService(Builder.DBusService):
         self.queue = {}
         self.handler_id = 0
 
-    @Builder.DBusMethod('org.gnome.builder.plugins.jedi', in_signature='siis', out_signature='a(issas)', 
async=True)
+    @Ide.DBusMethod('org.gnome.builder.plugins.jedi', in_signature='siis', out_signature='a(issas)', 
async=True)
     def CodeComplete(self, invocation, filename, line, column, content):
         if filename in self.queue:
             request = self.queue.pop(filename)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]