diff --git a/dbus-python.spec b/dbus-python.spec index 1865cf8..19fb17f 100644 --- a/dbus-python.spec +++ b/dbus-python.spec @@ -1,15 +1,18 @@ Summary: D-Bus Python Bindings Name: dbus-python Version: 1.2.0 -Release: 9%{?dist} +Release: 8%{?dist} License: MIT URL: http://www.freedesktop.org/wiki/Software/DBusBindings/ Source0: http://dbus.freedesktop.org/releases/dbus-python/%{name}-%{version}.tar.gz Source1: http://dbus.freedesktop.org/releases/dbus-python/%{name}-%{version}.tar.gz.asc +# Added functionality for Fedora server dbus api requested by sgallagh +# https://bugs.freedesktop.org/show_bug.cgi?id=26903#c9 +Patch0: object_manager.patch # borrow centos7 patch to use sitearch properly -Patch0: 0001-Move-python-modules-to-architecture-specific-directo.patch +Patch2: 0001-Move-python-modules-to-architecture-specific-directo.patch BuildRequires: dbus-devel BuildRequires: dbus-glib-devel @@ -42,7 +45,8 @@ Summary: D-Bus bindings for python3 %prep %setup -q -%patch0 -p1 -b .sitearch +%patch0 -p1 -b .object_manager +%patch2 -p1 -b .sitearch # For new arches (aarch64/ppc64le), and patch2 autoreconf -vif @@ -94,9 +98,6 @@ make check -k -C python3-build %changelog -* Wed Aug 19 2015 Leigh Scott - 1.2.0-9 -- drop object patch which was rejected by upstream because it breaks API - * Wed Jun 17 2015 Fedora Release Engineering - 1.2.0-8 - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild diff --git a/object_manager.patch b/object_manager.patch new file mode 100644 index 0000000..df0c53d --- /dev/null +++ b/object_manager.patch @@ -0,0 +1,473 @@ +From b5f097c622ac89df3ccb97931decd45bae3c4bd2 Mon Sep 17 00:00:00 2001 +From: Marko Kohtala +Date: Tue, 13 May 2014 22:06:07 +0300 +Subject: [PATCH] Implement dbus.service.property decorator and + PropertiesInterface + +This adds dbus server side support for properties using a decorator. +The decorator automagically adds PropertiesInterface to the object. + +It also simplifies the _dbus_class_table shared by all derived classes +and containing them to a _dbus_interface_table on each derived class. +--- + dbus/decorators.py | 95 ++++++++++++++++++++++++++ + dbus/service.py | 163 ++++++++++++++++++++++++++++++++++++++------ + examples/example-client.py | 18 +++-- + examples/example-service.py | 14 +++- + 4 files changed, 261 insertions(+), 29 deletions(-) + +diff --git a/dbus/decorators.py b/dbus/decorators.py +index b164582..d41869a 100644 +--- a/dbus/decorators.py ++++ b/dbus/decorators.py +@@ -343,3 +343,98 @@ def signal(dbus_interface, signature=None, path_keyword=None, + return emit_signal + + return decorator ++ ++ ++class property(object): ++ """A decorator used to mark properties of a `dbus.service.Object`. ++ """ ++ ++ def __init__(self, dbus_interface=None, signature=None, ++ property_name=None, emits_changed_signal=None, ++ fget=None, fset=None, doc=None): ++ """Initialize the decorator used to mark properties of a ++ `dbus.service.Object`. ++ ++ :Parameters: ++ `dbus_interface` : str ++ The D-Bus interface owning the property ++ ++ `signature` : str ++ The signature of the property in the usual D-Bus notation. The ++ signature must be suitable to be carried in a variant. ++ ++ `property_name` : str ++ A name for the property. Defaults to the name of the getter or ++ setter function. ++ ++ `emits_changed_signal` : True, False, "invalidates", or None ++ Tells for introspection if the object emits PropertiesChanged ++ signal. ++ ++ `fget` : func ++ Getter function taking the instance from which to read the ++ property. ++ ++ `fset` : func ++ Setter function taking the instance to which set the property ++ and the property value. ++ ++ `doc` : str ++ Documentation string for the property. Defaults to documentation ++ string of getter function. ++ ++ :Since: 1.3.0 ++ """ ++ validate_interface_name(dbus_interface) ++ self._dbus_interface = dbus_interface ++ ++ self._init_property_name = property_name ++ if property_name is None: ++ if fget is not None: ++ property_name = fget.__name__ ++ elif fset is not None: ++ property_name = fset.__name__ ++ if property_name: ++ validate_member_name(property_name) ++ self.__name__ = property_name ++ ++ self._init_doc = doc ++ if doc is None and fget is not None: ++ doc = getattr(fget, "__doc__", None) ++ self.fget = fget ++ self.fset = fset ++ self.__doc__ = doc ++ ++ self._emits_changed_signal = emits_changed_signal ++ if len(tuple(Signature(signature))) != 1: ++ raise ValueError('signature must have only one item') ++ self._dbus_signature = signature ++ ++ def __get__(self, inst, type=None): ++ if inst is None: ++ return self ++ if self.fget is None: ++ raise AttributeError("unreadable attribute") ++ return self.fget(inst) ++ ++ def __set__(self, inst, value): ++ if self.fset is None: ++ raise AttributeError("can't set attribute") ++ self.fset(inst, value) ++ ++ def __call__(self, fget): ++ return self.getter(fget) ++ ++ def _copy(self, fget=None, fset=None): ++ return property(dbus_interface=self._dbus_interface, ++ signature=self._dbus_signature, ++ property_name=self._init_property_name, ++ emits_changed_signal=self._emits_changed_signal, ++ fget=fget or self.fget, fset=fset or self.fset, ++ doc=self._init_doc) ++ ++ def getter(self, fget): ++ return self._copy(fget=fget) ++ ++ def setter(self, fset): ++ return self._copy(fset=fset) +diff --git a/dbus/service.py b/dbus/service.py +index b1fc21d..fdb3ee4 100644 +--- a/dbus/service.py ++++ b/dbus/service.py +@@ -23,7 +23,7 @@ + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + # DEALINGS IN THE SOFTWARE. + +-__all__ = ('BusName', 'Object', 'method', 'signal') ++__all__ = ('BusName', 'Object', 'PropertiesInterface', 'method', 'property', 'signal') + __docformat__ = 'restructuredtext' + + import sys +@@ -34,8 +34,10 @@ from collections import Sequence + + import _dbus_bindings + from dbus import ( +- INTROSPECTABLE_IFACE, ObjectPath, SessionBus, Signature, Struct, +- validate_bus_name, validate_object_path) ++ INTROSPECTABLE_IFACE, ObjectPath, PROPERTIES_IFACE, SessionBus, Signature, ++ Struct, validate_bus_name, validate_object_path) ++_builtin_property = property ++from dbus.decorators import method, signal, property + from dbus.decorators import method, signal + from dbus.exceptions import ( + DBusException, NameExistsException, UnknownMethodException) +@@ -297,20 +299,25 @@ def _method_reply_error(connection, message, exception): + + + class InterfaceType(type): +- def __init__(cls, name, bases, dct): +- # these attributes are shared between all instances of the Interface +- # object, so this has to be a dictionary that maps class names to +- # the per-class introspection/interface data +- class_table = getattr(cls, '_dbus_class_table', {}) +- cls._dbus_class_table = class_table +- interface_table = class_table[cls.__module__ + '.' + name] = {} ++ def __new__(cls, name, bases, dct): ++ # Properties require the PropertiesInterface base. ++ for func in dct.values(): ++ if isinstance(func, property): ++ for b in bases: ++ if issubclass(b, PropertiesInterface): ++ break ++ else: ++ bases += (PropertiesInterface,) ++ break ++ ++ interface_table = dct.setdefault('_dbus_interface_table', {}) + + # merge all the name -> method tables for all the interfaces + # implemented by our base classes into our own + for b in bases: +- base_name = b.__module__ + '.' + b.__name__ +- if getattr(b, '_dbus_class_table', False): +- for (interface, method_table) in class_table[base_name].items(): ++ base_interface_table = getattr(b, '_dbus_interface_table', False) ++ if base_interface_table: ++ for (interface, method_table) in base_interface_table.items(): + our_method_table = interface_table.setdefault(interface, {}) + our_method_table.update(method_table) + +@@ -320,9 +327,9 @@ class InterfaceType(type): + method_table = interface_table.setdefault(func._dbus_interface, {}) + method_table[func.__name__] = func + +- super(InterfaceType, cls).__init__(name, bases, dct) ++ return type.__new__(cls, name, bases, dct) + +- # methods are different to signals, so we have two functions... :) ++ # methods are different to signals and properties, so we have three functions... :) + def _reflect_on_method(cls, func): + args = func._dbus_args + +@@ -370,12 +377,107 @@ class InterfaceType(type): + + return reflection_data + ++ def _reflect_on_property(cls, descriptor): ++ signature = descriptor._dbus_signature ++ if signature is None: ++ signature = 'v' ++ ++ if descriptor.fget: ++ if descriptor.fset: ++ access = "readwrite" ++ else: ++ access = "read" ++ elif descriptor.fset: ++ access = "write" ++ else: ++ return "" ++ reflection_data = '