Python 3中从dbus迁移至GDBus:寻求Python版GDBus服务示例
Hey Dominik, I totally get it—scouring for Python GDBus examples when most resources are C-focused is frustrating. Since you already have experience building D-Bus services, switching to GDBus using Python's Gio bindings should click once you see a working example tailored to your needs. Below is a complete, tested service that includes methods, properties, and signals—core pieces you’ll need for most GDBus work.
Full Working Example
First, make sure you have the python3-gi package installed (on Debian/Ubuntu: sudo apt install python3-gi). This gives you access to the Gio bindings for GDBus.
import gi gi.require_version('Gio', '2.0') from gi.repository import Gio, GLib # Define your GDBus interface using XML (matches C-style IDL) INTERFACE_XML = """ <node> <interface name="com.example.MyGDBusService"> <!-- A simple method that takes a string and returns a greeting --> <method name="Hello"> <arg type="s" name="username" direction="in"/> <arg type="s" name="greeting" direction="out"/> </method> <!-- A read-write integer property --> <property name="RequestCount" type="u" access="readwrite"/> <!-- A signal emitted when the property changes --> <signal name="RequestCountUpdated"> <arg type="u" name="new_count"/> </signal> </interface> </node> """ class GDBusService(Gio.Application): def __init__(self): # Use a unique application ID (follows reverse domain notation) super().__init__( application_id="com.example.MyGDBusService", flags=Gio.ApplicationFlags.FLAGS_NONE ) self.request_count = 0 def do_activate(self): """Called when the application is activated (starts the service)""" # Get the D-Bus connection tied to our application dbus_connection = self.get_dbus_connection() # Register our GDBus object with the connection self.registration_id = dbus_connection.register_object( object_path="/com/example/MyGDBusService", interface_info=Gio.DBusNodeInfo.new_for_xml(INTERFACE_XML).lookup_interface("com.example.MyGDBusService"), method_call_closure=self._handle_method_calls, get_property_closure=self._handle_get_property, set_property_closure=self._handle_set_property, user_data=None ) print("GDBus service running. Use gdbus to interact with it!") def _handle_method_calls(self, connection, sender, object_path, interface_name, method_name, parameters, invocation): """Handle incoming method calls from clients""" if method_name == "Hello": username = parameters[0] self.request_count += 1 # Emit the signal to notify clients of the count change connection.emit_signal( None, # No specific destination (broadcast) "/com/example/MyGDBusService", "com.example.MyGDBusService", "RequestCountUpdated", GLib.Variant("(u)", (self.request_count,)) ) # Return the greeting to the caller invocation.return_value(GLib.Variant("(s)", (f"Hello {username}! You've made {self.request_count} requests.",))) else: invocation.return_error_literal(Gio.dbus_error_quark(), Gio.DBusError.UNKNOWN_METHOD, f"Method {method_name} not found") def _handle_get_property(self, connection, sender, object_path, interface_name, property_name): """Handle property read requests""" if property_name == "RequestCount": return GLib.Variant("u", self.request_count) raise GLib.Error(f"Unknown property: {property_name}") def _handle_set_property(self, connection, sender, object_path, interface_name, property_name, value): """Handle property write requests""" if property_name == "RequestCount": old_count = self.request_count self.request_count = value.get_uint32() if old_count != self.request_count: # Emit signal if the count changed connection.emit_signal( None, "/com/example/MyGDBusService", "com.example.MyGDBusService", "RequestCountUpdated", GLib.Variant("(u)", (self.request_count,)) ) else: raise GLib.Error(f"Unknown property: {property_name}") if __name__ == "__main__": app = GDBusService() app.run(None)
How to Test the Service
- Run the script:
python3 gdbus_service.py - In a separate terminal, test the method:
gdbus call --session --dest com.example.MyGDBusService --object-path /com/example/MyGDBusService --method com.example.MyGDBusService.Hello "Dominik" - Check the property value:
gdbus get --session --dest com.example.MyGDBusService --object-path /com/example/MyGDBusService --property com.example.MyGDBusService.RequestCount - Monitor for the signal (run this in another terminal):
Then set the property to trigger the signal:gdbus monitor --session --dest com.example.MyGDBusServicegdbus set --session --dest com.example.MyGDBusService --object-path /com/example/MyGDBusService --property com.example.MyGDBusService.RequestCount 10
Key Notes for Your Workflow
- Interface XML: This is the same IDL format used in C GDBus code, so you can reuse or adapt existing interface definitions you might have.
- Application Integration: Since this uses
Gio.Application, it plays nicely with other GLib-based tools and handles D-Bus registration cleanly (no need for manual bus connection setup). - System Bus vs Session Bus: If you need to run this on the system bus instead of the session bus, you’ll need to add a policy file in
/usr/share/dbus-1/system.d/to grant permissions for your service ID and object path.
This example covers the core GDBus features you’ll likely need, and you can extend it with more methods, properties, or signals as your project requires.
内容的提问来源于stack exchange,提问作者Dominik Möslinger




