Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-dasbus for openSUSE:Factory checked in at 2021-06-09 21:52:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-dasbus (Old) and /work/SRC/openSUSE:Factory/.python-dasbus.new.32437 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-dasbus" Wed Jun 9 21:52:59 2021 rev:2 rq:898671 version:1.6 Changes: -------- --- /work/SRC/openSUSE:Factory/python-dasbus/python-dasbus.changes 2021-05-20 19:25:25.249853786 +0200 +++ /work/SRC/openSUSE:Factory/.python-dasbus.new.32437/python-dasbus.changes 2021-06-09 21:53:21.314587371 +0200 @@ -1,0 +2,10 @@ +Tue Jun 8 13:13:14 UTC 2021 - Predrag Ivanovi?? <predi...@mts.rs> + +- Update to dasbus-1.6 + * Allow to generate multiple output arguments (vponcova) + * Support multiple output arguments (vponcova) + * Add the is_tuple_of_one function (vponcova) +- Package changes: + * Switch from PyPI to Github download. + +------------------------------------------------------------------- Old: ---- dasbus-1.5.tar.gz New: ---- dasbus-1.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-dasbus.spec ++++++ --- /var/tmp/diff_new_pack.jBStIn/_old 2021-06-09 21:53:21.770588184 +0200 +++ /var/tmp/diff_new_pack.jBStIn/_new 2021-06-09 21:53:21.774588191 +0200 @@ -19,17 +19,17 @@ %define skip_python2 1 %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-dasbus -Version: 1.5 +Version: 1.6 Release: 0 Summary: DBus library in Python 3 License: LGPL-2.0-or-later Group: Development/Libraries/Python URL: https://github.com/rhinstaller/dasbus -Source: https://files.pythonhosted.org/packages/source/d/dasbus/dasbus-%{version}.tar.gz +Source: https://github.com/rhinstaller/dasbus/releases/download/v%{version}/dasbus-%{version}.tar.gz BuildRequires: %{python_module devel} BuildRequires: %{python_module setuptools} -BuildRequires: gobject-introspection BuildRequires: fdupes +BuildRequires: gobject-introspection Requires: python-gobject BuildArch: noarch %python_subpackages ++++++ dasbus-1.5.tar.gz -> dasbus-1.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/PKG-INFO new/dasbus-1.6/PKG-INFO --- old/dasbus-1.5/PKG-INFO 2021-05-03 16:38:39.873418000 +0200 +++ new/dasbus-1.6/PKG-INFO 2021-05-31 17:16:53.949654300 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: dasbus -Version: 1.5 +Version: 1.6 Summary: DBus library in Python 3 Home-page: https://github.com/rhinstaller/dasbus Author: Vendula Poncova diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/dasbus/server/handler.py new/dasbus-1.6/dasbus/server/handler.py --- old/dasbus-1.5/dasbus/server/handler.py 2021-05-03 16:35:50.000000000 +0200 +++ new/dasbus-1.6/dasbus/server/handler.py 2021-05-31 17:14:31.000000000 +0200 @@ -26,7 +26,7 @@ from dasbus.signal import Signal from dasbus.server.interface import get_xml, are_additional_arguments_supported from dasbus.specification import DBusSpecification, DBusSpecificationError -from dasbus.typing import get_variant, unwrap_variant +from dasbus.typing import get_variant, unwrap_variant, is_tuple_of_one import gi gi.require_version("Gio", "2.0") @@ -147,12 +147,19 @@ :param out_type: a type of the reply :param out_value: a value of the reply """ - reply_value = None + reply_value = cls._get_reply_value(out_type, out_value) + invocation.return_value(reply_value) + + @classmethod + def _get_reply_value(cls, out_type, out_value): + """Get the reply value of the DBus call.""" + if out_type is None: + return None - if out_type is not None: - reply_value = get_variant(out_type, (out_value, )) + if is_tuple_of_one(out_type): + out_value = (out_value, ) - invocation.return_value(reply_value) + return get_variant(out_type, out_value) class AbstractServerObjectHandler(metaclass=ABCMeta): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/dasbus/server/interface.py new/dasbus-1.6/dasbus/server/interface.py --- old/dasbus-1.5/dasbus/server/interface.py 2021-05-03 16:35:50.000000000 +0200 +++ new/dasbus-1.6/dasbus/server/interface.py 2021-05-31 17:14:31.000000000 +0200 @@ -30,7 +30,8 @@ from dasbus.namespace import get_dbus_name from dasbus.signal import Signal from dasbus.specification import DBusSpecificationError, DBusSpecification -from dasbus.typing import get_dbus_type +from dasbus.typing import get_dbus_type, is_base_type, get_type_arguments, \ + Tuple from dasbus.xml import XMLGenerator __all__ = [ @@ -45,11 +46,49 @@ # Class attribute for the XML specification. DBUS_XML_ATTRIBUTE = "__dbus_xml__" +# Method attribute for the @returns_multiple_arguments decorator. +RETURNS_MULTIPLE_ARGUMENTS_ATTRIBUTE = \ + "__dbus_method_returns_multiple_arguments__" + # Method attribute for the @accepts_additional_arguments decorator. ACCEPTS_ADDITIONAL_ARGUMENTS_ATTRIBUTE = \ "__dbus_handler_accepts_additional_arguments__" +def returns_multiple_arguments(method): + """Decorator for returning multiple arguments from a DBus method. + + The decorator allows to generate multiple output arguments in the + XML specification of the decorated DBus method. Otherwise, there + will be only one output argument in the specification. + + Define a DBus method with multiple output arguments: + + .. code-block:: python + + @returns_multiple_arguments + def Method(self) -> Tuple[Int, Bool]: + return 0, False + + The generated XML specification of the example: + + .. code-block:: xml + + <method name="Method"> + <arg direction="out" name="return_0" type="i"/> + <arg direction="out" name="return_1" type="b"/> + </method> + + If the XML specification is not generated by the dbus_interface + decorator, the returns_multiple_arguments decorator has no effect. + + :param method: a DBus method + :return: a DBus method with a flag + """ + setattr(method, RETURNS_MULTIPLE_ARGUMENTS_ATTRIBUTE, True) + return method + + def accepts_additional_arguments(method): """Decorator for accepting extra arguments in a DBus method. @@ -455,12 +494,17 @@ raises DBusSpecificationError: if parameters are invalid """ + signature = inspect.signature(member) + yield from cls._iterate_in_parameters(member, signature) + yield from cls._iterate_out_parameters(member, signature) + + @classmethod + def _iterate_in_parameters(cls, member, signature): + """Iterate over input parameters.""" # Get type hints for parameters. + direction = DBusSpecification.DIRECTION_IN type_hints = get_type_hints(member) - # Get method signature. - signature = inspect.signature(member) - # Iterate over method parameters, skip cls. for name in list(signature.parameters)[1:]: # Check the kind of the parameter @@ -483,21 +527,47 @@ "Undefined type of parameter '{}'.".format(name) ) - yield name, type_hints[name], DBusSpecification.DIRECTION_IN + yield name, type_hints[name], direction + + @classmethod + def _iterate_out_parameters(cls, member, signature): + """Iterate over output parameters.""" + name = DBusSpecification.RETURN_PARAMETER + direction = DBusSpecification.DIRECTION_OUT + type_hint = signature.return_annotation # Is the return type defined? - if signature.return_annotation is signature.empty: + if type_hint is signature.empty: return # Is the return type other than None? - if signature.return_annotation is None: + if type_hint is None: return - yield ( - DBusSpecification.RETURN_PARAMETER, - signature.return_annotation, - DBusSpecification.DIRECTION_OUT - ) + # Generate multiple output arguments if requested. + if getattr(member, RETURNS_MULTIPLE_ARGUMENTS_ATTRIBUTE, False): + # The return type has to be a tuple. + if not is_base_type(type_hint, Tuple): + raise DBusSpecificationError( + "Expected a tuple of multiple arguments." + ) + + # The return type has to contain multiple arguments. + type_args = get_type_arguments(type_hint) + + if len(type_args) < 2: + raise DBusSpecificationError( + "Expected a tuple of more than one argument." + ) + + # Iterate over types in the tuple + for i, type_arg in enumerate(type_args): + yield "{}_{}".format(name, i), type_arg, direction + + return + + # Otherwise, return only one output argument. + yield name, type_hint, direction @classmethod def _is_property(cls, member): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/dasbus/typing.py new/dasbus-1.6/dasbus/typing.py --- old/dasbus-1.5/dasbus/typing.py 2021-05-03 16:35:50.000000000 +0200 +++ new/dasbus-1.6/dasbus/typing.py 2021-05-31 17:14:31.000000000 +0200 @@ -51,6 +51,7 @@ "get_native", "get_variant", "get_variant_type", + "is_tuple_of_one", "unwrap_variant", "is_base_type", "get_type_arguments", @@ -138,6 +139,16 @@ return VariantType.new(type_string) +def is_tuple_of_one(type_hint): + """Is the type hint a tuple of one item? + + :param type_hint: a type hint or a type string + :return: True or False + """ + variant_type = get_variant_type(type_hint) + return variant_type.is_tuple() and variant_type.n_items() == 1 + + def get_native(value): """Decompose a DBus value into a native Python object. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/dasbus.egg-info/PKG-INFO new/dasbus-1.6/dasbus.egg-info/PKG-INFO --- old/dasbus-1.5/dasbus.egg-info/PKG-INFO 2021-05-03 16:38:39.000000000 +0200 +++ new/dasbus-1.6/dasbus.egg-info/PKG-INFO 2021-05-31 17:16:53.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: dasbus -Version: 1.5 +Version: 1.6 Summary: DBus library in Python 3 Home-page: https://github.com/rhinstaller/dasbus Author: Vendula Poncova diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/setup.py new/dasbus-1.6/setup.py --- old/dasbus-1.5/setup.py 2021-05-03 16:37:01.000000000 +0200 +++ new/dasbus-1.6/setup.py 2021-05-31 17:14:51.000000000 +0200 @@ -22,7 +22,7 @@ setup( name="dasbus", - version="1.5", + version="1.6", author="Vendula Poncova", author_email="vponc...@redhat.com", description="DBus library in Python 3", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/tests/test_dbus.py new/dasbus-1.6/tests/test_dbus.py --- old/dasbus-1.5/tests/test_dbus.py 2021-05-03 16:35:50.000000000 +0200 +++ new/dasbus-1.6/tests/test_dbus.py 2021-05-31 17:14:31.000000000 +0200 @@ -26,8 +26,10 @@ from dasbus.error import ErrorMapper, get_error_decorator from dasbus.loop import EventLoop from dasbus.server.interface import dbus_interface, dbus_signal, \ - accepts_additional_arguments -from dasbus.typing import get_variant, Str, Int, Dict, Variant, List + accepts_additional_arguments, returns_multiple_arguments +from dasbus.typing import get_variant, Str, Int, Dict, Variant, List, \ + Tuple, Bool +from dasbus.xml import XMLGenerator import gi gi.require_version("Gio", "2.0") @@ -136,6 +138,10 @@ def GetInfo(self, arg: Str, *, call_info) -> Str: return "{}: {}".format(arg, call_info) + @returns_multiple_arguments + def ReturnArgs(self) -> Tuple[Int, Bool, Str]: + return 0, False, "zero" + class DBusTestCase(unittest.TestCase): """Test DBus support with a real DBus connection.""" @@ -152,6 +158,7 @@ self.service = None self.clients = [] + self.maxDiff = None def tearDown(self): self.message_bus.disconnect() @@ -166,6 +173,49 @@ def _set_service(self, service): self.service = service + def test_xml_specification(self): + """Test the generated specification.""" + self._set_service(ExampleInterface()) + + expected_xml = ''' + <node> + <!--Specifies ExampleInterface--> + <interface name="my.testing.Example"> + <method name="GetInfo"> + <arg direction="in" name="arg" type="s"></arg> + <arg direction="out" name="return" type="s"></arg> + </method> + <method name="Hello"> + <arg direction="in" name="name" type="s"></arg> + <arg direction="out" name="return" type="s"></arg> + </method> + <method name="Knock"></method> + <signal name="Knocked"></signal> + <property access="read" name="Name" type="s"></property> + <method name="Raise"> + <arg direction="in" name="message" type="s"></arg> + </method> + <method name="ReturnArgs"> + <arg direction="out" name="return_0" type="i"></arg> + <arg direction="out" name="return_1" type="b"></arg> + <arg direction="out" name="return_2" type="s"></arg> + </method> + <property access="write" name="Secret" type="s"></property> + <property access="readwrite" name="Value" type="i"></property> + <signal name="Visited"> + <arg direction="out" name="name" type="s"></arg> + </signal> + </interface> + </node> + ''' + + generated_xml = self.service.__dbus_xml__ + + self.assertEqual( + XMLGenerator.prettify_xml(expected_xml), + XMLGenerator.prettify_xml(generated_xml) + ) + def _add_client(self, client_test): thread = Thread(None, client_test) thread.daemon = True @@ -548,3 +598,17 @@ self._add_client(test1) self._add_client(test2) self._run_test() + + def test_multiple_output_arguments(self): + """Call a DBus method with multiple output arguments.""" + self._set_service(ExampleInterface()) + + def test1(): + proxy = self._get_proxy() + self.assertEqual( + proxy.ReturnArgs(), + (0, False, "zero") + ) + + self._add_client(test1) + self._run_test() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/tests/test_interface.py new/dasbus-1.6/tests/test_interface.py --- old/dasbus-1.5/tests/test_interface.py 2021-05-03 16:35:50.000000000 +0200 +++ new/dasbus-1.6/tests/test_interface.py 2021-05-31 17:14:31.000000000 +0200 @@ -18,10 +18,10 @@ # import unittest -from dasbus.typing import Int, Str, List, Double, File, Tuple, Bool +from dasbus.typing import Int, Str, List, Double, File, Tuple, Bool, Dict from dasbus.server.interface import dbus_interface, dbus_class, dbus_signal, \ get_xml, DBusSpecificationGenerator, DBusSpecificationError, \ - accepts_additional_arguments + accepts_additional_arguments, returns_multiple_arguments from dasbus.xml import XMLGenerator @@ -762,3 +762,87 @@ ''' self._compare(AdditionalArgumentsClass, expected_xml) + + def test_multiple_output_arguments(self): + """Test interface methods with multiple output arguments.""" + + @dbus_interface("my.example.Interface") + class MultipleOutputArgumentsClass(object): + + @returns_multiple_arguments + def Method1(self): + pass + + @returns_multiple_arguments + def Method2(self) -> None: + pass + + @returns_multiple_arguments + def Method3(self) -> Tuple[Int, Bool, Str]: + pass + + @returns_multiple_arguments + def Method4(self) -> Tuple[Tuple[Int], List[Str]]: + pass + + expected_xml = ''' + <node> + <!--Specifies MultipleOutputArgumentsClass--> + <interface name="my.example.Interface"> + <method name="Method1"/> + <method name="Method2"/> + <method name="Method3"> + <arg direction="out" name="return_0" type="i"/> + <arg direction="out" name="return_1" type="b"/> + <arg direction="out" name="return_2" type="s"/> + </method> + <method name="Method4"> + <arg direction="out" name="return_0" type="(i)"/> + <arg direction="out" name="return_1" type="as"/> + </method> + </interface> + </node> + ''' + + self._compare(MultipleOutputArgumentsClass, expected_xml) + + def test_invalid_multiple_output_arguments(self): + """Test interface methods with invalid output arguments.""" + + class InvalidOutputArgumentsClass(object): + + @returns_multiple_arguments + def Method1(self) -> Int: + pass + + @returns_multiple_arguments + def Method2(self) -> List[Bool]: + pass + + @returns_multiple_arguments + def Method3(self) -> Dict[Str, Bool]: + pass + + @returns_multiple_arguments + def Method4(self) -> Tuple[Int]: + pass + + self._check_invalid_method( + InvalidOutputArgumentsClass.Method1, + "Expected a tuple of multiple arguments." + ) + + self._check_invalid_method( + InvalidOutputArgumentsClass.Method2, + "Expected a tuple of multiple arguments." + ) + + self._check_invalid_method( + InvalidOutputArgumentsClass.Method3, + "Expected a tuple of multiple arguments." + ) + + self._check_invalid_method( + InvalidOutputArgumentsClass.Method4, + "Expected a tuple of more than one argument." + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/tests/test_server.py new/dasbus-1.6/tests/test_server.py --- old/dasbus-1.5/tests/test_server.py 2021-05-03 16:35:50.000000000 +0200 +++ new/dasbus-1.6/tests/test_server.py 2021-05-31 17:14:31.000000000 +0200 @@ -145,6 +145,10 @@ <arg direction="in" name="y" type="o"/> <arg direction="out" name="return" type="(ib)"/> </method> + <method name="Method5"> + <arg direction="out" name="return" type="i"/> + <arg direction="out" name="return" type="b"/> + </method> </interface> </node> """) @@ -178,6 +182,14 @@ ) self.object.Method4.assert_called_once_with([1.2, 2.3], "/my/path") + self.object.Method5.return_value = (1, True) + self._call_method( + "Interface", + "Method5", + reply=get_variant("(ib)", (1, True)) + ) + self.object.Method5.assert_called_once_with() + self._call_method_with_error( "Interface", "MethodInvalid", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dasbus-1.5/tests/test_typing.py new/dasbus-1.6/tests/test_typing.py --- old/dasbus-1.5/tests/test_typing.py 2021-05-03 16:35:50.000000000 +0200 +++ new/dasbus-1.6/tests/test_typing.py 2021-05-31 17:14:31.000000000 +0200 @@ -24,7 +24,7 @@ from dasbus.typing import get_dbus_type, is_base_type, get_native, \ get_variant, get_variant_type, Int, Int16, Int32, Int64, UInt16, UInt32, \ UInt64, Bool, Byte, Str, Dict, List, Tuple, Variant, Double, ObjPath, \ - File, unwrap_variant, get_type_name + File, unwrap_variant, get_type_name, is_tuple_of_one, get_type_arguments import gi gi.require_version("GLib", "2.0") @@ -53,6 +53,16 @@ self.assertIsInstance(variant_type, GLib.VariantType) self.assertTrue(expected_type.equal(variant_type)) + # Test the is_tuple_of_one function. + expected_value = is_base_type(type_hint, Tuple) \ + and len(get_type_arguments(type_hint)) == 1 + + self.assertEqual(is_tuple_of_one(type_hint), expected_value) + self.assertEqual(is_tuple_of_one(expected_string), expected_value) + + self.assertTrue(is_tuple_of_one(Tuple[type_hint])) + self.assertTrue(is_tuple_of_one("({})".format(expected_string))) + def test_unknown(self): """Test the unknown type."""